saturndocs 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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/dist/auth-FRCFGNYT.js +14 -0
  3. package/dist/brokenLinks-TTOBP4P7.js +48 -0
  4. package/dist/build-F5PWGP57.js +39 -0
  5. package/dist/chunk-3P2OFTXR.js +71 -0
  6. package/dist/chunk-3V753MRI.js +100 -0
  7. package/dist/chunk-5KX4ZK5E.js +104 -0
  8. package/dist/chunk-CMNX5DLQ.js +119 -0
  9. package/dist/chunk-GYRVGWDM.js +3499 -0
  10. package/dist/chunk-I6U4V7B4.js +1552 -0
  11. package/dist/chunk-J6P3VGGE.js +21 -0
  12. package/dist/chunk-KGJESHJC.js +37 -0
  13. package/dist/chunk-M2BZEDAS.js +57 -0
  14. package/dist/chunk-N7QPZMLP.js +82 -0
  15. package/dist/chunk-OEAEX5YW.js +51 -0
  16. package/dist/chunk-OZWTXMO3.js +584 -0
  17. package/dist/chunk-QLFODLVN.js +46 -0
  18. package/dist/chunk-R3X2DPFF.js +568 -0
  19. package/dist/chunk-S45UWCML.js +588 -0
  20. package/dist/chunk-SABK3R2P.js +2452 -0
  21. package/dist/chunk-STCCGFKC.js +246 -0
  22. package/dist/chunk-TKISMN3P.js +39 -0
  23. package/dist/chunk-U7PKMSB3.js +465 -0
  24. package/dist/chunk-VNYDYHXM.js +22 -0
  25. package/dist/chunk-VXEUNRVA.js +26 -0
  26. package/dist/chunk-XO4CUC7V.js +99 -0
  27. package/dist/cli.d.ts +1 -0
  28. package/dist/cli.js +95 -0
  29. package/dist/deploy-QU7DCKWU.js +11 -0
  30. package/dist/dev-VDSDCBO2.js +43 -0
  31. package/dist/index.d.ts +382 -0
  32. package/dist/index.js +191 -0
  33. package/dist/init-7T5TEPBH.js +14 -0
  34. package/dist/manage-MKH27U3B.js +12 -0
  35. package/dist/openapiCheck-KGBQJTIQ.js +66 -0
  36. package/dist/pages-HIPXRLSY.js +15 -0
  37. package/dist/read-DMSJUEDA.js +160 -0
  38. package/dist/read-ZEVUZNNB.js +146 -0
  39. package/dist/requests-H5MIGBIS.js +13 -0
  40. package/dist/schema-XJUEZSIW.js +13 -0
  41. package/dist/sites-I4WI2MPG.js +14 -0
  42. package/dist/status-7R3NOI5H.js +14 -0
  43. package/dist/suggestions-4WFQ3APX.js +739 -0
  44. package/dist/validate-VXL4PL42.js +30 -0
  45. package/package.json +68 -0
