@inspecto-dev/cli 0.2.0-alpha.5 → 0.3.0-alpha.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/.turbo/turbo-build.log +19 -20
- package/CHANGELOG.md +22 -0
- package/README.md +93 -11
- package/bin/inspecto.js +5 -1
- package/dist/bin.d.ts +5 -1
- package/dist/bin.js +530 -49
- package/dist/chunk-FZS2TLXQ.js +3140 -0
- package/dist/index.d.ts +233 -2
- package/dist/index.js +17 -3
- package/package.json +3 -2
- package/src/bin.ts +286 -66
- package/src/commands/apply.ts +118 -0
- package/src/commands/detect.ts +59 -0
- package/src/commands/doctor.ts +225 -72
- package/src/commands/init.ts +143 -183
- package/src/commands/integration-install.ts +452 -0
- package/src/commands/onboard.ts +50 -0
- package/src/commands/plan.ts +41 -0
- package/src/detect/build-tool.ts +107 -3
- package/src/index.ts +17 -2
- package/src/inject/ast-injector.ts +17 -6
- package/src/inject/extension.ts +40 -22
- package/src/inject/gitignore.ts +10 -3
- package/src/instructions.ts +60 -46
- package/src/onboarding/apply.ts +364 -0
- package/src/onboarding/context.ts +36 -0
- package/src/onboarding/planner.ts +284 -0
- package/src/onboarding/session.ts +434 -0
- package/src/onboarding/target-resolution.ts +116 -0
- package/src/prompts.ts +54 -11
- package/src/types.ts +184 -0
- package/src/utils/fs.ts +2 -1
- package/src/utils/logger.ts +9 -0
- package/src/utils/output.ts +40 -0
- package/tests/apply.test.ts +583 -0
- package/tests/ast-injector.test.ts +50 -0
- package/tests/build-tool.test.ts +3 -5
- package/tests/detect.test.ts +94 -0
- package/tests/doctor.test.ts +224 -0
- package/tests/init.test.ts +364 -0
- package/tests/install-wrapper.test.ts +76 -0
- package/tests/instructions.test.ts +61 -0
- package/tests/integration-install.test.ts +294 -0
- package/tests/logger.test.ts +100 -0
- package/tests/onboard.test.ts +258 -0
- package/tests/plan.test.ts +713 -0
- package/tests/workspace-build-tool.test.ts +75 -0
- package/.turbo/turbo-test.log +0 -16
- package/dist/chunk-MIHQGC3L.js +0 -1720
package/dist/bin.js
CHANGED
|
@@ -1,65 +1,546 @@
|
|
|
1
1
|
import {
|
|
2
|
+
apply,
|
|
3
|
+
detect,
|
|
2
4
|
doctor,
|
|
5
|
+
exists,
|
|
3
6
|
init,
|
|
4
7
|
log,
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
onboard,
|
|
9
|
+
plan,
|
|
10
|
+
reportCommandError,
|
|
11
|
+
teardown,
|
|
12
|
+
writeFile
|
|
13
|
+
} from "./chunk-FZS2TLXQ.js";
|
|
7
14
|
|
|
8
15
|
// src/bin.ts
|
|
9
16
|
import { cac } from "cac";
|
|
17
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10
18
|
import { createRequire } from "module";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
|
|
20
|
+
// src/commands/integration-install.ts
|
|
21
|
+
import fs from "fs/promises";
|
|
22
|
+
import { homedir } from "os";
|
|
23
|
+
import path from "path";
|
|
24
|
+
import { fileURLToPath } from "url";
|
|
25
|
+
var REPO_RAW_BASE = "https://raw.githubusercontent.com/inspecto-dev/inspecto/main";
|
|
26
|
+
var INTEGRATION_MANIFESTS = [
|
|
27
|
+
{
|
|
28
|
+
assistant: "codex",
|
|
29
|
+
type: "native-skill",
|
|
30
|
+
installTarget: "~/.codex/skills/",
|
|
31
|
+
preferredInstall: "npx @inspecto-dev/cli integrations install codex",
|
|
32
|
+
cliSupported: true
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
assistant: "claude-code",
|
|
36
|
+
type: "native-skill",
|
|
37
|
+
installTarget: ".claude/skills/ or ~/.claude/skills/",
|
|
38
|
+
preferredInstall: "npx @inspecto-dev/cli integrations install claude-code --scope project",
|
|
39
|
+
cliSupported: true
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
assistant: "copilot",
|
|
43
|
+
type: "instruction-template",
|
|
44
|
+
installTarget: ".github/copilot-instructions.md or AGENTS.md",
|
|
45
|
+
preferredInstall: "npx @inspecto-dev/cli integrations install copilot",
|
|
46
|
+
cliSupported: true
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
assistant: "cursor",
|
|
50
|
+
type: "rule-template",
|
|
51
|
+
installTarget: ".cursor/rules/inspecto-onboarding.mdc or AGENTS.md",
|
|
52
|
+
preferredInstall: "npx @inspecto-dev/cli integrations install cursor --mode rules",
|
|
53
|
+
cliSupported: true
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
assistant: "gemini",
|
|
57
|
+
type: "context-template",
|
|
58
|
+
installTarget: "GEMINI.md",
|
|
59
|
+
preferredInstall: "npx @inspecto-dev/cli integrations install gemini",
|
|
60
|
+
cliSupported: true
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
assistant: "trae",
|
|
64
|
+
type: "compatibility-template",
|
|
65
|
+
installTarget: "AGENTS.md",
|
|
66
|
+
preferredInstall: "npx @inspecto-dev/cli integrations install trae",
|
|
67
|
+
cliSupported: true
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
assistant: "coco",
|
|
71
|
+
type: "compatibility-template",
|
|
72
|
+
installTarget: "AGENTS.md",
|
|
73
|
+
preferredInstall: "npx @inspecto-dev/cli integrations install coco",
|
|
74
|
+
cliSupported: true
|
|
75
|
+
}
|
|
76
|
+
];
|
|
77
|
+
async function installIntegration(assistant, options = {}) {
|
|
78
|
+
const plan2 = resolveInstallPlan(assistant, options);
|
|
79
|
+
log.header("Inspecto Integration Install");
|
|
80
|
+
for (const asset of plan2.assets) {
|
|
81
|
+
if (await exists(asset.target) && !options.force) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`Refusing to overwrite existing file: ${asset.target}. Re-run with --force if you want to replace it.`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const downloadedAssets = [];
|
|
88
|
+
for (const asset of plan2.assets) {
|
|
89
|
+
const content = await loadAsset(asset);
|
|
90
|
+
downloadedAssets.push({ asset, content });
|
|
91
|
+
}
|
|
92
|
+
for (const { asset, content } of downloadedAssets) {
|
|
93
|
+
await writeFile(asset.target, content);
|
|
94
|
+
if (asset.executable) {
|
|
95
|
+
await fs.chmod(asset.target, 493);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
log.success(plan2.successMessage);
|
|
99
|
+
log.hint(plan2.nextStep);
|
|
100
|
+
}
|
|
101
|
+
function describeIntegration(assistant, options = {}) {
|
|
102
|
+
const manifest = getIntegrationManifest(assistant);
|
|
103
|
+
const targets = manifest.cliSupported ? resolveInstallPlan(assistant, options).assets.map((asset) => asset.target) : [manifest.installTarget];
|
|
104
|
+
return {
|
|
105
|
+
assistant: manifest.assistant,
|
|
106
|
+
type: manifest.type,
|
|
107
|
+
targets,
|
|
108
|
+
preferredInstall: manifest.preferredInstall,
|
|
109
|
+
cliSupported: manifest.cliSupported
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function printIntegrationList() {
|
|
113
|
+
log.header("Inspecto Integrations");
|
|
114
|
+
for (const manifest of INTEGRATION_MANIFESTS) {
|
|
115
|
+
const support = manifest.cliSupported ? "CLI" : "native installer";
|
|
116
|
+
log.info(`${manifest.assistant} \u2014 ${manifest.type} \u2014 ${manifest.installTarget} \u2014 ${support}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function printIntegrationPath(assistant, options = {}) {
|
|
120
|
+
const description = describeIntegration(assistant, options);
|
|
121
|
+
log.header(`Inspecto Integration Paths: ${description.assistant}`);
|
|
122
|
+
for (const target of description.targets) {
|
|
123
|
+
log.info(target);
|
|
124
|
+
}
|
|
125
|
+
if (description.cliSupported) {
|
|
126
|
+
log.hint(`Preferred install: ${description.preferredInstall}`);
|
|
127
|
+
} else {
|
|
128
|
+
log.hint(`Native install required: ${description.preferredInstall}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function resolveInstallPlan(assistant, options) {
|
|
132
|
+
switch (assistant) {
|
|
133
|
+
case "codex":
|
|
134
|
+
return resolveCodexPlan(options);
|
|
135
|
+
case "claude-code":
|
|
136
|
+
return resolveClaudeCodePlan(options);
|
|
137
|
+
case "copilot":
|
|
138
|
+
return resolveCopilotPlan(options);
|
|
139
|
+
case "cursor":
|
|
140
|
+
return resolveCursorPlan(options);
|
|
141
|
+
case "gemini":
|
|
142
|
+
return {
|
|
143
|
+
assets: [
|
|
144
|
+
{
|
|
145
|
+
source: `${REPO_RAW_BASE}/assistant-integrations/gemini/GEMINI.md`,
|
|
146
|
+
target: "GEMINI.md",
|
|
147
|
+
localSource: "assistant-integrations/gemini/GEMINI.md"
|
|
148
|
+
}
|
|
149
|
+
],
|
|
150
|
+
successMessage: "Installed Gemini context to GEMINI.md",
|
|
151
|
+
nextStep: "Start a new Gemini CLI session."
|
|
152
|
+
};
|
|
153
|
+
case "trae":
|
|
154
|
+
return {
|
|
155
|
+
assets: [
|
|
156
|
+
{
|
|
157
|
+
source: `${REPO_RAW_BASE}/assistant-integrations/trae/AGENTS.md`,
|
|
158
|
+
target: "AGENTS.md",
|
|
159
|
+
localSource: "assistant-integrations/trae/AGENTS.md"
|
|
160
|
+
}
|
|
161
|
+
],
|
|
162
|
+
successMessage: "Installed Trae compatibility instructions to AGENTS.md",
|
|
163
|
+
nextStep: "Open a new Trae chat."
|
|
164
|
+
};
|
|
165
|
+
case "coco":
|
|
166
|
+
return {
|
|
167
|
+
assets: [
|
|
168
|
+
{
|
|
169
|
+
source: `${REPO_RAW_BASE}/assistant-integrations/coco/AGENTS.md`,
|
|
170
|
+
target: "AGENTS.md",
|
|
171
|
+
localSource: "assistant-integrations/coco/AGENTS.md"
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
successMessage: "Installed Coco compatibility instructions to AGENTS.md",
|
|
175
|
+
nextStep: "Start a new Coco session."
|
|
176
|
+
};
|
|
177
|
+
default:
|
|
178
|
+
throw new Error(`Unknown assistant: ${assistant}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function getIntegrationManifest(assistant) {
|
|
182
|
+
const manifest = INTEGRATION_MANIFESTS.find((item) => item.assistant === assistant);
|
|
183
|
+
if (!manifest) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
`Unknown assistant: ${assistant}. Run 'inspecto integrations list' to see available targets.`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
return manifest;
|
|
189
|
+
}
|
|
190
|
+
function resolveCodexPlan(options) {
|
|
191
|
+
if (options.scope !== void 0) {
|
|
192
|
+
throw new Error("`--scope` is not supported for codex.");
|
|
193
|
+
}
|
|
194
|
+
if (options.mode !== void 0) {
|
|
195
|
+
throw new Error("`--mode` is not supported for codex.");
|
|
196
|
+
}
|
|
197
|
+
const baseDir = path.join(homedir(), ".codex/skills/inspecto-onboarding-codex");
|
|
198
|
+
return {
|
|
199
|
+
assets: [
|
|
200
|
+
{
|
|
201
|
+
source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-codex/SKILL.md`,
|
|
202
|
+
target: path.join(baseDir, "SKILL.md"),
|
|
203
|
+
localSource: "skills/inspecto-onboarding-codex/SKILL.md"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-codex/agents/openai.yaml`,
|
|
207
|
+
target: path.join(baseDir, "agents/openai.yaml"),
|
|
208
|
+
localSource: "skills/inspecto-onboarding-codex/agents/openai.yaml"
|
|
25
209
|
},
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
210
|
+
{
|
|
211
|
+
source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-codex/scripts/run-inspecto.sh`,
|
|
212
|
+
target: path.join(baseDir, "scripts/run-inspecto.sh"),
|
|
213
|
+
executable: true,
|
|
214
|
+
localSource: "skills/inspecto-onboarding-codex/scripts/run-inspecto.sh"
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
successMessage: `Installed Codex skill to ${baseDir}`,
|
|
218
|
+
nextStep: "Restart Codex or start a new Codex session to load the skill."
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function resolveClaudeCodePlan(options) {
|
|
222
|
+
const scope = options.scope ?? "project";
|
|
223
|
+
const unsupportedMode = options.mode !== void 0;
|
|
224
|
+
if (unsupportedMode) {
|
|
225
|
+
throw new Error(
|
|
226
|
+
"`--mode` is not supported for claude-code. Use `--scope project|user` instead."
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
if (scope !== "project" && scope !== "user") {
|
|
230
|
+
throw new Error(`Unknown Claude Code scope: ${scope}`);
|
|
231
|
+
}
|
|
232
|
+
const baseDir = scope === "user" ? path.join(homedir(), ".claude/skills/inspecto-onboarding-claude-code") : ".claude/skills/inspecto-onboarding-claude-code";
|
|
233
|
+
return {
|
|
234
|
+
assets: [
|
|
235
|
+
{
|
|
236
|
+
source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-claude-code/SKILL.md`,
|
|
237
|
+
target: path.join(baseDir, "SKILL.md"),
|
|
238
|
+
localSource: "skills/inspecto-onboarding-claude-code/SKILL.md"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-claude-code/agents/openai.yaml`,
|
|
242
|
+
target: path.join(baseDir, "agents/openai.yaml"),
|
|
243
|
+
localSource: "skills/inspecto-onboarding-claude-code/agents/openai.yaml"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-claude-code/scripts/run-inspecto.sh`,
|
|
247
|
+
target: path.join(baseDir, "scripts/run-inspecto.sh"),
|
|
248
|
+
executable: true,
|
|
249
|
+
localSource: "skills/inspecto-onboarding-claude-code/scripts/run-inspecto.sh"
|
|
250
|
+
}
|
|
251
|
+
],
|
|
252
|
+
successMessage: `Installed Claude Code skill to ${baseDir}`,
|
|
253
|
+
nextStep: "Restart Claude Code to load the new skill."
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function resolveCopilotPlan(options) {
|
|
257
|
+
const mode = options.mode ?? "instructions";
|
|
258
|
+
if (options.scope !== void 0) {
|
|
259
|
+
throw new Error(
|
|
260
|
+
"`--scope` is not supported for copilot. Use `--mode instructions|agents` instead."
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
switch (mode) {
|
|
264
|
+
case "instructions":
|
|
265
|
+
return {
|
|
266
|
+
assets: [
|
|
267
|
+
{
|
|
268
|
+
source: `${REPO_RAW_BASE}/assistant-integrations/copilot/.github/copilot-instructions.md`,
|
|
269
|
+
target: ".github/copilot-instructions.md",
|
|
270
|
+
localSource: "assistant-integrations/copilot/.github/copilot-instructions.md"
|
|
271
|
+
}
|
|
272
|
+
],
|
|
273
|
+
successMessage: "Installed Copilot instructions to .github/copilot-instructions.md",
|
|
274
|
+
nextStep: "Open a new Copilot chat or agent session."
|
|
275
|
+
};
|
|
276
|
+
case "agents":
|
|
277
|
+
return {
|
|
278
|
+
assets: [
|
|
279
|
+
{
|
|
280
|
+
source: `${REPO_RAW_BASE}/assistant-integrations/copilot/AGENTS.md`,
|
|
281
|
+
target: "AGENTS.md",
|
|
282
|
+
localSource: "assistant-integrations/copilot/AGENTS.md"
|
|
283
|
+
}
|
|
284
|
+
],
|
|
285
|
+
successMessage: "Installed Copilot compatibility instructions to AGENTS.md",
|
|
286
|
+
nextStep: "Open a new Copilot chat or agent session."
|
|
287
|
+
};
|
|
288
|
+
default:
|
|
289
|
+
throw new Error(`Unknown Copilot mode: ${mode}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function resolveCursorPlan(options) {
|
|
293
|
+
const mode = options.mode ?? "rules";
|
|
294
|
+
if (options.scope !== void 0) {
|
|
295
|
+
throw new Error("`--scope` is not supported for cursor. Use `--mode rules|agents` instead.");
|
|
296
|
+
}
|
|
297
|
+
switch (mode) {
|
|
298
|
+
case "rules":
|
|
299
|
+
return {
|
|
300
|
+
assets: [
|
|
301
|
+
{
|
|
302
|
+
source: `${REPO_RAW_BASE}/assistant-integrations/cursor/.cursor/rules/inspecto-onboarding.mdc`,
|
|
303
|
+
target: ".cursor/rules/inspecto-onboarding.mdc",
|
|
304
|
+
localSource: "assistant-integrations/cursor/.cursor/rules/inspecto-onboarding.mdc"
|
|
305
|
+
}
|
|
306
|
+
],
|
|
307
|
+
successMessage: "Installed Cursor rule to .cursor/rules/inspecto-onboarding.mdc",
|
|
308
|
+
nextStep: "Open a new Cursor chat."
|
|
309
|
+
};
|
|
310
|
+
case "agents":
|
|
311
|
+
return {
|
|
312
|
+
assets: [
|
|
313
|
+
{
|
|
314
|
+
source: `${REPO_RAW_BASE}/assistant-integrations/cursor/AGENTS.md`,
|
|
315
|
+
target: "AGENTS.md",
|
|
316
|
+
localSource: "assistant-integrations/cursor/AGENTS.md"
|
|
317
|
+
}
|
|
318
|
+
],
|
|
319
|
+
successMessage: "Installed Cursor compatibility instructions to AGENTS.md",
|
|
320
|
+
nextStep: "Open a new Cursor chat."
|
|
321
|
+
};
|
|
322
|
+
default:
|
|
323
|
+
throw new Error(`Unknown Cursor mode: ${mode}`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
async function loadAsset(asset) {
|
|
327
|
+
if (asset.localSource) {
|
|
328
|
+
const localPath = await resolveBundledAssetPath(asset.localSource);
|
|
329
|
+
if (localPath) {
|
|
330
|
+
return await fs.readFile(localPath, "utf-8");
|
|
32
331
|
}
|
|
33
|
-
process.exit(1);
|
|
34
332
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
333
|
+
return await downloadAsset(asset.source);
|
|
334
|
+
}
|
|
335
|
+
async function resolveBundledAssetPath(relativePath) {
|
|
336
|
+
const startDir = path.dirname(fileURLToPath(import.meta.url));
|
|
337
|
+
let currentDir = startDir;
|
|
338
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
339
|
+
const candidate = path.join(currentDir, relativePath);
|
|
340
|
+
if (await exists(candidate)) {
|
|
341
|
+
return candidate;
|
|
43
342
|
}
|
|
44
|
-
|
|
343
|
+
const parent = path.dirname(currentDir);
|
|
344
|
+
if (parent === currentDir) break;
|
|
345
|
+
currentDir = parent;
|
|
45
346
|
}
|
|
46
|
-
|
|
47
|
-
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
async function downloadAsset(source) {
|
|
350
|
+
let response;
|
|
48
351
|
try {
|
|
49
|
-
await
|
|
50
|
-
} catch (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
352
|
+
response = await fetch(source);
|
|
353
|
+
} catch (error) {
|
|
354
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
355
|
+
throw new Error(`Failed to download ${source}: ${reason}`);
|
|
356
|
+
}
|
|
357
|
+
if (!response.ok) {
|
|
358
|
+
throw new Error(`Failed to download ${source}: ${response.status} ${response.statusText}`);
|
|
359
|
+
}
|
|
360
|
+
return await response.text();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// src/bin.ts
|
|
364
|
+
var require2 = createRequire(import.meta.url);
|
|
365
|
+
var { version } = require2("../package.json");
|
|
366
|
+
var integrationScopes = ["project", "user"];
|
|
367
|
+
var integrationModes = ["instructions", "agents", "rules"];
|
|
368
|
+
function exitWithError(error, options = {}) {
|
|
369
|
+
reportCommandError(error, {
|
|
370
|
+
debug: options.debug ?? false,
|
|
371
|
+
json: options.json ?? false
|
|
372
|
+
});
|
|
64
373
|
process.exit(1);
|
|
65
374
|
}
|
|
375
|
+
function createCli(_argv = process.argv) {
|
|
376
|
+
const cli = cac("inspecto");
|
|
377
|
+
cli.command("init", "Set up Inspecto in your project").option("--shared", "Share .inspecto/settings.json with your team via Git", { default: false }).option("--skip-install", "Skip npm dependency installation", { default: false }).option("--dry-run", "Preview changes without modifying files", { default: false }).option("--provider <provider>", "Set default provider (e.g. copilot, claude-code)").option("--no-extension", "Skip VS Code extension installation", { default: false }).option("--packages <names>", "(Monorepo) Comma-separated list of packages to inject").option("--force", "Force initialization even if environment is unsupported", {
|
|
378
|
+
default: false
|
|
379
|
+
}).option("--debug", "Enable debug mode to show full error traces", { default: false }).action(async (options) => {
|
|
380
|
+
try {
|
|
381
|
+
await init({
|
|
382
|
+
shared: options.shared ?? false,
|
|
383
|
+
skipInstall: options.skipInstall ?? false,
|
|
384
|
+
dryRun: options.dryRun ?? false,
|
|
385
|
+
...options.provider && { provider: options.provider },
|
|
386
|
+
noExtension: options.noExtension ?? false,
|
|
387
|
+
...options.packages && {
|
|
388
|
+
packages: options.packages.split(",").map((s) => s.trim())
|
|
389
|
+
},
|
|
390
|
+
force: options.force ?? false
|
|
391
|
+
});
|
|
392
|
+
} catch (error) {
|
|
393
|
+
exitWithError(error, options);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
cli.command("doctor", "Diagnose your Inspecto installation").option("--json", "Print machine-readable JSON output", { default: false }).option("--debug", "Enable debug mode to show full error traces", { default: false }).action(async (options) => {
|
|
397
|
+
try {
|
|
398
|
+
await doctor({ json: options.json ?? false });
|
|
399
|
+
} catch (error) {
|
|
400
|
+
exitWithError(error, options);
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
cli.command("onboard", "Run assistant-oriented Inspecto onboarding in one structured flow").option("--json", "Print machine-readable JSON output", { default: false }).option("--target <packagePath>", "Select a monorepo target package explicitly").option("--yes", "Accept a lightweight confirmation gate automatically", { default: false }).option("--shared", "Write shared Inspecto settings instead of local-only settings").option("--skip-install", "Skip npm dependency installation").option("--dry-run", "Preview changes without modifying files").option("--no-extension", "Skip IDE extension installation").option("--debug", "Enable debug mode to show full error traces", { default: false }).action(async (options) => {
|
|
404
|
+
try {
|
|
405
|
+
await onboard({
|
|
406
|
+
json: options.json ?? false,
|
|
407
|
+
...options.target && { target: options.target },
|
|
408
|
+
yes: options.yes ?? false,
|
|
409
|
+
...options.shared !== void 0 && { shared: options.shared },
|
|
410
|
+
...options.skipInstall !== void 0 && { skipInstall: options.skipInstall },
|
|
411
|
+
...options.dryRun !== void 0 && { dryRun: options.dryRun },
|
|
412
|
+
...options.extension === false && { noExtension: true }
|
|
413
|
+
});
|
|
414
|
+
} catch (error) {
|
|
415
|
+
exitWithError(error, options);
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
cli.command("detect", "Detect whether the current project can be onboarded automatically").option("--json", "Print machine-readable JSON output", { default: false }).option("--debug", "Enable debug mode to show full error traces", { default: false }).action(async (options) => {
|
|
419
|
+
try {
|
|
420
|
+
await detect(options.json ?? false);
|
|
421
|
+
} catch (error) {
|
|
422
|
+
exitWithError(error, options);
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
cli.command("plan", "Preview the onboarding plan for the current project").option("--json", "Print machine-readable JSON output", { default: false }).option("--debug", "Enable debug mode to show full error traces", { default: false }).action(async (options) => {
|
|
426
|
+
try {
|
|
427
|
+
await plan(options.json ?? false);
|
|
428
|
+
} catch (error) {
|
|
429
|
+
exitWithError(error, options);
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
cli.command("apply", "Apply the onboarding plan to the current project").option("--json", "Print machine-readable JSON output", { default: false }).option("--shared", "Write shared Inspecto settings instead of local-only settings").option("--skip-install", "Skip npm dependency installation").option("--dry-run", "Preview changes without modifying files").option("--no-extension", "Skip IDE extension installation").option("--debug", "Enable debug mode to show full error traces", { default: false }).action(async (options) => {
|
|
433
|
+
try {
|
|
434
|
+
await apply({
|
|
435
|
+
json: options.json ?? false,
|
|
436
|
+
...options.shared !== void 0 && { shared: options.shared },
|
|
437
|
+
...options.skipInstall !== void 0 && { skipInstall: options.skipInstall },
|
|
438
|
+
...options.dryRun !== void 0 && { dryRun: options.dryRun },
|
|
439
|
+
...options.extension === false && { noExtension: true }
|
|
440
|
+
});
|
|
441
|
+
} catch (error) {
|
|
442
|
+
exitWithError(error, options);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
cli.command("teardown", "Remove Inspecto from your project").option("--debug", "Enable debug mode to show full error traces", { default: false }).action(async (options) => {
|
|
446
|
+
try {
|
|
447
|
+
await teardown();
|
|
448
|
+
} catch (error) {
|
|
449
|
+
exitWithError(error, options);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
cli.command("integrations [...args]", "Manage assistant integration assets").option(
|
|
453
|
+
"--scope <scope>",
|
|
454
|
+
"Set install scope for supported assistants (e.g. claude-code: project|user)"
|
|
455
|
+
).option(
|
|
456
|
+
"--mode <mode>",
|
|
457
|
+
"Set install mode for supported assistants (e.g. copilot: instructions|agents)"
|
|
458
|
+
).option("--force", "Overwrite existing integration files", { default: false }).option("--debug", "Enable debug mode to show full error traces", { default: false }).action(async (args, options) => {
|
|
459
|
+
try {
|
|
460
|
+
const [subcommand, assistant, ...rest] = args;
|
|
461
|
+
const integrationOptions = buildIntegrationOptions(options);
|
|
462
|
+
if (subcommand === "list") {
|
|
463
|
+
if (assistant || rest.length > 0 || options.scope || options.mode || options.force) {
|
|
464
|
+
throw new Error(
|
|
465
|
+
"The `list` subcommand does not accept assistant names, --scope, --mode, or --force."
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
printIntegrationList();
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (subcommand === "path" && assistant) {
|
|
472
|
+
if (rest.length > 0) {
|
|
473
|
+
throw new Error("The `path` subcommand accepts exactly one assistant argument.");
|
|
474
|
+
}
|
|
475
|
+
if (options.force) {
|
|
476
|
+
throw new Error("The `path` subcommand does not support `--force`.");
|
|
477
|
+
}
|
|
478
|
+
printIntegrationPath(assistant, integrationOptions);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (subcommand !== "install" || !assistant) {
|
|
482
|
+
throw new Error(
|
|
483
|
+
[
|
|
484
|
+
"Usage:",
|
|
485
|
+
" inspecto integrations list",
|
|
486
|
+
" inspecto integrations path <assistant> [--scope <scope>] [--mode <mode>]",
|
|
487
|
+
" inspecto integrations install <assistant> [--scope <scope>] [--mode <mode>] [--force]"
|
|
488
|
+
].join("\n")
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
if (rest.length > 0) {
|
|
492
|
+
throw new Error("The `install` subcommand accepts exactly one assistant argument.");
|
|
493
|
+
}
|
|
494
|
+
await installIntegration(assistant, {
|
|
495
|
+
...integrationOptions,
|
|
496
|
+
force: options.force ?? false
|
|
497
|
+
});
|
|
498
|
+
} catch (error) {
|
|
499
|
+
exitWithError(error, options);
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
cli.help();
|
|
503
|
+
cli.version(version);
|
|
504
|
+
return cli;
|
|
505
|
+
}
|
|
506
|
+
function buildIntegrationOptions(options) {
|
|
507
|
+
const resolved = {};
|
|
508
|
+
if (options.scope) {
|
|
509
|
+
if (isIntegrationScope(options.scope)) {
|
|
510
|
+
resolved.scope = options.scope;
|
|
511
|
+
} else {
|
|
512
|
+
throw new Error(`Unknown integration scope: ${options.scope}`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (options.mode) {
|
|
516
|
+
if (isIntegrationMode(options.mode)) {
|
|
517
|
+
resolved.mode = options.mode;
|
|
518
|
+
} else {
|
|
519
|
+
throw new Error(`Unknown integration mode: ${options.mode}`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return resolved;
|
|
523
|
+
}
|
|
524
|
+
function isIntegrationScope(value) {
|
|
525
|
+
return integrationScopes.includes(value);
|
|
526
|
+
}
|
|
527
|
+
function isIntegrationMode(value) {
|
|
528
|
+
return integrationModes.includes(value);
|
|
529
|
+
}
|
|
530
|
+
async function runCli(argv = process.argv) {
|
|
531
|
+
const cli = createCli(argv);
|
|
532
|
+
const parsedArgv = [...argv];
|
|
533
|
+
try {
|
|
534
|
+
await cli.parse(parsedArgv);
|
|
535
|
+
} catch (error) {
|
|
536
|
+
exitWithError(error, { json: argv.includes("--json") });
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
var entryPath = process.argv[1];
|
|
540
|
+
if (entryPath && fileURLToPath2(import.meta.url) === entryPath) {
|
|
541
|
+
void runCli();
|
|
542
|
+
}
|
|
543
|
+
export {
|
|
544
|
+
createCli,
|
|
545
|
+
runCli
|
|
546
|
+
};
|