@spec0/cli 0.1.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.md +67 -0
- package/LICENSE +21 -0
- package/README.md +235 -0
- package/dist/commands/api/changelog.d.ts +9 -0
- package/dist/commands/api/changelog.d.ts.map +1 -0
- package/dist/commands/api/changelog.js +144 -0
- package/dist/commands/api/changelog.js.map +1 -0
- package/dist/commands/api/index.d.ts +6 -0
- package/dist/commands/api/index.d.ts.map +1 -0
- package/dist/commands/api/index.js +13 -0
- package/dist/commands/api/index.js.map +1 -0
- package/dist/commands/api/list.d.ts +10 -0
- package/dist/commands/api/list.d.ts.map +1 -0
- package/dist/commands/api/list.js +79 -0
- package/dist/commands/api/list.js.map +1 -0
- package/dist/commands/api/show.d.ts +9 -0
- package/dist/commands/api/show.d.ts.map +1 -0
- package/dist/commands/api/show.js +88 -0
- package/dist/commands/api/show.js.map +1 -0
- package/dist/commands/auth.d.ts +6 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +166 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/ci/generate.d.ts +10 -0
- package/dist/commands/ci/generate.d.ts.map +1 -0
- package/dist/commands/ci/generate.js +72 -0
- package/dist/commands/ci/generate.js.map +1 -0
- package/dist/commands/ci/index.d.ts +3 -0
- package/dist/commands/ci/index.d.ts.map +1 -0
- package/dist/commands/ci/index.js +6 -0
- package/dist/commands/ci/index.js.map +1 -0
- package/dist/commands/commands.d.ts +19 -0
- package/dist/commands/commands.d.ts.map +1 -0
- package/dist/commands/commands.js +127 -0
- package/dist/commands/commands.js.map +1 -0
- package/dist/commands/diff.d.ts +6 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +102 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/doctor.d.ts +11 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +54 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +67 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +6 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +109 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/log.d.ts +6 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +95 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/mcp.d.ts +6 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +59 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/mock/create.d.ts +14 -0
- package/dist/commands/mock/create.d.ts.map +1 -0
- package/dist/commands/mock/create.js +75 -0
- package/dist/commands/mock/create.js.map +1 -0
- package/dist/commands/mock/index.d.ts +9 -0
- package/dist/commands/mock/index.d.ts.map +1 -0
- package/dist/commands/mock/index.js +18 -0
- package/dist/commands/mock/index.js.map +1 -0
- package/dist/commands/mock/list.d.ts +8 -0
- package/dist/commands/mock/list.d.ts.map +1 -0
- package/dist/commands/mock/list.js +52 -0
- package/dist/commands/mock/list.js.map +1 -0
- package/dist/commands/mock/show.d.ts +9 -0
- package/dist/commands/mock/show.d.ts.map +1 -0
- package/dist/commands/mock/show.js +68 -0
- package/dist/commands/mock/show.js.map +1 -0
- package/dist/commands/mock/url.d.ts +10 -0
- package/dist/commands/mock/url.d.ts.map +1 -0
- package/dist/commands/mock/url.js +42 -0
- package/dist/commands/mock/url.js.map +1 -0
- package/dist/commands/mock.d.ts +6 -0
- package/dist/commands/mock.d.ts.map +1 -0
- package/dist/commands/mock.js +116 -0
- package/dist/commands/mock.js.map +1 -0
- package/dist/commands/publish.d.ts +11 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +242 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/pull.d.ts +6 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +62 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +18 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +302 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/register.d.ts +6 -0
- package/dist/commands/register.d.ts.map +1 -0
- package/dist/commands/register.js +213 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/search.d.ts +6 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +58 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +86 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync-status.d.ts +14 -0
- package/dist/commands/sync-status.d.ts.map +1 -0
- package/dist/commands/sync-status.js +119 -0
- package/dist/commands/sync-status.js.map +1 -0
- package/dist/commands/team.d.ts +6 -0
- package/dist/commands/team.d.ts.map +1 -0
- package/dist/commands/team.js +30 -0
- package/dist/commands/team.js.map +1 -0
- package/dist/commands/version.d.ts +6 -0
- package/dist/commands/version.d.ts.map +1 -0
- package/dist/commands/version.js +31 -0
- package/dist/commands/version.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/agent-mode.d.ts +25 -0
- package/dist/lib/agent-mode.d.ts.map +1 -0
- package/dist/lib/agent-mode.js +36 -0
- package/dist/lib/agent-mode.js.map +1 -0
- package/dist/lib/api-client.d.ts +37 -0
- package/dist/lib/api-client.d.ts.map +1 -0
- package/dist/lib/api-client.js +144 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/auth-context.d.ts +18 -0
- package/dist/lib/auth-context.d.ts.map +1 -0
- package/dist/lib/auth-context.js +48 -0
- package/dist/lib/auth-context.js.map +1 -0
- package/dist/lib/breaking-change.d.ts +12 -0
- package/dist/lib/breaking-change.d.ts.map +1 -0
- package/dist/lib/breaking-change.js +10 -0
- package/dist/lib/breaking-change.js.map +1 -0
- package/dist/lib/ci-detect.d.ts +33 -0
- package/dist/lib/ci-detect.d.ts.map +1 -0
- package/dist/lib/ci-detect.js +136 -0
- package/dist/lib/ci-detect.js.map +1 -0
- package/dist/lib/cli-spec-path.d.ts +6 -0
- package/dist/lib/cli-spec-path.d.ts.map +1 -0
- package/dist/lib/cli-spec-path.js +34 -0
- package/dist/lib/cli-spec-path.js.map +1 -0
- package/dist/lib/codeowners.d.ts +11 -0
- package/dist/lib/codeowners.d.ts.map +1 -0
- package/dist/lib/codeowners.js +43 -0
- package/dist/lib/codeowners.js.map +1 -0
- package/dist/lib/config.d.ts +24 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +49 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/deprecation.d.ts +17 -0
- package/dist/lib/deprecation.d.ts.map +1 -0
- package/dist/lib/deprecation.js +22 -0
- package/dist/lib/deprecation.js.map +1 -0
- package/dist/lib/doctor.d.ts +40 -0
- package/dist/lib/doctor.d.ts.map +1 -0
- package/dist/lib/doctor.js +107 -0
- package/dist/lib/doctor.js.map +1 -0
- package/dist/lib/exit-codes.d.ts +51 -0
- package/dist/lib/exit-codes.d.ts.map +1 -0
- package/dist/lib/exit-codes.js +78 -0
- package/dist/lib/exit-codes.js.map +1 -0
- package/dist/lib/lint.d.ts +18 -0
- package/dist/lib/lint.d.ts.map +1 -0
- package/dist/lib/lint.js +41 -0
- package/dist/lib/lint.js.map +1 -0
- package/dist/lib/local-config-yaml.d.ts +14 -0
- package/dist/lib/local-config-yaml.d.ts.map +1 -0
- package/dist/lib/local-config-yaml.js +29 -0
- package/dist/lib/local-config-yaml.js.map +1 -0
- package/dist/lib/output/index.d.ts +69 -0
- package/dist/lib/output/index.d.ts.map +1 -0
- package/dist/lib/output/index.js +120 -0
- package/dist/lib/output/index.js.map +1 -0
- package/dist/lib/output/table.d.ts +19 -0
- package/dist/lib/output/table.d.ts.map +1 -0
- package/dist/lib/output/table.js +48 -0
- package/dist/lib/output/table.js.map +1 -0
- package/dist/lib/output.d.ts +32 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +64 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/platform-defaults.d.ts +27 -0
- package/dist/lib/platform-defaults.d.ts.map +1 -0
- package/dist/lib/platform-defaults.js +36 -0
- package/dist/lib/platform-defaults.js.map +1 -0
- package/dist/lib/ref-resolver.d.ts +37 -0
- package/dist/lib/ref-resolver.d.ts.map +1 -0
- package/dist/lib/ref-resolver.js +56 -0
- package/dist/lib/ref-resolver.js.map +1 -0
- package/dist/lib/registry-ref.d.ts +10 -0
- package/dist/lib/registry-ref.d.ts.map +1 -0
- package/dist/lib/registry-ref.js +18 -0
- package/dist/lib/registry-ref.js.map +1 -0
- package/dist/lib/spec-finder.d.ts +6 -0
- package/dist/lib/spec-finder.d.ts.map +1 -0
- package/dist/lib/spec-finder.js +42 -0
- package/dist/lib/spec-finder.js.map +1 -0
- package/dist/lib/update-check.d.ts +12 -0
- package/dist/lib/update-check.d.ts.map +1 -0
- package/dist/lib/update-check.js +62 -0
- package/dist/lib/update-check.js.map +1 -0
- package/dist/lib/version.d.ts +17 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +33 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/lib/winspect-yaml.d.ts +14 -0
- package/dist/lib/winspect-yaml.d.ts.map +1 -0
- package/dist/lib/winspect-yaml.js +28 -0
- package/dist/lib/winspect-yaml.js.map +1 -0
- package/dist/types.d.ts +664 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +87 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spec0 diff — compare two OpenAPI specs (registry refs and/or local files)
|
|
3
|
+
*/
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { existsSync, readFileSync } from "fs";
|
|
6
|
+
import { createTwoFilesPatch } from "diff";
|
|
7
|
+
import { createOrgApiClient, is401, extractErrorMessage } from "../lib/api-client.js";
|
|
8
|
+
import { requireOrgContext } from "../lib/auth-context.js";
|
|
9
|
+
import { resolveRef } from "../lib/ref-resolver.js";
|
|
10
|
+
import { ExitCode, exit, exitCodeForHttpStatus } from "../lib/exit-codes.js";
|
|
11
|
+
async function loadSpecContent(token, ctx) {
|
|
12
|
+
const trimmed = token.trim();
|
|
13
|
+
if (existsSync(trimmed)) {
|
|
14
|
+
return readFileSync(trimmed, "utf-8");
|
|
15
|
+
}
|
|
16
|
+
const client = createOrgApiClient(ctx);
|
|
17
|
+
const parsed = resolveRef(trimmed);
|
|
18
|
+
if (parsed.kind !== "name" || !parsed.org) {
|
|
19
|
+
throw new Error(`Diff requires '<org>/<api>[@<tag>]' or a local file. Got '${trimmed}'.`);
|
|
20
|
+
}
|
|
21
|
+
const path = parsed.tag
|
|
22
|
+
? `/registry/${encodeURIComponent(parsed.org)}/${encodeURIComponent(parsed.api)}/versions/${encodeURIComponent(parsed.tag)}`
|
|
23
|
+
: `/registry/${encodeURIComponent(parsed.org)}/${encodeURIComponent(parsed.api)}?format=yaml`;
|
|
24
|
+
return client.getText(path);
|
|
25
|
+
}
|
|
26
|
+
async function breakingChangesViaBackend(ctx, leftContent, rightContent, leftLabel, rightLabel) {
|
|
27
|
+
const client = createOrgApiClient(ctx);
|
|
28
|
+
const result = await client.postMultipart("/api-management/cli/v1/diff", {
|
|
29
|
+
base: { content: leftContent, filename: leftLabel },
|
|
30
|
+
revision: { content: rightContent, filename: rightLabel },
|
|
31
|
+
});
|
|
32
|
+
if (!result.hasBreakingChanges) {
|
|
33
|
+
console.log(chalk.green("No breaking changes detected."));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log(chalk.red(`Breaking changes detected:`));
|
|
37
|
+
if (result.breakingChanges?.length) {
|
|
38
|
+
for (const bc of result.breakingChanges) {
|
|
39
|
+
const id = bc["id"] ?? bc["text"] ?? JSON.stringify(bc);
|
|
40
|
+
const level = bc["level"] ?? "";
|
|
41
|
+
const msg = bc["message"] ?? bc["text"] ?? "";
|
|
42
|
+
console.log(chalk.red(` [${level}] ${id}${msg ? ": " + msg : ""}`));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function registerDiffCommand(program) {
|
|
47
|
+
program
|
|
48
|
+
.command("diff")
|
|
49
|
+
.description("Diff two specs: each side is a file path or registry ref org/api[@tag] (latest if tag omitted)")
|
|
50
|
+
.argument("<a>", "Left: local path or org/api[@tag]")
|
|
51
|
+
.argument("<b>", "Right: local path or org/api[@tag]")
|
|
52
|
+
.option("--breaking-only", "Show breaking changes only (via backend oasdiff service)")
|
|
53
|
+
.option("--org <uuid>", "Org id override for registry fetches")
|
|
54
|
+
.action(async (a, b, opts) => {
|
|
55
|
+
let ctx;
|
|
56
|
+
try {
|
|
57
|
+
ctx = requireOrgContext(opts.org);
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
console.error(chalk.red(e.message));
|
|
61
|
+
exit(ExitCode.AUTH_MISSING);
|
|
62
|
+
}
|
|
63
|
+
let left;
|
|
64
|
+
let right;
|
|
65
|
+
try {
|
|
66
|
+
left = await loadSpecContent(a, ctx);
|
|
67
|
+
right = await loadSpecContent(b, ctx);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
if (is401(err)) {
|
|
71
|
+
console.error(chalk.red("Token invalid. Run 'spec0 auth login'."));
|
|
72
|
+
exit(ExitCode.AUTH_MISSING);
|
|
73
|
+
}
|
|
74
|
+
const status = err?.response?.statusCode;
|
|
75
|
+
console.error(chalk.red(`Failed to load spec: ${err.message}`));
|
|
76
|
+
exit(status ? exitCodeForHttpStatus(status) : ExitCode.GENERIC);
|
|
77
|
+
}
|
|
78
|
+
if (opts.breakingOnly) {
|
|
79
|
+
try {
|
|
80
|
+
await breakingChangesViaBackend(ctx, left, right, a, b);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
if (is401(err)) {
|
|
84
|
+
console.error(chalk.red("Token invalid. Run 'spec0 auth login'."));
|
|
85
|
+
exit(ExitCode.AUTH_MISSING);
|
|
86
|
+
}
|
|
87
|
+
const status = err?.response?.statusCode;
|
|
88
|
+
const msg = extractErrorMessage(err) ?? err.message;
|
|
89
|
+
console.error(chalk.red(`Breaking change check failed: ${msg}`));
|
|
90
|
+
exit(status ? exitCodeForHttpStatus(status) : ExitCode.GENERIC);
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const patch = createTwoFilesPatch(a, b, left, right, "", "", { context: 3 });
|
|
95
|
+
if (!patch.trim()) {
|
|
96
|
+
console.log(chalk.green("No textual differences."));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
process.stdout.write(patch);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAA2B,MAAM,wBAAwB,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAQ7E,KAAK,UAAU,eAAe,CAAC,KAAa,EAAE,GAAuB;IACnE,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,OAAO,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IACD,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,6DAA6D,OAAO,IAAI,CAAC,CAAC;IAC5F,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG;QACrB,CAAC,CAAC,aAAa,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;QAC5H,CAAC,CAAC,aAAa,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC;IAChG,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,KAAK,UAAU,yBAAyB,CACtC,GAAuB,EACvB,WAAmB,EACnB,YAAoB,EACpB,SAAiB,EACjB,UAAkB;IAElB,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAmB,6BAA6B,EAAE;QACzF,IAAI,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE;QACnD,QAAQ,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE;KAC1D,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;QAC1D,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,CAAC;IACrD,IAAI,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;QACnC,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;YACxC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACxD,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAChC,MAAM,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC9C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CACV,gGAAgG,CACjG;SACA,QAAQ,CAAC,KAAK,EAAE,mCAAmC,CAAC;SACpD,QAAQ,CAAC,KAAK,EAAE,oCAAoC,CAAC;SACrD,MAAM,CAAC,iBAAiB,EAAE,0DAA0D,CAAC;SACrF,MAAM,CAAC,cAAc,EAAE,sCAAsC,CAAC;SAC9D,MAAM,CAAC,KAAK,EAAE,CAAS,EAAE,CAAS,EAAE,IAA8C,EAAE,EAAE;QACrF,IAAI,GAAG,CAAC;QACR,IAAI,CAAC;YACH,GAAG,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAE,CAAW,CAAC,OAAO,CAAC,CAAC,CAAC;YAC/C,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC9B,CAAC;QAED,IAAI,IAAY,CAAC;QACjB,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,eAAe,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACrC,KAAK,GAAG,MAAM,eAAe,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC,CAAC;gBACnE,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YAC9B,CAAC;YACD,MAAM,MAAM,GAAI,GAA8C,EAAE,QAAQ,EAAE,UAAU,CAAC;YACrF,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,wBAAyB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC3E,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC;gBACH,MAAM,yBAAyB,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC,CAAC;oBACnE,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;gBAC9B,CAAC;gBACD,MAAM,MAAM,GAAI,GAA8C,EAAE,QAAQ,EAAE,UAAU,CAAC;gBACrF,MAAM,GAAG,GAAG,mBAAmB,CAAC,GAAG,CAAC,IAAK,GAAa,CAAC,OAAO,CAAC;gBAC/D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,iCAAiC,GAAG,EAAE,CAAC,CAAC,CAAC;gBACjE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAClE,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7E,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC;YACpD,OAAO;QACT,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spec0 doctor — print which config sources are in effect.
|
|
3
|
+
*
|
|
4
|
+
* Useful when an `auth missing` or `wrong URL` error fires and the user
|
|
5
|
+
* wants to know "which env var or config file is the CLI actually reading?".
|
|
6
|
+
*
|
|
7
|
+
* Exits 0 when token + orgId resolve, otherwise the corresponding ExitCode.
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from "commander";
|
|
10
|
+
export declare function registerDoctorCommand(program: Command): void;
|
|
11
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,QAiBrD"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spec0 doctor — print which config sources are in effect.
|
|
3
|
+
*
|
|
4
|
+
* Useful when an `auth missing` or `wrong URL` error fires and the user
|
|
5
|
+
* wants to know "which env var or config file is the CLI actually reading?".
|
|
6
|
+
*
|
|
7
|
+
* Exits 0 when token + orgId resolve, otherwise the corresponding ExitCode.
|
|
8
|
+
*/
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import { ExitCode, exit } from "../lib/exit-codes.js";
|
|
11
|
+
import { emit, resolveOutputContext } from "../lib/output/index.js";
|
|
12
|
+
import { buildDoctorReport, describeSource } from "../lib/doctor.js";
|
|
13
|
+
export function registerDoctorCommand(program) {
|
|
14
|
+
program
|
|
15
|
+
.command("doctor")
|
|
16
|
+
.description("Diagnose CLI configuration: where each setting is being read from.")
|
|
17
|
+
.option("--output <format>", "Output format: text, json, or yaml (default: text)")
|
|
18
|
+
.action((opts) => {
|
|
19
|
+
const ctx = resolveOutputContext(opts);
|
|
20
|
+
const report = buildDoctorReport();
|
|
21
|
+
emit(ctx, report, renderDoctorText);
|
|
22
|
+
if (!report.ok) {
|
|
23
|
+
// No message here — emit() already printed the diagnostic.
|
|
24
|
+
process.exit(ExitCode.AUTH_MISSING);
|
|
25
|
+
}
|
|
26
|
+
exit(ExitCode.SUCCESS);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function renderDoctorText(report) {
|
|
30
|
+
const lines = [];
|
|
31
|
+
lines.push(chalk.bold("spec0 configuration"));
|
|
32
|
+
lines.push("");
|
|
33
|
+
const colWidth = Math.max(...report.settings.map((s) => s.name.length));
|
|
34
|
+
for (const s of report.settings) {
|
|
35
|
+
const name = s.name.padEnd(colWidth);
|
|
36
|
+
const src = describeSource(s.source);
|
|
37
|
+
const colour = s.source.kind === "missing" ? chalk.red : chalk.gray;
|
|
38
|
+
// describeSource for "missing" returns "(not set)" already; everything else is bare text.
|
|
39
|
+
const srcDisplay = s.source.kind === "missing" ? src : `(${src})`;
|
|
40
|
+
lines.push(` ${name} ${s.value} ${colour(srcDisplay)}`);
|
|
41
|
+
}
|
|
42
|
+
lines.push("");
|
|
43
|
+
lines.push(` config file: ${report.configPath}`);
|
|
44
|
+
lines.push("");
|
|
45
|
+
if (report.ok) {
|
|
46
|
+
lines.push(chalk.green("✓ ready to talk to the platform"));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
lines.push(chalk.red("✗ missing required settings — see above"));
|
|
50
|
+
lines.push(chalk.gray(" Set SPEC0_TOKEN + SPEC0_ORG_ID for non-interactive use, or run 'spec0 auth login'."));
|
|
51
|
+
}
|
|
52
|
+
return lines.join("\n");
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,QA0DnD"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spec0 init — onboarding, spec auto-detect, CODEOWNERS, .spec0.yaml, optional register
|
|
3
|
+
*/
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { findSpecInDir } from "../lib/spec-finder.js";
|
|
6
|
+
import { getTeamFromCodeowners } from "../lib/codeowners.js";
|
|
7
|
+
import { writeFileSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
import { execSync } from "child_process";
|
|
10
|
+
import { ExitCode, exit } from "../lib/exit-codes.js";
|
|
11
|
+
export function registerInitCommand(program) {
|
|
12
|
+
program
|
|
13
|
+
.command("init")
|
|
14
|
+
.description("Detect your OpenAPI spec and create a .spec0.yaml config file")
|
|
15
|
+
.option("--all", "Scan subdirectories for .spec0.yaml (monorepo)")
|
|
16
|
+
.option("--push", "Run spec0 push after writing config")
|
|
17
|
+
.action(async (opts) => {
|
|
18
|
+
const cwd = process.cwd();
|
|
19
|
+
const specPath = findSpecInDir(cwd);
|
|
20
|
+
if (!specPath) {
|
|
21
|
+
console.error(chalk.red("No OpenAPI spec found. Add openapi.yaml, openapi.json, or swagger.yaml"));
|
|
22
|
+
exit(ExitCode.USAGE);
|
|
23
|
+
}
|
|
24
|
+
const specName = specPath.split("/").pop() ?? "openapi.yaml";
|
|
25
|
+
const team = getTeamFromCodeowners(cwd, specPath);
|
|
26
|
+
const defaultName = specPath.split("/").slice(-2, -1)[0] ?? "api";
|
|
27
|
+
const suggestedName = defaultName.replace(/[^a-z0-9-]/gi, "-").toLowerCase();
|
|
28
|
+
console.log(chalk.blue(`Found ${specName}. Suggested API name: ${suggestedName}`));
|
|
29
|
+
if (team)
|
|
30
|
+
console.log(chalk.blue(`Team from CODEOWNERS: ${team}`));
|
|
31
|
+
const config = {
|
|
32
|
+
spec: specName,
|
|
33
|
+
name: suggestedName,
|
|
34
|
+
owner: team ?? "default",
|
|
35
|
+
namespace: `${team ?? "default"}/${suggestedName}`,
|
|
36
|
+
autoCreateTeam: false,
|
|
37
|
+
strict: false,
|
|
38
|
+
checkBreaking: true,
|
|
39
|
+
};
|
|
40
|
+
const yamlPath = join(cwd, ".spec0.yaml");
|
|
41
|
+
const yaml = [
|
|
42
|
+
`# Spec0 config — generated by spec0 init`,
|
|
43
|
+
`spec: ${specName}`,
|
|
44
|
+
`name: ${config.name}`,
|
|
45
|
+
`owner: ${config.owner}`,
|
|
46
|
+
`namespace: ${config.namespace}`,
|
|
47
|
+
`auto-create-team: ${config.autoCreateTeam}`,
|
|
48
|
+
`strict: ${config.strict}`,
|
|
49
|
+
`check-breaking: ${config.checkBreaking}`,
|
|
50
|
+
].join("\n");
|
|
51
|
+
writeFileSync(yamlPath, yaml);
|
|
52
|
+
console.log(chalk.green("Initialized! Spec0 config written to .spec0.yaml"));
|
|
53
|
+
if (opts.push) {
|
|
54
|
+
try {
|
|
55
|
+
execSync("spec0 push", { stdio: "inherit", cwd });
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
console.error(chalk.red("Push failed. Run 'spec0 push' manually."));
|
|
59
|
+
exit(ExitCode.GENERIC);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
console.log(chalk.blue("Run 'spec0 push' to upload your spec (or use --push)."));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,+DAA+D,CAAC;SAC5E,MAAM,CAAC,OAAO,EAAE,gDAAgD,CAAC;SACjE,MAAM,CAAC,QAAQ,EAAE,qCAAqC,CAAC;SACvD,MAAM,CAAC,KAAK,EAAE,IAAuC,EAAE,EAAE;QACxD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,wEAAwE,CAAC,CACpF,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;QACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,cAAc,CAAC;QAC7D,MAAM,IAAI,GAAG,qBAAqB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAClD,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;QAClE,MAAM,aAAa,GAAG,WAAW,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAE7E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,QAAQ,yBAAyB,aAAa,EAAE,CAAC,CAAC,CAAC;QACnF,IAAI,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC,CAAC;QAEnE,MAAM,MAAM,GAAG;YACb,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,aAAa;YACnB,KAAK,EAAE,IAAI,IAAI,SAAS;YACxB,SAAS,EAAE,GAAG,IAAI,IAAI,SAAS,IAAI,aAAa,EAAE;YAClD,cAAc,EAAE,KAAK;YACrB,MAAM,EAAE,KAAK;YACb,aAAa,EAAE,IAAI;SACpB,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG;YACX,0CAA0C;YAC1C,SAAS,QAAQ,EAAE;YACnB,SAAS,MAAM,CAAC,IAAI,EAAE;YACtB,UAAU,MAAM,CAAC,KAAK,EAAE;YACxB,cAAc,MAAM,CAAC,SAAS,EAAE;YAChC,qBAAqB,MAAM,CAAC,cAAc,EAAE;YAC5C,WAAW,MAAM,CAAC,MAAM,EAAE;YAC1B,mBAAmB,MAAM,CAAC,aAAa,EAAE;SAC1C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC,CAAC;QAC7E,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC;gBACH,QAAQ,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;YACpD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC,CAAC;gBACpE,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC,CAAC;QACnF,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,QAiFnD"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spec0 lint — Spectral bundled, org ruleset fetch, JSON/text/github output
|
|
3
|
+
*/
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
6
|
+
import { tmpdir } from "os";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import { findSpecInDir } from "../lib/spec-finder.js";
|
|
9
|
+
import { resolveCliSpecPathFromFlags } from "../lib/cli-spec-path.js";
|
|
10
|
+
import { runSpectral } from "../lib/lint.js";
|
|
11
|
+
import { formatLintText, formatGitHubAnnotation } from "../lib/output.js";
|
|
12
|
+
import { createOrgApiClient } from "../lib/api-client.js";
|
|
13
|
+
import { requireOrgContext } from "../lib/auth-context.js";
|
|
14
|
+
import { ExitCode, exit } from "../lib/exit-codes.js";
|
|
15
|
+
export function registerLintCommand(program) {
|
|
16
|
+
program
|
|
17
|
+
.command("lint")
|
|
18
|
+
.description("Lint OpenAPI spec with Spectral")
|
|
19
|
+
.argument("[spec-file]", "Path to OpenAPI spec (or use --spec-file / global --spec-file)")
|
|
20
|
+
.option("--spec-file <path>", "Path to OpenAPI spec file")
|
|
21
|
+
.option("--ruleset <file>", "Use custom ruleset file")
|
|
22
|
+
.option("--org-ruleset", "Fetch org ruleset from server")
|
|
23
|
+
.option("--save-ruleset <file>", "Upload <file> as the org's stored Spectral ruleset (skips the lint step)")
|
|
24
|
+
.option("--format <fmt>", "Output: text, json, github, sarif", "text")
|
|
25
|
+
.option("--min-score <n>", "Exit 1 if score below n (0-100)", "0")
|
|
26
|
+
.option("--strict", "Exit 1 on any warning")
|
|
27
|
+
.action(async (specArg, opts, command) => {
|
|
28
|
+
// --save-ruleset is an upload-only mode; short-circuit the lint path.
|
|
29
|
+
if (typeof opts.saveRuleset === "string" && opts.saveRuleset) {
|
|
30
|
+
await uploadRuleset(opts.saveRuleset);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const cwd = process.cwd();
|
|
34
|
+
const specPath = resolveCliSpecPathFromFlags(command, cwd, opts.specFile, specArg) ??
|
|
35
|
+
findSpecInDir(cwd);
|
|
36
|
+
if (!specPath || !existsSync(specPath)) {
|
|
37
|
+
console.error(chalk.red("Spec file not found."));
|
|
38
|
+
exit(ExitCode.USAGE);
|
|
39
|
+
}
|
|
40
|
+
let rulesetFile = opts.ruleset;
|
|
41
|
+
if (opts.orgRuleset) {
|
|
42
|
+
try {
|
|
43
|
+
const ctx = requireOrgContext();
|
|
44
|
+
const client = createOrgApiClient(ctx);
|
|
45
|
+
const res = (await client.getJson("/api-management/cli/v1/spectral-ruleset"));
|
|
46
|
+
const yaml = res.rulesetYaml?.trim() ?? "";
|
|
47
|
+
if (!yaml) {
|
|
48
|
+
console.warn(chalk.yellow("No org ruleset stored on the server; using built-in OAS ruleset."));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
rulesetFile = join(tmpdir(), `spec0-org-ruleset-${Date.now()}.yaml`);
|
|
52
|
+
writeFileSync(rulesetFile, yaml, "utf-8");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
console.error(chalk.red(e.message));
|
|
57
|
+
exit(ExitCode.AUTH_MISSING);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const result = await runSpectral(specPath, rulesetFile);
|
|
61
|
+
if (opts.format === "json") {
|
|
62
|
+
console.log(JSON.stringify(result, null, 2));
|
|
63
|
+
}
|
|
64
|
+
else if (opts.format === "github") {
|
|
65
|
+
for (const e of result.errors) {
|
|
66
|
+
console.log(formatGitHubAnnotation(specPath, e.line ?? 0, "error", e.message));
|
|
67
|
+
}
|
|
68
|
+
for (const w of result.warnings) {
|
|
69
|
+
console.log(formatGitHubAnnotation(specPath, w.line ?? 0, "warning", w.message));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
console.log(`Linting ${specPath}... (oas ruleset)\n`);
|
|
74
|
+
console.log(formatLintText(result));
|
|
75
|
+
}
|
|
76
|
+
const minScore = parseInt(String(opts.minScore ?? "0"), 10);
|
|
77
|
+
if (result.score < minScore)
|
|
78
|
+
exit(ExitCode.VALIDATION);
|
|
79
|
+
if (opts.strict === true && result.warnings.length > 0)
|
|
80
|
+
exit(ExitCode.VALIDATION);
|
|
81
|
+
if (result.errors.length > 0)
|
|
82
|
+
exit(ExitCode.VALIDATION);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async function uploadRuleset(filePath) {
|
|
86
|
+
if (!existsSync(filePath)) {
|
|
87
|
+
console.error(chalk.red(`Ruleset file not found: ${filePath}`));
|
|
88
|
+
exit(ExitCode.USAGE);
|
|
89
|
+
}
|
|
90
|
+
const rulesetYaml = readFileSync(filePath, "utf-8");
|
|
91
|
+
let ctx;
|
|
92
|
+
try {
|
|
93
|
+
ctx = requireOrgContext();
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
console.error(chalk.red(e.message));
|
|
97
|
+
exit(ExitCode.AUTH_MISSING);
|
|
98
|
+
}
|
|
99
|
+
const client = createOrgApiClient(ctx);
|
|
100
|
+
try {
|
|
101
|
+
await client.putJson("/api-management/cli/v1/spectral-ruleset", { rulesetYaml });
|
|
102
|
+
console.log(chalk.green(`✓ uploaded ${filePath} as the org's Spectral ruleset`));
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
console.error(chalk.red(`Failed to upload ruleset: ${err.message}`));
|
|
106
|
+
exit(ExitCode.GENERIC);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/commands/log.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,QAmElD"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spec0 log — version history from registry
|
|
3
|
+
*/
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { createOrgApiClient, is401 } from "../lib/api-client.js";
|
|
6
|
+
import { requireOrgContext } from "../lib/auth-context.js";
|
|
7
|
+
import { getDefaultOrgId, getOrgConfig } from "../lib/config.js";
|
|
8
|
+
import { parseRegistryRef } from "../lib/registry-ref.js";
|
|
9
|
+
import { ExitCode, exit } from "../lib/exit-codes.js";
|
|
10
|
+
import { emit, resolveOutputContext } from "../lib/output/index.js";
|
|
11
|
+
import { renderTable } from "../lib/output/table.js";
|
|
12
|
+
import { warnDeprecated } from "../lib/deprecation.js";
|
|
13
|
+
export function registerLogCommand(program) {
|
|
14
|
+
program
|
|
15
|
+
.command("log <api-ref>")
|
|
16
|
+
.description("Show published version history. api-ref: api-name (default org) or org-slug/api-name")
|
|
17
|
+
.option("--org <uuid>", "Org id override (auth)")
|
|
18
|
+
.option("--org-slug <slug>", "Organisation slug/name for registry path when api-ref has no slash (default: name from spec0 auth config)")
|
|
19
|
+
.option("--output <format>", "Output format: text, json, or yaml (default: text)")
|
|
20
|
+
.option("--json", "Deprecated. Use --output=json instead.")
|
|
21
|
+
.action(async (apiRef, opts) => {
|
|
22
|
+
if (opts.json) {
|
|
23
|
+
warnDeprecated({
|
|
24
|
+
what: "the --json flag on `spec0 log`",
|
|
25
|
+
removeIn: "v1.0.0",
|
|
26
|
+
alternative: "--output=json",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const outCtx = resolveOutputContext(opts);
|
|
30
|
+
let orgSlug;
|
|
31
|
+
let apiName;
|
|
32
|
+
try {
|
|
33
|
+
if (apiRef.includes("/")) {
|
|
34
|
+
const p = parseRegistryRef(apiRef);
|
|
35
|
+
orgSlug = p.org;
|
|
36
|
+
apiName = p.api;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const orgId = process.env.PLATFORM_ORG_ID ?? getDefaultOrgId();
|
|
40
|
+
const cfg = orgId ? getOrgConfig(orgId) : undefined;
|
|
41
|
+
const fallback = cfg?.name?.trim();
|
|
42
|
+
orgSlug = (opts.orgSlug ?? fallback ?? "").trim();
|
|
43
|
+
if (!orgSlug) {
|
|
44
|
+
exit(ExitCode.USAGE, "Set --org-slug <slug> or use org-slug/api-name, or run 'spec0 auth login'.");
|
|
45
|
+
}
|
|
46
|
+
apiName = apiRef.trim();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
exit(ExitCode.USAGE, e.message);
|
|
51
|
+
}
|
|
52
|
+
let authCtx;
|
|
53
|
+
try {
|
|
54
|
+
authCtx = requireOrgContext(opts.org);
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
exit(ExitCode.AUTH_MISSING, e.message);
|
|
58
|
+
}
|
|
59
|
+
const client = createOrgApiClient(authCtx);
|
|
60
|
+
const path = `/registry/${encodeURIComponent(orgSlug)}/${encodeURIComponent(apiName)}/versions`;
|
|
61
|
+
try {
|
|
62
|
+
const rows = (await client.getJson(path));
|
|
63
|
+
emit(outCtx, rows, (data) => renderLogText(data, orgSlug, apiName));
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
if (is401(err)) {
|
|
67
|
+
exit(ExitCode.AUTH_MISSING, "Token invalid or expired. Run 'spec0 auth login'.");
|
|
68
|
+
}
|
|
69
|
+
exit(ExitCode.GENERIC, `Log failed: ${err.message}`);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function renderLogText(rows, orgSlug, apiName) {
|
|
74
|
+
if (!rows.length)
|
|
75
|
+
return chalk.yellow("No published versions found.");
|
|
76
|
+
const table = renderTable(rows, [
|
|
77
|
+
{ key: "tag", header: "Tag" },
|
|
78
|
+
{ key: "publishedAt", header: "Published" },
|
|
79
|
+
{ key: "gitSha", header: "Git SHA", format: (v) => String(v ?? "—").slice(0, 12) },
|
|
80
|
+
{
|
|
81
|
+
key: "breakingChangesRecorded",
|
|
82
|
+
header: "Breaking",
|
|
83
|
+
format: (v) => (v ? "yes" : "—"),
|
|
84
|
+
},
|
|
85
|
+
]);
|
|
86
|
+
const lines = [chalk.blue(`${orgSlug}/${apiName} version history:`), table];
|
|
87
|
+
for (const r of rows) {
|
|
88
|
+
if (r.breakingChangeSummary) {
|
|
89
|
+
const prev = (r.breakingChangeSummary ?? "").slice(0, 500);
|
|
90
|
+
lines.push("", chalk.gray(`${r.tag}: ${prev}${prev.length >= 500 ? "…" : ""}`));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return lines.join("\n");
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/commands/log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,QAyDnD"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spec0 mcp url | test
|
|
3
|
+
*/
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import got from "got";
|
|
6
|
+
import { getDefaultOrgId, getOrgConfig } from "../lib/config.js";
|
|
7
|
+
import { ExitCode, exit, exitCodeForHttpStatus } from "../lib/exit-codes.js";
|
|
8
|
+
export function registerMcpCommands(program) {
|
|
9
|
+
const mcp = program.command("mcp").description("MCP server URL and config");
|
|
10
|
+
mcp
|
|
11
|
+
.command("url")
|
|
12
|
+
.description("Print MCP server URL for Cursor/Claude config")
|
|
13
|
+
.action(async () => {
|
|
14
|
+
const orgId = process.env.PLATFORM_ORG_ID ?? getDefaultOrgId();
|
|
15
|
+
if (!orgId || !getOrgConfig(orgId)) {
|
|
16
|
+
console.error(chalk.red("Not authenticated. Run 'spec0 auth login'."));
|
|
17
|
+
exit(ExitCode.AUTH_MISSING);
|
|
18
|
+
}
|
|
19
|
+
const org = getOrgConfig(orgId);
|
|
20
|
+
const mcpUrl = `https://mcp.spec0.io/org/${orgId}/mcp`;
|
|
21
|
+
console.log("Your MCP server URL:");
|
|
22
|
+
console.log(` ${mcpUrl}`);
|
|
23
|
+
console.log("");
|
|
24
|
+
console.log("Add to Cursor settings:");
|
|
25
|
+
console.log(JSON.stringify({
|
|
26
|
+
mcpServers: {
|
|
27
|
+
spec0: {
|
|
28
|
+
url: mcpUrl,
|
|
29
|
+
apiKey: org.apiKey,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
}, null, 2));
|
|
33
|
+
});
|
|
34
|
+
mcp
|
|
35
|
+
.command("test")
|
|
36
|
+
.description("Verify MCP server is responding")
|
|
37
|
+
.action(async () => {
|
|
38
|
+
const orgId = process.env.PLATFORM_ORG_ID ?? getDefaultOrgId();
|
|
39
|
+
if (!orgId || !getOrgConfig(orgId)) {
|
|
40
|
+
console.error(chalk.red("Not authenticated. Run 'spec0 auth login'."));
|
|
41
|
+
exit(ExitCode.AUTH_MISSING);
|
|
42
|
+
}
|
|
43
|
+
const org = getOrgConfig(orgId);
|
|
44
|
+
const base = org.apiUrl.replace(/\/$/, "");
|
|
45
|
+
const url = `${base}/mcp/org/${orgId}/health`;
|
|
46
|
+
try {
|
|
47
|
+
const res = await got.get(url, {
|
|
48
|
+
headers: { Authorization: `Bearer ${org.apiKey}`, "X-Org-Id": orgId },
|
|
49
|
+
});
|
|
50
|
+
console.log(chalk.green("MCP gateway OK:"), res.body);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
const status = e?.response?.statusCode;
|
|
54
|
+
console.error(chalk.red("MCP health check failed:"), e.message);
|
|
55
|
+
exit(status ? exitCodeForHttpStatus(status) : ExitCode.NETWORK_ERROR);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spec0 mock create — provision (or fetch) the default mock server for an API.
|
|
3
|
+
*
|
|
4
|
+
* The backend endpoint is idempotent: POST /api-management/cli/v1/mocks either
|
|
5
|
+
* returns the existing mock or creates a fresh one. The API key is only ever
|
|
6
|
+
* returned once (on initial creation), so CI callers should capture it on the
|
|
7
|
+
* very first run — we surface it prominently in text mode and include it in
|
|
8
|
+
* the JSON payload.
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from "commander";
|
|
11
|
+
import type { components } from "../../types.js";
|
|
12
|
+
export declare function registerMockCreateCommand(mock: Command): void;
|
|
13
|
+
export type MockItem = components["schemas"]["MockItem"];
|
|
14
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/mock/create.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,OAAO,KAAK,EAAE,UAAU,EAAS,MAAM,gBAAgB,CAAC;AAexD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,OAAO,QAsDtD;AAeD,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC"}
|