@intentius/chant 0.101.0 → 0.102.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/dist/agents/checks.d.ts.map +1 -1
- package/dist/attrref.d.ts.map +1 -1
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/nginx.d.ts.map +1 -1
- package/dist/audit/prior-art.d.ts +48 -0
- package/dist/audit/prior-art.d.ts.map +1 -1
- package/dist/behaviour-kinds.d.ts.map +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/cli/commands/carve-emit.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts +16 -0
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/import.d.ts +8 -0
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +9 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
- package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +9 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/lsp/server.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/tools/build.d.ts.map +1 -1
- package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
- package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
- package/dist/cli/mcp/tools/import.d.ts.map +1 -1
- package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
- package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
- package/dist/cli/mcp/tools/search.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +11 -2
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/naming.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.d.ts +67 -3
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/verbs/process-runner.d.ts.map +1 -1
- package/dist/components/verbs/r2-sync.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
- package/dist/components/verbs/sign.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts.map +1 -1
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
- package/dist/components/verbs/wrangler.d.ts.map +1 -1
- package/dist/composite.d.ts.map +1 -1
- package/dist/config.d.ts +19 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/declarable.d.ts +16 -0
- package/dist/declarable.d.ts.map +1 -1
- package/dist/discovery/cache.d.ts.map +1 -1
- package/dist/discovery/fold-import.d.ts +15 -5
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +16 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
- package/dist/discovery/specifier-resolve.d.ts +37 -0
- package/dist/discovery/specifier-resolve.d.ts.map +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/fold/fold.d.ts +3 -1
- package/dist/fold/fold.d.ts.map +1 -1
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-layout.d.ts.map +1 -1
- package/dist/import/base-parser.d.ts.map +1 -1
- package/dist/import/embedded.d.ts +7 -0
- package/dist/import/embedded.d.ts.map +1 -1
- package/dist/import/parser-options.d.ts +14 -0
- package/dist/import/parser-options.d.ts.map +1 -0
- package/dist/import/parser.d.ts +17 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts.map +1 -1
- package/dist/lexicon-output.d.ts.map +1 -1
- package/dist/lexicon-schema.d.ts +3 -3
- package/dist/lexicon.d.ts +55 -3
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/assert-live.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +15 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/member-ledger.d.ts.map +1 -1
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/scenario.d.ts.map +1 -1
- package/dist/lifecycle/status.d.ts.map +1 -1
- package/dist/lifecycle/work-lease.d.ts +61 -2
- package/dist/lifecycle/work-lease.d.ts.map +1 -1
- package/dist/lint/config.d.ts +8 -8
- package/dist/lint/engine.d.ts +6 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +11 -11
- package/dist/op/activities/apply.d.ts +79 -9
- package/dist/op/activities/apply.d.ts.map +1 -1
- package/dist/op/activities/decide.d.ts.map +1 -1
- package/dist/op/activities/index.d.ts +1 -1
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts +1 -1
- package/dist/op/activity-failure.d.ts.map +1 -1
- package/dist/op/activity-profiles.d.ts.map +1 -1
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/apply-op.d.ts +12 -5
- package/dist/op/composites/apply-op.d.ts.map +1 -1
- package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
- package/dist/op/decide-backend.d.ts.map +1 -1
- package/dist/op/decide-read-inputs.d.ts.map +1 -1
- package/dist/op/emulator-lifecycle.d.ts +21 -2
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate-approval.d.ts +5 -1
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-wait.d.ts.map +1 -1
- package/dist/op/gate.d.ts +19 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/index.d.ts +2 -0
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +6 -0
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/run-context.d.ts +39 -0
- package/dist/op/run-context.d.ts.map +1 -0
- package/dist/op/run-live.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/op/source-archive.d.ts.map +1 -1
- package/dist/op/steward-beside.d.ts.map +1 -1
- package/dist/op/steward-points.d.ts.map +1 -1
- package/dist/op/steward.d.ts.map +1 -1
- package/dist/op/types.d.ts +8 -3
- package/dist/op/types.d.ts.map +1 -1
- package/dist/op/work-lease-run.d.ts +24 -4
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/project-root.d.ts.map +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/pseudo-parameter.d.ts.map +1 -1
- package/dist/reconcile.d.ts.map +1 -1
- package/dist/secret-materialization.d.ts.map +1 -1
- package/dist/terraform/emit-source.d.ts.map +1 -1
- package/dist/terraform/parse.d.ts.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
- package/dist/workspace/agent-cli.d.ts +5 -0
- package/dist/workspace/agent-cli.d.ts.map +1 -1
- package/dist/workspace/box-factory.d.ts +73 -0
- package/dist/workspace/box-factory.d.ts.map +1 -0
- package/dist/workspace/changes.d.ts.map +1 -1
- package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
- package/dist/workspace/checks/boxes.d.ts.map +1 -1
- package/dist/workspace/checks.d.ts +5 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/compose-graph.d.ts +10 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/conformance/index.d.ts +67 -6
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +12 -3
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +368 -0
- package/dist/workspace/conformance/writer.d.ts.map +1 -0
- package/dist/workspace/decide.d.ts +1 -1
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/declaration.d.ts +91 -4
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +234 -5
- package/dist/workspace/generated-files.d.ts.map +1 -1
- package/dist/workspace/graph-cache.d.ts.map +1 -1
- package/dist/workspace/graph-cli.d.ts +2 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/identity.d.ts +111 -0
- package/dist/workspace/identity.d.ts.map +1 -0
- package/dist/workspace/intent-cli.d.ts +7 -4
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-record.d.ts +8 -1
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +149 -5
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/kinds.d.ts +18 -4
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/lineage-hash-index.d.ts.map +1 -1
- package/dist/workspace/lineage-lock.d.ts +2 -2
- package/dist/workspace/lineage-lock.d.ts.map +1 -1
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/points.d.ts.map +1 -1
- package/dist/workspace/principal-classes.d.ts +114 -0
- package/dist/workspace/principal-classes.d.ts.map +1 -0
- package/dist/workspace/reason-codes.d.ts +21 -1
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/record-assets.d.ts.map +1 -1
- package/dist/workspace/records-checkout.d.ts +54 -0
- package/dist/workspace/records-checkout.d.ts.map +1 -0
- package/dist/workspace/records-cli.d.ts +27 -1
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-close.d.ts +1 -1
- package/dist/workspace/records-close.d.ts.map +1 -1
- package/dist/workspace/records-since.d.ts.map +1 -1
- package/dist/workspace/records-write.d.ts +5 -4
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +15 -0
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/runs-cli.d.ts +164 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -0
- package/dist/workspace/runs.d.ts +423 -0
- package/dist/workspace/runs.d.ts.map +1 -0
- package/dist/workspace/source-block.d.ts +1 -1
- package/dist/workspace/source-block.d.ts.map +1 -1
- package/dist/workspace/status-gates.d.ts +15 -3
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +10 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +52 -0
- package/dist/workspace/symbols.d.ts.map +1 -0
- package/dist/workspace/trailer-joins.d.ts +46 -0
- package/dist/workspace/trailer-joins.d.ts.map +1 -0
- package/dist/workspace/trailers.d.ts +89 -0
- package/dist/workspace/trailers.d.ts.map +1 -0
- package/dist/workspace/trust/attestor.d.ts.map +1 -1
- package/dist/workspace/trust/rotation.d.ts.map +1 -1
- package/dist/workspace/trust/seal.d.ts +33 -0
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/test-repo.d.ts.map +1 -1
- package/dist/workspace/work-cli.d.ts +39 -3
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-evidence.d.ts +1 -1
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/work.d.ts +26 -1
- package/dist/workspace/work.d.ts.map +1 -1
- package/dist/workspace/workspace-principals.schema.json +60 -0
- package/dist/workspace/write-scope.d.ts +79 -19
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/yaml.d.ts +21 -39
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/audit/prior-art.ts +15 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
- package/src/cli/commands/carve-emit-state.test.ts +4 -0
- package/src/cli/commands/carve-emit.ts +5 -19
- package/src/cli/commands/check-lexicon.test.ts +62 -1
- package/src/cli/commands/check-lexicon.ts +36 -6
- package/src/cli/commands/import-live.test.ts +18 -0
- package/src/cli/commands/import-parser-options.test.ts +133 -0
- package/src/cli/commands/import.ts +21 -3
- package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
- package/src/cli/commands/init.test.ts +8 -1
- package/src/cli/commands/init.ts +23 -8
- package/src/cli/commands/lint.test.ts +37 -0
- package/src/cli/commands/onboard.test.ts +53 -3
- package/src/cli/commands/onboard.ts +52 -4
- package/src/cli/commands/pinned-upgrade.ts +73 -33
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
- package/src/cli/handlers/components.ts +2 -2
- package/src/cli/handlers/dev.ts +8 -6
- package/src/cli/handlers/lifecycle.test.ts +67 -0
- package/src/cli/handlers/lifecycle.ts +6 -5
- package/src/cli/handlers/misc.ts +2 -0
- package/src/cli/handlers/operator.ts +87 -3
- package/src/cli/handlers/run.test.ts +111 -0
- package/src/cli/handlers/run.ts +85 -24
- package/src/cli/handlers/scenario.ts +2 -2
- package/src/cli/main.test.ts +1 -0
- package/src/cli/main.ts +65 -11
- package/src/cli/mcp/workspace-tools.test.ts +5 -2
- package/src/cli/mcp/workspace-tools.ts +29 -2
- package/src/cli/registry.ts +11 -2
- package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
- package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
- package/src/codegen/pinned-upgrade.test.ts +104 -0
- package/src/codegen/pinned-upgrade.ts +250 -56
- package/src/codegen/testdata/postgres-tags.json +242 -0
- package/src/config.test.ts +21 -0
- package/src/config.ts +15 -0
- package/src/declarable.test.ts +21 -0
- package/src/declarable.ts +19 -0
- package/src/discovery/fold-composite.test.ts +41 -5
- package/src/discovery/fold-import.test.ts +129 -0
- package/src/discovery/fold-import.ts +643 -131
- package/src/discovery/fold-package-composite.test.ts +264 -0
- package/src/discovery/fold-specifiers.test.ts +191 -0
- package/src/discovery/param-deps.test.ts +66 -1
- package/src/discovery/param-deps.ts +45 -0
- package/src/discovery/specifier-resolve.ts +344 -0
- package/src/fold/fold.test.ts +39 -1
- package/src/fold/fold.ts +83 -9
- package/src/fold-provenance.test.ts +140 -0
- package/src/graph-ir.test.ts +83 -0
- package/src/graph-ir.ts +29 -0
- package/src/import/embedded.test.ts +20 -0
- package/src/import/embedded.ts +13 -0
- package/src/import/parser-options.ts +46 -0
- package/src/import/parser.ts +20 -0
- package/src/lexicon.ts +55 -3
- package/src/lifecycle/gate-ledger.ts +16 -0
- package/src/lifecycle/observe.test.ts +18 -0
- package/src/lifecycle/observe.ts +6 -4
- package/src/lifecycle/snapshot.ts +2 -2
- package/src/lifecycle/work-lease.test.ts +1 -1
- package/src/lifecycle/work-lease.ts +93 -2
- package/src/lint/engine.test.ts +55 -0
- package/src/lint/engine.ts +30 -4
- package/src/lint/output-docs.test.ts +59 -56
- package/src/op/activities/apply.test.ts +189 -5
- package/src/op/activities/apply.ts +230 -8
- package/src/op/activities/index.ts +3 -0
- package/src/op/activities/lexicon-upgrade.test.ts +160 -6
- package/src/op/activities/lexicon-upgrade.ts +154 -51
- package/src/op/composites/apply-op.ts +12 -5
- package/src/op/composites/composites.test.ts +30 -3
- package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
- package/src/op/composites/lexicon-upgrade-op.ts +29 -8
- package/src/op/emulator-lifecycle.test.ts +23 -0
- package/src/op/emulator-lifecycle.ts +52 -14
- package/src/op/gate-approval.test.ts +74 -0
- package/src/op/gate-approval.ts +5 -1
- package/src/op/gate.ts +31 -5
- package/src/op/index.ts +2 -0
- package/src/op/local-executor.test.ts +15 -0
- package/src/op/local-executor.ts +40 -12
- package/src/op/local-output.ts +1 -1
- package/src/op/operator.ts +4 -0
- package/src/op/run-context.test.ts +141 -0
- package/src/op/run-context.ts +51 -0
- package/src/op/runtimes/local.test.ts +14 -0
- package/src/op/runtimes/local.ts +2 -0
- package/src/op/steward-beside.ts +2 -0
- package/src/op/types.ts +8 -3
- package/src/op/work-lease-run.test.ts +47 -0
- package/src/op/work-lease-run.ts +73 -11
- package/src/provenance.ts +35 -0
- package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
- package/src/workspace/agent-cli.ts +7 -3
- package/src/workspace/agent.schema.json +22 -0
- package/src/workspace/box-factory.test.ts +320 -0
- package/src/workspace/box-factory.ts +103 -0
- package/src/workspace/changes.schema.json +12 -20
- package/src/workspace/changes.ts +4 -1
- package/src/workspace/checks/boxes.test.ts +2 -0
- package/src/workspace/checks.ts +29 -5
- package/src/workspace/compose-graph.ts +7 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +27 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +95 -0
- package/src/workspace/conformance/__writer_fixture__/decisions/points.json +132 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +48 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +108 -0
- package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +578 -0
- package/src/workspace/conformance/conformance.e2e.test.ts +35 -3
- package/src/workspace/conformance/index.mjs +30 -3
- package/src/workspace/conformance/index.ts +103 -15
- package/src/workspace/conformance/vitest.ts +44 -2
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +131 -0
- package/src/workspace/conformance/writer.test.ts +156 -0
- package/src/workspace/conformance/writer.ts +880 -0
- package/src/workspace/decide.ts +7 -1
- package/src/workspace/declaration.schema.json +234 -5
- package/src/workspace/declaration.ts +174 -10
- package/src/workspace/graph-cli.ts +5 -2
- package/src/workspace/graph.schema.json +247 -0
- package/src/workspace/identity.test.ts +196 -0
- package/src/workspace/identity.ts +186 -0
- package/src/workspace/intent-cli.ts +64 -10
- package/src/workspace/intent-record.schema.json +208 -0
- package/src/workspace/intent-record.ts +35 -1
- package/src/workspace/intent-why.test.ts +274 -0
- package/src/workspace/intent.schema.json +718 -7
- package/src/workspace/intent.test.ts +11 -2
- package/src/workspace/intent.ts +495 -32
- package/src/workspace/kinds.ts +44 -37
- package/src/workspace/points-write.schema.json +1 -0
- package/src/workspace/principal-classes.test.ts +175 -0
- package/src/workspace/principal-classes.ts +307 -0
- package/src/workspace/reason-codes.test.ts +11 -3
- package/src/workspace/reason-codes.ts +24 -1
- package/src/workspace/records-amend.schema.json +2 -0
- package/src/workspace/records-checkout.ts +106 -0
- package/src/workspace/records-cli.ts +103 -11
- package/src/workspace/records-close.schema.json +1 -0
- package/src/workspace/records-new.schema.json +2 -0
- package/src/workspace/records-review.schema.json +2 -0
- package/src/workspace/records-uncommitted.test.ts +171 -0
- package/src/workspace/records-write.ts +28 -6
- package/src/workspace/records.schema.json +72 -1
- package/src/workspace/records.ts +27 -0
- package/src/workspace/runs-cli.ts +381 -0
- package/src/workspace/runs-write.schema.json +583 -0
- package/src/workspace/runs.schema.json +810 -0
- package/src/workspace/runs.test.ts +242 -0
- package/src/workspace/runs.ts +709 -0
- package/src/workspace/status-contract.test.ts +5 -0
- package/src/workspace/status-gates.ts +22 -8
- package/src/workspace/status.schema.json +127 -2
- package/src/workspace/status.ts +21 -1
- package/src/workspace/symbols.ts +180 -0
- package/src/workspace/trailer-joins.test.ts +171 -0
- package/src/workspace/trailer-joins.ts +82 -0
- package/src/workspace/trailers.ts +148 -0
- package/src/workspace/trust/seal.ts +52 -1
- package/src/workspace/work-cli.e2e.test.ts +28 -1
- package/src/workspace/work-cli.ts +133 -8
- package/src/workspace/work-evidence.schema.json +2 -0
- package/src/workspace/work-history.schema.json +73 -1
- package/src/workspace/work-history.test.ts +48 -5
- package/src/workspace/work-kind-fields.test.ts +154 -0
- package/src/workspace/work-lease.schema.json +14 -1
- package/src/workspace/work.ts +82 -0
- package/src/workspace/workspace-principals.schema.json +60 -0
- package/src/workspace/write-scope.test.ts +128 -2
- package/src/workspace/write-scope.ts +170 -45
- package/src/yaml.test.ts +111 -1
- package/src/yaml.ts +141 -549
|
@@ -106,6 +106,36 @@ export async function coverageReportCheck(plugin: LexiconPlugin | undefined): Pr
|
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* #3104 — how many composites a lexicon ships.
|
|
111
|
+
*
|
|
112
|
+
* This counted every `.ts` file in `src/composites/` except `index.ts`, so
|
|
113
|
+
* `catalog.ts`, `catalog.test.ts`, `composites.test.ts` and helper modules all
|
|
114
|
+
* counted: otel reported "4 composite(s)" for `NodeAgent` alone. The same rule
|
|
115
|
+
* as #1342 applies: a capability is what the plugin exposes, and a lexicon
|
|
116
|
+
* with composites exposes them through `composites()`, the catalog generated
|
|
117
|
+
* from its real exports (#2662). Ask that when it is there. Only a lexicon
|
|
118
|
+
* without it falls back to the files, and then not to tests, the catalog, the
|
|
119
|
+
* barrel or helper modules.
|
|
120
|
+
*/
|
|
121
|
+
export function countComposites(
|
|
122
|
+
plugin: LexiconPlugin | undefined,
|
|
123
|
+
dir: string,
|
|
124
|
+
): { count: number; detail: string } {
|
|
125
|
+
if (registers(plugin, "composites")) {
|
|
126
|
+
const { items, error } = safeList(plugin!.composites!.bind(plugin));
|
|
127
|
+
if (error !== undefined) return { count: 0, detail: `composites() threw: ${error}` };
|
|
128
|
+
const names = new Set(items.map((e) => e.name));
|
|
129
|
+
return { count: names.size, detail: `${names.size} composite(s) in composites()` };
|
|
130
|
+
}
|
|
131
|
+
const files = listTsFiles(join(dir, "src/composites"), ["index.ts", "catalog.ts", "helpers.ts", "shared.ts"])
|
|
132
|
+
.filter((f) => !f.endsWith(".test.ts") && !f.endsWith(".d.ts") && !f.endsWith("-helpers.ts"));
|
|
133
|
+
return {
|
|
134
|
+
count: files.length,
|
|
135
|
+
detail: `${files.length} composite file(s) in src/composites/; the plugin has no composites()`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
109
139
|
/**
|
|
110
140
|
* #2535 — a lexicon that supplies member kinds publishes them as data at a
|
|
111
141
|
* `./workspace-kinds` subpath (ws-031). The file must be JSON, validate as
|
|
@@ -551,12 +581,12 @@ export async function checkLexicon(dir: string): Promise<CheckResult> {
|
|
|
551
581
|
: "reads no config namespace of its own",
|
|
552
582
|
});
|
|
553
583
|
|
|
554
|
-
const
|
|
584
|
+
const composites = countComposites(plugin, dir);
|
|
555
585
|
items.push({
|
|
556
|
-
name: "At least 1 composite
|
|
586
|
+
name: "At least 1 composite",
|
|
557
587
|
tier: 2,
|
|
558
|
-
pass:
|
|
559
|
-
detail:
|
|
588
|
+
pass: composites.count > 0,
|
|
589
|
+
detail: composites.detail,
|
|
560
590
|
});
|
|
561
591
|
|
|
562
592
|
items.push({
|
|
@@ -678,8 +708,8 @@ export async function checkLexicon(dir: string): Promise<CheckResult> {
|
|
|
678
708
|
items.push({
|
|
679
709
|
name: "At least 5 composites",
|
|
680
710
|
tier: 3,
|
|
681
|
-
pass:
|
|
682
|
-
detail:
|
|
711
|
+
pass: composites.count >= 5,
|
|
712
|
+
detail: composites.detail,
|
|
683
713
|
});
|
|
684
714
|
|
|
685
715
|
const hasActions = existsSync(join(dir, "src/actions")) &&
|
|
@@ -106,6 +106,24 @@ describe("liveImportFromPlugins (#114)", () => {
|
|
|
106
106
|
expect(result.error).toContain("live export");
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
+
test("warnings an exporter returns reach the result (#3336)", async () => {
|
|
110
|
+
const withWarnings: ExportedTemplate = { ...sampleIR, warnings: ["bucket is kept by Terraform; left out"] };
|
|
111
|
+
const result = await liveImportFromPlugins([fakeExporter("fake", withWarnings)], {
|
|
112
|
+
environment: "prod",
|
|
113
|
+
output: outputDir,
|
|
114
|
+
force: true,
|
|
115
|
+
});
|
|
116
|
+
expect(result.success).toBe(true);
|
|
117
|
+
expect(result.warnings).toContain("bucket is kept by Terraform; left out");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("warnings from an export with no resources are kept on the error result (#3336)", async () => {
|
|
121
|
+
const empty = fakeExporter("fake", { resources: [], parameters: [], warnings: ["everything is kept by Prisma"] });
|
|
122
|
+
const result = await liveImportFromPlugins([empty], { environment: "prod", output: outputDir });
|
|
123
|
+
expect(result.success).toBe(false);
|
|
124
|
+
expect(result.warnings).toContain("everything is kept by Prisma");
|
|
125
|
+
});
|
|
126
|
+
|
|
109
127
|
test("--lexicon narrows to the named exporter", async () => {
|
|
110
128
|
const result = await liveImportFromPlugins(
|
|
111
129
|
[fakeExporter("a", sampleIR), fakeExporter("b", sampleIR)],
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import type { LexiconPlugin } from "../../lexicon";
|
|
6
|
+
import type { ParserOptions } from "../../import/parser";
|
|
7
|
+
import { resolveParserOptions } from "../../import/parser-options";
|
|
8
|
+
import { parseArgs } from "../main";
|
|
9
|
+
import { importCommand, importFromContent } from "./import";
|
|
10
|
+
|
|
11
|
+
const { seen, withOptions, withoutOptions } = vi.hoisted(() => {
|
|
12
|
+
const seen: unknown[] = [];
|
|
13
|
+
const parser = {
|
|
14
|
+
parse: () => ({ resources: [], parameters: [], warnings: ["parsed"] }),
|
|
15
|
+
};
|
|
16
|
+
const generator = { generate: () => [{ path: "x.ts", content: "export {};\n" }] };
|
|
17
|
+
const withOptions = {
|
|
18
|
+
name: "with-options",
|
|
19
|
+
detectTemplate: (d: unknown) => typeof d === "object" && d !== null && "marker" in d,
|
|
20
|
+
parserOptions: () => [
|
|
21
|
+
{ name: "flag", type: "boolean", description: "a switch" },
|
|
22
|
+
{ name: "level", type: "number", description: "a number" },
|
|
23
|
+
{ name: "label", type: "string", description: "a string" },
|
|
24
|
+
],
|
|
25
|
+
templateParser: (options?: ParserOptions) => {
|
|
26
|
+
seen.push(options);
|
|
27
|
+
return parser;
|
|
28
|
+
},
|
|
29
|
+
templateGenerator: () => generator,
|
|
30
|
+
} as unknown as LexiconPlugin;
|
|
31
|
+
const withoutOptions = {
|
|
32
|
+
name: "without-options",
|
|
33
|
+
templateParser: () => parser,
|
|
34
|
+
templateGenerator: () => generator,
|
|
35
|
+
} as unknown as LexiconPlugin;
|
|
36
|
+
return { seen, withOptions, withoutOptions };
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
vi.mock("../plugins", () => ({
|
|
40
|
+
resolveProjectLexicons: async () => ["with-options"],
|
|
41
|
+
loadPlugins: async (names: string[]) => names.map((n) => (n === "without-options" ? withoutOptions : withOptions)),
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
describe("resolveParserOptions (#2994)", () => {
|
|
45
|
+
const specs = withOptions as Pick<LexiconPlugin, "name" | "parserOptions">;
|
|
46
|
+
|
|
47
|
+
test("no entries is an empty record", () => {
|
|
48
|
+
expect(resolveParserOptions(specs, undefined)).toEqual({ options: {} });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("converts to the declared types; a bare boolean is true", () => {
|
|
52
|
+
expect(resolveParserOptions(specs, ["flag", "level=3", "label=a=b"])).toEqual({
|
|
53
|
+
options: { flag: true, level: 3, label: "a=b" },
|
|
54
|
+
});
|
|
55
|
+
expect(resolveParserOptions(specs, ["flag=false"])).toEqual({ options: { flag: false } });
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("refuses an unknown name and lists what the lexicon accepts", () => {
|
|
59
|
+
const r = resolveParserOptions(specs, ["nope"]);
|
|
60
|
+
expect(r).toMatchObject({ error: expect.stringContaining('Unknown parser option "nope" for lexicon "with-options"') });
|
|
61
|
+
expect((r as { error: string }).error).toContain("flag (boolean): a switch");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("a lexicon with no options says so", () => {
|
|
65
|
+
const r = resolveParserOptions({ name: "plain" }, ["x"]);
|
|
66
|
+
expect((r as { error: string }).error).toBe('Unknown parser option "x" for lexicon "plain"; lexicon "plain" declares no parser options.');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("refuses a bad value", () => {
|
|
70
|
+
expect(resolveParserOptions(specs, ["flag=maybe"])).toHaveProperty("error");
|
|
71
|
+
expect(resolveParserOptions(specs, ["level=abc"])).toHaveProperty("error");
|
|
72
|
+
expect(resolveParserOptions(specs, ["level"])).toHaveProperty("error");
|
|
73
|
+
expect(resolveParserOptions(specs, ["label"])).toHaveProperty("error");
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("chant import --parser-option (#2994)", () => {
|
|
78
|
+
let dir: string;
|
|
79
|
+
let templatePath: string;
|
|
80
|
+
|
|
81
|
+
beforeEach(async () => {
|
|
82
|
+
seen.length = 0;
|
|
83
|
+
dir = join(tmpdir(), `chant-import-parser-options-${Date.now()}-${Math.random()}`);
|
|
84
|
+
await mkdir(dir, { recursive: true });
|
|
85
|
+
templatePath = join(dir, "t.json");
|
|
86
|
+
await writeFile(templatePath, JSON.stringify({ marker: true }));
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
afterEach(async () => {
|
|
90
|
+
await rm(dir, { recursive: true, force: true });
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("the flag is parsed, repeatable", () => {
|
|
94
|
+
const args = parseArgs(["import", "t.json", "--lexicon", "x", "--parser-option", "a", "--parser-option", "b=1"]);
|
|
95
|
+
expect(args.parserOption).toEqual(["a", "b=1"]);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("--lexicon: the parser receives the typed options", async () => {
|
|
99
|
+
const result = await importCommand({
|
|
100
|
+
templatePath, output: join(dir, "out"), lexicon: "with-options", parserOptions: ["flag", "level=2"],
|
|
101
|
+
});
|
|
102
|
+
expect(result.success).toBe(true);
|
|
103
|
+
expect(seen).toEqual([{ flag: true, level: 2 }]);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("detection: the options go to the detected lexicon", async () => {
|
|
107
|
+
const result = await importCommand({ templatePath, output: join(dir, "out"), parserOptions: ["label=x"] });
|
|
108
|
+
expect(result.success).toBe(true);
|
|
109
|
+
expect(seen).toEqual([{ label: "x" }]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("no options: the parser gets an empty record", async () => {
|
|
113
|
+
await importCommand({ templatePath, output: join(dir, "out"), lexicon: "with-options" });
|
|
114
|
+
expect(seen).toEqual([{}]);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("an unknown option is refused before parsing", async () => {
|
|
118
|
+
const result = await importCommand({
|
|
119
|
+
templatePath, output: join(dir, "out"), lexicon: "with-options", parserOptions: ["bogus"],
|
|
120
|
+
});
|
|
121
|
+
expect(result.success).toBe(false);
|
|
122
|
+
expect(result.error).toContain('Unknown parser option "bogus"');
|
|
123
|
+
expect(seen).toEqual([]);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("content import refuses an option on a lexicon that declares none", async () => {
|
|
127
|
+
const result = await importFromContent({
|
|
128
|
+
content: "{}", lexicon: "without-options", output: join(dir, "out"), parserOptions: ["x"],
|
|
129
|
+
});
|
|
130
|
+
expect(result.success).toBe(false);
|
|
131
|
+
expect(result.error).toContain('lexicon "without-options" declares no parser options');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -7,6 +7,7 @@ import { listInstalledLexicons, loadPlugin, loadPlugins, resolveProjectLexicons
|
|
|
7
7
|
import type { ExportedTemplate, LexiconPlugin, ResourceSelector } from "../../lexicon";
|
|
8
8
|
import { parseYAMLDocument, splitYAMLDocuments } from "../../yaml";
|
|
9
9
|
import { importLexiconPackage } from "../../lexicon-module";
|
|
10
|
+
import { resolveParserOptions } from "../../import/parser-options";
|
|
10
11
|
import { EmbeddedImports, type EmbeddedContent, type RegisteredEmbeddedImporter } from "../../import/embedded";
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -24,6 +25,12 @@ export interface ImportOptions {
|
|
|
24
25
|
* JSON/YAML check: the raw content goes straight to that plugin's parser.
|
|
25
26
|
*/
|
|
26
27
|
lexicon?: string;
|
|
28
|
+
/**
|
|
29
|
+
* `--parser-option` entries (`key` or `key=value`) for the lexicon's parser
|
|
30
|
+
* (#2994). Checked against the lexicon's `parserOptions()`; an unknown name
|
|
31
|
+
* fails the import before anything is parsed.
|
|
32
|
+
*/
|
|
33
|
+
parserOptions?: string[];
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
/**
|
|
@@ -345,6 +352,7 @@ export async function importCommand(options: ImportOptions): Promise<ImportResul
|
|
|
345
352
|
lexicon: options.lexicon,
|
|
346
353
|
output: options.output,
|
|
347
354
|
force: options.force,
|
|
355
|
+
parserOptions: options.parserOptions,
|
|
348
356
|
});
|
|
349
357
|
}
|
|
350
358
|
|
|
@@ -383,7 +391,7 @@ export async function importCommand(options: ImportOptions): Promise<ImportResul
|
|
|
383
391
|
);
|
|
384
392
|
}
|
|
385
393
|
|
|
386
|
-
const result = await parseAndWrite(plugin, content, outputDir, options.force, warnings, generatedFiles, plugin.name, projectDir);
|
|
394
|
+
const result = await parseAndWrite(plugin, content, outputDir, options.force, warnings, generatedFiles, plugin.name, projectDir, options.parserOptions);
|
|
387
395
|
return { ...result, detected: true };
|
|
388
396
|
}
|
|
389
397
|
|
|
@@ -402,6 +410,8 @@ export interface ContentImportOptions {
|
|
|
402
410
|
lexicon: string;
|
|
403
411
|
output?: string;
|
|
404
412
|
force?: boolean;
|
|
413
|
+
/** `--parser-option` entries for the lexicon's parser (#2994); see {@link ImportOptions.parserOptions}. */
|
|
414
|
+
parserOptions?: string[];
|
|
405
415
|
}
|
|
406
416
|
|
|
407
417
|
export async function importFromContent(options: ContentImportOptions): Promise<ImportResult> {
|
|
@@ -422,7 +432,7 @@ export async function importFromContent(options: ContentImportOptions): Promise<
|
|
|
422
432
|
return { success: false, generatedFiles: [], warnings: [], error: `Lexicon "${options.lexicon}" not available.` };
|
|
423
433
|
}
|
|
424
434
|
const projectDir = resolve(options.output ? dirname(options.output) : ".");
|
|
425
|
-
return parseAndWrite(plugin, options.content, outputDir, options.force, [], [], plugin.name, projectDir);
|
|
435
|
+
return parseAndWrite(plugin, options.content, outputDir, options.force, [], [], plugin.name, projectDir, options.parserOptions);
|
|
426
436
|
}
|
|
427
437
|
|
|
428
438
|
/**
|
|
@@ -520,6 +530,7 @@ async function parseAndWrite(
|
|
|
520
530
|
generatedFiles: string[],
|
|
521
531
|
lexicon: string,
|
|
522
532
|
projectDir: string,
|
|
533
|
+
parserOptionEntries?: readonly string[],
|
|
523
534
|
): Promise<ImportResult> {
|
|
524
535
|
// A lexicon can recognize a template (detectTemplate) without being able to
|
|
525
536
|
// import it (grafana had no parser until #2945). Every path funnels through here, so
|
|
@@ -534,11 +545,16 @@ async function parseAndWrite(
|
|
|
534
545
|
};
|
|
535
546
|
}
|
|
536
547
|
|
|
548
|
+
const resolved = resolveParserOptions(plugin, parserOptionEntries);
|
|
549
|
+
if ("error" in resolved) {
|
|
550
|
+
return { success: false, generatedFiles: [], warnings: [], error: resolved.error, lexicon: plugin.name };
|
|
551
|
+
}
|
|
552
|
+
|
|
537
553
|
// Parse template
|
|
538
554
|
let ir: TemplateIR;
|
|
539
555
|
let embedded: EmbeddedImports | undefined;
|
|
540
556
|
try {
|
|
541
|
-
const parser = plugin.templateParser();
|
|
557
|
+
const parser = plugin.templateParser(resolved.options);
|
|
542
558
|
let irs: TemplateIR[];
|
|
543
559
|
({ irs, embedded } = await parseWithEmbedded([(context) => parser.parse(content, context)], [plugin], projectDir));
|
|
544
560
|
ir = irs[0];
|
|
@@ -743,6 +759,8 @@ export async function liveImportFromPlugins(
|
|
|
743
759
|
warnings.push(`${plugin.name}: live export failed — ${err instanceof Error ? err.message : String(err)}`);
|
|
744
760
|
continue;
|
|
745
761
|
}
|
|
762
|
+
// What the exporter left out or could not carry (#3336).
|
|
763
|
+
if (ir.warnings) warnings.push(...ir.warnings);
|
|
746
764
|
if (ir.resources.length === 0) continue;
|
|
747
765
|
irParts.push(ir);
|
|
748
766
|
generatorLexicon ??= plugin;
|
|
@@ -37,7 +37,7 @@ export function generatePackageJson(name: string, names: { packageName: string }
|
|
|
37
37
|
// (the `workspace:` protocol is rejected outside a workspace).
|
|
38
38
|
"@intentius/chant": "*",
|
|
39
39
|
"tsc-alias": "^1.8.17",
|
|
40
|
-
typescript: "^5.9.3",
|
|
40
|
+
typescript: "^5.9.3 || ^7.0.0",
|
|
41
41
|
},
|
|
42
42
|
};
|
|
43
43
|
|
|
@@ -87,7 +87,9 @@ describe("initCommand", () => {
|
|
|
87
87
|
|
|
88
88
|
expect(pkg.dependencies["@intentius/chant"]).toBeDefined();
|
|
89
89
|
expect(pkg.dependencies["@intentius/chant-lexicon-aws"]).toBeDefined();
|
|
90
|
-
|
|
90
|
+
// #3089: the project's TypeScript admits 7, and @types/node backs `types: ["node"]`.
|
|
91
|
+
expect(pkg.devDependencies["typescript"]).toBe("^5.9.3 || ^7.0.0");
|
|
92
|
+
expect(pkg.devDependencies["@types/node"]).toBeDefined();
|
|
91
93
|
expect(pkg.scripts.build).toBe("chant build src --lexicon aws");
|
|
92
94
|
expect(pkg.scripts.dev).toBe("chant build src --lexicon aws --watch");
|
|
93
95
|
expect(pkg.scripts.lint).toBe("chant lint src");
|
|
@@ -115,6 +117,11 @@ describe("initCommand", () => {
|
|
|
115
117
|
expect(tsconfig.compilerOptions.rootDir).toBe("./src");
|
|
116
118
|
expect(tsconfig.include).toContain("src");
|
|
117
119
|
expect(tsconfig.compilerOptions.paths).toBeUndefined();
|
|
120
|
+
// #3089: bundler resolution accepts the extensionless `./config` imports
|
|
121
|
+
// the templates use; NodeNext rejects them (TS2835).
|
|
122
|
+
expect(tsconfig.compilerOptions.module).toBe("esnext");
|
|
123
|
+
expect(tsconfig.compilerOptions.moduleResolution).toBe("bundler");
|
|
124
|
+
expect(tsconfig.compilerOptions.types).toEqual(["node"]);
|
|
118
125
|
});
|
|
119
126
|
});
|
|
120
127
|
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -62,6 +62,16 @@ export interface InitResult {
|
|
|
62
62
|
lexiconModule?: string;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* The devDependencies a scaffolded project gets, from `chant init` and from
|
|
67
|
+
* `chant carve` (#3233). The project's TypeScript is for its editor and `tsc`
|
|
68
|
+
* only; chant parses with its own copy, so any 5.9+ or 7 release works (#3089).
|
|
69
|
+
*/
|
|
70
|
+
export const SCAFFOLD_DEV_DEPENDENCIES = {
|
|
71
|
+
"@types/node": "^24.0.0",
|
|
72
|
+
typescript: "^5.9.3 || ^7.0.0",
|
|
73
|
+
} as const;
|
|
74
|
+
|
|
65
75
|
/**
|
|
66
76
|
* Generate package.json content
|
|
67
77
|
*/
|
|
@@ -88,23 +98,28 @@ function generatePackageJson(
|
|
|
88
98
|
...extraScripts,
|
|
89
99
|
},
|
|
90
100
|
dependencies,
|
|
91
|
-
devDependencies: {
|
|
92
|
-
typescript: "^5.0.0",
|
|
93
|
-
},
|
|
101
|
+
devDependencies: { ...SCAFFOLD_DEV_DEPENDENCIES },
|
|
94
102
|
};
|
|
95
103
|
|
|
96
104
|
return JSON.stringify(pkg, null, 2);
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
/**
|
|
100
|
-
* Generate tsconfig.json content
|
|
108
|
+
* Generate tsconfig.json content.
|
|
109
|
+
*
|
|
110
|
+
* `bundler` resolution, because chant resolves a project's imports the way tsx
|
|
111
|
+
* and fold do: `./config` with no extension. NodeNext rejects that form
|
|
112
|
+
* (TS2835), and its suggested `./config.js` makes fold fall back to running the
|
|
113
|
+
* file (#3089). `types` names node because TypeScript 6 and later no longer load
|
|
114
|
+
* every `@types` package by default.
|
|
101
115
|
*/
|
|
102
|
-
function generateTsConfig(
|
|
116
|
+
export function generateTsConfig(): string {
|
|
103
117
|
const config = {
|
|
104
118
|
compilerOptions: {
|
|
105
119
|
target: "ES2022",
|
|
106
|
-
module: "
|
|
107
|
-
moduleResolution: "
|
|
120
|
+
module: "esnext",
|
|
121
|
+
moduleResolution: "bundler",
|
|
122
|
+
types: ["node"],
|
|
108
123
|
strict: true,
|
|
109
124
|
esModuleInterop: true,
|
|
110
125
|
skipLibCheck: true,
|
|
@@ -307,7 +322,7 @@ export async function initCommand(options: InitOptions): Promise<InitResult> {
|
|
|
307
322
|
// Generate tsconfig.json
|
|
308
323
|
writeIfNotExists(
|
|
309
324
|
join(targetDir, "tsconfig.json"),
|
|
310
|
-
generateTsConfig(
|
|
325
|
+
generateTsConfig(),
|
|
311
326
|
"tsconfig.json",
|
|
312
327
|
createdFiles,
|
|
313
328
|
warnings,
|
|
@@ -281,6 +281,43 @@ export const b = new Bucket({ config: { y: 2 } });
|
|
|
281
281
|
expect(result.diagnostics.some(d => d.ruleId === "COR001")).toBe(true);
|
|
282
282
|
expect(result.diagnostics.filter(d => d.ruleId === "COR001")).toHaveLength(2);
|
|
283
283
|
});
|
|
284
|
+
|
|
285
|
+
// #2511: a project-local rule that throws is an error, never a clean pass.
|
|
286
|
+
test("a project-local rule that throws fails the lint and names the rule, file and message", async () => {
|
|
287
|
+
await mkdir(join(testDir, ".chant", "rules"), { recursive: true });
|
|
288
|
+
await writeFile(
|
|
289
|
+
join(testDir, ".chant", "rules", "local.ts"),
|
|
290
|
+
`
|
|
291
|
+
export const boom = {
|
|
292
|
+
id: "LOCAL_BOOM",
|
|
293
|
+
severity: "warning",
|
|
294
|
+
category: "correctness",
|
|
295
|
+
check() { throw new Error("cannot read sibling file"); },
|
|
296
|
+
};
|
|
297
|
+
export const fine = {
|
|
298
|
+
id: "LOCAL_FINE",
|
|
299
|
+
severity: "warning",
|
|
300
|
+
category: "correctness",
|
|
301
|
+
check(ctx) {
|
|
302
|
+
return [{ file: ctx.filePath, line: 1, column: 1, ruleId: "LOCAL_FINE", severity: "warning", message: "fine ran" }];
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
`,
|
|
306
|
+
);
|
|
307
|
+
const file = join(testDir, "clean.ts");
|
|
308
|
+
await writeFile(file, `// chant-disable\nexport const config = { a: 1 };\n`);
|
|
309
|
+
|
|
310
|
+
const result = await lintCommand({ path: testDir, format: "stylish" });
|
|
311
|
+
|
|
312
|
+
expect(result.success).toBe(false);
|
|
313
|
+
const threw = result.diagnostics.filter((d) => d.ruleId === "LOCAL_BOOM");
|
|
314
|
+
expect(threw).toHaveLength(1);
|
|
315
|
+
expect(threw[0].severity).toBe("error");
|
|
316
|
+
expect(threw[0].file).toBe(file);
|
|
317
|
+
expect(threw[0].message).toContain("LOCAL_BOOM");
|
|
318
|
+
expect(threw[0].message).toContain(file);
|
|
319
|
+
expect(threw[0].message).toContain("cannot read sibling file");
|
|
320
|
+
});
|
|
284
321
|
});
|
|
285
322
|
|
|
286
323
|
describe("isLintRule", () => {
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
patchDockerfile,
|
|
8
8
|
patchRootTsconfigPaths,
|
|
9
9
|
insertPrepackAfterEach,
|
|
10
|
+
patchLexiconList,
|
|
10
11
|
} from "./onboard";
|
|
11
12
|
|
|
12
13
|
function makeTempDir(): string {
|
|
@@ -184,6 +185,8 @@ function writeFixtureRepo(root: string): void {
|
|
|
184
185
|
writeFileSync(join(root, ".github/workflows/publish.yml"), publishContent);
|
|
185
186
|
writeFileSync(join(root, "test/Dockerfile.smoke"), dockerLoopContent);
|
|
186
187
|
writeFileSync(join(root, "test/Dockerfile.smoke-npm"), dockerNpmContent);
|
|
188
|
+
writeFileSync(join(root, "test/smoke-npm-lexicons.txt"), "aws\ngitlab\nk8s\n");
|
|
189
|
+
writeFileSync(join(root, "test/smoke-e2e-lexicons.txt"), "aws\nk8s\n");
|
|
187
190
|
}
|
|
188
191
|
|
|
189
192
|
const TRACKED = [
|
|
@@ -193,6 +196,8 @@ const TRACKED = [
|
|
|
193
196
|
".github/workflows/publish.yml",
|
|
194
197
|
"test/Dockerfile.smoke",
|
|
195
198
|
"test/Dockerfile.smoke-npm",
|
|
199
|
+
"test/smoke-npm-lexicons.txt",
|
|
200
|
+
"test/smoke-e2e-lexicons.txt",
|
|
196
201
|
];
|
|
197
202
|
|
|
198
203
|
function snapshot(root: string): Record<string, string> {
|
|
@@ -223,8 +228,12 @@ describe("onboardCommand", () => {
|
|
|
223
228
|
"publish.yml (prepack)",
|
|
224
229
|
"Dockerfile.smoke (lexicon list)",
|
|
225
230
|
"Dockerfile.smoke-npm (lexicon list)",
|
|
231
|
+
"smoke-npm-lexicons.txt (lexicon list)",
|
|
226
232
|
]);
|
|
227
|
-
expect(result.skipped).
|
|
233
|
+
expect(result.skipped).toHaveLength(1);
|
|
234
|
+
expect(result.skipped[0]).toContain("smoke-e2e-lexicons.txt: not patched");
|
|
235
|
+
expect(readFileSync(join(root, "test/smoke-npm-lexicons.txt"), "utf-8")).toBe("aws\ngitlab\nk8s\nterraform\n");
|
|
236
|
+
expect(readFileSync(join(root, "test/smoke-e2e-lexicons.txt"), "utf-8")).toBe("aws\nk8s\n");
|
|
228
237
|
|
|
229
238
|
const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf-8"));
|
|
230
239
|
expect(pkg.dependencies["@intentius/chant-lexicon-terraform"]).toBe("workspace:*");
|
|
@@ -254,6 +263,8 @@ describe("onboardCommand", () => {
|
|
|
254
263
|
"publish.yml: prepack for terraform already present",
|
|
255
264
|
"Dockerfile.smoke: already covers terraform",
|
|
256
265
|
"Dockerfile.smoke-npm: already covers terraform",
|
|
266
|
+
"smoke-npm-lexicons.txt: terraform already in test/smoke-npm-lexicons.txt",
|
|
267
|
+
expect.stringContaining("smoke-e2e-lexicons.txt: not patched"),
|
|
257
268
|
]);
|
|
258
269
|
});
|
|
259
270
|
|
|
@@ -312,9 +323,9 @@ describe("root tsconfig.json paths (#1614)", () => {
|
|
|
312
323
|
|
|
313
324
|
const cfg = JSON.parse(readFileSync(join(root, "tsconfig.json"), "utf-8"));
|
|
314
325
|
expect(cfg.compilerOptions.paths["@intentius/chant-lexicon-terraform"]).toEqual([
|
|
315
|
-
"lexicons/terraform/src/index.ts",
|
|
326
|
+
"./lexicons/terraform/src/index.ts",
|
|
316
327
|
]);
|
|
317
|
-
expect(cfg.compilerOptions.paths["@intentius/chant-lexicon-terraform/*"]).toEqual(["lexicons/terraform/src/*"]);
|
|
328
|
+
expect(cfg.compilerOptions.paths["@intentius/chant-lexicon-terraform/*"]).toEqual(["./lexicons/terraform/src/*"]);
|
|
318
329
|
// Existing entries untouched
|
|
319
330
|
expect(cfg.compilerOptions.paths["@intentius/chant-lexicon-aws"]).toEqual(["lexicons/aws/src/index.ts"]);
|
|
320
331
|
expect(cfg.compilerOptions.moduleResolution).toBe("node");
|
|
@@ -462,3 +473,42 @@ describe("insertPrepackAfterEach", () => {
|
|
|
462
473
|
]);
|
|
463
474
|
});
|
|
464
475
|
});
|
|
476
|
+
|
|
477
|
+
describe("smoke lists and publish.yml reporting (#3227)", () => {
|
|
478
|
+
let root: string;
|
|
479
|
+
|
|
480
|
+
beforeEach(() => {
|
|
481
|
+
root = makeTempDir();
|
|
482
|
+
writeFixtureRepo(root);
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
afterEach(() => {
|
|
486
|
+
rmSync(root, { recursive: true, force: true });
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
test("patchLexiconList appends once and keeps the trailing newline", () => {
|
|
490
|
+
const file = join(root, "test/smoke-npm-lexicons.txt");
|
|
491
|
+
writeFileSync(file, "aws\nk8s");
|
|
492
|
+
expect(patchLexiconList(file, "sql").patched).toBe(true);
|
|
493
|
+
expect(readFileSync(file, "utf-8")).toBe("aws\nk8s\nsql\n");
|
|
494
|
+
expect(patchLexiconList(file, "sql").patched).toBe(false);
|
|
495
|
+
expect(readFileSync(file, "utf-8")).toBe("aws\nk8s\nsql\n");
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
test("a Dockerfile that reads the list file points at it instead of claiming coverage", () => {
|
|
499
|
+
const file = join(root, "test/Dockerfile.smoke-npm");
|
|
500
|
+
writeFileSync(file, "RUN LEXICONS=$(cat /app/test/smoke-npm-lexicons.txt) && \\\n for lex in $LEXICONS; do :; done\n");
|
|
501
|
+
const result = patchDockerfile(file, "sql");
|
|
502
|
+
expect(result.patched).toBe(false);
|
|
503
|
+
expect(result.reason).toContain("test/smoke-npm-lexicons.txt");
|
|
504
|
+
expect(result.reason).not.toContain("already covers");
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
test("publish.yml with no per-lexicon prepack lines says nothing needs patching", () => {
|
|
508
|
+
writeFileSync(join(root, ".github/workflows/publish.yml"), "name: publish\njobs:\n test:\n steps:\n - run: bash scripts/publish-verify-ci.sh\n");
|
|
509
|
+
const result = onboardCommand({ name: "sql", root });
|
|
510
|
+
const line = result.skipped.find((s) => s.startsWith("publish.yml:"));
|
|
511
|
+
expect(line).toContain("nothing to patch");
|
|
512
|
+
expect(line).toContain("scripts/ci-lexicon-artifacts.sh");
|
|
513
|
+
});
|
|
514
|
+
});
|
|
@@ -117,6 +117,10 @@ function patchRootPackageJson(root: string, name: string): PatchResult {
|
|
|
117
117
|
* The whole-repo typecheck runs with `moduleResolution: node`, which never
|
|
118
118
|
* reads package exports maps, so every lexicon needs a bare + subpath
|
|
119
119
|
* mapping here or an example importing the package fails to resolve.
|
|
120
|
+
*
|
|
121
|
+
* Entries are `./`-prefixed like every other entry (#3227): with no `baseUrl`
|
|
122
|
+
* (removed in #3205) a bare `lexicons/...` path is invalid and tsx's tsconfig
|
|
123
|
+
* loader throws on it for every run in the repo.
|
|
120
124
|
*/
|
|
121
125
|
export function patchRootTsconfigPaths(root: string, name: string): PatchResult {
|
|
122
126
|
const tsconfigPath = join(root, "tsconfig.json");
|
|
@@ -128,8 +132,8 @@ export function patchRootTsconfigPaths(root: string, name: string): PatchResult
|
|
|
128
132
|
|
|
129
133
|
const bare = `@intentius/chant-lexicon-${name}`;
|
|
130
134
|
const wanted: Record<string, string[]> = {
|
|
131
|
-
[bare]: [
|
|
132
|
-
[`${bare}/*`]: [
|
|
135
|
+
[bare]: [`./lexicons/${name}/src/index.ts`],
|
|
136
|
+
[`${bare}/*`]: [`./lexicons/${name}/src/*`],
|
|
133
137
|
};
|
|
134
138
|
|
|
135
139
|
let changed = false;
|
|
@@ -297,7 +301,15 @@ function patchPublishWorkflow(root: string, name: string): PatchResult {
|
|
|
297
301
|
}
|
|
298
302
|
|
|
299
303
|
if (!insertPrepackAfterEach(lines, name)) {
|
|
300
|
-
|
|
304
|
+
// #3227 — not a failure and not "covered by a prepack line": publish.yml
|
|
305
|
+
// carries no per-lexicon lines. The run builds every lexicon through
|
|
306
|
+
// scripts/ci-lexicon-artifacts.sh and publishes through
|
|
307
|
+
// scripts/publish-packages.sh, both of which enumerate the workspace.
|
|
308
|
+
return {
|
|
309
|
+
patched: false,
|
|
310
|
+
reason:
|
|
311
|
+
"nothing to patch: it has no per-lexicon prepack lines; scripts/ci-lexicon-artifacts.sh and scripts/publish-packages.sh enumerate the workspace",
|
|
312
|
+
};
|
|
301
313
|
}
|
|
302
314
|
writeFileSync(filePath, lines.join("\n"));
|
|
303
315
|
return { patched: true };
|
|
@@ -321,6 +333,12 @@ export function patchDockerfile(filePath: string, name: string): PatchResult {
|
|
|
321
333
|
|
|
322
334
|
const changed = addToLexiconLoops(lines, name) || insertPrepackAfterEach(lines, name);
|
|
323
335
|
if (!changed) {
|
|
336
|
+
// #3227 — the smoke-npm and smoke-e2e images read their lexicon list from
|
|
337
|
+
// a file. Point at it instead of reporting a missing anchor.
|
|
338
|
+
const listFile = lines.join("\n").match(/test\/(smoke-[\w-]+-lexicons\.txt)/)?.[1];
|
|
339
|
+
if (listFile) {
|
|
340
|
+
return { patched: false, reason: `reads its lexicon list from test/${listFile}, not from the Dockerfile` };
|
|
341
|
+
}
|
|
324
342
|
return { patched: false, reason: "no lexicon loop or prepack line found to anchor on" };
|
|
325
343
|
}
|
|
326
344
|
|
|
@@ -328,6 +346,22 @@ export function patchDockerfile(filePath: string, name: string): PatchResult {
|
|
|
328
346
|
return { patched: true };
|
|
329
347
|
}
|
|
330
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Append a lexicon to a one-name-per-line list file (test/smoke-npm-lexicons.txt).
|
|
351
|
+
* Idempotent; keeps the file's trailing newline.
|
|
352
|
+
*/
|
|
353
|
+
export function patchLexiconList(filePath: string, name: string): PatchResult {
|
|
354
|
+
const rel = filePath.split("/").slice(-2).join("/");
|
|
355
|
+
if (!existsSync(filePath)) return { patched: false, reason: `${rel} not found` };
|
|
356
|
+
const content = readFileSync(filePath, "utf-8");
|
|
357
|
+
if (content.split("\n").some((l) => l.trim() === name)) {
|
|
358
|
+
return { patched: false, reason: `${name} already in ${rel}` };
|
|
359
|
+
}
|
|
360
|
+
const sep = content === "" || content.endsWith("\n") ? "" : "\n";
|
|
361
|
+
writeFileSync(filePath, `${content}${sep}${name}\n`);
|
|
362
|
+
return { patched: true };
|
|
363
|
+
}
|
|
364
|
+
|
|
331
365
|
/**
|
|
332
366
|
* Execute the onboard command — patches monorepo infrastructure for a new lexicon.
|
|
333
367
|
*/
|
|
@@ -375,6 +409,20 @@ export function onboardCommand(options: OnboardOptions): OnboardResult {
|
|
|
375
409
|
patchDockerfile(join(root, "test/Dockerfile.smoke-npm"), options.name),
|
|
376
410
|
);
|
|
377
411
|
|
|
412
|
+
// 6. Smoke image lexicon lists (#3227). The npm smoke packs every lexicon.
|
|
413
|
+
// The e2e list is opt-in: it names the lexicons an example uses plus
|
|
414
|
+
// their dependencies, so onboard leaves it alone and says so.
|
|
415
|
+
record(
|
|
416
|
+
"smoke-npm-lexicons.txt",
|
|
417
|
+
"lexicon list",
|
|
418
|
+
patchLexiconList(join(root, "test/smoke-npm-lexicons.txt"), options.name),
|
|
419
|
+
);
|
|
420
|
+
if (existsSync(join(root, "test/smoke-e2e-lexicons.txt"))) {
|
|
421
|
+
skipped.push(
|
|
422
|
+
`smoke-e2e-lexicons.txt: not patched; it lists only lexicons an e2e example uses (and their dependencies). Add ${options.name} to test/smoke-e2e-lexicons.txt when an example needs it`,
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
|
|
378
426
|
return { success: true, patched, skipped, verbose: options.verbose };
|
|
379
427
|
}
|
|
380
428
|
|
|
@@ -396,7 +444,7 @@ export async function printOnboardResult(result: OnboardResult, name: string): P
|
|
|
396
444
|
|
|
397
445
|
if (result.skipped.length > 0) {
|
|
398
446
|
console.log("");
|
|
399
|
-
console.log("
|
|
447
|
+
console.log("Not patched (already covered, or nothing to patch):");
|
|
400
448
|
for (const s of result.skipped) {
|
|
401
449
|
console.log(` ${s}`);
|
|
402
450
|
}
|