@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/check.ts
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { existsSync, readFileSync } from "node:fs"
|
|
20
|
-
import { dirname, isAbsolute, join } from "node:path"
|
|
20
|
+
import { dirname, isAbsolute, join, relative } from "node:path"
|
|
21
|
+
import { BACKEND_APP_FILE } from "./app-files.ts"
|
|
21
22
|
import {
|
|
22
23
|
type CheckAssuranceContext,
|
|
23
24
|
type CheckConfig,
|
|
@@ -26,11 +27,13 @@ import {
|
|
|
26
27
|
collectCheckDiagnostics,
|
|
27
28
|
type RuleOverride,
|
|
28
29
|
} from "./check-diagnostics.ts"
|
|
30
|
+
import { checkContractsLock, DEFAULT_CONTRACTS_LOCK } from "./contracts.ts"
|
|
31
|
+
import { type Diagnostic, normalizeSeverity, toSarifLog } from "./diagnostics.ts"
|
|
29
32
|
import { createSourceFacts } from "./internal/source-facts.ts"
|
|
30
|
-
import {
|
|
33
|
+
import { loadProjectTypeScript, type TypeScriptApi } from "./internal/typescript-import.ts"
|
|
31
34
|
// Type-only: `pipeline-report.ts` imports this module's source scanners, so a value import here would
|
|
32
35
|
// close a cycle. Doctor is what actually runs the collector (see the `pipeline` rule below).
|
|
33
|
-
import type { ProjectFactsSeed } from "./project-facts.ts"
|
|
36
|
+
import type { ContractCheckFacts, ProjectFactsSeed } from "./project-facts.ts"
|
|
34
37
|
import { RULE_CODES } from "./rules/codes.ts"
|
|
35
38
|
import { sourceIndex } from "./rules/index.ts"
|
|
36
39
|
|
|
@@ -48,6 +51,7 @@ export type {
|
|
|
48
51
|
|
|
49
52
|
import {
|
|
50
53
|
createProjectSqlImports,
|
|
54
|
+
isBrowserSource,
|
|
51
55
|
type ModuleReader,
|
|
52
56
|
type ModuleResolver,
|
|
53
57
|
resolveServerOnlyChains,
|
|
@@ -59,6 +63,7 @@ import {
|
|
|
59
63
|
scanResponseRoutes,
|
|
60
64
|
scanServerManifestDrift,
|
|
61
65
|
scanStaticRouteText,
|
|
66
|
+
scanStreamText,
|
|
62
67
|
scanUntypedClient,
|
|
63
68
|
type TransitiveServerImportFinding,
|
|
64
69
|
walkSource,
|
|
@@ -66,7 +71,6 @@ import {
|
|
|
66
71
|
|
|
67
72
|
export * from "./check-scan.ts"
|
|
68
73
|
|
|
69
|
-
const ROUTE_FILE = /(^|\/)routes\//
|
|
70
74
|
interface TypecheckResult {
|
|
71
75
|
readonly ran: boolean
|
|
72
76
|
readonly ok: boolean
|
|
@@ -101,6 +105,9 @@ async function typecheck(cwd: string, signal?: AbortSignal): Promise<TypecheckRe
|
|
|
101
105
|
const tsconfig = join(cwd, "tsconfig.json")
|
|
102
106
|
if (!(await Bun.file(tsconfig).exists()))
|
|
103
107
|
return { ran: false, ok: true, note: "no tsconfig.json" }
|
|
108
|
+
// Routes import their generated `./+types` modules; bring them up to date before tsc reads them.
|
|
109
|
+
const { refreshRouteTypes } = await import("./route-types.ts")
|
|
110
|
+
refreshRouteTypes(cwd, () => {})
|
|
104
111
|
const tscBin = resolveTscBin(cwd)
|
|
105
112
|
if (tscBin === undefined) {
|
|
106
113
|
return {
|
|
@@ -111,7 +118,7 @@ async function typecheck(cwd: string, signal?: AbortSignal): Promise<TypecheckRe
|
|
|
111
118
|
}
|
|
112
119
|
}
|
|
113
120
|
if (signal?.aborted) return { ran: true, ok: false, cancelled: true, output: "cancelled" }
|
|
114
|
-
const proc = Bun.spawn([
|
|
121
|
+
const proc = Bun.spawn([process.execPath, tscBin, "--noEmit", "-p", tsconfig], {
|
|
115
122
|
cwd,
|
|
116
123
|
stdout: "pipe",
|
|
117
124
|
stderr: "pipe",
|
|
@@ -230,10 +237,30 @@ interface CheckCollectionOptions {
|
|
|
230
237
|
|
|
231
238
|
interface ProjectScan {
|
|
232
239
|
readonly facts: ProjectFactsSeed
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function collectContractFacts(cwd: string): Promise<ContractCheckFacts> {
|
|
243
|
+
const hasBackend = existsSync(join(cwd, BACKEND_APP_FILE))
|
|
244
|
+
const hasLock = existsSync(join(cwd, DEFAULT_CONTRACTS_LOCK))
|
|
245
|
+
if (!hasBackend && !hasLock) return { present: false, vacuous: false, diagnostics: [] }
|
|
246
|
+
try {
|
|
247
|
+
const result = await checkContractsLock(cwd)
|
|
248
|
+
return {
|
|
249
|
+
present: result.present,
|
|
250
|
+
vacuous: result.vacuous,
|
|
251
|
+
diagnostics: result.diagnostics,
|
|
252
|
+
}
|
|
253
|
+
} catch (error) {
|
|
254
|
+
if (error instanceof Error && error.message === "contract source not configured") {
|
|
255
|
+
return { present: false, vacuous: false, diagnostics: [] }
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
present: hasLock,
|
|
259
|
+
vacuous: false,
|
|
260
|
+
diagnostics: [],
|
|
261
|
+
error: error instanceof Error ? error.message : String(error),
|
|
262
|
+
}
|
|
263
|
+
}
|
|
237
264
|
}
|
|
238
265
|
|
|
239
266
|
/** Build the rule input from one source walk and the other check-wide scans. */
|
|
@@ -242,79 +269,111 @@ async function buildProjectScan(
|
|
|
242
269
|
opts: Pick<CheckCollectionOptions, "lintsOnly" | "signal" | "loadTypeScript">,
|
|
243
270
|
): Promise<ProjectScan> {
|
|
244
271
|
const fetches: SourceFinding[] = []
|
|
272
|
+
const streams: SourceFinding[] = []
|
|
245
273
|
const staticRoutes: StaticRouteFinding[] = []
|
|
246
274
|
const untypedClients: SourceFinding[] = []
|
|
247
275
|
const removedImports: SourceFinding[] = []
|
|
248
276
|
const serverImports: TransitiveServerImportFinding[] = []
|
|
249
277
|
const responseRoutes: SourceFinding[] = []
|
|
250
278
|
const interpolatedSql: SourceFinding[] = []
|
|
251
|
-
const
|
|
279
|
+
const browserModules: Array<{ rel: string; content: string }> = []
|
|
252
280
|
const sourceFiles: Array<{ file: string; content: string }> = []
|
|
253
281
|
const {
|
|
254
282
|
config: checkConfig,
|
|
255
283
|
error: checkConfigError,
|
|
256
284
|
warnings: checkConfigWarnings,
|
|
257
285
|
} = await loadCheckConfig(cwd)
|
|
258
|
-
const
|
|
259
|
-
const sourceFacts = sqlCompiler === undefined ? undefined : createSourceFacts(sqlCompiler)
|
|
260
|
-
const sqlImports = sqlCompiler === undefined ? undefined : createProjectSqlImports(cwd)
|
|
261
|
-
|
|
262
|
-
const [typecheckResult, _, doctor, manifestDrift] = await Promise.all([
|
|
286
|
+
const [typecheckResult, _, doctor, manifestDrift, contracts] = await Promise.all([
|
|
263
287
|
opts.lintsOnly
|
|
264
288
|
? Promise.resolve<TypecheckResult>({ ran: false, ok: true, note: "lints-only mode" })
|
|
265
289
|
: typecheck(cwd, opts.signal),
|
|
266
290
|
walkSource(cwd, (rel, content) => {
|
|
267
291
|
sourceFiles.push({ file: rel, content })
|
|
268
292
|
fetches.push(...scanFetchText(rel, content, checkConfig.externalMounts))
|
|
269
|
-
|
|
293
|
+
streams.push(...scanStreamText(rel, content, checkConfig.externalMounts))
|
|
270
294
|
untypedClients.push(...scanUntypedClient(rel, content))
|
|
271
295
|
removedImports.push(...scanRemovedImports(rel, content))
|
|
272
|
-
if (
|
|
273
|
-
responseRoutes.push(...scanResponseRoutes(rel, content, sourceFacts))
|
|
274
|
-
if (sqlCompiler !== undefined)
|
|
275
|
-
interpolatedSql.push(...scanInterpolatedSql(rel, content, sqlCompiler, sqlImports))
|
|
296
|
+
if (isBrowserSource(rel)) browserModules.push({ rel, content })
|
|
276
297
|
}),
|
|
277
298
|
import("./doctor.ts").then((m) => m.collectDoctorResult(cwd)),
|
|
278
299
|
scanServerManifestDrift(cwd),
|
|
300
|
+
collectContractFacts(cwd),
|
|
279
301
|
])
|
|
280
302
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
303
|
+
// TypeScript 7's unstable API materializes source files through one project session. Build the
|
|
304
|
+
// source index first so every syntax-backed scanner (including the independent rule registry)
|
|
305
|
+
// shares that session instead of spawning one compiler process per rule.
|
|
306
|
+
const source = sourceIndex(sourceFiles)
|
|
307
|
+
const loadedTypeScript = await loadProjectTypeScript(cwd, opts.loadTypeScript, source)
|
|
308
|
+
try {
|
|
309
|
+
const sqlCompiler = loadedTypeScript.compiler
|
|
310
|
+
const sourceFacts = sqlCompiler === undefined ? undefined : createSourceFacts(sqlCompiler)
|
|
311
|
+
const sqlImports = sqlCompiler === undefined ? undefined : createProjectSqlImports(cwd)
|
|
312
|
+
for (const { file, content } of sourceFiles) {
|
|
313
|
+
staticRoutes.push(...scanStaticRouteText(file, content, sourceFacts))
|
|
314
|
+
responseRoutes.push(...scanResponseRoutes(file, content, sourceFacts))
|
|
315
|
+
if (sqlCompiler !== undefined)
|
|
316
|
+
interpolatedSql.push(...scanInterpolatedSql(file, content, sqlCompiler, sqlImports))
|
|
287
317
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
318
|
+
|
|
319
|
+
// Resolved modules stay project-relative, as the scanned files are: the zone of a path is read
|
|
320
|
+
// from its folders, and a checkout under a folder named `backend/` must not make it all backend.
|
|
321
|
+
const resolveModule: ModuleResolver = (fromFile, specifier) => {
|
|
322
|
+
try {
|
|
323
|
+
const fromAbs = isAbsolute(fromFile) ? fromFile : join(cwd, fromFile)
|
|
324
|
+
const resolved = Bun.resolveSync(specifier, dirname(fromAbs))
|
|
325
|
+
const rel = relative(cwd, resolved).replaceAll("\\", "/")
|
|
326
|
+
return rel.startsWith("../") || isAbsolute(rel) ? resolved : rel
|
|
327
|
+
} catch {
|
|
328
|
+
return undefined
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const readModule: ModuleReader = (path) => {
|
|
332
|
+
try {
|
|
333
|
+
return readFileSync(isAbsolute(path) ? path : join(cwd, path), "utf8")
|
|
334
|
+
} catch {
|
|
335
|
+
return undefined
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
for (const { rel, content } of browserModules) {
|
|
339
|
+
serverImports.push(
|
|
340
|
+
...resolveServerOnlyChains(rel, content, resolveModule, readModule, sourceFacts),
|
|
341
|
+
)
|
|
294
342
|
}
|
|
295
|
-
}
|
|
296
|
-
for (const { rel, content } of routeModules) {
|
|
297
|
-
serverImports.push(
|
|
298
|
-
...resolveServerOnlyChains(rel, content, resolveModule, readModule, sourceFacts),
|
|
299
|
-
)
|
|
300
|
-
}
|
|
301
343
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
344
|
+
const facts: ProjectFactsSeed = {
|
|
345
|
+
source,
|
|
346
|
+
routes: staticRoutes,
|
|
347
|
+
importGraph: serverImports,
|
|
348
|
+
packages: { doctor, manifestDrift },
|
|
349
|
+
...(doctor.pipeline === undefined ? {} : { pipeline: doctor.pipeline }),
|
|
350
|
+
policies: { checkConfig, rulePacks: [] },
|
|
351
|
+
check: {
|
|
352
|
+
typecheck: typecheckResult,
|
|
353
|
+
sqlCompilerAvailable: sqlCompiler !== undefined,
|
|
354
|
+
...(loadedTypeScript.unsupported === undefined
|
|
355
|
+
? {}
|
|
356
|
+
: { unsupportedTypeScriptVersion: loadedTypeScript.unsupported.version }),
|
|
357
|
+
...(loadedTypeScript.session === undefined
|
|
358
|
+
? {}
|
|
359
|
+
: { typescriptSession: loadedTypeScript.session }),
|
|
360
|
+
...(checkConfigError === undefined ? {} : { checkConfigError }),
|
|
361
|
+
checkConfigWarnings,
|
|
362
|
+
contracts,
|
|
363
|
+
},
|
|
364
|
+
sourceFindings: {
|
|
365
|
+
fetches,
|
|
366
|
+
streams,
|
|
367
|
+
untypedClients,
|
|
368
|
+
removedImports,
|
|
369
|
+
responseRoutes,
|
|
370
|
+
interpolatedSql,
|
|
371
|
+
},
|
|
372
|
+
}
|
|
373
|
+
return { facts }
|
|
374
|
+
} catch (error) {
|
|
375
|
+
await loadedTypeScript.session?.close()
|
|
376
|
+
throw error
|
|
318
377
|
}
|
|
319
378
|
}
|
|
320
379
|
|
|
@@ -326,7 +385,11 @@ export async function collectCheckResult(
|
|
|
326
385
|
opts: CheckCollectionOptions = {},
|
|
327
386
|
): Promise<CheckResult> {
|
|
328
387
|
const scan = await buildProjectScan(cwd, opts)
|
|
329
|
-
|
|
388
|
+
try {
|
|
389
|
+
return await collectCheckDiagnostics(cwd, scan, opts)
|
|
390
|
+
} finally {
|
|
391
|
+
await scan.facts.check.typescriptSession?.close()
|
|
392
|
+
}
|
|
330
393
|
}
|
|
331
394
|
|
|
332
395
|
/** The named rule sections of the human report, in print order. A rule absent from this list is NOT
|
|
@@ -334,9 +397,9 @@ export async function collectCheckResult(
|
|
|
334
397
|
* its rule code, so a finding that can flip the exit code is never invisible in the default output. */
|
|
335
398
|
const REPORT_SECTIONS = [
|
|
336
399
|
["typecheck", "typecheck"],
|
|
337
|
-
["typed-client", "hand-rolled fetch() to your own API"],
|
|
400
|
+
["typed-client", "hand-rolled fetch()/EventSource/WebSocket to your own API"],
|
|
338
401
|
["untyped-client", 'client("…") missing its <typeof app> type argument'],
|
|
339
|
-
["server-only-import", "
|
|
402
|
+
["server-only-import", "backend code in browser code"],
|
|
340
403
|
["interpolated-sql", "SQL built by interpolating a value into the statement"],
|
|
341
404
|
["response-route", "route returns a raw Response (typed client → data: never)"],
|
|
342
405
|
["undeclared-dependency", "undeclared dependency in package.json"],
|
|
@@ -380,6 +443,14 @@ export function renderCheckReport(result: CheckResult): string[] {
|
|
|
380
443
|
`• intentional external mounts (not typed-client checked): ${result.externalMounts.join(", ")}`,
|
|
381
444
|
)
|
|
382
445
|
}
|
|
446
|
+
for (const gap of result.knownGaps ?? []) {
|
|
447
|
+
lines.push(`• known gap, not capability-analyzed: ${gap.path} - ${gap.reason}`)
|
|
448
|
+
}
|
|
449
|
+
const deduplicated = result.identityPreflight?.deduplicated ?? []
|
|
450
|
+
if (deduplicated.length > 0) {
|
|
451
|
+
const packages = deduplicated.map((finding) => finding.package).join(", ")
|
|
452
|
+
lines.push(`• identity-sensitive duplicate installs handled by singleCopy: ${packages}`)
|
|
453
|
+
}
|
|
383
454
|
if (result.ruleOverrides !== undefined) {
|
|
384
455
|
const active = Object.entries(result.ruleOverrides).map(([rule, override]) => {
|
|
385
456
|
const parts: string[] = []
|
|
@@ -468,12 +539,29 @@ export async function runCheck(
|
|
|
468
539
|
readonly json?: boolean
|
|
469
540
|
readonly lintsOnly?: boolean
|
|
470
541
|
readonly structured?: boolean
|
|
542
|
+
readonly sarif?: boolean
|
|
471
543
|
} = {},
|
|
472
544
|
): Promise<boolean> {
|
|
473
545
|
// The check view over the one project verification: the same collector `assure` and `levels` read.
|
|
474
546
|
const { collectProjectVerification } = await import("./verification.ts")
|
|
475
547
|
const verification = await collectProjectVerification(cwd, { lintsOnly: opts.lintsOnly ?? false })
|
|
476
548
|
const result = await verification.check()
|
|
549
|
+
if (opts.sarif) {
|
|
550
|
+
const diagnostics: readonly Diagnostic[] =
|
|
551
|
+
result.structuredDiagnostics ??
|
|
552
|
+
result.diagnostics.map((value) => ({
|
|
553
|
+
code: value.code ?? value.rule,
|
|
554
|
+
severity: normalizeSeverity(value.severity),
|
|
555
|
+
message: value.message,
|
|
556
|
+
...(value.file === undefined ? {} : { file: value.file }),
|
|
557
|
+
...(value.line === undefined ? {} : { line: value.line }),
|
|
558
|
+
...(value.evidence === undefined ? {} : { evidence: value.evidence }),
|
|
559
|
+
...(value.fix === undefined ? {} : { fix: { recipe: value.fix } }),
|
|
560
|
+
...(value.verify === undefined ? {} : { verify: value.verify }),
|
|
561
|
+
}))
|
|
562
|
+
console.log(JSON.stringify(toSarifLog(diagnostics), null, 2))
|
|
563
|
+
return result.ok
|
|
564
|
+
}
|
|
477
565
|
if (opts.json) {
|
|
478
566
|
console.log(
|
|
479
567
|
JSON.stringify(
|
|
@@ -489,7 +577,7 @@ export async function runCheck(
|
|
|
489
577
|
|
|
490
578
|
console.log(renderCheckReport(result).join("\n"))
|
|
491
579
|
// Discoverability nudge: a project with no `.mcp.json` hasn't wired its nifra MCP for coding agents.
|
|
492
|
-
// `nifra init-agents` writes it (+ .cursor/mcp.json +
|
|
580
|
+
// `nifra init-agents` writes it (+ .cursor/mcp.json + each agent's pointer to AGENTS.md), no-clobber. A non-fatal
|
|
493
581
|
// one-line tip in the human report only (the `--json` path returns above, unaffected).
|
|
494
582
|
if (!existsSync(join(cwd, ".mcp.json"))) {
|
|
495
583
|
console.log(
|