@archora/forge-cli 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,363 @@
1
+ import { ContractDiffReport, ForgeDiagnostic, SchemaCoverageMatrix, GenerationPlan } from '@archora/forge-core';
2
+ import { ResolvedForgeConfig } from '@archora/forge-config';
3
+
4
+ declare function printPendingPhaseMessage(command: string, detail: string): void;
5
+ declare const logger: {
6
+ title(): void;
7
+ line(message?: string): void;
8
+ success(message: string): void;
9
+ warn(message: string): void;
10
+ error(message: string): void;
11
+ };
12
+
13
+ declare function writeReportFile(path: string, content: string): Promise<string>;
14
+
15
+ type SchemaRequestCliOptions = {
16
+ schemaHeader?: string | string[];
17
+ };
18
+ declare function parseSchemaRequestHeaders(value: string | string[] | undefined): Record<string, string>;
19
+
20
+ type DiagnosticLike = {
21
+ severity?: string;
22
+ code?: string;
23
+ message?: string;
24
+ location?: string;
25
+ suggestion?: string;
26
+ };
27
+ type DriftLike = {
28
+ path?: string;
29
+ kind?: string;
30
+ };
31
+ type SchemaLike = {
32
+ name?: string;
33
+ schema?: string;
34
+ configPath?: string | null;
35
+ healthScore?: number;
36
+ health?: {
37
+ score?: number;
38
+ endpointCount?: number;
39
+ schemaCount?: number;
40
+ tagCount?: number;
41
+ crudCandidateCount?: number;
42
+ };
43
+ resourceCount?: number;
44
+ resources?: unknown[] | number;
45
+ generatedFiles?: number;
46
+ protectedFiles?: number;
47
+ diagnosticsCount?: number;
48
+ failedChecks?: string[];
49
+ coverage?: CoverageLike;
50
+ };
51
+ type CoverageLike = {
52
+ operations?: {
53
+ total?: number;
54
+ generated?: number;
55
+ diagnosticOnly?: number;
56
+ byKind?: Record<string, number>;
57
+ byRequestShape?: Record<string, number>;
58
+ byResponseShape?: Record<string, number>;
59
+ };
60
+ schemas?: {
61
+ total?: number;
62
+ unsupportedConstructs?: Record<string, number>;
63
+ };
64
+ cases?: {
65
+ generated?: number;
66
+ skipped?: number;
67
+ fallback?: number;
68
+ diagnosticOnly?: number;
69
+ };
70
+ };
71
+ type HtmlReportPayload = {
72
+ ok?: boolean;
73
+ schema?: string;
74
+ configPath?: string | null;
75
+ healthScore?: number;
76
+ health?: {
77
+ score?: number;
78
+ endpointCount?: number;
79
+ schemaCount?: number;
80
+ tagCount?: number;
81
+ crudCandidateCount?: number;
82
+ };
83
+ resources?: unknown[] | number;
84
+ resourceCount?: number;
85
+ generatedFiles?: number;
86
+ protectedFiles?: number;
87
+ failedChecks?: string[];
88
+ readiness?: {
89
+ status?: string;
90
+ decision?: string;
91
+ gate?: {
92
+ result?: string;
93
+ recommendedCiMode?: string;
94
+ reason?: string;
95
+ };
96
+ blockers?: string[];
97
+ warnings?: string[];
98
+ nextActions?: string[];
99
+ reviewerChecklist?: string[];
100
+ };
101
+ drift?: DriftLike[];
102
+ diagnostics?: DiagnosticLike[];
103
+ schemas?: SchemaLike[];
104
+ files?: {
105
+ create?: number;
106
+ update?: number;
107
+ protected?: number;
108
+ };
109
+ changes?: Array<{
110
+ severity?: string;
111
+ code?: string;
112
+ message?: string;
113
+ location?: string;
114
+ }>;
115
+ affectedResources?: string[];
116
+ affectedFiles?: string[];
117
+ summary?: {
118
+ breaking?: number;
119
+ warnings?: number;
120
+ nonBreaking?: number;
121
+ total?: number;
122
+ };
123
+ decision?: {
124
+ status?: string;
125
+ mergeRisk?: string;
126
+ reason?: string;
127
+ };
128
+ impactedSurface?: {
129
+ operationIds?: string[];
130
+ clientMethods?: string[];
131
+ queryHooks?: string[];
132
+ };
133
+ migrationHints?: string[];
134
+ prSummary?: string;
135
+ resourceExplorer?: Array<{
136
+ name?: string;
137
+ operations?: Array<{
138
+ id?: string;
139
+ method?: string;
140
+ path?: string;
141
+ kind?: string;
142
+ }>;
143
+ generatedFiles?: string[];
144
+ }>;
145
+ coverage?: CoverageLike;
146
+ sourceUsages?: Array<{
147
+ path?: string;
148
+ matches?: string[];
149
+ lines?: number[];
150
+ }>;
151
+ };
152
+ declare function createHtmlReport(title: string, payload: HtmlReportPayload): string;
153
+
154
+ type SourceUsage = {
155
+ path: string;
156
+ matches: string[];
157
+ lines: number[];
158
+ };
159
+ type ImpactPayload = ContractDiffReport & {
160
+ ok: boolean;
161
+ base?: string;
162
+ oldSchema: string;
163
+ newSchema: string;
164
+ sourceUsages?: SourceUsage[];
165
+ };
166
+ declare function formatImpactReport(format: 'json' | 'markdown' | 'html', payload: ImpactPayload): string;
167
+ declare function formatImpactMarkdown(payload: ImpactPayload): string;
168
+ declare function formatPullRequestComment(payload: ImpactPayload): string;
169
+ declare function formatSourceUsageLines(usages: SourceUsage[]): string[];
170
+ declare function scanSourceUsages(repo: string, report: ContractDiffReport): Promise<SourceUsage[]>;
171
+
172
+ type AuditOptions = {
173
+ config?: string;
174
+ out?: string;
175
+ json?: boolean;
176
+ skipTypecheck?: boolean;
177
+ minHealthScore?: string | number;
178
+ } & SchemaRequestCliOptions;
179
+ type TypecheckResult = {
180
+ status: 'passed' | 'failed' | 'skipped';
181
+ command: string;
182
+ workspace: string;
183
+ errors: string[];
184
+ };
185
+ type AuditEntry = {
186
+ name: string;
187
+ schema: string;
188
+ configPath: string | null;
189
+ healthScore: number;
190
+ resources: number;
191
+ generatedFiles: number;
192
+ protectedFiles: number;
193
+ drift: Array<{
194
+ path: string;
195
+ kind: string;
196
+ }>;
197
+ diagnostics: ForgeDiagnostic[];
198
+ coverage: SchemaCoverageMatrix;
199
+ plan: GenerationPlan;
200
+ resourceExplorer: ResourceExplorerEntry[];
201
+ };
202
+ type ResourceExplorerEntry = {
203
+ name: string;
204
+ entity: string;
205
+ kind: string;
206
+ operations: Array<{
207
+ method: string;
208
+ path: string;
209
+ operationId: string | null;
210
+ kind: string;
211
+ }>;
212
+ generatedFiles: string[];
213
+ };
214
+ declare function runAuditPackage(schema: string | undefined, options: AuditOptions): Promise<{
215
+ outDir: string;
216
+ entries: AuditEntry[];
217
+ payload: {
218
+ ok: boolean;
219
+ schema: string;
220
+ schemas: {
221
+ name: string;
222
+ schema: string;
223
+ configPath: string | null;
224
+ healthScore: number;
225
+ resources: number;
226
+ generatedFiles: number;
227
+ protectedFiles: number;
228
+ driftCount: number;
229
+ diagnosticsCount: number;
230
+ coverage: SchemaCoverageMatrix;
231
+ }[];
232
+ audit: {
233
+ outDir: string;
234
+ generatedPreview: string;
235
+ artifacts: string[];
236
+ };
237
+ healthScore: number;
238
+ resources: number;
239
+ generatedFiles: number;
240
+ protectedFiles: number;
241
+ failedChecks: string[];
242
+ scorecard: {
243
+ frontendReadiness: number;
244
+ typeSafety: number;
245
+ resourceCoverage: number;
246
+ driftSafety: number;
247
+ ciAdoption: number;
248
+ };
249
+ generator: {
250
+ status: string;
251
+ version: string;
252
+ files: {
253
+ total: number;
254
+ missingMetadata: {
255
+ path: string;
256
+ }[];
257
+ versionMismatches: never[];
258
+ schemaHashMismatches: never[];
259
+ configHashMismatches: never[];
260
+ };
261
+ };
262
+ coverage: SchemaCoverageMatrix;
263
+ typecheck: TypecheckResult;
264
+ resourceExplorer: ResourceExplorerEntry[];
265
+ fixSuggestions: {
266
+ code: string;
267
+ count: number;
268
+ suggestion: string;
269
+ }[];
270
+ readiness: {
271
+ status: string;
272
+ gate: {
273
+ result: "pass";
274
+ recommendedCiMode: "block";
275
+ reason: string;
276
+ } | {
277
+ result: "warn";
278
+ recommendedCiMode: "comment";
279
+ reason: string;
280
+ } | {
281
+ result: "fail";
282
+ recommendedCiMode: "block";
283
+ reason: string;
284
+ };
285
+ decision: string;
286
+ blockers: string[];
287
+ warnings: string[];
288
+ nextActions: string[];
289
+ reviewerChecklist: string[];
290
+ summary: {
291
+ healthScore: number;
292
+ resources: number;
293
+ generatedFiles: number;
294
+ protectedFiles: number;
295
+ diagnostics: number;
296
+ drift: number;
297
+ failedChecks: number;
298
+ };
299
+ };
300
+ drift: {
301
+ path: string;
302
+ kind: string;
303
+ }[];
304
+ diagnostics: ForgeDiagnostic[];
305
+ };
306
+ }>;
307
+
308
+ type GitBaseSchema = {
309
+ path: string;
310
+ label: string;
311
+ base: string;
312
+ cleanup: () => Promise<void>;
313
+ };
314
+ declare function readGitBaseSchema(schemaPath: string, options: {
315
+ base: string;
316
+ repo?: string;
317
+ }): Promise<GitBaseSchema>;
318
+
319
+ type CliConfigResult = {
320
+ name?: string;
321
+ config: ResolvedForgeConfig;
322
+ schema: string;
323
+ configPath: string | null;
324
+ cwd: string;
325
+ };
326
+ declare function loadCliConfig(schema: string | undefined, options?: ({
327
+ config?: string;
328
+ force?: boolean;
329
+ } & SchemaRequestCliOptions)): Promise<CliConfigResult>;
330
+ declare function loadCliConfigSet(schema: string | undefined, options?: ({
331
+ config?: string;
332
+ force?: boolean;
333
+ } & SchemaRequestCliOptions)): Promise<CliConfigResult[]>;
334
+
335
+ type LicensePlan = 'trial' | 'pilot' | 'team' | 'organization';
336
+ type LicensePayload = {
337
+ licenseId: string;
338
+ customer: string;
339
+ issuedAt: string;
340
+ expiresAt: string;
341
+ plan: LicensePlan;
342
+ };
343
+ type LicenseValidation = {
344
+ status: 'active' | 'expired' | 'invalid' | 'clockRollback' | 'missing' | 'missingPublicKey';
345
+ payload: LicensePayload | null;
346
+ message: string;
347
+ };
348
+ declare function isLicenseEnforcementConfigured(): boolean;
349
+ declare function activateLicenseKey(licenseKey: string, options?: {
350
+ now?: Date;
351
+ }): Promise<LicenseValidation>;
352
+ declare function getStoredLicenseStatus(options?: {
353
+ now?: Date;
354
+ }): Promise<LicenseValidation>;
355
+ declare function removeStoredLicense(): Promise<void>;
356
+ declare function requireCommercialLicense(command: string): Promise<void>;
357
+ declare function validateLicenseKey(licenseKey: string, options?: {
358
+ now?: Date;
359
+ lastSeenAt?: string | null;
360
+ publicKey?: JsonWebKey | null;
361
+ }): Promise<LicenseValidation>;
362
+
363
+ export { type AuditOptions, type CliConfigResult, type GitBaseSchema, type ImpactPayload, type LicensePayload, type LicensePlan, type LicenseValidation, type SchemaRequestCliOptions, type SourceUsage, activateLicenseKey, createHtmlReport, formatImpactMarkdown, formatImpactReport, formatPullRequestComment, formatSourceUsageLines, getStoredLicenseStatus, isLicenseEnforcementConfigured, loadCliConfig, loadCliConfigSet, logger, parseSchemaRequestHeaders, printPendingPhaseMessage, readGitBaseSchema, removeStoredLicense, requireCommercialLicense, runAuditPackage, scanSourceUsages, validateLicenseKey, writeReportFile };
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ activateLicenseKey,
4
+ createHtmlReport,
5
+ formatImpactMarkdown,
6
+ formatImpactReport,
7
+ formatPullRequestComment,
8
+ formatSourceUsageLines,
9
+ getStoredLicenseStatus,
10
+ isLicenseEnforcementConfigured,
11
+ loadCliConfig,
12
+ loadCliConfigSet,
13
+ logger,
14
+ parseSchemaRequestHeaders,
15
+ printPendingPhaseMessage,
16
+ removeStoredLicense,
17
+ requireCommercialLicense,
18
+ runAuditPackage,
19
+ scanSourceUsages,
20
+ validateLicenseKey,
21
+ writeReportFile
22
+ } from "./chunk-RL23SDLM.js";
23
+
24
+ // src/git-base-schema.ts
25
+ import { execFile } from "child_process";
26
+ import { mkdtemp, rm, writeFile } from "fs/promises";
27
+ import { tmpdir } from "os";
28
+ import { isAbsolute, relative, resolve, sep } from "path";
29
+ import { promisify } from "util";
30
+ var execFileAsync = promisify(execFile);
31
+ async function readGitBaseSchema(schemaPath, options) {
32
+ const repo = resolve(options.repo ?? process.cwd());
33
+ const absoluteSchemaPath = isAbsolute(schemaPath) ? resolve(schemaPath) : resolve(repo, schemaPath);
34
+ const repoRelativePath = relative(repo, absoluteSchemaPath).split(sep).join("/");
35
+ if (!repoRelativePath || repoRelativePath.startsWith("..") || isAbsolute(repoRelativePath)) {
36
+ throw new Error(`Schema path must be inside the repository when using --base: ${schemaPath}`);
37
+ }
38
+ let stdout;
39
+ try {
40
+ const result = await execFileAsync("git", ["-C", repo, "show", `${options.base}:${repoRelativePath}`], {
41
+ maxBuffer: 20 * 1024 * 1024,
42
+ timeout: 15e3
43
+ });
44
+ stdout = result.stdout;
45
+ } catch (error) {
46
+ const message = error instanceof Error ? error.message : String(error);
47
+ throw new Error(`Cannot read ${repoRelativePath} from git ref "${options.base}". ${message}`);
48
+ }
49
+ const tempDir = await mkdtemp(resolve(tmpdir(), "archora-forge-base-"));
50
+ const tempPath = resolve(tempDir, repoRelativePath.replace(/\//g, "__"));
51
+ await writeFile(tempPath, stdout, "utf8");
52
+ return {
53
+ path: tempPath,
54
+ label: `${options.base}:${repoRelativePath}`,
55
+ base: options.base,
56
+ cleanup: () => rm(tempDir, { recursive: true, force: true })
57
+ };
58
+ }
59
+ export {
60
+ activateLicenseKey,
61
+ createHtmlReport,
62
+ formatImpactMarkdown,
63
+ formatImpactReport,
64
+ formatPullRequestComment,
65
+ formatSourceUsageLines,
66
+ getStoredLicenseStatus,
67
+ isLicenseEnforcementConfigured,
68
+ loadCliConfig,
69
+ loadCliConfigSet,
70
+ logger,
71
+ parseSchemaRequestHeaders,
72
+ printPendingPhaseMessage,
73
+ readGitBaseSchema,
74
+ removeStoredLicense,
75
+ requireCommercialLicense,
76
+ runAuditPackage,
77
+ scanSourceUsages,
78
+ validateLicenseKey,
79
+ writeReportFile
80
+ };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@archora/forge-cli",
3
- "version": "1.4.0",
3
+ "version": "2.0.0",
4
4
  "description": "CLI for generating typed frontend resource contracts from OpenAPI contracts.",
5
- "license": "SEE LICENSE IN LICENSE",
5
+ "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/archora-dev/archora-forge.git"
@@ -21,6 +21,10 @@
21
21
  ".": {
22
22
  "types": "./dist/index.d.ts",
23
23
  "import": "./dist/index.js"
24
+ },
25
+ "./internal": {
26
+ "types": "./dist/internal.d.ts",
27
+ "import": "./dist/internal.js"
24
28
  }
25
29
  },
26
30
  "files": [
@@ -40,9 +44,9 @@
40
44
  "@types/node": "^22.15.17",
41
45
  "tsup": "^8.4.0",
42
46
  "typescript": "^5.8.3",
43
- "@archora/forge-adapters": "1.4.0",
44
- "@archora/forge-core": "1.4.0",
45
- "@archora/forge-config": "1.4.0"
47
+ "@archora/forge-adapters": "2.0.0",
48
+ "@archora/forge-config": "2.0.0",
49
+ "@archora/forge-core": "2.0.0"
46
50
  },
47
51
  "scripts": {
48
52
  "build": "tsup",