package/dist/cli.js ADDED
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ COMMAND_GROUPS,
4
+ selectCommandGroup
5
+ } from "./chunk-QLFODLVN.js";
6
+ import {
7
+ installInterrupt
8
+ } from "./chunk-KGJESHJC.js";
9
+ import {
10
+ EXIT,
11
+ applyGlobalFlags,
12
+ applyGlobalFlagsDeep,
13
+ createResultWriter,
14
+ failureResult,
15
+ invalidInput,
16
+ wantsJson
17
+ } from "./chunk-GYRVGWDM.js";
18
+
19
+ // src/cli.ts
20
+ import { readFileSync } from "fs";
21
+ import { dirname } from "path";
22
+ import { fileURLToPath } from "url";
23
+ import { Command, CommanderError } from "commander";
24
+ var cliDir = dirname(fileURLToPath(import.meta.url));
25
+ function cliVersion() {
26
+ try {
27
+ const manifest = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
28
+ const version = manifest.version;
29
+ return typeof version === "string" ? version : "0.0.0";
30
+ } catch {
31
+ return "0.0.0";
32
+ }
33
+ }
34
+ function commandFromArgv(argv) {
35
+ const group = selectCommandGroup(argv);
36
+ if (group === void 0) return "saturndocs";
37
+ const index = argv.indexOf(group.name);
38
+ const next = argv[index + 1];
39
+ return next !== void 0 && !next.startsWith("-") ? `${group.name} ${next}` : group.name;
40
+ }
41
+ function createProgram() {
42
+ const program = new Command();
43
+ program.name("saturndocs").description("SaturnDocs CLI: init, validate, dev, build, deploy, broken-links, openapi-check").version(cliVersion()).addHelpCommand(false).showHelpAfterError().configureHelp({ subcommandTerm: (command) => command.name() });
44
+ applyGlobalFlags(program);
45
+ return program;
46
+ }
47
+ async function registerGroup(program, group) {
48
+ const register = await group.load();
49
+ const before = new Set(program.commands);
50
+ register(program, cliDir);
51
+ for (const command of program.commands) {
52
+ if (!before.has(command)) applyGlobalFlagsDeep(command);
53
+ }
54
+ }
55
+ function addPlaceholder(program, group, writer) {
56
+ program.command(group.name).description(group.summary).allowUnknownOption(true).allowExcessArguments(true).helpOption(false).argument("[args...]").action(async () => {
57
+ process.exitCode = await run(process.argv, group, writer);
58
+ });
59
+ }
60
+ async function run(argv, forced, reuse) {
61
+ const json = wantsJson(argv);
62
+ const writer = reuse ?? createResultWriter({ json });
63
+ const program = createProgram();
64
+ if (json) program.exitOverride();
65
+ const selected = forced ?? selectCommandGroup(argv);
66
+ for (const group of COMMAND_GROUPS) {
67
+ if (group === selected) await registerGroup(program, group);
68
+ else addPlaceholder(program, group, writer);
69
+ }
70
+ const interrupt = reuse === void 0 ? installInterrupt({ writer, context: () => ({ command: commandFromArgv(argv) }) }) : void 0;
71
+ try {
72
+ await program.parseAsync([...argv]);
73
+ return process.exitCode === void 0 ? EXIT.success : Number(process.exitCode);
74
+ } catch (error) {
75
+ return report(error, argv, writer);
76
+ } finally {
77
+ interrupt?.dispose();
78
+ }
79
+ }
80
+ function report(error, argv, writer) {
81
+ const context = { command: commandFromArgv(argv) };
82
+ if (error instanceof CommanderError) {
83
+ if (error.exitCode === 0) return EXIT.success;
84
+ if (!writer.json) return error.exitCode;
85
+ writer.write(failureResult(invalidInput(error.message.replace(/^error: /, "")), context));
86
+ return EXIT.invalid_input;
87
+ }
88
+ if (!writer.json) {
89
+ process.stderr.write(`error: ${error instanceof Error ? error.message : String(error)}
90
+ `);
91
+ return 1;
92
+ }
93
+ return writer.write(failureResult(error, context));
94
+ }
95
+ process.exitCode = await run(process.argv);
@@ -0,0 +1,11 @@
1
+ import {
2
+ deployBundle,
3
+ registerDeploy
4
+ } from "./chunk-I6U4V7B4.js";
5
+ import "./chunk-S45UWCML.js";
6
+ import "./chunk-R3X2DPFF.js";
7
+ import "./chunk-VNYDYHXM.js";
8
+ export {
9
+ deployBundle,
10
+ registerDeploy
11
+ };
@@ -0,0 +1,43 @@
1
+ import {
2
+ findWebDir
3
+ } from "./chunk-VXEUNRVA.js";
4
+ import {
5
+ messageOf,
6
+ resolveDocsDir
7
+ } from "./chunk-VNYDYHXM.js";
8
+
9
+ // src/commands/dev.ts
10
+ import { execa } from "execa";
11
+ import pc from "picocolors";
12
+ function registerDev(program, cliDir) {
13
+ program.command("dev").description("Start the Astro dev server for a docs directory").argument("[dir]", "docs directory (contains docs.json)").option("--port <port>", "port for the dev server").action(async (dir, options) => {
14
+ const docsDir = resolveDocsDir(dir);
15
+ let webDir;
16
+ try {
17
+ webDir = findWebDir(cliDir);
18
+ } catch (error) {
19
+ console.error(pc.red(`error: ${messageOf(error)}`));
20
+ process.exit(1);
21
+ }
22
+ const args = ["dev"];
23
+ if (options.port) args.push("--port", options.port);
24
+ console.log(
25
+ pc.dim(`saturndocs dev: astro ${args.join(" ")} in ${webDir}`)
26
+ );
27
+ try {
28
+ await execa("astro", args, {
29
+ cwd: webDir,
30
+ preferLocal: true,
31
+ localDir: webDir,
32
+ stdio: "inherit",
33
+ env: { SATURNDOCS_DOCS_DIR: docsDir }
34
+ });
35
+ } catch (error) {
36
+ console.error(pc.red(`astro dev failed: ${messageOf(error)}`));
37
+ process.exit(1);
38
+ }
39
+ });
40
+ }
41
+ export {
42
+ registerDev
43
+ };
@@ -0,0 +1,382 @@
1
+ import { Command } from 'commander';
2
+ import { CommandMetadata, ClientErrorCode, ServerFault, MutationOutcome, ExitCode, ClientLimitation, ClientRecovery, DurableIds, ClientError, ClientFailure, ClientSuccess, ClientResult, TextInput, ManagementClient, SiteDiscovery, PagesResult, SiteStatus } from '@saturndocs/management-client';
3
+ import { DocsConfig } from '@saturndocs/config';
4
+ import { AbiViolation } from '@saturndocs/source-abi';
5
+ import { BrandExtraction, extractBrandFromUrl } from '@saturndocs/brand';
6
+ export { BrandAssetExtraction, BrandExtraction, BrandFetchOptions, BrandFetcher, ColorCandidate, DEFAULT_PRIMARY_COLOR, FetchImplementation, LogoCandidate, LogoSelection, ScoredColor, UrlValidator, colorToHex, deriveDocsJson, extensionForContentType, extractBrandFromUrl, extractBrandText, extractCssColorCandidates, extractManifestUrl, extractStylesheetUrls, extractThemeColorMetas, fetchBrandAsset, normalizeHexColor, normalizeHttpUrl, parseCssColor, pickPrimaryColor, scoreColorCandidates, selectLogoAssets } from '@saturndocs/brand';
7
+
8
+ /** Every group registers the same way, whether or not it takes the cli directory. */
9
+ type RegisterGroup = (program: Command, cliDir: string) => void;
10
+ interface CommandGroup {
11
+ /** The top-level command name, as it appears in help. */
12
+ readonly name: string;
13
+ readonly summary: string;
14
+ /**
15
+ * Pulls in the renderer or the workspace build. Kept out of help and out of
16
+ * every management run, which must work from a directory with no docs in it.
17
+ */
18
+ readonly renderer: boolean;
19
+ readonly load: () => Promise<RegisterGroup>;
20
+ /**
21
+ * The group's command metadata, for `saturndocs schema` and for help. Lazy for
22
+ * the same reason as `load`. A management group without it is a drift-test
23
+ * failure; a local workspace group (`renderer: true`) has none.
24
+ */
25
+ readonly metadata?: () => Promise<readonly CommandMetadata[]>;
26
+ }
27
+ /**
28
+ * The order help prints. A later issue adds one line; nothing else in the
29
+ * entry point or the smoke test changes.
30
+ */
31
+ declare const COMMAND_GROUPS: readonly CommandGroup[];
32
+ declare const COMMAND_GROUP_NAMES: readonly string[];
33
+ declare function findCommandGroup(name: string): CommandGroup | undefined;
34
+ /**
35
+ * Which group this invocation runs, read from raw argv so only that group's
36
+ * module is imported. Everything else stays a name and a summary in help.
37
+ */
38
+ declare function selectCommandGroup(argv: readonly string[]): CommandGroup | undefined;
39
+
40
+ /** The envelope fields a command knows before it knows whether it succeeded. */
41
+ interface ResultContext {
42
+ command: string;
43
+ siteId?: string | null;
44
+ ids?: DurableIds;
45
+ limitations?: readonly ClientLimitation[];
46
+ recovery?: ClientRecovery | null;
47
+ }
48
+ interface CliErrorOptions {
49
+ server?: ServerFault | null;
50
+ retryable?: boolean;
51
+ mutation?: MutationOutcome;
52
+ exit?: ExitCode;
53
+ limitations?: readonly ClientLimitation[];
54
+ recovery?: ClientRecovery | null;
55
+ /** A partial result worth keeping beside the failure, such as a dismissal whose cleanup did not finish. */
56
+ data?: unknown;
57
+ cause?: unknown;
58
+ }
59
+ /** An error the client classified. Anything else reaching the top level is unclassified. */
60
+ declare class CliError extends Error {
61
+ readonly code: ClientErrorCode;
62
+ readonly server: ServerFault | null;
63
+ readonly retryable: boolean;
64
+ readonly mutation: MutationOutcome;
65
+ readonly exit: ExitCode;
66
+ readonly limitations: readonly ClientLimitation[];
67
+ readonly recovery: ClientRecovery | null;
68
+ readonly data: unknown;
69
+ constructor(code: ClientErrorCode, message: string, options?: CliErrorOptions);
70
+ }
71
+ /** Every refusal the client makes before a request leaves the process. */
72
+ declare function invalidInput(message: string, options?: CliErrorOptions): CliError;
73
+ declare function interrupted(message?: string, options?: CliErrorOptions): CliError;
74
+ declare function clientError(code: ClientErrorCode, message: string, server?: ServerFault | null): ClientError;
75
+ declare function successResult(context: ResultContext, data: unknown): ClientSuccess;
76
+ declare function failureResult(error: unknown, context: ResultContext): ClientFailure;
77
+
78
+ interface TextSink {
79
+ write(chunk: string): unknown;
80
+ }
81
+ interface ResultWriterOptions {
82
+ json: boolean;
83
+ stdout?: TextSink;
84
+ stderr?: TextSink;
85
+ }
86
+ interface WriteOptions {
87
+ /** What a person sees on stdout for a success when `--json` is off. */
88
+ text?: string;
89
+ }
90
+ /**
91
+ * The single stdout path for a command that reports a result. One invocation
92
+ * writes one envelope: a second call is dropped so an interrupt racing a
93
+ * finished command cannot append a second object to a stream an agent parses
94
+ * whole.
95
+ */
96
+ interface ResultWriter {
97
+ readonly json: boolean;
98
+ readonly written: boolean;
99
+ write(result: ClientResult, options?: WriteOptions): ExitCode;
100
+ }
101
+ declare function createResultWriter(options: ResultWriterOptions): ResultWriter;
102
+ /** Whether the invocation asked for one machine-readable result, read before Commander parses. */
103
+ declare function wantsJson(argv: readonly string[]): boolean;
104
+
105
+ /** The stdin cap for a command whose operation declares no text limit. */
106
+ declare const STDIN_BYTE_CEILING = 1048576;
107
+ interface TextInputFlags {
108
+ text?: string;
109
+ file?: string;
110
+ }
111
+ interface StdinSource extends AsyncIterable<Uint8Array | string> {
112
+ isTTY?: boolean;
113
+ }
114
+ interface ReadTextOptions {
115
+ /** The command name, so the refusal names what needs the text. */
116
+ command: string;
117
+ requirement: TextInput;
118
+ /** Code points the operation accepts. Checked before any HTTP call. */
119
+ limit: number | null;
120
+ /** False under `--no-input`: stdin is read only when `--file -` names it. */
121
+ interactive?: boolean;
122
+ stdin?: StdinSource;
123
+ readFileImpl?: (path: string) => Promise<string>;
124
+ }
125
+ /**
126
+ * Resolve the one text source a mutation accepts. Exclusivity, the size limit,
127
+ * and the stdin bound are all settled here so no oversized or ambiguous body
128
+ * reaches the transport.
129
+ */
130
+ declare function readTextInput(flags: TextInputFlags, options: ReadTextOptions): Promise<string | null>;
131
+
132
+ interface GlobalOptions {
133
+ json: boolean;
134
+ site: string | null;
135
+ api: string | null;
136
+ /** False under `--no-input`: nothing is read from a terminal. */
137
+ input: boolean;
138
+ /** Seconds. */
139
+ timeout: number | null;
140
+ }
141
+ /**
142
+ * The same five flags on every level, so `--json` before the subcommand and
143
+ * `--json` after it are the same invocation. Commander otherwise refuses a
144
+ * parent's option once a subcommand name has been read. A command that already
145
+ * declares one of these keeps its own: the global is not redeclared over it.
146
+ */
147
+ declare function applyGlobalFlags(command: Command): Command;
148
+ /** Every command a group registered, including nested subcommands. */
149
+ declare function applyGlobalFlagsDeep(command: Command): void;
150
+ /**
151
+ * Root to leaf, explicit values only: a default on the subcommand must not
152
+ * overwrite what the caller put before the subcommand name.
153
+ */
154
+ declare function resolveGlobalOptions(command: Command): GlobalOptions;
155
+
156
+ interface SignalSource {
157
+ on(signal: "SIGINT", handler: () => void): unknown;
158
+ off(signal: "SIGINT", handler: () => void): unknown;
159
+ }
160
+ interface InterruptOptions {
161
+ writer: ResultWriter;
162
+ /** Read when the signal arrives, so a command that has learnt its ids still reports them. */
163
+ context: () => ResultContext;
164
+ exit?: (code: number) => void;
165
+ source?: SignalSource;
166
+ }
167
+ interface InterruptHandle {
168
+ /** Aborted on SIGINT so local work stops instead of racing the exit. */
169
+ readonly signal: AbortSignal;
170
+ dispose(): void;
171
+ }
172
+ /** The running invocation's interrupt signal, for work a command starts after the entry point installed it. */
173
+ declare function interruptSignal(): AbortSignal | null;
174
+ /**
175
+ * SIGINT stops local work, reports what the command knew, and exits 130.
176
+ * Nothing remote is cancelled, so the result never says the work was undone.
177
+ */
178
+ declare function installInterrupt(options: InterruptOptions): InterruptHandle;
179
+
180
+ /** The `after` help body, built so schema and `--help` cannot describe the command differently. */
181
+ declare function helpBody(metadata: CommandMetadata): string;
182
+ /**
183
+ * Description, flags, and examples from the one metadata entry, so help and
184
+ * `saturndocs schema` cannot drift apart. A flag the command already declared
185
+ * keeps its own declaration, including its parser and default.
186
+ */
187
+ declare function applyCommandHelp(command: Command, metadata: CommandMetadata): Command;
188
+
189
+ declare const SCHEMA_METADATA: readonly CommandMetadata[];
190
+ /**
191
+ * The metadata document for a selector, or for the whole CLI when there is
192
+ * none. Only the named group's module is imported, so asking about one command
193
+ * does not load every other one.
194
+ */
195
+ declare function schemaDocument(selector: string | null, groups?: readonly CommandGroup[]): Promise<Record<string, unknown>>;
196
+ declare function registerSchema(program: Command): void;
197
+
198
+ declare const MANAGE_METADATA: readonly CommandMetadata[];
199
+
200
+ /** The only place a management credential is read. It never reaches argv, help, or a result. */
201
+ declare const TOKEN_VARIABLE = "SATURNDOCS_MANAGEMENT_TOKEN";
202
+ interface ClientEnvironment {
203
+ env?: Record<string, string | undefined>;
204
+ /** Injected for tests; passed on as a bare function, never as a method of this object. */
205
+ fetchImpl?: typeof fetch;
206
+ signal?: AbortSignal;
207
+ }
208
+ /**
209
+ * One client per invocation, built from the global flags and the environment.
210
+ * The token is read here rather than passed through a command's options, so a
211
+ * credential cannot arrive on a command line an agent later logs.
212
+ */
213
+ declare function clientFor(globals: GlobalOptions, environment?: ClientEnvironment): ManagementClient;
214
+ /**
215
+ * A classified client failure carried into the CLI's own error type, so the
216
+ * envelope reports the code and the server's own fault rather than the
217
+ * unclassified bucket every uncaught throw lands in.
218
+ */
219
+ declare function asCliError(error: unknown): unknown;
220
+
221
+ declare const AUTH_METADATA: readonly CommandMetadata[];
222
+ interface AuthStatus {
223
+ /** The site the credential resolves to, exactly as discovery returned it. */
224
+ current: string;
225
+ sites: SiteDiscovery["sites"];
226
+ /** One read answered. It says nothing about write or approve permission. */
227
+ read_verified: true;
228
+ }
229
+ declare function authStatusOf(discovery: SiteDiscovery): AuthStatus;
230
+ declare function registerAuth(program: Command, _cliDir: string, environment?: ClientEnvironment): void;
231
+
232
+ declare const SITES_METADATA: readonly CommandMetadata[];
233
+ /** The one site id, from the argument or the global flag; two that disagree are refused before any read. */
234
+ declare function requestedSite(positional: string | undefined, flag: string | null): string | undefined;
235
+ declare function registerSites(program: Command, _cliDir: string, environment?: ClientEnvironment): void;
236
+
237
+ declare const PAGES_METADATA: readonly CommandMetadata[];
238
+ /**
239
+ * What the answer does not cover. An unpublished site and counts the edge could
240
+ * not supply in full are both reported here, so a caller reading only the
241
+ * limitations still learns the list is not a complete picture.
242
+ */
243
+ declare function pagesLimitations(result: PagesResult): readonly ClientLimitation[];
244
+ declare function registerPages(program: Command, _cliDir: string, environment?: ClientEnvironment): void;
245
+
246
+ declare const REQUESTS_METADATA: readonly CommandMetadata[];
247
+ /** The one `requests` command tree. A later sibling module adds its own register call and metadata here. */
248
+ declare function registerRequests(program: Command, _cliDir: string, environment?: ClientEnvironment): void;
249
+
250
+ declare const REQUESTS_CREATE_METADATA: readonly CommandMetadata[];
251
+ interface CreateEnvironment extends ClientEnvironment {
252
+ stdin?: StdinSource;
253
+ readFileImpl?: (path: string) => Promise<string>;
254
+ }
255
+ declare function registerRequestsCreate(group: Command, environment?: CreateEnvironment): void;
256
+
257
+ declare const STATUS_METADATA: readonly CommandMetadata[];
258
+ declare function statusText(status: SiteStatus): string;
259
+ declare function registerStatus(program: Command, _cliDir: string, environment?: ClientEnvironment): void;
260
+
261
+ /**
262
+ * Walk up the directory tree from `startDir` looking for the SaturnDocs
263
+ * workspace root. The root is the first ancestor directory that contains BOTH
264
+ * a `pnpm-workspace.yaml` file and an `apps/web` directory. Returns the
265
+ * absolute path of that root.
266
+ *
267
+ * Throws a readable Error when no such ancestor exists.
268
+ */
269
+ declare function findWorkspaceRoot(startDir: string): string;
270
+ /**
271
+ * Resolve the absolute path of the `apps/web` Astro application directory by
272
+ * finding the workspace root above `startDir`.
273
+ */
274
+ declare function findWebDir(startDir: string): string;
275
+
276
+ interface ResolvedPage {
277
+ /** The navigation page entry, e.g. "writing/components" or "index". */
278
+ entry: string;
279
+ /** Absolute path of the source file on disk. */
280
+ file: string;
281
+ /** Which extension resolved. */
282
+ ext: ".mdx" | ".md";
283
+ }
284
+ /**
285
+ * Apply the fixed file-resolution rule shared by validate and the web app:
286
+ * for entry `p`, the source file is
287
+ * `<docsDir>/pages/p.mdx`, falling back to `<docsDir>/pages/p.md`. If both
288
+ * exist it is an error; if neither exists it is an error.
289
+ */
290
+ declare function resolvePageFile(docsDir: string, entry: string): ResolvedPage;
291
+ /**
292
+ * Site URL for a navigation page entry. The literal entry "index" maps to the
293
+ * site root "/"; every other entry maps to "/" + entry.
294
+ */
295
+ declare function pageUrl(entry: string): string;
296
+ /** All page entries across every navigation group, in navigation order. */
297
+ declare function collectPageEntries(config: DocsConfig): string[];
298
+
299
+ /** A single internal link in the built site that does not resolve to a file. */
300
+ interface BrokenLink {
301
+ /** The HTML file containing the link, relative to the dist directory. */
302
+ source: string;
303
+ /** The raw href/src value as written in the HTML. */
304
+ href: string;
305
+ }
306
+ /**
307
+ * Scan every `*.html` file under `distDir` for internal `href`/`src` targets
308
+ * and return the ones that do not resolve to a file in dist. Results are
309
+ * de-duplicated by (source file, href).
310
+ */
311
+ declare function scanBrokenLinks(distDir: string): Promise<BrokenLink[]>;
312
+
313
+ /**
314
+ * Validate a docs directory. Returns a list of human-readable error strings;
315
+ * an empty list means the directory is valid. Checks performed:
316
+ * - `docs.json` loads and passes the schema.
317
+ * - `models.toml` (only if present) loads and passes the schema.
318
+ * - every navigation page resolves under the file-resolution rule.
319
+ * - every navigation-group `openapi` file exists and parses.
320
+ */
321
+ declare function validateDocs(docsDir: string): Promise<string[]>;
322
+
323
+ /**
324
+ * Render a list of rows as a fixed-width, column-aligned text table with a
325
+ * header row and a divider. Each cell is left-aligned and padded to the widest
326
+ * value in its column. Returns the table as a single newline-joined string.
327
+ */
328
+ declare function renderTable(headers: string[], rows: string[][]): string;
329
+
330
+ interface BundleArchive {
331
+ path: string;
332
+ byteLength: number;
333
+ sha256: string;
334
+ warnings: AbiViolation[];
335
+ cleanup(): Promise<void>;
336
+ }
337
+ declare function createBundleArchive(inputDir: string): Promise<BundleArchive>;
338
+
339
+ type JobStatus = {
340
+ job_id: string;
341
+ state: string;
342
+ revision_id?: string;
343
+ release_id?: string;
344
+ generation?: number;
345
+ error_code?: string;
346
+ };
347
+ declare function deployBundle(input: {
348
+ docsDir: string;
349
+ apiUrl: string;
350
+ token: string;
351
+ promote: boolean;
352
+ idempotencyKey?: string;
353
+ pollIntervalMs?: number;
354
+ timeoutMs?: number;
355
+ fetchImpl?: typeof fetch;
356
+ onState?: (status: JobStatus) => void;
357
+ }): Promise<JobStatus>;
358
+
359
+ interface InitOptions {
360
+ name?: string;
361
+ primary?: string;
362
+ fromUrl?: string;
363
+ yes?: boolean;
364
+ }
365
+ interface InitDependencies {
366
+ extractBrand?: typeof extractBrandFromUrl;
367
+ }
368
+ interface InitResult {
369
+ docsDir: string;
370
+ config: DocsConfig;
371
+ extraction?: BrandExtraction;
372
+ }
373
+ declare function scaffoldDocsProject(dir?: string, options?: InitOptions, dependencies?: InitDependencies): Promise<InitResult>;
374
+ declare function buildDocsConfig(input: {
375
+ name: string;
376
+ description: string;
377
+ primary: string;
378
+ logo?: string;
379
+ favicon?: string;
380
+ }): DocsConfig;
381
+
382
+ export { AUTH_METADATA, type AuthStatus, type BrokenLink, type BundleArchive, COMMAND_GROUPS, COMMAND_GROUP_NAMES, CliError, type ClientEnvironment, type CommandGroup, type CreateEnvironment, type GlobalOptions, type InitOptions, type InitResult, type InterruptHandle, MANAGE_METADATA, PAGES_METADATA, REQUESTS_CREATE_METADATA, REQUESTS_METADATA, type RegisterGroup, type ResolvedPage, type ResultContext, type ResultWriter, SCHEMA_METADATA, SITES_METADATA, STATUS_METADATA, STDIN_BYTE_CEILING, TOKEN_VARIABLE, type TextInputFlags, applyCommandHelp, applyGlobalFlags, applyGlobalFlagsDeep, asCliError, authStatusOf, buildDocsConfig, clientError, clientFor, collectPageEntries, createBundleArchive, createResultWriter, deployBundle, failureResult, findCommandGroup, findWebDir, findWorkspaceRoot, helpBody, installInterrupt, interruptSignal, interrupted, invalidInput, pageUrl, pagesLimitations, readTextInput, registerAuth, registerPages, registerRequests, registerRequestsCreate, registerSchema, registerSites, registerStatus, renderTable, requestedSite, resolveGlobalOptions, resolvePageFile, scaffoldDocsProject, scanBrokenLinks, schemaDocument, selectCommandGroup, statusText, successResult, validateDocs, wantsJson };