@nifrajs/cli 3.3.0 → 4.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.
- package/README.md +42 -3
- package/dist/app-files.d.ts +11 -0
- package/dist/app-files.d.ts.map +1 -0
- package/dist/app-files.js +34 -0
- package/dist/app-files.js.map +1 -0
- package/dist/assure-hydration.d.ts +7 -1
- package/dist/assure-hydration.d.ts.map +1 -1
- package/dist/assure-hydration.js +128 -43
- package/dist/assure-hydration.js.map +1 -1
- package/dist/assure.d.ts.map +1 -1
- package/dist/assure.js +16 -2
- package/dist/assure.js.map +1 -1
- package/dist/capabilities-tool.d.ts +5 -1
- package/dist/capabilities-tool.d.ts.map +1 -1
- package/dist/capabilities-tool.js +32 -10
- package/dist/capabilities-tool.js.map +1 -1
- package/dist/cdn-check.d.ts +41 -0
- package/dist/cdn-check.d.ts.map +1 -0
- package/dist/cdn-check.js +207 -0
- package/dist/cdn-check.js.map +1 -0
- package/dist/check-diagnostics.d.ts +7 -15
- package/dist/check-diagnostics.d.ts.map +1 -1
- package/dist/check-diagnostics.js +162 -713
- package/dist/check-diagnostics.js.map +1 -1
- package/dist/check-scan.d.ts +58 -7
- package/dist/check-scan.d.ts.map +1 -1
- package/dist/check-scan.js +323 -62
- package/dist/check-scan.js.map +1 -1
- package/dist/check.d.ts +1 -0
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +145 -54
- package/dist/check.js.map +1 -1
- package/dist/cli.d.ts +42 -16
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +306 -87
- package/dist/cli.js.map +1 -1
- package/dist/command-catalog.d.ts +60 -5
- package/dist/command-catalog.d.ts.map +1 -1
- package/dist/command-catalog.js +298 -33
- package/dist/command-catalog.js.map +1 -1
- package/dist/config-target.d.ts +8 -0
- package/dist/config-target.d.ts.map +1 -0
- package/dist/config-target.js +45 -0
- package/dist/config-target.js.map +1 -0
- package/dist/contracts.d.ts +3 -2
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +56 -16
- package/dist/contracts.js.map +1 -1
- package/dist/db-audit.d.ts +37 -0
- package/dist/db-audit.d.ts.map +1 -0
- package/dist/db-audit.js +99 -0
- package/dist/db-audit.js.map +1 -0
- package/dist/db-child.d.ts +64 -0
- package/dist/db-child.d.ts.map +1 -0
- package/dist/db-child.js +213 -0
- package/dist/db-child.js.map +1 -0
- package/dist/db-config.d.ts +60 -0
- package/dist/db-config.d.ts.map +1 -0
- package/dist/db-config.js +176 -0
- package/dist/db-config.js.map +1 -0
- package/dist/db-tool.d.ts +84 -0
- package/dist/db-tool.d.ts.map +1 -0
- package/dist/db-tool.js +537 -0
- package/dist/db-tool.js.map +1 -0
- package/dist/dev-bun-config.d.ts +20 -13
- package/dist/dev-bun-config.d.ts.map +1 -1
- package/dist/dev-bun-config.js +98 -41
- package/dist/dev-bun-config.js.map +1 -1
- package/dist/dev-feed-tool.d.ts +106 -0
- package/dist/dev-feed-tool.d.ts.map +1 -0
- package/dist/dev-feed-tool.js +713 -0
- package/dist/dev-feed-tool.js.map +1 -0
- package/dist/dev-server-client.d.ts +67 -0
- package/dist/dev-server-client.d.ts.map +1 -0
- package/dist/dev-server-client.js +195 -0
- package/dist/dev-server-client.js.map +1 -0
- package/dist/diagnostics.d.ts +86 -0
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +85 -0
- package/dist/diagnostics.js.map +1 -1
- package/dist/diff-tool.d.ts +3 -3
- package/dist/diff-tool.d.ts.map +1 -1
- package/dist/diff-tool.js +6 -5
- package/dist/diff-tool.js.map +1 -1
- package/dist/docs-search.d.ts.map +1 -1
- package/dist/docs-search.js +12 -4
- package/dist/docs-search.js.map +1 -1
- package/dist/doctor.d.ts +17 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +76 -15
- package/dist/doctor.js.map +1 -1
- package/dist/env-file.d.ts +15 -0
- package/dist/env-file.d.ts.map +1 -1
- package/dist/env-file.js +73 -1
- package/dist/env-file.js.map +1 -1
- package/dist/fix-recipes.d.ts.map +1 -1
- package/dist/fix-recipes.js +41 -21
- package/dist/fix-recipes.js.map +1 -1
- package/dist/frontend-guidance.js +5 -5
- package/dist/frontend-guidance.js.map +1 -1
- package/dist/i18n-check.d.ts +16 -0
- package/dist/i18n-check.d.ts.map +1 -0
- package/dist/i18n-check.js +154 -0
- package/dist/i18n-check.js.map +1 -0
- package/dist/init-agents.d.ts +49 -13
- package/dist/init-agents.d.ts.map +1 -1
- package/dist/init-agents.js +239 -34
- package/dist/init-agents.js.map +1 -1
- package/dist/internal/code-unit-order.d.ts +4 -0
- package/dist/internal/code-unit-order.d.ts.map +1 -0
- package/dist/internal/code-unit-order.js +6 -0
- package/dist/internal/code-unit-order.js.map +1 -0
- package/dist/internal/script-kind.d.ts +7 -0
- package/dist/internal/script-kind.d.ts.map +1 -0
- package/dist/internal/script-kind.js +12 -0
- package/dist/internal/script-kind.js.map +1 -0
- package/dist/internal/source-facts.d.ts +5 -0
- package/dist/internal/source-facts.d.ts.map +1 -1
- package/dist/internal/source-facts.js +61 -5
- package/dist/internal/source-facts.js.map +1 -1
- package/dist/internal/typescript-import.d.ts +49 -24
- package/dist/internal/typescript-import.d.ts.map +1 -1
- package/dist/internal/typescript-import.js +507 -67
- package/dist/internal/typescript-import.js.map +1 -1
- package/dist/introspect.d.ts +6 -4
- package/dist/introspect.d.ts.map +1 -1
- package/dist/introspect.js +93 -74
- package/dist/introspect.js.map +1 -1
- package/dist/learn.js +3 -3
- package/dist/learn.js.map +1 -1
- package/dist/levels-tool.d.ts +10 -0
- package/dist/levels-tool.d.ts.map +1 -1
- package/dist/levels-tool.js +33 -3
- package/dist/levels-tool.js.map +1 -1
- package/dist/load.d.ts +71 -16
- package/dist/load.d.ts.map +1 -1
- package/dist/load.js +78 -18
- package/dist/load.js.map +1 -1
- package/dist/manifest-tool.d.ts.map +1 -1
- package/dist/manifest-tool.js +3 -2
- package/dist/manifest-tool.js.map +1 -1
- package/dist/mcp-app-tool.d.ts.map +1 -1
- package/dist/mcp-app-tool.js +2 -0
- package/dist/mcp-app-tool.js.map +1 -1
- package/dist/mcp-context.d.ts.map +1 -1
- package/dist/mcp-context.js +5 -6
- package/dist/mcp-context.js.map +1 -1
- package/dist/mcp-delegate.d.ts +57 -0
- package/dist/mcp-delegate.d.ts.map +1 -0
- package/dist/mcp-delegate.js +130 -0
- package/dist/mcp-delegate.js.map +1 -0
- package/dist/mcp-docs-tools.d.ts.map +1 -1
- package/dist/mcp-docs-tools.js +23 -5
- package/dist/mcp-docs-tools.js.map +1 -1
- package/dist/mcp-exec.d.ts +3 -0
- package/dist/mcp-exec.d.ts.map +1 -1
- package/dist/mcp-exec.js +263 -131
- package/dist/mcp-exec.js.map +1 -1
- package/dist/mcp-http.d.ts.map +1 -1
- package/dist/mcp-http.js +20 -5
- package/dist/mcp-http.js.map +1 -1
- package/dist/mcp-io.d.ts +26 -0
- package/dist/mcp-io.d.ts.map +1 -1
- package/dist/mcp-io.js +113 -0
- package/dist/mcp-io.js.map +1 -1
- package/dist/mcp-isolate.d.ts +48 -0
- package/dist/mcp-isolate.d.ts.map +1 -0
- package/dist/mcp-isolate.js +222 -0
- package/dist/mcp-isolate.js.map +1 -0
- package/dist/mcp-path.d.ts +10 -0
- package/dist/mcp-path.d.ts.map +1 -0
- package/dist/mcp-path.js +51 -0
- package/dist/mcp-path.js.map +1 -0
- package/dist/mcp-project-child.d.ts +74 -0
- package/dist/mcp-project-child.d.ts.map +1 -0
- package/dist/mcp-project-child.js +130 -0
- package/dist/mcp-project-child.js.map +1 -0
- package/dist/mcp-reflect.d.ts.map +1 -1
- package/dist/mcp-reflect.js +2 -2
- package/dist/mcp-reflect.js.map +1 -1
- package/dist/mcp-render.d.ts.map +1 -1
- package/dist/mcp-render.js +64 -45
- package/dist/mcp-render.js.map +1 -1
- package/dist/mcp-root.d.ts +37 -9
- package/dist/mcp-root.d.ts.map +1 -1
- package/dist/mcp-root.js +124 -25
- package/dist/mcp-root.js.map +1 -1
- package/dist/mcp-run.d.ts +18 -1
- package/dist/mcp-run.d.ts.map +1 -1
- package/dist/mcp-run.js +159 -55
- package/dist/mcp-run.js.map +1 -1
- package/dist/mcp-ws.js +4 -1
- package/dist/mcp-ws.js.map +1 -1
- package/dist/mcp.d.ts +18 -5
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +165 -82
- package/dist/mcp.js.map +1 -1
- package/dist/migrate-layout.d.ts +44 -0
- package/dist/migrate-layout.d.ts.map +1 -0
- package/dist/migrate-layout.js +982 -0
- package/dist/migrate-layout.js.map +1 -0
- package/dist/openapi-tool.d.ts +2 -2
- package/dist/openapi-tool.d.ts.map +1 -1
- package/dist/openapi-tool.js.map +1 -1
- package/dist/openapi-types.d.ts +2 -1
- package/dist/openapi-types.d.ts.map +1 -1
- package/dist/openapi-types.js +240 -12
- package/dist/openapi-types.js.map +1 -1
- package/dist/pipeline-report.d.ts +3 -2
- package/dist/pipeline-report.d.ts.map +1 -1
- package/dist/pipeline-report.js +19 -16
- package/dist/pipeline-report.js.map +1 -1
- package/dist/port.d.ts +5 -4
- package/dist/port.d.ts.map +1 -1
- package/dist/port.js +46 -29
- package/dist/port.js.map +1 -1
- package/dist/project-facts.d.ts +28 -4
- package/dist/project-facts.d.ts.map +1 -1
- package/dist/project-facts.js +12 -2
- package/dist/project-facts.js.map +1 -1
- package/dist/recipes/4.0.0.d.ts +9 -0
- package/dist/recipes/4.0.0.d.ts.map +1 -0
- package/dist/recipes/4.0.0.js +34 -0
- package/dist/recipes/4.0.0.js.map +1 -0
- package/dist/recipes/index.d.ts.map +1 -1
- package/dist/recipes/index.js +2 -0
- package/dist/recipes/index.js.map +1 -1
- package/dist/release-verification.d.ts +11 -1
- package/dist/release-verification.d.ts.map +1 -1
- package/dist/release-verification.js +47 -4
- package/dist/release-verification.js.map +1 -1
- package/dist/review.d.ts +21 -0
- package/dist/review.d.ts.map +1 -0
- package/dist/review.js +823 -0
- package/dist/review.js.map +1 -0
- package/dist/route-types.d.ts +28 -0
- package/dist/route-types.d.ts.map +1 -0
- package/dist/route-types.js +106 -0
- package/dist/route-types.js.map +1 -0
- package/dist/rules/codes.d.ts +9 -0
- package/dist/rules/codes.d.ts.map +1 -1
- package/dist/rules/codes.js +9 -0
- package/dist/rules/codes.js.map +1 -1
- package/dist/rules/data-guard.d.ts +12 -0
- package/dist/rules/data-guard.d.ts.map +1 -0
- package/dist/rules/data-guard.js +213 -0
- package/dist/rules/data-guard.js.map +1 -0
- package/dist/rules/index.d.ts +3 -0
- package/dist/rules/index.d.ts.map +1 -1
- package/dist/rules/index.js +17 -5
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/islands.d.ts.map +1 -1
- package/dist/rules/islands.js +7 -4
- package/dist/rules/islands.js.map +1 -1
- package/dist/rules/legacy.d.ts +3 -1
- package/dist/rules/legacy.d.ts.map +1 -1
- package/dist/rules/legacy.js +829 -34
- package/dist/rules/legacy.js.map +1 -1
- package/dist/rules/nano.d.ts.map +1 -1
- package/dist/rules/nano.js +15 -6
- package/dist/rules/nano.js.map +1 -1
- package/dist/rules/pages.d.ts +15 -0
- package/dist/rules/pages.d.ts.map +1 -0
- package/dist/rules/pages.js +88 -0
- package/dist/rules/pages.js.map +1 -0
- package/dist/rules/routes.d.ts +11 -0
- package/dist/rules/routes.d.ts.map +1 -1
- package/dist/rules/routes.js +180 -2
- package/dist/rules/routes.js.map +1 -1
- package/dist/rules/secrets.d.ts +10 -0
- package/dist/rules/secrets.d.ts.map +1 -0
- package/dist/rules/secrets.js +169 -0
- package/dist/rules/secrets.js.map +1 -0
- package/dist/rules/security.d.ts +7 -0
- package/dist/rules/security.d.ts.map +1 -1
- package/dist/rules/security.js +171 -65
- package/dist/rules/security.js.map +1 -1
- package/dist/rules/typescript.d.ts +16 -0
- package/dist/rules/typescript.d.ts.map +1 -0
- package/dist/rules/typescript.js +59 -0
- package/dist/rules/typescript.js.map +1 -0
- package/dist/rules/zones.d.ts +17 -0
- package/dist/rules/zones.d.ts.map +1 -0
- package/dist/rules/zones.js +174 -0
- package/dist/rules/zones.js.map +1 -0
- package/dist/scaffold.d.ts +25 -12
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +154 -90
- package/dist/scaffold.js.map +1 -1
- package/dist/sdk.d.ts +17 -3
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +941 -153
- package/dist/sdk.js.map +1 -1
- package/dist/search-terms.d.ts +2 -0
- package/dist/search-terms.d.ts.map +1 -1
- package/dist/search-terms.js +23 -8
- package/dist/search-terms.js.map +1 -1
- package/dist/smoke.d.ts +79 -0
- package/dist/smoke.d.ts.map +1 -0
- package/dist/smoke.js +494 -0
- package/dist/smoke.js.map +1 -0
- package/dist/sync-manifest.d.ts.map +1 -1
- package/dist/sync-manifest.js +2 -1
- package/dist/sync-manifest.js.map +1 -1
- package/dist/sync-routes.d.ts +4 -3
- package/dist/sync-routes.d.ts.map +1 -1
- package/dist/sync-routes.js +4 -3
- package/dist/sync-routes.js.map +1 -1
- package/dist/test-tool.d.ts.map +1 -1
- package/dist/test-tool.js +30 -11
- package/dist/test-tool.js.map +1 -1
- package/dist/types-search.d.ts.map +1 -1
- package/dist/types-search.js +11 -5
- package/dist/types-search.js.map +1 -1
- package/dist/upgrade.d.ts +36 -6
- package/dist/upgrade.d.ts.map +1 -1
- package/dist/upgrade.js +167 -29
- package/dist/upgrade.js.map +1 -1
- package/dist/verification-plan.d.ts.map +1 -1
- package/dist/verification-plan.js +8 -0
- package/dist/verification-plan.js.map +1 -1
- package/dist/verification.d.ts.map +1 -1
- package/dist/verification.js +45 -12
- package/dist/verification.js.map +1 -1
- package/dist/web-app-options.d.ts +19 -0
- package/dist/web-app-options.d.ts.map +1 -0
- package/dist/web-app-options.js +49 -0
- package/dist/web-app-options.js.map +1 -0
- package/dist/work-graph.d.ts +3 -0
- package/dist/work-graph.d.ts.map +1 -1
- package/dist/work-graph.js +33 -16
- package/dist/work-graph.js.map +1 -1
- package/docs/examples.json +185 -29
- package/docs/llms-full.txt +4123 -548
- package/docs/types.json +14391 -10060
- package/package.json +19 -11
- package/src/app-files.ts +40 -0
- package/src/assure-hydration.ts +139 -46
- package/src/assure.ts +17 -2
- package/src/capabilities-tool.ts +35 -9
- package/src/cdn-check.ts +268 -0
- package/src/check-diagnostics.ts +199 -797
- package/src/check-scan.ts +394 -63
- package/src/check.ts +146 -58
- package/src/cli.ts +347 -92
- package/src/command-catalog.ts +407 -45
- package/src/config-target.ts +47 -0
- package/src/contracts.ts +66 -15
- package/src/db-audit.ts +128 -0
- package/src/db-child.ts +285 -0
- package/src/db-config.ts +224 -0
- package/src/db-tool.ts +690 -0
- package/src/dev-bun-config.ts +116 -40
- package/src/dev-feed-tool.ts +912 -0
- package/src/dev-server-client.ts +267 -0
- package/src/diagnostics.ts +179 -0
- package/src/diff-tool.ts +6 -5
- package/src/docs-search.ts +10 -3
- package/src/doctor.ts +98 -15
- package/src/env-file.ts +78 -1
- package/src/fix-recipes.ts +44 -31
- package/src/frontend-guidance.ts +5 -5
- package/src/i18n-check.ts +179 -0
- package/src/init-agents.ts +301 -38
- package/src/internal/code-unit-order.ts +5 -0
- package/src/internal/script-kind.ts +11 -0
- package/src/internal/source-facts.ts +96 -22
- package/src/internal/typescript-import.ts +663 -68
- package/src/introspect.ts +93 -82
- package/src/learn.ts +3 -3
- package/src/levels-tool.ts +47 -2
- package/src/load.ts +144 -32
- package/src/manifest-tool.ts +3 -2
- package/src/mcp-app-tool.ts +2 -0
- package/src/mcp-context.ts +5 -7
- package/src/mcp-delegate.ts +162 -0
- package/src/mcp-docs-tools.ts +23 -5
- package/src/mcp-exec.ts +301 -161
- package/src/mcp-http.ts +22 -5
- package/src/mcp-io.ts +130 -0
- package/src/mcp-isolate.ts +287 -0
- package/src/mcp-path.ts +50 -0
- package/src/mcp-project-child.ts +182 -0
- package/src/mcp-reflect.ts +3 -2
- package/src/mcp-render.ts +72 -42
- package/src/mcp-root.ts +130 -24
- package/src/mcp-run.ts +190 -56
- package/src/mcp-ws.ts +4 -1
- package/src/mcp.ts +193 -91
- package/src/migrate-layout.ts +1121 -0
- package/src/openapi-tool.ts +7 -3
- package/src/openapi-types.ts +315 -13
- package/src/pipeline-report.ts +22 -18
- package/src/port.ts +53 -30
- package/src/project-facts.ts +42 -8
- package/src/recipes/4.0.0.ts +35 -0
- package/src/recipes/index.ts +2 -0
- package/src/release-verification.ts +74 -5
- package/src/review.ts +988 -0
- package/src/route-types.ts +133 -0
- package/src/rules/codes.ts +9 -0
- package/src/rules/data-guard.ts +230 -0
- package/src/rules/index.ts +18 -5
- package/src/rules/islands.ts +12 -4
- package/src/rules/legacy.ts +947 -35
- package/src/rules/nano.ts +18 -6
- package/src/rules/pages.ts +99 -0
- package/src/rules/routes.ts +181 -2
- package/src/rules/secrets.ts +174 -0
- package/src/rules/security.ts +198 -70
- package/src/rules/typescript.ts +77 -0
- package/src/rules/zones.ts +195 -0
- package/src/scaffold.ts +175 -98
- package/src/sdk.ts +1215 -158
- package/src/search-terms.ts +24 -7
- package/src/smoke.ts +607 -0
- package/src/sync-manifest.ts +2 -1
- package/src/sync-routes.ts +4 -3
- package/src/test-tool.ts +32 -11
- package/src/types-search.ts +11 -4
- package/src/upgrade.ts +205 -25
- package/src/verification-plan.ts +27 -0
- package/src/verification.ts +50 -12
- package/src/web-app-options.ts +57 -0
- package/src/work-graph.ts +40 -16
package/src/command-catalog.ts
CHANGED
|
@@ -13,14 +13,23 @@ import type {
|
|
|
13
13
|
CapabilityExplainCommandResult,
|
|
14
14
|
CapabilitySnapshotCommandResult,
|
|
15
15
|
} from "./capabilities-tool.ts"
|
|
16
|
+
import { cdnCheckSpec } from "./cdn-check.ts"
|
|
16
17
|
import { type CheckResult, renderCheckReport } from "./check.ts"
|
|
17
18
|
import type { ContractsLock } from "./contracts.ts"
|
|
19
|
+
import { dbAuditSpec, dbQuerySpec, dbRoleSpec, dbSchemaSpec } from "./db-tool.ts"
|
|
20
|
+
import { errorsSpec, logsSpec } from "./dev-feed-tool.ts"
|
|
21
|
+
import { type Diagnostic, diagnostic, normalizeSeverity, toSarifLog } from "./diagnostics.ts"
|
|
18
22
|
import type { DoctorResult } from "./doctor.ts"
|
|
23
|
+
import { type I18nCheckOutput, i18nCheckPassed, renderI18nCheck } from "./i18n-check.ts"
|
|
19
24
|
import type { VerificationLevelsResult } from "./levels-tool.ts"
|
|
20
25
|
import type { LoadedApp } from "./load.ts"
|
|
21
26
|
import type { ManifestEmitCommandResult } from "./manifest-tool.ts"
|
|
27
|
+
import type { LayoutMigrationResult } from "./migrate-layout.ts"
|
|
22
28
|
import { collectPortResult, type PortResult, renderReport } from "./port.ts"
|
|
23
29
|
import type { ReplayResult } from "./replay.ts"
|
|
30
|
+
import { reviewSpec } from "./review.ts"
|
|
31
|
+
import type { RouteTypesReport } from "./route-types.ts"
|
|
32
|
+
import type { SmokeReport } from "./smoke.ts"
|
|
24
33
|
import type { StylexMigrationResult } from "./stylex-migrate.ts"
|
|
25
34
|
import {
|
|
26
35
|
collectProjectWorkGraph,
|
|
@@ -77,9 +86,16 @@ export interface CommandSpec<Input, Output> {
|
|
|
77
86
|
readonly transports: readonly CommandTransport[]
|
|
78
87
|
readonly stability: CommandStability
|
|
79
88
|
readonly argv?: CommandArgvBinding<Input>
|
|
89
|
+
/**
|
|
90
|
+
* Input fields only the CLI may set: MCP neither advertises nor accepts them. For a field that acts
|
|
91
|
+
* with the operator's own credentials, such as a signing key, which an agent must not invoke.
|
|
92
|
+
*/
|
|
93
|
+
readonly cliOnlyFields?: readonly string[]
|
|
80
94
|
readonly run: (input: Input, ctx: CommandCtx) => Promise<Output>
|
|
81
95
|
readonly render: (out: Output, input?: Input) => readonly string[]
|
|
82
96
|
readonly success?: (out: Output, input: Input) => boolean
|
|
97
|
+
/** Optional command-specific process status. Legacy commands retain the boolean fallback. */
|
|
98
|
+
readonly exitCode?: (out: Output, input: Input) => number
|
|
83
99
|
/** JSON-compatible view. Defaults to the raw command result. */
|
|
84
100
|
readonly json?: (out: Output, input: Input) => unknown
|
|
85
101
|
}
|
|
@@ -91,6 +107,8 @@ export interface CommandCatalogEntry {
|
|
|
91
107
|
readonly outputVersion: number
|
|
92
108
|
readonly transports: readonly CommandTransport[]
|
|
93
109
|
readonly stability: CommandStability
|
|
110
|
+
/** {@link CommandSpec.cliOnlyFields}: present in `inputSchema`, absent from the MCP tool's. */
|
|
111
|
+
readonly cliOnlyFields: readonly string[]
|
|
94
112
|
}
|
|
95
113
|
|
|
96
114
|
function freezeJson<T>(value: T): T {
|
|
@@ -112,6 +130,20 @@ export function toCommandCatalogEntry<Input, Output>(
|
|
|
112
130
|
outputVersion: spec.output.version,
|
|
113
131
|
transports: Object.freeze([...spec.transports]),
|
|
114
132
|
stability: spec.stability,
|
|
133
|
+
cliOnlyFields: Object.freeze([...(spec.cliOnlyFields ?? [])]),
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** The input schema a command's MCP tool advertises: its catalog schema without CLI-only fields. */
|
|
138
|
+
export function commandMcpInputSchema(entry: CommandCatalogEntry): CommandJsonSchema {
|
|
139
|
+
const properties = entry.inputSchema.properties
|
|
140
|
+
if (entry.cliOnlyFields.length === 0 || typeof properties !== "object" || properties === null)
|
|
141
|
+
return entry.inputSchema
|
|
142
|
+
return freezeJson({
|
|
143
|
+
...entry.inputSchema,
|
|
144
|
+
properties: Object.fromEntries(
|
|
145
|
+
Object.entries(properties).filter(([key]) => !entry.cliOnlyFields.includes(key)),
|
|
146
|
+
),
|
|
115
147
|
})
|
|
116
148
|
}
|
|
117
149
|
|
|
@@ -240,6 +272,7 @@ function parseBooleanFlags(
|
|
|
240
272
|
interface CheckInput {
|
|
241
273
|
readonly lintsOnly?: boolean | undefined
|
|
242
274
|
readonly json?: boolean | undefined
|
|
275
|
+
readonly sarif?: boolean | undefined
|
|
243
276
|
readonly maxDiagnostics?: number | undefined
|
|
244
277
|
readonly dir?: string | undefined
|
|
245
278
|
}
|
|
@@ -319,14 +352,38 @@ interface FixInput {
|
|
|
319
352
|
readonly dir?: string | undefined
|
|
320
353
|
}
|
|
321
354
|
|
|
355
|
+
/** `migrate layout`, or `migrate --from tailwind --to stylex`; the parser admits only those two. */
|
|
322
356
|
interface MigrateInput {
|
|
323
|
-
readonly
|
|
324
|
-
readonly
|
|
357
|
+
readonly kind?: "layout" | undefined
|
|
358
|
+
readonly from?: "tailwind" | undefined
|
|
359
|
+
readonly to?: "stylex" | undefined
|
|
325
360
|
readonly write?: boolean | undefined
|
|
326
361
|
readonly json?: boolean | undefined
|
|
327
362
|
readonly dir?: string | undefined
|
|
328
363
|
}
|
|
329
364
|
|
|
365
|
+
interface TargetInput {
|
|
366
|
+
readonly target?: string | undefined
|
|
367
|
+
readonly json?: boolean | undefined
|
|
368
|
+
readonly dir?: string | undefined
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
interface TargetOutput {
|
|
372
|
+
readonly ok: boolean
|
|
373
|
+
readonly target: string
|
|
374
|
+
/** The target before this run, when it switched one; `undefined` when none was declared. */
|
|
375
|
+
readonly previous?: string | undefined
|
|
376
|
+
readonly changed: boolean
|
|
377
|
+
/** What `nifra build` now emits, and how it deploys. */
|
|
378
|
+
readonly run: string
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
interface TypesInput {
|
|
382
|
+
readonly check?: boolean | undefined
|
|
383
|
+
readonly json?: boolean | undefined
|
|
384
|
+
readonly dir?: string | undefined
|
|
385
|
+
}
|
|
386
|
+
|
|
330
387
|
interface SnapshotInput {
|
|
331
388
|
readonly out?: string | undefined
|
|
332
389
|
readonly json?: boolean | undefined
|
|
@@ -371,6 +428,21 @@ interface PortInput {
|
|
|
371
428
|
readonly dir?: string | undefined
|
|
372
429
|
}
|
|
373
430
|
|
|
431
|
+
interface SmokeInput {
|
|
432
|
+
readonly fixture?: string | undefined
|
|
433
|
+
readonly inProcess?: boolean | undefined
|
|
434
|
+
readonly json?: boolean | undefined
|
|
435
|
+
readonly dir?: string | undefined
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
interface I18nInput {
|
|
439
|
+
readonly action: "check"
|
|
440
|
+
readonly entry?: string | undefined
|
|
441
|
+
readonly json?: boolean | undefined
|
|
442
|
+
readonly strict?: boolean | undefined
|
|
443
|
+
readonly dir?: string | undefined
|
|
444
|
+
}
|
|
445
|
+
|
|
374
446
|
interface CheckCommandOutput extends CheckResult {}
|
|
375
447
|
interface AssureCommandOutput {
|
|
376
448
|
readonly report?: unknown
|
|
@@ -401,7 +473,9 @@ interface FixCommandOutput {
|
|
|
401
473
|
readonly failed: readonly { readonly code: string; readonly reason: string }[]
|
|
402
474
|
readonly diagnostics: readonly unknown[]
|
|
403
475
|
}
|
|
404
|
-
|
|
476
|
+
type MigrateCommandOutput =
|
|
477
|
+
| (StylexMigrationResult & { readonly kind?: undefined })
|
|
478
|
+
| (LayoutMigrationResult & { readonly kind: "layout" })
|
|
405
479
|
interface SnapshotCommandOutput {
|
|
406
480
|
readonly ok: true
|
|
407
481
|
readonly file: string
|
|
@@ -425,10 +499,13 @@ interface SyncCommandOutput {
|
|
|
425
499
|
readonly results: readonly unknown[]
|
|
426
500
|
}
|
|
427
501
|
|
|
502
|
+
interface SmokeCommandOutput extends SmokeReport {}
|
|
503
|
+
|
|
428
504
|
const CHECK_SCHEMA = input<CheckInput>(
|
|
429
505
|
objectSchema({
|
|
430
506
|
lintsOnly: { type: "boolean" },
|
|
431
507
|
json: { type: "boolean" },
|
|
508
|
+
sarif: { type: "boolean" },
|
|
432
509
|
maxDiagnostics: { type: "integer", minimum: 1 },
|
|
433
510
|
dir: { type: "string" },
|
|
434
511
|
}),
|
|
@@ -438,7 +515,7 @@ const CHECK_SCHEMA = input<CheckInput>(
|
|
|
438
515
|
if (maxDiagnostics !== undefined && (!Number.isInteger(maxDiagnostics) || maxDiagnostics < 1))
|
|
439
516
|
throw new TypeError("maxDiagnostics must be a positive integer")
|
|
440
517
|
return {
|
|
441
|
-
...parseBooleanFlags(raw, ["lintsOnly", "json"]),
|
|
518
|
+
...parseBooleanFlags(raw, ["lintsOnly", "json", "sarif"]),
|
|
442
519
|
...(maxDiagnostics === undefined ? {} : { maxDiagnostics }),
|
|
443
520
|
...(raw.dir === undefined ? {} : { dir: raw.dir }),
|
|
444
521
|
} as CheckInput
|
|
@@ -642,26 +719,53 @@ const FIX_SCHEMA = input<FixInput>(
|
|
|
642
719
|
)
|
|
643
720
|
|
|
644
721
|
const MIGRATE_SCHEMA = input<MigrateInput>(
|
|
645
|
-
objectSchema(
|
|
646
|
-
{
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
["from", "to"],
|
|
654
|
-
),
|
|
722
|
+
objectSchema({
|
|
723
|
+
kind: { type: "string", enum: ["layout"] },
|
|
724
|
+
from: { type: "string", enum: ["tailwind"] },
|
|
725
|
+
to: { type: "string", enum: ["stylex"] },
|
|
726
|
+
write: { type: "boolean" },
|
|
727
|
+
json: { type: "boolean" },
|
|
728
|
+
dir: { type: "string" },
|
|
729
|
+
}),
|
|
655
730
|
(value) => {
|
|
656
731
|
const raw = withDir(record(value))
|
|
732
|
+
const flags = {
|
|
733
|
+
...parseBooleanFlags(raw, ["write", "json"]),
|
|
734
|
+
...(raw.dir === undefined ? {} : { dir: raw.dir }),
|
|
735
|
+
}
|
|
736
|
+
const kind = optionalString(raw.kind, "kind")
|
|
737
|
+
if (kind !== undefined) {
|
|
738
|
+
if (kind !== "layout")
|
|
739
|
+
throw new TypeError("the migration must be `layout` (or --from tailwind --to stylex)")
|
|
740
|
+
return { kind, ...flags }
|
|
741
|
+
}
|
|
657
742
|
const from = optionalString(raw.from, "from")
|
|
658
743
|
const to = optionalString(raw.to, "to")
|
|
659
744
|
if (from !== "tailwind") throw new TypeError("from must be tailwind")
|
|
660
745
|
if (to !== "stylex") throw new TypeError("to must be stylex")
|
|
746
|
+
return { from, to, ...flags }
|
|
747
|
+
},
|
|
748
|
+
)
|
|
749
|
+
|
|
750
|
+
const TARGET_SCHEMA = input<TargetInput>(
|
|
751
|
+
objectSchema({ target: { type: "string" }, json: { type: "boolean" }, dir: { type: "string" } }),
|
|
752
|
+
(value) => {
|
|
753
|
+
const raw = withDir(record(value))
|
|
754
|
+
const target = optionalString(raw.target, "target")
|
|
661
755
|
return {
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
...
|
|
756
|
+
...parseBooleanFlags(raw, ["json"]),
|
|
757
|
+
...(raw.dir === undefined ? {} : { dir: raw.dir }),
|
|
758
|
+
...(target === undefined ? {} : { target }),
|
|
759
|
+
}
|
|
760
|
+
},
|
|
761
|
+
)
|
|
762
|
+
|
|
763
|
+
const TYPES_SCHEMA = input<TypesInput>(
|
|
764
|
+
objectSchema({ check: { type: "boolean" }, json: { type: "boolean" }, dir: { type: "string" } }),
|
|
765
|
+
(value) => {
|
|
766
|
+
const raw = withDir(record(value))
|
|
767
|
+
return {
|
|
768
|
+
...parseBooleanFlags(raw, ["check", "json"]),
|
|
665
769
|
...(raw.dir === undefined ? {} : { dir: raw.dir }),
|
|
666
770
|
}
|
|
667
771
|
},
|
|
@@ -784,15 +888,76 @@ const PORT_SCHEMA = input<PortInput>(
|
|
|
784
888
|
},
|
|
785
889
|
)
|
|
786
890
|
|
|
891
|
+
const SMOKE_SCHEMA = input<SmokeInput>(
|
|
892
|
+
objectSchema({
|
|
893
|
+
fixture: { type: "string" },
|
|
894
|
+
inProcess: { type: "boolean" },
|
|
895
|
+
json: { type: "boolean" },
|
|
896
|
+
dir: { type: "string" },
|
|
897
|
+
}),
|
|
898
|
+
(value) => {
|
|
899
|
+
const raw = withDir(record(value))
|
|
900
|
+
return {
|
|
901
|
+
fixture: optionalString(raw.fixture, "fixture"),
|
|
902
|
+
...parseBooleanFlags(raw, ["inProcess", "json"]),
|
|
903
|
+
...(raw.dir === undefined ? {} : { dir: raw.dir }),
|
|
904
|
+
}
|
|
905
|
+
},
|
|
906
|
+
)
|
|
907
|
+
|
|
908
|
+
const I18N_SCHEMA = input<I18nInput>(
|
|
909
|
+
objectSchema(
|
|
910
|
+
{
|
|
911
|
+
action: { type: "string", enum: ["check"] },
|
|
912
|
+
entry: { type: "string" },
|
|
913
|
+
json: { type: "boolean" },
|
|
914
|
+
strict: { type: "boolean" },
|
|
915
|
+
dir: { type: "string" },
|
|
916
|
+
},
|
|
917
|
+
["action"],
|
|
918
|
+
),
|
|
919
|
+
(value) => {
|
|
920
|
+
const raw = withDir(record(value))
|
|
921
|
+
if (raw.action !== "check") {
|
|
922
|
+
throw new TypeError(
|
|
923
|
+
raw.action === undefined
|
|
924
|
+
? "i18n needs an action: nifra i18n check [entry]"
|
|
925
|
+
: `unknown i18n action: ${String(raw.action)} (the one action is check)`,
|
|
926
|
+
)
|
|
927
|
+
}
|
|
928
|
+
return {
|
|
929
|
+
action: "check",
|
|
930
|
+
entry: optionalString(raw.entry, "entry"),
|
|
931
|
+
...parseBooleanFlags(raw, ["json", "strict"]),
|
|
932
|
+
...(raw.dir === undefined ? {} : { dir: raw.dir }),
|
|
933
|
+
}
|
|
934
|
+
},
|
|
935
|
+
)
|
|
936
|
+
|
|
787
937
|
function loadAppFor(ctx: CommandCtx): Promise<LoadedApp> {
|
|
788
938
|
if (ctx.loadApp !== undefined) return ctx.loadApp()
|
|
789
939
|
return import("./load.ts").then(({ loadApp }) => loadApp(ctx.cwd))
|
|
790
940
|
}
|
|
791
941
|
|
|
792
|
-
function
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
942
|
+
function structuredDiagnostics(out: CheckCommandOutput): readonly Diagnostic[] {
|
|
943
|
+
if (out.structuredDiagnostics !== undefined) return out.structuredDiagnostics
|
|
944
|
+
return out.diagnostics.map((value) =>
|
|
945
|
+
diagnostic({
|
|
946
|
+
code: value.code ?? value.rule,
|
|
947
|
+
severity: normalizeSeverity(value.severity),
|
|
948
|
+
message: value.message,
|
|
949
|
+
...(value.file === undefined ? {} : { file: value.file }),
|
|
950
|
+
...(value.line === undefined ? {} : { line: value.line }),
|
|
951
|
+
...(value.evidence === undefined ? {} : { evidence: value.evidence }),
|
|
952
|
+
...(value.fix === undefined ? {} : { fix: { recipe: value.fix } }),
|
|
953
|
+
...(value.verify === undefined ? {} : { verify: value.verify }),
|
|
954
|
+
}),
|
|
955
|
+
)
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
function checkJson(out: CheckCommandOutput, input?: CheckInput): unknown {
|
|
959
|
+
if (input?.sarif === true) return toSarifLog(structuredDiagnostics(out))
|
|
960
|
+
return { ...out, diagnostics: structuredDiagnostics(out) }
|
|
796
961
|
}
|
|
797
962
|
|
|
798
963
|
const checkSpec: CommandSpec<CheckInput, CheckCommandOutput> = {
|
|
@@ -810,6 +975,7 @@ const checkSpec: CommandSpec<CheckInput, CheckCommandOutput> = {
|
|
|
810
975
|
flags: [
|
|
811
976
|
{ name: "lints-only", field: "lintsOnly", type: "boolean" },
|
|
812
977
|
{ name: "json", field: "json", type: "boolean" },
|
|
978
|
+
{ name: "sarif", field: "sarif", type: "boolean" },
|
|
813
979
|
],
|
|
814
980
|
},
|
|
815
981
|
async run(value, ctx) {
|
|
@@ -822,9 +988,12 @@ const checkSpec: CommandSpec<CheckInput, CheckCommandOutput> = {
|
|
|
822
988
|
})
|
|
823
989
|
).check()
|
|
824
990
|
},
|
|
825
|
-
render: (out) =>
|
|
991
|
+
render: (out, input) =>
|
|
992
|
+
input?.sarif === true
|
|
993
|
+
? JSON.stringify(checkJson(out, input), null, 2).split("\n")
|
|
994
|
+
: renderCheckReport(out),
|
|
826
995
|
success: (out) => out.ok,
|
|
827
|
-
json: (out) => checkJson(out),
|
|
996
|
+
json: (out, input) => checkJson(out, input),
|
|
828
997
|
}
|
|
829
998
|
|
|
830
999
|
const assureSpec: CommandSpec<AssureInput, AssureCommandOutput> = {
|
|
@@ -970,6 +1139,8 @@ const manifestSpec: CommandSpec<ManifestInput, ManifestEmitCommandResult | DiffC
|
|
|
970
1139
|
output: output({ type: "object" }),
|
|
971
1140
|
transports: ["cli", "mcp"],
|
|
972
1141
|
stability: "stable",
|
|
1142
|
+
// The signer is the operator's KMS/HSM callback; an agent signing its own manifest defeats it.
|
|
1143
|
+
cliOnlyFields: ["sign"],
|
|
973
1144
|
argv: {
|
|
974
1145
|
positionals: ["action", "before", "after"],
|
|
975
1146
|
flags: [
|
|
@@ -1111,7 +1282,10 @@ const openApiSpec: CommandSpec<OpenApiInput, OpenApiCommandOutput> = {
|
|
|
1111
1282
|
],
|
|
1112
1283
|
},
|
|
1113
1284
|
async run(value, ctx) {
|
|
1114
|
-
const app =
|
|
1285
|
+
const app =
|
|
1286
|
+
ctx.loadApp !== undefined
|
|
1287
|
+
? await ctx.loadApp()
|
|
1288
|
+
: await import("./load.ts").then(({ loadBackendApp }) => loadBackendApp(ctx.cwd))
|
|
1115
1289
|
const { renderOpenApiWithTypes } = await import("./openapi-tool.ts")
|
|
1116
1290
|
const format = value.format ?? "json"
|
|
1117
1291
|
return {
|
|
@@ -1227,12 +1401,14 @@ const fixSpec: CommandSpec<FixInput, FixCommandOutput> = {
|
|
|
1227
1401
|
|
|
1228
1402
|
const migrateSpec: CommandSpec<MigrateInput, MigrateCommandOutput> = {
|
|
1229
1403
|
name: "migrate",
|
|
1230
|
-
summary:
|
|
1404
|
+
summary:
|
|
1405
|
+
"Move an app onto the frontend/backend split (`migrate layout`), or migrate static Tailwind utilities to StyleX.",
|
|
1231
1406
|
input: MIGRATE_SCHEMA,
|
|
1232
1407
|
output: output({
|
|
1233
1408
|
type: "object",
|
|
1234
1409
|
properties: {
|
|
1235
1410
|
ok: { type: "boolean" },
|
|
1411
|
+
kind: { type: "string" },
|
|
1236
1412
|
from: { type: "string" },
|
|
1237
1413
|
to: { type: "string" },
|
|
1238
1414
|
write: { type: "boolean" },
|
|
@@ -1241,12 +1417,16 @@ const migrateSpec: CommandSpec<MigrateInput, MigrateCommandOutput> = {
|
|
|
1241
1417
|
written: { type: "array" },
|
|
1242
1418
|
issues: { type: "array" },
|
|
1243
1419
|
files: { type: "array" },
|
|
1420
|
+
splits: { type: "array" },
|
|
1421
|
+
moves: { type: "array" },
|
|
1422
|
+
rewritten: { type: "array" },
|
|
1244
1423
|
},
|
|
1245
|
-
required: ["ok", "
|
|
1424
|
+
required: ["ok", "write", "issues"],
|
|
1246
1425
|
}),
|
|
1247
1426
|
transports: ["cli"],
|
|
1248
1427
|
stability: "stable",
|
|
1249
1428
|
argv: {
|
|
1429
|
+
positionals: ["kind"],
|
|
1250
1430
|
flags: [
|
|
1251
1431
|
{ name: "from", field: "from", type: "string" },
|
|
1252
1432
|
{ name: "to", field: "to", type: "string" },
|
|
@@ -1256,27 +1436,142 @@ const migrateSpec: CommandSpec<MigrateInput, MigrateCommandOutput> = {
|
|
|
1256
1436
|
],
|
|
1257
1437
|
},
|
|
1258
1438
|
async run(value, ctx) {
|
|
1439
|
+
const dir = resolve(ctx.cwd, value.dir ?? ".")
|
|
1440
|
+
const write = value.write === undefined ? {} : { write: value.write }
|
|
1441
|
+
if (value.kind === "layout") {
|
|
1442
|
+
const { migrateLayout } = await import("./migrate-layout.ts")
|
|
1443
|
+
return { kind: "layout" as const, ...(await migrateLayout(dir, write)) }
|
|
1444
|
+
}
|
|
1259
1445
|
const { migrateTailwindToStylex } = await import("./stylex-migrate.ts")
|
|
1260
|
-
return migrateTailwindToStylex(
|
|
1261
|
-
...(value.write === undefined ? {} : { write: value.write }),
|
|
1262
|
-
})
|
|
1446
|
+
return migrateTailwindToStylex(dir, write)
|
|
1263
1447
|
},
|
|
1264
|
-
render: (out) =>
|
|
1265
|
-
out.
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1448
|
+
render: (out) => {
|
|
1449
|
+
if (out.kind === "layout") {
|
|
1450
|
+
return [
|
|
1451
|
+
out.ok
|
|
1452
|
+
? `✓ ${out.splits.length} route file${out.splits.length === 1 ? "" : "s"} split, ${out.moves.length} file${out.moves.length === 1 ? "" : "s"} moved`
|
|
1453
|
+
: `⚠ ${out.issues.length} issue${out.issues.length === 1 ? "" : "s"} need a decision; everything else is planned`,
|
|
1454
|
+
...out.splits.map(
|
|
1455
|
+
(split) => ` split ${split.file} → ${split.backend} (${split.moved.join(", ")})`,
|
|
1456
|
+
),
|
|
1457
|
+
...out.moves.map((move) => ` move ${move.from} → ${move.to}`),
|
|
1458
|
+
...out.rewritten.map((file) => ` edit ${file} (imports)`),
|
|
1459
|
+
...out.issues.map((issue) => ` ⚠ ${issue.file}: ${issue.reason}`),
|
|
1460
|
+
...(out.write ? [] : [" dry run: pass --write to apply"]),
|
|
1461
|
+
]
|
|
1462
|
+
}
|
|
1463
|
+
return [
|
|
1464
|
+
out.ok
|
|
1465
|
+
? `✓ migrated ${out.changed.length} file${out.changed.length === 1 ? "" : "s"}`
|
|
1466
|
+
: `⚠ migrated ${out.changed.length} safe file${out.changed.length === 1 ? "" : "s"}; ${out.issues.length} manual issue${out.issues.length === 1 ? "" : "s"} remain`,
|
|
1467
|
+
` scanned ${out.scanned} source file${out.scanned === 1 ? "" : "s"}`,
|
|
1468
|
+
...(out.write
|
|
1469
|
+
? [` wrote ${out.written.length} file${out.written.length === 1 ? "" : "s"}`]
|
|
1470
|
+
: out.changed.length > 0
|
|
1471
|
+
? [" dry run: pass --write to apply the safe changes"]
|
|
1472
|
+
: []),
|
|
1473
|
+
...out.issues
|
|
1474
|
+
.slice(0, 30)
|
|
1475
|
+
.map((issue) => ` ${issue.file}:${issue.line} ${issue.token} — ${issue.reason}`),
|
|
1476
|
+
...(out.issues.length > 30
|
|
1477
|
+
? [` … ${out.issues.length - 30} more issue${out.issues.length - 30 === 1 ? "" : "s"}`]
|
|
1273
1478
|
: []),
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1479
|
+
]
|
|
1480
|
+
},
|
|
1481
|
+
success: (out) => out.ok,
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
const targetSpec: CommandSpec<TargetInput, TargetOutput> = {
|
|
1485
|
+
name: "target",
|
|
1486
|
+
summary:
|
|
1487
|
+
"Show the app's deploy target, or switch it (`nifra target cloudflare`): the `target` `nifra build` emits, kept in nifra.config.ts.",
|
|
1488
|
+
input: TARGET_SCHEMA,
|
|
1489
|
+
output: output({
|
|
1490
|
+
type: "object",
|
|
1491
|
+
properties: {
|
|
1492
|
+
ok: { type: "boolean" },
|
|
1493
|
+
target: { type: "string" },
|
|
1494
|
+
previous: { type: "string" },
|
|
1495
|
+
changed: { type: "boolean" },
|
|
1496
|
+
run: { type: "string" },
|
|
1497
|
+
},
|
|
1498
|
+
required: ["ok", "target", "changed", "run"],
|
|
1499
|
+
}),
|
|
1500
|
+
transports: ["cli"],
|
|
1501
|
+
stability: "stable",
|
|
1502
|
+
argv: {
|
|
1503
|
+
positionals: ["target"],
|
|
1504
|
+
flags: [
|
|
1505
|
+
{ name: "json", field: "json", type: "boolean" },
|
|
1506
|
+
{ name: "dir", field: "dir", type: "string" },
|
|
1507
|
+
],
|
|
1508
|
+
},
|
|
1509
|
+
async run(value, ctx) {
|
|
1510
|
+
const dir = resolve(ctx.cwd, value.dir ?? ".")
|
|
1511
|
+
const { parseBuildTarget, planBuildTarget } = await import("@nifrajs/web/build")
|
|
1512
|
+
const { readConfigTarget, writeConfigTarget } = await import("./config-target.ts")
|
|
1513
|
+
const current = readConfigTarget(dir)
|
|
1514
|
+
const target = parseBuildTarget(
|
|
1515
|
+
value.target ?? current ?? "bun",
|
|
1516
|
+
value.target === undefined ? "target in nifra.config.ts" : "target",
|
|
1517
|
+
)
|
|
1518
|
+
const changed = value.target !== undefined && value.target !== current
|
|
1519
|
+
if (changed) writeConfigTarget(dir, target)
|
|
1520
|
+
return {
|
|
1521
|
+
ok: true,
|
|
1522
|
+
target,
|
|
1523
|
+
...(changed && current !== undefined ? { previous: current } : {}),
|
|
1524
|
+
changed,
|
|
1525
|
+
run: planBuildTarget(target, "dist").run,
|
|
1526
|
+
}
|
|
1527
|
+
},
|
|
1528
|
+
render: (out) => [
|
|
1529
|
+
out.changed
|
|
1530
|
+
? `✓ target: ${out.target}${out.previous === undefined ? "" : ` (was ${out.previous})`}`
|
|
1531
|
+
: `target: ${out.target}`,
|
|
1532
|
+
` nifra build → ${out.run}`,
|
|
1533
|
+
],
|
|
1534
|
+
success: (out) => out.ok,
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
const typesSpec: CommandSpec<TypesInput, RouteTypesReport> = {
|
|
1538
|
+
name: "types",
|
|
1539
|
+
summary:
|
|
1540
|
+
"Generate each route's `./+types` module (params, schema-typed data, typed `api`); `--check` fails when one is stale.",
|
|
1541
|
+
input: TYPES_SCHEMA,
|
|
1542
|
+
output: output({
|
|
1543
|
+
type: "object",
|
|
1544
|
+
properties: {
|
|
1545
|
+
ok: { type: "boolean" },
|
|
1546
|
+
check: { type: "boolean" },
|
|
1547
|
+
written: { type: "array" },
|
|
1548
|
+
removed: { type: "array" },
|
|
1549
|
+
stale: { type: "array" },
|
|
1550
|
+
tsconfig: { type: "string" },
|
|
1551
|
+
},
|
|
1552
|
+
required: ["ok", "check", "written", "removed", "stale"],
|
|
1553
|
+
}),
|
|
1554
|
+
transports: ["cli"],
|
|
1555
|
+
stability: "stable",
|
|
1556
|
+
argv: {
|
|
1557
|
+
flags: [
|
|
1558
|
+
{ name: "check", field: "check", type: "boolean" },
|
|
1559
|
+
{ name: "json", field: "json", type: "boolean" },
|
|
1560
|
+
{ name: "dir", field: "dir", type: "string" },
|
|
1561
|
+
],
|
|
1562
|
+
},
|
|
1563
|
+
async run(value, ctx) {
|
|
1564
|
+
const { routeTypes } = await import("./route-types.ts")
|
|
1565
|
+
return routeTypes(resolve(ctx.cwd, value.dir ?? "."), { check: value.check === true })
|
|
1566
|
+
},
|
|
1567
|
+
render: (out) => [
|
|
1568
|
+
out.check
|
|
1569
|
+
? out.ok
|
|
1570
|
+
? "✓ route types are up to date"
|
|
1571
|
+
: `✖ ${out.stale.length} route type file${out.stale.length === 1 ? " is" : "s are"} stale - run \`nifra types\``
|
|
1572
|
+
: `✓ route types: ${out.written.length} written, ${out.removed.length} removed`,
|
|
1573
|
+
...out.stale.map((file) => ` stale ${file}`),
|
|
1574
|
+
...(out.tsconfig === undefined ? [] : [` ⚠ ${out.tsconfig}`]),
|
|
1280
1575
|
],
|
|
1281
1576
|
success: (out) => out.ok,
|
|
1282
1577
|
}
|
|
@@ -1468,6 +1763,34 @@ const replaySpec: CommandSpec<ReplayInput, ReplayResult> = {
|
|
|
1468
1763
|
success: (out) => out.ok,
|
|
1469
1764
|
}
|
|
1470
1765
|
|
|
1766
|
+
const smokeSpec: CommandSpec<SmokeInput, SmokeCommandOutput> = {
|
|
1767
|
+
name: "smoke",
|
|
1768
|
+
summary:
|
|
1769
|
+
"Run the declared production SSR, mounted-API, 404, header, auth, contract, and hydration smoke checks.",
|
|
1770
|
+
input: SMOKE_SCHEMA,
|
|
1771
|
+
output: output({ type: "object" }),
|
|
1772
|
+
transports: ["cli", "mcp"],
|
|
1773
|
+
stability: "stable",
|
|
1774
|
+
argv: {
|
|
1775
|
+
flags: [
|
|
1776
|
+
{ name: "fixture", field: "fixture", type: "string" },
|
|
1777
|
+
{ name: "in-process", field: "inProcess", type: "boolean" },
|
|
1778
|
+
{ name: "json", field: "json", type: "boolean" },
|
|
1779
|
+
],
|
|
1780
|
+
},
|
|
1781
|
+
async run(value, ctx) {
|
|
1782
|
+
const { loadSmokeFixture, runSmoke } = await import("./smoke.ts")
|
|
1783
|
+
const fixture = await loadSmokeFixture(ctx.cwd, value.fixture)
|
|
1784
|
+
return runSmoke(fixture, { inProcess: value.inProcess === true })
|
|
1785
|
+
},
|
|
1786
|
+
render: (out) =>
|
|
1787
|
+
out.checks.map(
|
|
1788
|
+
(check) =>
|
|
1789
|
+
`${check.status === "pass" ? "✓" : check.status === "skip" ? "•" : "✖"} ${check.id}${check.message === undefined ? "" : ` - ${check.message}`}`,
|
|
1790
|
+
),
|
|
1791
|
+
success: (out) => out.ok,
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1471
1794
|
const portSpec: CommandSpec<PortInput, PortResult> = {
|
|
1472
1795
|
name: "port",
|
|
1473
1796
|
summary:
|
|
@@ -1497,7 +1820,7 @@ const portSpec: CommandSpec<PortInput, PortResult> = {
|
|
|
1497
1820
|
return [
|
|
1498
1821
|
report,
|
|
1499
1822
|
"",
|
|
1500
|
-
"[nifra] --ci needs a deploy target to gate against, and none was detected. Pass --target <bun|node|deno|
|
|
1823
|
+
"[nifra] --ci needs a deploy target to gate against, and none was detected. Pass --target <bun|node|deno|cloudflare|vercel>.",
|
|
1501
1824
|
]
|
|
1502
1825
|
return [report]
|
|
1503
1826
|
},
|
|
@@ -1510,8 +1833,36 @@ const portSpec: CommandSpec<PortInput, PortResult> = {
|
|
|
1510
1833
|
json: (out) => out.json,
|
|
1511
1834
|
}
|
|
1512
1835
|
|
|
1836
|
+
// CLI only: it imports app code (the catalogs), which a long-lived MCP server process would cache.
|
|
1837
|
+
const i18nSpec: CommandSpec<I18nInput, I18nCheckOutput> = {
|
|
1838
|
+
name: "i18n",
|
|
1839
|
+
summary:
|
|
1840
|
+
"Check i18n catalogs (imports the module exporting `locales` and `catalogs`): coverage, missing and unused keys, ICU syntax, placeholder and tag parity, plural cases, script purity, untranslated messages.",
|
|
1841
|
+
input: I18N_SCHEMA,
|
|
1842
|
+
output: output({ type: "object" }),
|
|
1843
|
+
transports: ["cli"],
|
|
1844
|
+
stability: "stable",
|
|
1845
|
+
argv: {
|
|
1846
|
+
positionals: ["action", "entry"],
|
|
1847
|
+
flags: [
|
|
1848
|
+
{ name: "json", field: "json", type: "boolean" },
|
|
1849
|
+
{ name: "strict", field: "strict", type: "boolean" },
|
|
1850
|
+
],
|
|
1851
|
+
},
|
|
1852
|
+
async run(value, ctx) {
|
|
1853
|
+
const { runI18nCheck } = await import("./i18n-check.ts")
|
|
1854
|
+
return runI18nCheck(value.dir === undefined ? ctx.cwd : resolve(ctx.cwd, value.dir), {
|
|
1855
|
+
entry: value.entry,
|
|
1856
|
+
})
|
|
1857
|
+
},
|
|
1858
|
+
render: (out) => renderI18nCheck(out),
|
|
1859
|
+
success: (out, input) => i18nCheckPassed(out, input.strict === true),
|
|
1860
|
+
json: (out) => out,
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1513
1863
|
export const commandSpecs = Object.freeze([
|
|
1514
1864
|
checkSpec,
|
|
1865
|
+
reviewSpec,
|
|
1515
1866
|
assureSpec,
|
|
1516
1867
|
levelsSpec,
|
|
1517
1868
|
capabilitiesSpec,
|
|
@@ -1522,6 +1873,8 @@ export const commandSpecs = Object.freeze([
|
|
|
1522
1873
|
doctorSpec,
|
|
1523
1874
|
fixSpec,
|
|
1524
1875
|
migrateSpec,
|
|
1876
|
+
targetSpec,
|
|
1877
|
+
typesSpec,
|
|
1525
1878
|
snapshotSpec,
|
|
1526
1879
|
diffSpec,
|
|
1527
1880
|
contractsSpec,
|
|
@@ -1529,7 +1882,16 @@ export const commandSpecs = Object.freeze([
|
|
|
1529
1882
|
syncRoutesSpec,
|
|
1530
1883
|
proveSpec,
|
|
1531
1884
|
replaySpec,
|
|
1885
|
+
smokeSpec,
|
|
1532
1886
|
portSpec,
|
|
1887
|
+
i18nSpec,
|
|
1888
|
+
errorsSpec,
|
|
1889
|
+
logsSpec,
|
|
1890
|
+
cdnCheckSpec,
|
|
1891
|
+
dbSchemaSpec,
|
|
1892
|
+
dbQuerySpec,
|
|
1893
|
+
dbRoleSpec,
|
|
1894
|
+
dbAuditSpec,
|
|
1533
1895
|
] as const)
|
|
1534
1896
|
|
|
1535
1897
|
const commandByName = new Map(commandSpecs.map((spec) => [spec.name, spec]))
|