diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3bd9d77..a793122 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -13,17 +13,51 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 + with: + fetch-depth: 0 - uses: actions/setup-node@v7 with: node-version: 22.14.0 - name: Check whitespace run: git diff --check "$(git hash-object -t tree /dev/null)" HEAD + - name: Install validation dependencies + run: npm ci --ignore-scripts --no-audit - name: Check generator syntax run: node --check scripts/generate.mjs - name: Test shared-source generation and drift rejection run: npm test - name: Verify committed generated content run: npm run check + - name: Preserve published immutable machine resources + env: + MACHINE_BASE_REVISION: ${{ github.event.pull_request.base.sha || github.event.before }} + run: node scripts/check-machine-immutability.mjs + - name: Verify machine resource integrity and actual WASM behavior + run: npm run machine:check + - name: Read native conformance pins + id: native + run: | + node --input-type=module -e 'import fs from "node:fs"; const p=JSON.parse(fs.readFileSync("content/machine-resources-v1.json")); console.log(`compiler=${p.compilerRevision}\nspecification=${p.specificationRevision}`)' >> "$GITHUB_OUTPUT" + - uses: actions/checkout@v7 + with: + repository: stack-sh/compiler + ref: ${{ steps.native.outputs.compiler }} + path: .stack-compiler + persist-credentials: false + - uses: actions/checkout@v7 + with: + repository: stack-sh/specification + ref: ${{ steps.native.outputs.specification }} + path: .stack-specification + persist-credentials: false + - name: Verify native compiler IR and language intelligence conformance + env: + STACK_SPECIFICATION_DIR: ${{ github.workspace }}/.stack-specification + run: | + rustup toolchain install stable --profile minimal + cargo +stable test --manifest-path .stack-compiler/Cargo.toml --locked --features conformance --test conformance --test language_intelligence_conformance + - name: Run a resource consumer against local discovery and immutable upstream URLs + run: node examples/read-machine-resources.mjs --local - name: Check published CLI freshness run: npm run release:check env: diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c206489 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +.stack-compiler/ +.stack-specification/ diff --git a/MACHINE_RESOURCES.md b/MACHINE_RESOURCES.md new file mode 100644 index 0000000..175a287 --- /dev/null +++ b/MACHINE_RESOURCES.md @@ -0,0 +1,80 @@ +# Machine resource distribution + +## Discovery and versioning + +Discover the current manifest at `https://stack-diagram.com/machine/index.json`. +Its `current` record provides a versioned manifest URL and SHA-256. Version 1 is +published at `https://stack-diagram.com/machine/v1.0.0/manifest.json`, with its JSON +Schema at the adjacent `manifest.schema.json` URL. The site serves these generated +artifacts; source and generation are owned here. Language resources remain owned +by the specification repository, linked at immutable Git commits with byte hashes. + +The manifest includes the language specification, highlighting grammar, normalized +IR and diagnostic schemas, protocol-neutral language-intelligence schemas, example +catalog and every example source, canonical conformance fixtures, and a JSON +diagnostic catalog derived from the specification's portable-code table. + +## Compatibility + +Read `schemaVersion` and `requiredReaderFeatures` before using the manifest. Reject +unsupported reader requirements or an unknown schema version. Select one named +implementation and check the requested capability explicitly. Absence means +unsupported by this snapshot, not that another implementation or future release +cannot support it. CLI 0.4.0, Engine 0.7.0, and the pinned compiler snapshot have +different capabilities. Compiler `document-symbols` does not imply that the WASM +adapter exposes it; protocol schemas do not imply CLI JSON-output support. + +Versions in this manifest are a tested, immutable compatibility snapshot, not a +claim to always represent the latest CLI. Current installation guidance uses the +separate release lock and freshness audit. A future snapshot gets a new manifest +version and URL. Existing resource bytes, versions, and digests must not be edited +in place after publication, including to correct a mistake. Publish a replacement, +move discovery, and document the correction instead. + +Stack source is not JSON: these schemas validate interchange envelopes and result +objects, not `.stack` syntax. Use the compiler or engine to validate Stack source. +The TextMate grammar highlights syntax; it is not a semantic validator. Relative +schema references resolve against their immutable canonical resource URL, not the +manifest URL. Every referenced schema is also listed in the manifest. + +## Cache, integrity, and lifecycle + +Revalidate the mutable discovery document using normal HTTP conditional requests; +do not treat it as an indefinitely immutable cache entry. Cache versioned manifests +and commit-addressed resources by their verified SHA-256. Verify downloaded bytes +before parsing or caching and fail on retrieval errors or mismatches. Hashes prove +integrity relative to the manifest, not publisher identity: trust the HTTPS +discovery origin or a separately reviewed manifest digest. Do not silently replace +a pinned resource with a mutable `main` URL or a different version. + +Keep published versioned artifacts available when discovery moves. Deprecation +does not delete an old artifact. A security/legal takedown, if unavoidable, should +be documented in the repository and release notes; clients must report retrieval +failure rather than downgrade verification. No runtime service, credentials, +source upload, or vendor artwork distribution is introduced by this index. + +## Validation and consumer example + +```sh +npm ci --ignore-scripts +npm run generate +npm test +npm run machine:check +node examples/read-machine-resources.mjs --local +``` + +The example uses generated local discovery/manifest files with `--local`, but still +retrieves upstream resources through immutable URLs and checks their hashes. Omit +the flag after website publication to test the public discovery endpoint. + +CI validates all resource hashes, the manifest and upstream schemas, the derived +diagnostic catalog, rendered examples, actual WASM diagnostics/completion/hover, +and the pinned native compiler's full normalized-IR/language-intelligence suites. +Client fixtures cover unsupported capabilities, malformed hashes, mutable URLs, +missing content, and altered resources. Provider icon examples may render fallback +icons without installed packs; this is not proof that vendor artwork was loaded. + +`content/machine-resources-v1.json` records hashes extracted from the pinned +specification commit. When preparing a new snapshot, recalculate from those exact +Git object bytes (including invalid-UTF-8 fixtures), not text-decoded copies. The +diagnostic table must continue to match the pinned specification in CI. diff --git a/README.md b/README.md index 8751ff6..45bf862 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ Canonical user documentation and generated agent guidance for Stack architecture ## Ownership +See [machine resource distribution](./MACHINE_RESOURCES.md) for the versioned +schema, grammar, diagnostics, examples, capability manifest, and consumer example. + Edit the shared agent workflow in `content/agent-workflow.md`. Both the installable skill and the human-readable workflow are generated from this one source. Skill discovery metadata lives in `content/skill-metadata.json`, and published CLI diff --git a/content/machine-manifest-v1.schema.json b/content/machine-manifest-v1.schema.json new file mode 100644 index 0000000..3f8fbef --- /dev/null +++ b/content/machine-manifest-v1.schema.json @@ -0,0 +1,147 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://stack-diagram.com/machine/v1.0.0/manifest.schema.json", + "title": "Stack machine resource manifest v1", + "type": "object", + "additionalProperties": false, + "required": [ + "schemaVersion", + "version", + "languageVersion", + "requiredReaderFeatures", + "implementations", + "resources" + ], + "properties": { + "schemaVersion": { + "const": "1.0" + }, + "version": { + "const": "1.0.0" + }, + "languageVersion": { + "const": "1.0" + }, + "requiredReaderFeatures": { + "type": "array", + "uniqueItems": true, + "items": { + "enum": [ + "sha256", + "immutable-resources" + ] + } + }, + "implementations": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/implementation" + } + }, + "resources": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/resource" + } + } + }, + "$defs": { + "source": { + "type": "object", + "additionalProperties": false, + "required": [ + "repository", + "revision", + "path" + ], + "properties": { + "repository": { + "type": "string", + "pattern": "^stack-sh/[a-z-]+$" + }, + "revision": { + "type": "string", + "pattern": "^[a-f0-9]{40}$" + }, + "path": { + "type": "string", + "pattern": "^[A-Za-z0-9_./-]+$" + } + } + }, + "resource": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "url", + "sha256", + "bytes" + ], + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "url": { + "type": "string", + "pattern": "^https://" + }, + "sha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "bytes": { + "type": "integer", + "minimum": 0, + "maximum": 1048576 + }, + "source": { + "$ref": "#/$defs/source" + } + } + }, + "implementation": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "version", + "repository", + "revision", + "capabilities" + ], + "properties": { + "id": { + "enum": [ + "cli", + "engine", + "compiler" + ] + }, + "version": { + "type": "string", + "pattern": "^\\d+\\.\\d+\\.\\d+$" + }, + "repository": { + "type": "string", + "pattern": "^stack-sh/[a-z-]+$" + }, + "revision": { + "type": "string", + "pattern": "^[a-f0-9]{40}$" + }, + "capabilities": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "pattern": "^[a-z][a-z-]+$" + } + } + } + } + } +} diff --git a/content/machine-resources-v1.json b/content/machine-resources-v1.json new file mode 100644 index 0000000..d326598 --- /dev/null +++ b/content/machine-resources-v1.json @@ -0,0 +1,692 @@ +{ + "specificationRevision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "compilerRevision": "84ab5663a7f7c5b7dc0b5e9e2f04c8894ed02820", + "engineRevision": "a1c29b7caba2dc6cd91e56a6ebec1382859d4869", + "resources": [ + { + "id": "INTERCHANGE.md", + "path": "INTERCHANGE.md", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/INTERCHANGE.md", + "sha256": "34c5a6a09abe3a753334f60cd9cca7a50c5dad1ade41faaffb1ee13a0bdec097", + "bytes": 10382 + }, + { + "id": "LANGUAGE_INTELLIGENCE.md", + "path": "LANGUAGE_INTELLIGENCE.md", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/LANGUAGE_INTELLIGENCE.md", + "sha256": "207ac0b19af8e5b1bf8d6ba9b057048c5b733371b4ae6e86bab4b526ed785aad", + "bytes": 12224 + }, + { + "id": "SPECIFICATION.md", + "path": "SPECIFICATION.md", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/SPECIFICATION.md", + "sha256": "6d76a4e28aec4ef1f2a18835ca033b7b0c5c69b549e6caed644fe130f4e53ff8", + "bytes": 36660 + }, + { + "id": "conformance/README.md", + "path": "conformance/README.md", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/README.md", + "sha256": "5a46dbae13801aff73ea2a9e68696aae40ad037f4a03ac6c9d84e8db8b7ecdb1", + "bytes": 3553 + }, + { + "id": "conformance/formatter/comments-and-layout/expected.ir.json", + "path": "conformance/formatter/comments-and-layout/expected.ir.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/formatter/comments-and-layout/expected.ir.json", + "sha256": "d07ffadd1cd54e3007aee0a8b49313950d6f86a856b6e35cfdda7fc5ccded961", + "bytes": 1454 + }, + { + "id": "conformance/formatter/comments-and-layout/expected.stack", + "path": "conformance/formatter/comments-and-layout/expected.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/formatter/comments-and-layout/expected.stack", + "sha256": "69dc26cfc1333d7f458f8bb04611c1fea17057411966005097277e26e7b3e8ea", + "bytes": 599 + }, + { + "id": "conformance/formatter/comments-and-layout/input.stack", + "path": "conformance/formatter/comments-and-layout/input.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/formatter/comments-and-layout/input.stack", + "sha256": "b7224b96067bc8e6d5c3afb07e66bf44adc12f0a47c99a366518fcd6effb7eca", + "bytes": 538 + }, + { + "id": "conformance/invalid/byte-order-mark/expected.diagnostics.json", + "path": "conformance/invalid/byte-order-mark/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/byte-order-mark/expected.diagnostics.json", + "sha256": "30e3e11370f28eb2aaac2777d7183e343ec0b2de0e31273bc312302b1c2303e6", + "bytes": 263 + }, + { + "id": "conformance/invalid/byte-order-mark/source.stack", + "path": "conformance/invalid/byte-order-mark/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/byte-order-mark/source.stack", + "sha256": "8f7538040e38e97ca0e659a89b6ac024757f34968613dacdef34356bfcc71738", + "bytes": 48 + }, + { + "id": "conformance/invalid/duplicate-theme-dense-node/expected.diagnostics.json", + "path": "conformance/invalid/duplicate-theme-dense-node/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/duplicate-theme-dense-node/expected.diagnostics.json", + "sha256": "8394d1956db0b960937db8ee90b9c2e6f0e0c27e052306c26054b61282557400", + "bytes": 504 + }, + { + "id": "conformance/invalid/duplicate-theme-dense-node/source.stack", + "path": "conformance/invalid/duplicate-theme-dense-node/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/duplicate-theme-dense-node/source.stack", + "sha256": "167184ae7b9bd82dd66f495928b3e75ea187d7c9d5653a7f59087167d935a961", + "bytes": 512 + }, + { + "id": "conformance/invalid/edge-rules/expected.diagnostics.json", + "path": "conformance/invalid/edge-rules/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/edge-rules/expected.diagnostics.json", + "sha256": "21afde68cf5cef2390768dfd83122c2bd57d09612b58232d86f723fdf1f55666", + "bytes": 697 + }, + { + "id": "conformance/invalid/edge-rules/source.stack", + "path": "conformance/invalid/edge-rules/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/edge-rules/source.stack", + "sha256": "58f595efdb0d5b909678645088083af060eb806e173c7f826cae9daca6da05bd", + "bytes": 127 + }, + { + "id": "conformance/invalid/empty-diagram/expected.diagnostics.json", + "path": "conformance/invalid/empty-diagram/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/empty-diagram/expected.diagnostics.json", + "sha256": "f48b19f3aac38af879b4f978e9f20f7d7304065c5b20bea9fd62286b7d51d1ad", + "bytes": 266 + }, + { + "id": "conformance/invalid/empty-diagram/source.stack", + "path": "conformance/invalid/empty-diagram/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/empty-diagram/source.stack", + "sha256": "f6e76216ce9d51ff74e36902a6d5a1d31006775ab456155078371f587143239a", + "bytes": 29 + }, + { + "id": "conformance/invalid/independent-semantic-errors/expected.diagnostics.json", + "path": "conformance/invalid/independent-semantic-errors/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/independent-semantic-errors/expected.diagnostics.json", + "sha256": "6f68b3d547729146d7ac2431ca0cf6e5ec57ad2fc938d569739099f7611ffe18", + "bytes": 1981 + }, + { + "id": "conformance/invalid/independent-semantic-errors/source.stack", + "path": "conformance/invalid/independent-semantic-errors/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/independent-semantic-errors/source.stack", + "sha256": "36d8f56b49ac6d94bc358cde477b7cad66a5f6d157a2effbdc3fe59e1a54a8f2", + "bytes": 116 + }, + { + "id": "conformance/invalid/invalid-string-escape/expected.diagnostics.json", + "path": "conformance/invalid/invalid-string-escape/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/invalid-string-escape/expected.diagnostics.json", + "sha256": "3112ad17324bc2e305dd16a446f6ecb96e673b4ae0d828db7a62eee223f68033", + "bytes": 267 + }, + { + "id": "conformance/invalid/invalid-string-escape/source.stack", + "path": "conformance/invalid/invalid-string-escape/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/invalid-string-escape/source.stack", + "sha256": "e6359923f4f3b2714926e8b7aa6a00f168435876e8e26cd8bc3b30445c84d884", + "bytes": 47 + }, + { + "id": "conformance/invalid/invalid-utf8/expected.diagnostics.json", + "path": "conformance/invalid/invalid-utf8/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/invalid-utf8/expected.diagnostics.json", + "sha256": "edf46345443048f97f40402f3c3869c179c687fc6e3c06e6d9e4f1f7fa5d89cd", + "bytes": 265 + }, + { + "id": "conformance/invalid/invalid-utf8/source.stack", + "path": "conformance/invalid/invalid-utf8/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/invalid-utf8/source.stack", + "sha256": "14b7ba40d4dd19e10dce64ed4f9a4041ba7123b3fa22d19e211fc2ee5d6980ed", + "bytes": 18 + }, + { + "id": "conformance/invalid/layout-rules/expected.diagnostics.json", + "path": "conformance/invalid/layout-rules/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/layout-rules/expected.diagnostics.json", + "sha256": "a72705a9100ebb0724b1063e8f98b7aa17f56ab68ac0c6bfe2df4c1e32fb179d", + "bytes": 921 + }, + { + "id": "conformance/invalid/layout-rules/source.stack", + "path": "conformance/invalid/layout-rules/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/layout-rules/source.stack", + "sha256": "f60985445706598c266b1d0d41f465f31734f1b413b4d7921213eb5503c776f3", + "bytes": 184 + }, + { + "id": "conformance/invalid/nested-group-icon/expected.diagnostics.json", + "path": "conformance/invalid/nested-group-icon/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/nested-group-icon/expected.diagnostics.json", + "sha256": "22f1354a21a24b7c602b17f49a6136490e2ac1736da43b935653475848ae6d3a", + "bytes": 486 + }, + { + "id": "conformance/invalid/nested-group-icon/source.stack", + "path": "conformance/invalid/nested-group-icon/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/nested-group-icon/source.stack", + "sha256": "e3005827757edfd70f11a45c0c68c686ae624f28a58767fb22c983bfd952c48e", + "bytes": 204 + }, + { + "id": "conformance/invalid/unexpected-end/expected.diagnostics.json", + "path": "conformance/invalid/unexpected-end/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unexpected-end/expected.diagnostics.json", + "sha256": "de4a0f140eb52b03a8039badc98adf15a633f502170b64242a3835e50e437304", + "bytes": 265 + }, + { + "id": "conformance/invalid/unexpected-end/source.stack", + "path": "conformance/invalid/unexpected-end/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unexpected-end/source.stack", + "sha256": "a757fd3e150aece9441c16aae74ca74a3ad20580eced0e22f3c833888b0fbb1e", + "bytes": 50 + }, + { + "id": "conformance/invalid/unexpected-token/expected.diagnostics.json", + "path": "conformance/invalid/unexpected-token/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unexpected-token/expected.diagnostics.json", + "sha256": "b24dc4809425da1f096d2503adfe62e696bb832ea1cdfe20f614772ef624a2ea", + "bytes": 334 + }, + { + "id": "conformance/invalid/unexpected-token/source.stack", + "path": "conformance/invalid/unexpected-token/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unexpected-token/source.stack", + "sha256": "52d6bbb3cfcb6b963d57bae214ca608fce8e5bce0ce4738a4b824c543b48b694", + "bytes": 54 + }, + { + "id": "conformance/invalid/unknown-edge-endpoint/expected.diagnostics.json", + "path": "conformance/invalid/unknown-edge-endpoint/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unknown-edge-endpoint/expected.diagnostics.json", + "sha256": "63ae20580da730b2ab0b7b17670e2ee4083d1cebf46dcedbb12bd1b8e14284ae", + "bytes": 375 + }, + { + "id": "conformance/invalid/unknown-edge-endpoint/source.stack", + "path": "conformance/invalid/unknown-edge-endpoint/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unknown-edge-endpoint/source.stack", + "sha256": "885a06e1d2679beeb7256b88fec9575cc0820e39d6101a21c071e92b95146cff", + "bytes": 105 + }, + { + "id": "conformance/invalid/unknown-layout-direction/expected.diagnostics.json", + "path": "conformance/invalid/unknown-layout-direction/expected.diagnostics.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unknown-layout-direction/expected.diagnostics.json", + "sha256": "d5dd54b2358b19e5a4b3f0301a153cadfa34ea006e0cd525989aed47cfe5dd86", + "bytes": 304 + }, + { + "id": "conformance/invalid/unknown-layout-direction/source.stack", + "path": "conformance/invalid/unknown-layout-direction/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unknown-layout-direction/source.stack", + "sha256": "f37596e202223e5ce47b7ef4cb66d9e524cdafbdeb1c92e614967d343df968f8", + "bytes": 76 + }, + { + "id": "conformance/language-intelligence/format/fixture.json", + "path": "conformance/language-intelligence/format/fixture.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/format/fixture.json", + "sha256": "5f8430d9900b8f4537a0f25006348ca8d782ddf80132637acdca048b39f3d3c1", + "bytes": 784 + }, + { + "id": "conformance/language-intelligence/format/source.stack", + "path": "conformance/language-intelligence/format/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/format/source.stack", + "sha256": "db381aaea0f0aedb64d7e88ee1359b5d0d256a976102c6f6072ab7bad2f5dea3", + "bytes": 57 + }, + { + "id": "conformance/language-intelligence/partial/fixture.json", + "path": "conformance/language-intelligence/partial/fixture.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/partial/fixture.json", + "sha256": "4516d5b40b6f86c87806d8ff4fafe6c590d0ba3030df10db122db82e8d2f592a", + "bytes": 2406 + }, + { + "id": "conformance/language-intelligence/partial/source.stack", + "path": "conformance/language-intelligence/partial/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/partial/source.stack", + "sha256": "4880e629ee875ff319f2517248dc9dbd95e0166ccdd026ed70549d956ee24813", + "bytes": 57 + }, + { + "id": "conformance/language-intelligence/semantic/fixture.json", + "path": "conformance/language-intelligence/semantic/fixture.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/semantic/fixture.json", + "sha256": "7ea1cc7e7ea729e5fb9c6fac671c64fc1a80b95b451e256b11481cb9317117c5", + "bytes": 8518 + }, + { + "id": "conformance/language-intelligence/semantic/source.stack", + "path": "conformance/language-intelligence/semantic/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/semantic/source.stack", + "sha256": "ff32652ca5cfdb3e69352b2701bb75bbbeede4bea0f7978d225bcd8bd1d7bfb2", + "bytes": 240 + }, + { + "id": "conformance/valid/complete-semantics/expected.ir.json", + "path": "conformance/valid/complete-semantics/expected.ir.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/complete-semantics/expected.ir.json", + "sha256": "3f1f5572966d307388b2f22b9dcd10a022df25bd4b1039e3afdb1913165a7981", + "bytes": 4489 + }, + { + "id": "conformance/valid/complete-semantics/source.stack", + "path": "conformance/valid/complete-semantics/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/complete-semantics/source.stack", + "sha256": "11ec422ef2517ef55a0d232e04672ca44a955d1c8ce6074ece6852c834992f0c", + "bytes": 1365 + }, + { + "id": "conformance/valid/default-normalization/expected.ir.json", + "path": "conformance/valid/default-normalization/expected.ir.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/default-normalization/expected.ir.json", + "sha256": "e6716d42502e2ab0017b61ed047a95bbdc651c90fdd92e4027c9394a63fba014", + "bytes": 773 + }, + { + "id": "conformance/valid/default-normalization/source.stack", + "path": "conformance/valid/default-normalization/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/default-normalization/source.stack", + "sha256": "63c630ca5c360c7e9904ca412d7e355cb4145222683975fcbc67d60c0ff652ad", + "bytes": 103 + }, + { + "id": "conformance/valid/provider-icon-namespace/expected.ir.json", + "path": "conformance/valid/provider-icon-namespace/expected.ir.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/provider-icon-namespace/expected.ir.json", + "sha256": "314a20e7eddea98fdf0de6bc012abc871ba8eedf03fc3760d948595b163292f9", + "bytes": 456 + }, + { + "id": "conformance/valid/provider-icon-namespace/source.stack", + "path": "conformance/valid/provider-icon-namespace/source.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/provider-icon-namespace/source.stack", + "sha256": "5280e48bc7d3537701d9459e6a556cbaec1b0f57c9bc9d76674630e0e57c10dc", + "bytes": 116 + }, + { + "id": "examples/01-minimal.stack", + "path": "examples/01-minimal.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/01-minimal.stack", + "sha256": "c0d1ae9bd127c4f039e633add0ee51c3ede7b0b7952318e617e9550b6b884b22", + "bytes": 93 + }, + { + "id": "examples/02-node-semantics.stack", + "path": "examples/02-node-semantics.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/02-node-semantics.stack", + "sha256": "c07d2a03f7d296306b25c7f5e37e3cd079b83abba50be421aa9956ffcd4e020e", + "bytes": 307 + }, + { + "id": "examples/03-groups-and-layout.stack", + "path": "examples/03-groups-and-layout.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/03-groups-and-layout.stack", + "sha256": "54475a71adb3407e75fd460415d3cd093cee466bbb67c3a92224ca34e676b57e", + "bytes": 757 + }, + { + "id": "examples/04-commerce-platform.stack", + "path": "examples/04-commerce-platform.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/04-commerce-platform.stack", + "sha256": "297746969f28d4275d52e9e27d76327bfa1c8db2c161856d9cdad00a6cdc7d34", + "bytes": 2074 + }, + { + "id": "examples/05-aws-serverless.stack", + "path": "examples/05-aws-serverless.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/05-aws-serverless.stack", + "sha256": "22b7a750a7a8712d8ff6cae6b93849db3838efcbb5eb96c2fe4906df8029bb4f", + "bytes": 1261 + }, + { + "id": "examples/06-gcp-data-service.stack", + "path": "examples/06-gcp-data-service.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/06-gcp-data-service.stack", + "sha256": "320bec6f9aac23cafd8c93eb3512be1a2fb0c93b103d295a0a8ddba41ec8c62c", + "bytes": 902 + }, + { + "id": "examples/07-azure-event-platform.stack", + "path": "examples/07-azure-event-platform.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/07-azure-event-platform.stack", + "sha256": "f8552fab5e42038c6363ba0ecd59e5d005abbe21247664881987e8673598c532", + "bytes": 1306 + }, + { + "id": "examples/08-github-delivery.stack", + "path": "examples/08-github-delivery.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/08-github-delivery.stack", + "sha256": "01cc2af5508c3f34618d9ac814c640a9bfe6d6f0c313ecca8bad7f0e47ffcfcb", + "bytes": 810 + }, + { + "id": "examples/09-mixed-provider-platform.stack", + "path": "examples/09-mixed-provider-platform.stack", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/09-mixed-provider-platform.stack", + "sha256": "6363300892d680d3807abe61899ad3b2125875261c8da25cf650b4db92133ac3", + "bytes": 1404 + }, + { + "id": "examples/catalog.json", + "path": "examples/catalog.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/catalog.json", + "sha256": "6194d0f7403443101e933b42f65f90eb4a30778743f285683b4dd957d61a0a65", + "bytes": 7475 + }, + { + "id": "packages/language/grammars/stack.tmLanguage.json", + "path": "packages/language/grammars/stack.tmLanguage.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/packages/language/grammars/stack.tmLanguage.json", + "sha256": "abe19f7db0039b43a78a53c324f19251a29d2202b76b069acc2218cd8ccb5d3d", + "bytes": 2788 + }, + { + "id": "schemas/diagnostic-expectations.schema.json", + "path": "schemas/diagnostic-expectations.schema.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/diagnostic-expectations.schema.json", + "sha256": "1a8aba3a9ebc351cf84d549139c08bbfb46eeeb96b9657c4d4d9d7d302954482", + "bytes": 1721 + }, + { + "id": "schemas/diagnostic.schema.json", + "path": "schemas/diagnostic.schema.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/diagnostic.schema.json", + "sha256": "e7437c27d42e8cd4dd5ddce5f507563b6d5e0419c254fc62fcd00ede08c59697", + "bytes": 2115 + }, + { + "id": "schemas/example-catalog.schema.json", + "path": "schemas/example-catalog.schema.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/example-catalog.schema.json", + "sha256": "d71d91e78ec0cc45e9c818b609f647124daeb7391f8f8ddebcd09e60a26802e9", + "bytes": 3255 + }, + { + "id": "schemas/language-intelligence-fixture.schema.json", + "path": "schemas/language-intelligence-fixture.schema.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/language-intelligence-fixture.schema.json", + "sha256": "b9ea2fe701aead3540bd4184377620fe87f98ee88fa2faadd93559a4f95aeb84", + "bytes": 907 + }, + { + "id": "schemas/language-intelligence.schema.json", + "path": "schemas/language-intelligence.schema.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/language-intelligence.schema.json", + "sha256": "7b93ae37d7e91e91affe10375c7099f2d25f2c055906e553d80b7e5c45156391", + "bytes": 9726 + }, + { + "id": "schemas/normalized-ir.schema.json", + "path": "schemas/normalized-ir.schema.json", + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/normalized-ir.schema.json", + "sha256": "a7b857ecbf78bfb0aa2efca299242107470ea5f938a33bb8735a5b9f4bf0fab4", + "bytes": 5760 + } + ], + "diagnostics": [ + { + "code": "STK1001", + "severity": "error", + "meaning": "Input is not valid UTF-8" + }, + { + "code": "STK1002", + "severity": "error", + "meaning": "A byte order mark is present" + }, + { + "code": "STK1003", + "severity": "error", + "meaning": "A string contains an invalid escape or decoded value" + }, + { + "code": "STK2001", + "severity": "error", + "meaning": "The declared language version is unsupported" + }, + { + "code": "STK2002", + "severity": "error", + "meaning": "An unexpected token, declaration, property, value, or operator was found" + }, + { + "code": "STK2003", + "severity": "error", + "meaning": "Input ended before the current construct was complete" + }, + { + "code": "STK3001", + "severity": "error", + "meaning": "An identifier is invalid" + }, + { + "code": "STK3002", + "severity": "error", + "meaning": "An identifier is declared more than once" + }, + { + "code": "STK3003", + "severity": "error", + "meaning": "An edge references an unknown node" + }, + { + "code": "STK3004", + "severity": "error", + "meaning": "A group is used as an edge endpoint" + }, + { + "code": "STK3005", + "severity": "error", + "meaning": "An edge connects a node to itself" + }, + { + "code": "STK3006", + "severity": "error", + "meaning": "An exact duplicate edge is declared" + }, + { + "code": "STK3007", + "severity": "error", + "meaning": "A property occurs more than once in one block" + }, + { + "code": "STK3008", + "severity": "error", + "meaning": "A title, label, or detail violates its text constraints" + }, + { + "code": "STK3009", + "severity": "error", + "meaning": "A group has no descendant node" + }, + { + "code": "STK3010", + "severity": "error", + "meaning": "Group nesting exceeds the language limit" + }, + { + "code": "STK3011", + "severity": "error", + "meaning": "A layout reference is invalid in its scope" + }, + { + "code": "STK3012", + "severity": "error", + "meaning": "A layout block or singleton layout statement is duplicated" + }, + { + "code": "STK3013", + "severity": "error", + "meaning": "An icon identifier is malformed" + }, + { + "code": "STK3014", + "severity": "error", + "meaning": "A diagram contains more than one theme statement" + }, + { + "code": "STK4001", + "severity": "warning", + "meaning": "An order hint could not be satisfied" + }, + { + "code": "STK4002", + "severity": "warning", + "meaning": "A node exceeds the recommended incident-edge degree" + }, + { + "code": "STK4003", + "severity": "error", + "meaning": "A diagram exceeds a language complexity limit" + }, + { + "code": "STK5001", + "severity": "warning", + "meaning": "An icon identifier is unavailable in the effective theme" + }, + { + "code": "STK6001", + "severity": "warning", + "meaning": "A requested non-core theme is unavailable and `default` was used" + } + ] +} diff --git a/examples/read-machine-resources.mjs b/examples/read-machine-resources.mjs new file mode 100644 index 0000000..a87542b --- /dev/null +++ b/examples/read-machine-resources.mjs @@ -0,0 +1,25 @@ +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import { requireCapabilities, retrieveResource, sha256 } from '../scripts/machine-resources.mjs'; + +const local = process.argv.includes('--local'); +async function read(url) { + if (local) return readFile(new URL('../generated' + new URL(url).pathname, import.meta.url)); + assert.ok(url.startsWith('https://stack-diagram.com/machine/')); + const response = await fetch(url, { redirect: 'error', signal: AbortSignal.timeout(15_000), cache: 'no-cache' }); + assert.ok(response.ok, `Discovery unavailable: HTTP ${response.status}`); + return Buffer.from(await response.arrayBuffer()); +} +const discovery = JSON.parse((await read('https://stack-diagram.com/machine/index.json')).toString()); +assert.equal(discovery.schemaVersion, '1.0'); +const bytes = await read(discovery.current.url); +assert.equal(sha256(bytes), discovery.current.sha256, 'Manifest integrity mismatch'); +const manifest = JSON.parse(bytes.toString()); +requireCapabilities(manifest, 'engine', ['completion', 'hover']); +for (const id of ['packages/language/grammars/stack.tmLanguage.json', 'schemas/diagnostic.schema.json', 'examples/catalog.json']) { + const resource = manifest.resources.find(resource => resource.id === id); + assert.ok(resource, `Missing resource: ${id}`); + JSON.parse((await retrieveResource(resource)).toString('utf8')); + console.log(`Verified ${id}: ${resource.sha256}`); +} +console.log(`Manifest ${manifest.version}: Engine completion and hover supported. CLI JSON output is not advertised.`); diff --git a/generated/machine/index.json b/generated/machine/index.json new file mode 100644 index 0000000..810c1ad --- /dev/null +++ b/generated/machine/index.json @@ -0,0 +1,8 @@ +{ + "schemaVersion": "1.0", + "current": { + "version": "1.0.0", + "url": "https://stack-diagram.com/machine/v1.0.0/manifest.json", + "sha256": "cae7ef36ef39362954ca34dffafbef8ddb9cd0cc0034765643797cff1069446f" + } +} diff --git a/generated/machine/v1.0.0/diagnostics.json b/generated/machine/v1.0.0/diagnostics.json new file mode 100644 index 0000000..b0c088f --- /dev/null +++ b/generated/machine/v1.0.0/diagnostics.json @@ -0,0 +1,132 @@ +{ + "schemaVersion": "1.0", + "languageVersion": "1.0", + "source": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/SPECIFICATION.md", + "diagnostics": [ + { + "code": "STK1001", + "severity": "error", + "meaning": "Input is not valid UTF-8" + }, + { + "code": "STK1002", + "severity": "error", + "meaning": "A byte order mark is present" + }, + { + "code": "STK1003", + "severity": "error", + "meaning": "A string contains an invalid escape or decoded value" + }, + { + "code": "STK2001", + "severity": "error", + "meaning": "The declared language version is unsupported" + }, + { + "code": "STK2002", + "severity": "error", + "meaning": "An unexpected token, declaration, property, value, or operator was found" + }, + { + "code": "STK2003", + "severity": "error", + "meaning": "Input ended before the current construct was complete" + }, + { + "code": "STK3001", + "severity": "error", + "meaning": "An identifier is invalid" + }, + { + "code": "STK3002", + "severity": "error", + "meaning": "An identifier is declared more than once" + }, + { + "code": "STK3003", + "severity": "error", + "meaning": "An edge references an unknown node" + }, + { + "code": "STK3004", + "severity": "error", + "meaning": "A group is used as an edge endpoint" + }, + { + "code": "STK3005", + "severity": "error", + "meaning": "An edge connects a node to itself" + }, + { + "code": "STK3006", + "severity": "error", + "meaning": "An exact duplicate edge is declared" + }, + { + "code": "STK3007", + "severity": "error", + "meaning": "A property occurs more than once in one block" + }, + { + "code": "STK3008", + "severity": "error", + "meaning": "A title, label, or detail violates its text constraints" + }, + { + "code": "STK3009", + "severity": "error", + "meaning": "A group has no descendant node" + }, + { + "code": "STK3010", + "severity": "error", + "meaning": "Group nesting exceeds the language limit" + }, + { + "code": "STK3011", + "severity": "error", + "meaning": "A layout reference is invalid in its scope" + }, + { + "code": "STK3012", + "severity": "error", + "meaning": "A layout block or singleton layout statement is duplicated" + }, + { + "code": "STK3013", + "severity": "error", + "meaning": "An icon identifier is malformed" + }, + { + "code": "STK3014", + "severity": "error", + "meaning": "A diagram contains more than one theme statement" + }, + { + "code": "STK4001", + "severity": "warning", + "meaning": "An order hint could not be satisfied" + }, + { + "code": "STK4002", + "severity": "warning", + "meaning": "A node exceeds the recommended incident-edge degree" + }, + { + "code": "STK4003", + "severity": "error", + "meaning": "A diagram exceeds a language complexity limit" + }, + { + "code": "STK5001", + "severity": "warning", + "meaning": "An icon identifier is unavailable in the effective theme" + }, + { + "code": "STK6001", + "severity": "warning", + "meaning": "A requested non-core theme is unavailable and `default` was used" + } + ] +} diff --git a/generated/machine/v1.0.0/manifest.json b/generated/machine/v1.0.0/manifest.json new file mode 100644 index 0000000..5032661 --- /dev/null +++ b/generated/machine/v1.0.0/manifest.json @@ -0,0 +1,745 @@ +{ + "schemaVersion": "1.0", + "version": "1.0.0", + "languageVersion": "1.0", + "requiredReaderFeatures": [ + "sha256", + "immutable-resources" + ], + "implementations": [ + { + "id": "cli", + "version": "0.4.0", + "repository": "stack-sh/cli", + "revision": "7f4066884f7902d4c582d45184f3a9019fe59bf7", + "capabilities": [ + "check", + "format", + "render", + "lsp" + ] + }, + { + "id": "engine", + "version": "0.7.0", + "repository": "stack-sh/engine", + "revision": "a1c29b7caba2dc6cd91e56a6ebec1382859d4869", + "capabilities": [ + "check", + "format", + "render", + "completion", + "hover" + ] + }, + { + "id": "compiler", + "version": "0.1.0", + "repository": "stack-sh/compiler", + "revision": "84ab5663a7f7c5b7dc0b5e9e2f04c8894ed02820", + "capabilities": [ + "compile", + "diagnostics", + "completion", + "hover", + "document-symbols" + ] + } + ], + "resources": [ + { + "id": "INTERCHANGE.md", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/INTERCHANGE.md", + "sha256": "34c5a6a09abe3a753334f60cd9cca7a50c5dad1ade41faaffb1ee13a0bdec097", + "bytes": 10382, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "INTERCHANGE.md" + } + }, + { + "id": "LANGUAGE_INTELLIGENCE.md", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/LANGUAGE_INTELLIGENCE.md", + "sha256": "207ac0b19af8e5b1bf8d6ba9b057048c5b733371b4ae6e86bab4b526ed785aad", + "bytes": 12224, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "LANGUAGE_INTELLIGENCE.md" + } + }, + { + "id": "SPECIFICATION.md", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/SPECIFICATION.md", + "sha256": "6d76a4e28aec4ef1f2a18835ca033b7b0c5c69b549e6caed644fe130f4e53ff8", + "bytes": 36660, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "SPECIFICATION.md" + } + }, + { + "id": "conformance/README.md", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/README.md", + "sha256": "5a46dbae13801aff73ea2a9e68696aae40ad037f4a03ac6c9d84e8db8b7ecdb1", + "bytes": 3553, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/README.md" + } + }, + { + "id": "conformance/formatter/comments-and-layout/expected.ir.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/formatter/comments-and-layout/expected.ir.json", + "sha256": "d07ffadd1cd54e3007aee0a8b49313950d6f86a856b6e35cfdda7fc5ccded961", + "bytes": 1454, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/formatter/comments-and-layout/expected.ir.json" + } + }, + { + "id": "conformance/formatter/comments-and-layout/expected.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/formatter/comments-and-layout/expected.stack", + "sha256": "69dc26cfc1333d7f458f8bb04611c1fea17057411966005097277e26e7b3e8ea", + "bytes": 599, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/formatter/comments-and-layout/expected.stack" + } + }, + { + "id": "conformance/formatter/comments-and-layout/input.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/formatter/comments-and-layout/input.stack", + "sha256": "b7224b96067bc8e6d5c3afb07e66bf44adc12f0a47c99a366518fcd6effb7eca", + "bytes": 538, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/formatter/comments-and-layout/input.stack" + } + }, + { + "id": "conformance/invalid/byte-order-mark/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/byte-order-mark/expected.diagnostics.json", + "sha256": "30e3e11370f28eb2aaac2777d7183e343ec0b2de0e31273bc312302b1c2303e6", + "bytes": 263, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/byte-order-mark/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/byte-order-mark/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/byte-order-mark/source.stack", + "sha256": "8f7538040e38e97ca0e659a89b6ac024757f34968613dacdef34356bfcc71738", + "bytes": 48, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/byte-order-mark/source.stack" + } + }, + { + "id": "conformance/invalid/duplicate-theme-dense-node/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/duplicate-theme-dense-node/expected.diagnostics.json", + "sha256": "8394d1956db0b960937db8ee90b9c2e6f0e0c27e052306c26054b61282557400", + "bytes": 504, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/duplicate-theme-dense-node/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/duplicate-theme-dense-node/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/duplicate-theme-dense-node/source.stack", + "sha256": "167184ae7b9bd82dd66f495928b3e75ea187d7c9d5653a7f59087167d935a961", + "bytes": 512, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/duplicate-theme-dense-node/source.stack" + } + }, + { + "id": "conformance/invalid/edge-rules/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/edge-rules/expected.diagnostics.json", + "sha256": "21afde68cf5cef2390768dfd83122c2bd57d09612b58232d86f723fdf1f55666", + "bytes": 697, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/edge-rules/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/edge-rules/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/edge-rules/source.stack", + "sha256": "58f595efdb0d5b909678645088083af060eb806e173c7f826cae9daca6da05bd", + "bytes": 127, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/edge-rules/source.stack" + } + }, + { + "id": "conformance/invalid/empty-diagram/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/empty-diagram/expected.diagnostics.json", + "sha256": "f48b19f3aac38af879b4f978e9f20f7d7304065c5b20bea9fd62286b7d51d1ad", + "bytes": 266, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/empty-diagram/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/empty-diagram/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/empty-diagram/source.stack", + "sha256": "f6e76216ce9d51ff74e36902a6d5a1d31006775ab456155078371f587143239a", + "bytes": 29, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/empty-diagram/source.stack" + } + }, + { + "id": "conformance/invalid/independent-semantic-errors/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/independent-semantic-errors/expected.diagnostics.json", + "sha256": "6f68b3d547729146d7ac2431ca0cf6e5ec57ad2fc938d569739099f7611ffe18", + "bytes": 1981, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/independent-semantic-errors/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/independent-semantic-errors/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/independent-semantic-errors/source.stack", + "sha256": "36d8f56b49ac6d94bc358cde477b7cad66a5f6d157a2effbdc3fe59e1a54a8f2", + "bytes": 116, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/independent-semantic-errors/source.stack" + } + }, + { + "id": "conformance/invalid/invalid-string-escape/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/invalid-string-escape/expected.diagnostics.json", + "sha256": "3112ad17324bc2e305dd16a446f6ecb96e673b4ae0d828db7a62eee223f68033", + "bytes": 267, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/invalid-string-escape/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/invalid-string-escape/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/invalid-string-escape/source.stack", + "sha256": "e6359923f4f3b2714926e8b7aa6a00f168435876e8e26cd8bc3b30445c84d884", + "bytes": 47, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/invalid-string-escape/source.stack" + } + }, + { + "id": "conformance/invalid/invalid-utf8/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/invalid-utf8/expected.diagnostics.json", + "sha256": "edf46345443048f97f40402f3c3869c179c687fc6e3c06e6d9e4f1f7fa5d89cd", + "bytes": 265, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/invalid-utf8/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/invalid-utf8/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/invalid-utf8/source.stack", + "sha256": "14b7ba40d4dd19e10dce64ed4f9a4041ba7123b3fa22d19e211fc2ee5d6980ed", + "bytes": 18, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/invalid-utf8/source.stack" + } + }, + { + "id": "conformance/invalid/layout-rules/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/layout-rules/expected.diagnostics.json", + "sha256": "a72705a9100ebb0724b1063e8f98b7aa17f56ab68ac0c6bfe2df4c1e32fb179d", + "bytes": 921, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/layout-rules/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/layout-rules/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/layout-rules/source.stack", + "sha256": "f60985445706598c266b1d0d41f465f31734f1b413b4d7921213eb5503c776f3", + "bytes": 184, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/layout-rules/source.stack" + } + }, + { + "id": "conformance/invalid/nested-group-icon/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/nested-group-icon/expected.diagnostics.json", + "sha256": "22f1354a21a24b7c602b17f49a6136490e2ac1736da43b935653475848ae6d3a", + "bytes": 486, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/nested-group-icon/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/nested-group-icon/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/nested-group-icon/source.stack", + "sha256": "e3005827757edfd70f11a45c0c68c686ae624f28a58767fb22c983bfd952c48e", + "bytes": 204, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/nested-group-icon/source.stack" + } + }, + { + "id": "conformance/invalid/unexpected-end/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unexpected-end/expected.diagnostics.json", + "sha256": "de4a0f140eb52b03a8039badc98adf15a633f502170b64242a3835e50e437304", + "bytes": 265, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/unexpected-end/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/unexpected-end/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unexpected-end/source.stack", + "sha256": "a757fd3e150aece9441c16aae74ca74a3ad20580eced0e22f3c833888b0fbb1e", + "bytes": 50, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/unexpected-end/source.stack" + } + }, + { + "id": "conformance/invalid/unexpected-token/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unexpected-token/expected.diagnostics.json", + "sha256": "b24dc4809425da1f096d2503adfe62e696bb832ea1cdfe20f614772ef624a2ea", + "bytes": 334, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/unexpected-token/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/unexpected-token/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unexpected-token/source.stack", + "sha256": "52d6bbb3cfcb6b963d57bae214ca608fce8e5bce0ce4738a4b824c543b48b694", + "bytes": 54, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/unexpected-token/source.stack" + } + }, + { + "id": "conformance/invalid/unknown-edge-endpoint/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unknown-edge-endpoint/expected.diagnostics.json", + "sha256": "63ae20580da730b2ab0b7b17670e2ee4083d1cebf46dcedbb12bd1b8e14284ae", + "bytes": 375, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/unknown-edge-endpoint/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/unknown-edge-endpoint/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unknown-edge-endpoint/source.stack", + "sha256": "885a06e1d2679beeb7256b88fec9575cc0820e39d6101a21c071e92b95146cff", + "bytes": 105, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/unknown-edge-endpoint/source.stack" + } + }, + { + "id": "conformance/invalid/unknown-layout-direction/expected.diagnostics.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unknown-layout-direction/expected.diagnostics.json", + "sha256": "d5dd54b2358b19e5a4b3f0301a153cadfa34ea006e0cd525989aed47cfe5dd86", + "bytes": 304, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/unknown-layout-direction/expected.diagnostics.json" + } + }, + { + "id": "conformance/invalid/unknown-layout-direction/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/invalid/unknown-layout-direction/source.stack", + "sha256": "f37596e202223e5ce47b7ef4cb66d9e524cdafbdeb1c92e614967d343df968f8", + "bytes": 76, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/invalid/unknown-layout-direction/source.stack" + } + }, + { + "id": "conformance/language-intelligence/format/fixture.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/format/fixture.json", + "sha256": "5f8430d9900b8f4537a0f25006348ca8d782ddf80132637acdca048b39f3d3c1", + "bytes": 784, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/language-intelligence/format/fixture.json" + } + }, + { + "id": "conformance/language-intelligence/format/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/format/source.stack", + "sha256": "db381aaea0f0aedb64d7e88ee1359b5d0d256a976102c6f6072ab7bad2f5dea3", + "bytes": 57, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/language-intelligence/format/source.stack" + } + }, + { + "id": "conformance/language-intelligence/partial/fixture.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/partial/fixture.json", + "sha256": "4516d5b40b6f86c87806d8ff4fafe6c590d0ba3030df10db122db82e8d2f592a", + "bytes": 2406, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/language-intelligence/partial/fixture.json" + } + }, + { + "id": "conformance/language-intelligence/partial/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/partial/source.stack", + "sha256": "4880e629ee875ff319f2517248dc9dbd95e0166ccdd026ed70549d956ee24813", + "bytes": 57, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/language-intelligence/partial/source.stack" + } + }, + { + "id": "conformance/language-intelligence/semantic/fixture.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/semantic/fixture.json", + "sha256": "7ea1cc7e7ea729e5fb9c6fac671c64fc1a80b95b451e256b11481cb9317117c5", + "bytes": 8518, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/language-intelligence/semantic/fixture.json" + } + }, + { + "id": "conformance/language-intelligence/semantic/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/language-intelligence/semantic/source.stack", + "sha256": "ff32652ca5cfdb3e69352b2701bb75bbbeede4bea0f7978d225bcd8bd1d7bfb2", + "bytes": 240, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/language-intelligence/semantic/source.stack" + } + }, + { + "id": "conformance/valid/complete-semantics/expected.ir.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/complete-semantics/expected.ir.json", + "sha256": "3f1f5572966d307388b2f22b9dcd10a022df25bd4b1039e3afdb1913165a7981", + "bytes": 4489, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/valid/complete-semantics/expected.ir.json" + } + }, + { + "id": "conformance/valid/complete-semantics/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/complete-semantics/source.stack", + "sha256": "11ec422ef2517ef55a0d232e04672ca44a955d1c8ce6074ece6852c834992f0c", + "bytes": 1365, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/valid/complete-semantics/source.stack" + } + }, + { + "id": "conformance/valid/default-normalization/expected.ir.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/default-normalization/expected.ir.json", + "sha256": "e6716d42502e2ab0017b61ed047a95bbdc651c90fdd92e4027c9394a63fba014", + "bytes": 773, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/valid/default-normalization/expected.ir.json" + } + }, + { + "id": "conformance/valid/default-normalization/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/default-normalization/source.stack", + "sha256": "63c630ca5c360c7e9904ca412d7e355cb4145222683975fcbc67d60c0ff652ad", + "bytes": 103, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/valid/default-normalization/source.stack" + } + }, + { + "id": "conformance/valid/provider-icon-namespace/expected.ir.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/provider-icon-namespace/expected.ir.json", + "sha256": "314a20e7eddea98fdf0de6bc012abc871ba8eedf03fc3760d948595b163292f9", + "bytes": 456, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/valid/provider-icon-namespace/expected.ir.json" + } + }, + { + "id": "conformance/valid/provider-icon-namespace/source.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/conformance/valid/provider-icon-namespace/source.stack", + "sha256": "5280e48bc7d3537701d9459e6a556cbaec1b0f57c9bc9d76674630e0e57c10dc", + "bytes": 116, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "conformance/valid/provider-icon-namespace/source.stack" + } + }, + { + "id": "examples/01-minimal.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/01-minimal.stack", + "sha256": "c0d1ae9bd127c4f039e633add0ee51c3ede7b0b7952318e617e9550b6b884b22", + "bytes": 93, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "examples/01-minimal.stack" + } + }, + { + "id": "examples/02-node-semantics.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/02-node-semantics.stack", + "sha256": "c07d2a03f7d296306b25c7f5e37e3cd079b83abba50be421aa9956ffcd4e020e", + "bytes": 307, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "examples/02-node-semantics.stack" + } + }, + { + "id": "examples/03-groups-and-layout.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/03-groups-and-layout.stack", + "sha256": "54475a71adb3407e75fd460415d3cd093cee466bbb67c3a92224ca34e676b57e", + "bytes": 757, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "examples/03-groups-and-layout.stack" + } + }, + { + "id": "examples/04-commerce-platform.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/04-commerce-platform.stack", + "sha256": "297746969f28d4275d52e9e27d76327bfa1c8db2c161856d9cdad00a6cdc7d34", + "bytes": 2074, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "examples/04-commerce-platform.stack" + } + }, + { + "id": "examples/05-aws-serverless.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/05-aws-serverless.stack", + "sha256": "22b7a750a7a8712d8ff6cae6b93849db3838efcbb5eb96c2fe4906df8029bb4f", + "bytes": 1261, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "examples/05-aws-serverless.stack" + } + }, + { + "id": "examples/06-gcp-data-service.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/06-gcp-data-service.stack", + "sha256": "320bec6f9aac23cafd8c93eb3512be1a2fb0c93b103d295a0a8ddba41ec8c62c", + "bytes": 902, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "examples/06-gcp-data-service.stack" + } + }, + { + "id": "examples/07-azure-event-platform.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/07-azure-event-platform.stack", + "sha256": "f8552fab5e42038c6363ba0ecd59e5d005abbe21247664881987e8673598c532", + "bytes": 1306, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "examples/07-azure-event-platform.stack" + } + }, + { + "id": "examples/08-github-delivery.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/08-github-delivery.stack", + "sha256": "01cc2af5508c3f34618d9ac814c640a9bfe6d6f0c313ecca8bad7f0e47ffcfcb", + "bytes": 810, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "examples/08-github-delivery.stack" + } + }, + { + "id": "examples/09-mixed-provider-platform.stack", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/09-mixed-provider-platform.stack", + "sha256": "6363300892d680d3807abe61899ad3b2125875261c8da25cf650b4db92133ac3", + "bytes": 1404, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "examples/09-mixed-provider-platform.stack" + } + }, + { + "id": "examples/catalog.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/examples/catalog.json", + "sha256": "6194d0f7403443101e933b42f65f90eb4a30778743f285683b4dd957d61a0a65", + "bytes": 7475, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "examples/catalog.json" + } + }, + { + "id": "packages/language/grammars/stack.tmLanguage.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/packages/language/grammars/stack.tmLanguage.json", + "sha256": "abe19f7db0039b43a78a53c324f19251a29d2202b76b069acc2218cd8ccb5d3d", + "bytes": 2788, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "packages/language/grammars/stack.tmLanguage.json" + } + }, + { + "id": "schemas/diagnostic-expectations.schema.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/diagnostic-expectations.schema.json", + "sha256": "1a8aba3a9ebc351cf84d549139c08bbfb46eeeb96b9657c4d4d9d7d302954482", + "bytes": 1721, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "schemas/diagnostic-expectations.schema.json" + } + }, + { + "id": "schemas/diagnostic.schema.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/diagnostic.schema.json", + "sha256": "e7437c27d42e8cd4dd5ddce5f507563b6d5e0419c254fc62fcd00ede08c59697", + "bytes": 2115, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "schemas/diagnostic.schema.json" + } + }, + { + "id": "schemas/example-catalog.schema.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/example-catalog.schema.json", + "sha256": "d71d91e78ec0cc45e9c818b609f647124daeb7391f8f8ddebcd09e60a26802e9", + "bytes": 3255, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "schemas/example-catalog.schema.json" + } + }, + { + "id": "schemas/language-intelligence-fixture.schema.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/language-intelligence-fixture.schema.json", + "sha256": "b9ea2fe701aead3540bd4184377620fe87f98ee88fa2faadd93559a4f95aeb84", + "bytes": 907, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "schemas/language-intelligence-fixture.schema.json" + } + }, + { + "id": "schemas/language-intelligence.schema.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/language-intelligence.schema.json", + "sha256": "7b93ae37d7e91e91affe10375c7099f2d25f2c055906e553d80b7e5c45156391", + "bytes": 9726, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "schemas/language-intelligence.schema.json" + } + }, + { + "id": "schemas/normalized-ir.schema.json", + "url": "https://raw.githubusercontent.com/stack-sh/specification/0545936ecaebe77b9309bacd0447b8073a1d0701/schemas/normalized-ir.schema.json", + "sha256": "a7b857ecbf78bfb0aa2efca299242107470ea5f938a33bb8735a5b9f4bf0fab4", + "bytes": 5760, + "source": { + "repository": "stack-sh/specification", + "revision": "0545936ecaebe77b9309bacd0447b8073a1d0701", + "path": "schemas/normalized-ir.schema.json" + } + }, + { + "id": "diagnostic-catalog", + "url": "https://stack-diagram.com/machine/v1.0.0/diagnostics.json", + "sha256": "2c6303b773800a12d985119b69c65af7946de7eb9907f2f4d6fc3d903751d4b8", + "bytes": 3418 + }, + { + "id": "manifest-schema", + "url": "https://stack-diagram.com/machine/v1.0.0/manifest.schema.json", + "sha256": "48ffe1874039164aaa5306732372b32c73160b899d6d8a063540491468a78255", + "bytes": 3075 + } + ] +} diff --git a/generated/machine/v1.0.0/manifest.schema.json b/generated/machine/v1.0.0/manifest.schema.json new file mode 100644 index 0000000..3f8fbef --- /dev/null +++ b/generated/machine/v1.0.0/manifest.schema.json @@ -0,0 +1,147 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://stack-diagram.com/machine/v1.0.0/manifest.schema.json", + "title": "Stack machine resource manifest v1", + "type": "object", + "additionalProperties": false, + "required": [ + "schemaVersion", + "version", + "languageVersion", + "requiredReaderFeatures", + "implementations", + "resources" + ], + "properties": { + "schemaVersion": { + "const": "1.0" + }, + "version": { + "const": "1.0.0" + }, + "languageVersion": { + "const": "1.0" + }, + "requiredReaderFeatures": { + "type": "array", + "uniqueItems": true, + "items": { + "enum": [ + "sha256", + "immutable-resources" + ] + } + }, + "implementations": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/implementation" + } + }, + "resources": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/resource" + } + } + }, + "$defs": { + "source": { + "type": "object", + "additionalProperties": false, + "required": [ + "repository", + "revision", + "path" + ], + "properties": { + "repository": { + "type": "string", + "pattern": "^stack-sh/[a-z-]+$" + }, + "revision": { + "type": "string", + "pattern": "^[a-f0-9]{40}$" + }, + "path": { + "type": "string", + "pattern": "^[A-Za-z0-9_./-]+$" + } + } + }, + "resource": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "url", + "sha256", + "bytes" + ], + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "url": { + "type": "string", + "pattern": "^https://" + }, + "sha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "bytes": { + "type": "integer", + "minimum": 0, + "maximum": 1048576 + }, + "source": { + "$ref": "#/$defs/source" + } + } + }, + "implementation": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "version", + "repository", + "revision", + "capabilities" + ], + "properties": { + "id": { + "enum": [ + "cli", + "engine", + "compiler" + ] + }, + "version": { + "type": "string", + "pattern": "^\\d+\\.\\d+\\.\\d+$" + }, + "repository": { + "type": "string", + "pattern": "^stack-sh/[a-z-]+$" + }, + "revision": { + "type": "string", + "pattern": "^[a-f0-9]{40}$" + }, + "capabilities": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "pattern": "^[a-z][a-z-]+$" + } + } + } + } + } +} diff --git a/generated/manifest.json b/generated/manifest.json index 6e9432c..8906b62 100644 --- a/generated/manifest.json +++ b/generated/manifest.json @@ -253,6 +253,22 @@ { "path": "site/ko/guide/agent-workflow.md", "sha256": "35d435082b86b48fa4b456262d7eb219e622221ae0906dca6dbe9a6619d02ef9" + }, + { + "path": "machine/v1.0.0/manifest.json", + "sha256": "cae7ef36ef39362954ca34dffafbef8ddb9cd0cc0034765643797cff1069446f" + }, + { + "path": "machine/v1.0.0/manifest.schema.json", + "sha256": "48ffe1874039164aaa5306732372b32c73160b899d6d8a063540491468a78255" + }, + { + "path": "machine/v1.0.0/diagnostics.json", + "sha256": "2c6303b773800a12d985119b69c65af7946de7eb9907f2f4d6fc3d903751d4b8" + }, + { + "path": "machine/index.json", + "sha256": "39e14071f27135e6904970844780f33b778d5a18f5bb8cf36a8a6357a8e00f3d" } ] } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..5273d4b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,82 @@ +{ + "name": "@stack-sh/docs", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@stack-sh/docs", + "version": "0.1.0", + "license": "Apache-2.0", + "devDependencies": { + "@stack-sh/engine": "0.7.0", + "ajv": "8.20.0" + } + }, + "node_modules/@stack-sh/engine": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@stack-sh/engine/-/engine-0.7.0.tgz", + "integrity": "sha512-Y6HCbiNHfdyqD1TEsDy3kNNtiswy7DPCHInYHUdrExjAW/GeeCLigYjHqLtUlXVmE/ppRpKxThZOOhy2sUQL5g==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", + "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + } + } +} diff --git a/package.json b/package.json index 2b46131..2933fbf 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "type": "module", "license": "Apache-2.0", "scripts": { + "machine:check": "node scripts/validate-machine-resources.mjs", "consumers:check": "node scripts/consumer-freshness.mjs", "release:check": "node scripts/cli-release.mjs", "release:sync": "node scripts/cli-release.mjs --sync", @@ -12,5 +13,9 @@ "check": "node scripts/generate.mjs --check", "test": "node --test scripts/*.test.mjs", "smoke": "node scripts/smoke-skill.mjs" + }, + "devDependencies": { + "@stack-sh/engine": "0.7.0", + "ajv": "8.20.0" } } diff --git a/scripts/check-machine-immutability.mjs b/scripts/check-machine-immutability.mjs new file mode 100644 index 0000000..87df8d0 --- /dev/null +++ b/scripts/check-machine-immutability.mjs @@ -0,0 +1,27 @@ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +export function assertImmutable(previous, current) { + for (const [file, bytes] of previous) { + assert.ok(current.has(file), `Published machine resource removed: ${file}`); + assert.deepEqual(current.get(file), bytes, `Published machine resource changed: ${file}; publish a new version`); + } +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + const revision = process.env.MACHINE_BASE_REVISION; + assert.match(revision ?? '', /^[a-f0-9]{40}$/); + assert.notEqual(revision, '0'.repeat(40)); + const paths = execFileSync('git', ['ls-tree', '-r', '--name-only', revision, 'generated/machine'], { encoding: 'utf8' }).split('\n').filter(file => /^generated\/machine\/v\d+\.\d+\.\d+\//.test(file)); + const previous = new Map(); + const current = new Map(); + for (const file of paths) { + previous.set(file, execFileSync('git', ['show', `${revision}:${file}`])); + try { current.set(file, await readFile(file)); } catch (error) { if (error.code !== 'ENOENT') throw error; } + } + assertImmutable(previous, current); + console.log(`Preserved ${paths.length} previously published machine resources.`); +} diff --git a/scripts/consumer-freshness.mjs b/scripts/consumer-freshness.mjs index ea0b95c..778b8a8 100644 --- a/scripts/consumer-freshness.mjs +++ b/scripts/consumer-freshness.mjs @@ -14,7 +14,7 @@ export function compareConsumer(expected, actual, kind) { assert.deepEqual(actual.cli, expected.cli, `${kind}: published CLI identity is stale`); const select = manifest => { assert.ok(Array.isArray(manifest.files)); - const files = manifest.files.filter(file => kind === 'cli' ? file.path === skillPath : file.path.startsWith('site/') || file.path === skillPath); + const files = manifest.files.filter(file => kind === 'cli' ? file.path === skillPath : file.path.startsWith('site/') || file.path.startsWith('machine/') || file.path === skillPath); assert.ok(files.length > 0); const sorted = files.map(file => { assert.match(file.sha256, /^[a-f0-9]{64}$/); diff --git a/scripts/generate.mjs b/scripts/generate.mjs index d1ce474..0b3cf87 100644 --- a/scripts/generate.mjs +++ b/scripts/generate.mjs @@ -3,6 +3,7 @@ import { createHash } from 'node:crypto'; import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; +import { generateMachineResources } from './machine-resources.mjs'; const root = fileURLToPath(new URL('../', import.meta.url)); @@ -60,6 +61,7 @@ export async function generate(directory = root, check = false) { outputs[`site/${locale}guide/agent-workflow.md`] = outputs['guide/agent-workflow.md'].replace(/```sh\n([\s\S]*?)```/g, (_, commands) => '```sh\n' + commands.trimEnd().split('\n').map(line => '$ ' + line).join('\n') + '\n```'); } } + if ((await filePaths(path.join(directory, 'content'))).includes('machine-resources-v1.json')) Object.assign(outputs, await generateMachineResources(directory)); const manifest = { schemaVersion: '1.0', cli: release, diff --git a/scripts/machine-resources.mjs b/scripts/machine-resources.mjs new file mode 100644 index 0000000..327f24d --- /dev/null +++ b/scripts/machine-resources.mjs @@ -0,0 +1,59 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; + +export const sha256 = bytes => createHash('sha256').update(bytes).digest('hex'); +const json = value => JSON.stringify(value, null, 2) + '\n'; + +export async function generateMachineResources(root) { + const lock = JSON.parse(await readFile(path.join(root, 'content/machine-resources-v1.json'), 'utf8')); + const schema = await readFile(path.join(root, 'content/machine-manifest-v1.schema.json'), 'utf8'); + const base = 'https://stack-diagram.com/machine/v1.0.0/'; + const diagnostics = json({ schemaVersion: '1.0', languageVersion: '1.0', source: lock.resources.find(resource => resource.path === 'SPECIFICATION.md').url, diagnostics: lock.diagnostics }); + const resource = (id, name, bytes) => ({ id, url: base + name, sha256: sha256(bytes), bytes: Buffer.byteLength(bytes) }); + const manifest = { + schemaVersion: '1.0', version: '1.0.0', languageVersion: '1.0', + requiredReaderFeatures: ['sha256', 'immutable-resources'], + implementations: [ + { id: 'cli', version: '0.4.0', repository: 'stack-sh/cli', revision: '7f4066884f7902d4c582d45184f3a9019fe59bf7', capabilities: ['check', 'format', 'render', 'lsp'] }, + { id: 'engine', version: '0.7.0', repository: 'stack-sh/engine', revision: lock.engineRevision, capabilities: ['check', 'format', 'render', 'completion', 'hover'] }, + { id: 'compiler', version: '0.1.0', repository: 'stack-sh/compiler', revision: lock.compilerRevision, capabilities: ['compile', 'diagnostics', 'completion', 'hover', 'document-symbols'] }, + ], + resources: [ + ...lock.resources.map(({ id, url, sha256, bytes, repository, revision, path }) => ({ id, url, sha256, bytes, source: { repository, revision, path } })), + resource('diagnostic-catalog', 'diagnostics.json', diagnostics), + resource('manifest-schema', 'manifest.schema.json', schema), + ], + }; + const manifestBytes = json(manifest); + return { + 'machine/v1.0.0/manifest.json': manifestBytes, + 'machine/v1.0.0/manifest.schema.json': schema, + 'machine/v1.0.0/diagnostics.json': diagnostics, + 'machine/index.json': json({ schemaVersion: '1.0', current: { version: '1.0.0', url: base + 'manifest.json', sha256: sha256(manifestBytes) } }), + }; +} + +export function requireCapabilities(manifest, implementationId, capabilities, readerFeatures = ['sha256', 'immutable-resources']) { + assert.equal(manifest.schemaVersion, '1.0', 'Unsupported manifest schema'); + for (const feature of manifest.requiredReaderFeatures) assert.ok(readerFeatures.includes(feature), `Unsupported reader feature: ${feature}`); + const implementation = manifest.implementations.find(item => item.id === implementationId); + assert.ok(implementation, `Unknown implementation: ${implementationId}`); + for (const capability of capabilities) assert.ok(implementation.capabilities.includes(capability), `Unsupported capability: ${implementationId}/${capability}`); + return implementation; +} + +export async function retrieveResource(resource, fetchResource = fetch) { + const url = new URL(resource.url); + assert.equal(url.protocol, 'https:'); + assert.ok(['raw.githubusercontent.com', 'stack-diagram.com'].includes(url.hostname), 'Unexpected resource origin'); + if (url.hostname === 'raw.githubusercontent.com') assert.match(url.pathname, /^\/stack-sh\/[a-z-]+\/[a-f0-9]{40}\//); + else assert.ok(url.pathname.startsWith('/machine/v1.0.0/')); + const response = await fetchResource(resource.url, { signal: AbortSignal.timeout(15_000), redirect: 'error' }); + assert.ok(response.ok, `Machine resource unavailable: ${resource.id} HTTP ${response.status}`); + const bytes = Buffer.from(await response.arrayBuffer()); + assert.equal(bytes.length, resource.bytes, `Resource size mismatch: ${resource.id}`); + assert.equal(sha256(bytes), resource.sha256, `Resource integrity mismatch: ${resource.id}`); + return bytes; +} diff --git a/scripts/machine-resources.test.mjs b/scripts/machine-resources.test.mjs new file mode 100644 index 0000000..64d4bf6 --- /dev/null +++ b/scripts/machine-resources.test.mjs @@ -0,0 +1,43 @@ +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import test from 'node:test'; +import Ajv2020 from 'ajv/dist/2020.js'; +import { requireCapabilities, retrieveResource, sha256 } from './machine-resources.mjs'; +import { assertImmutable } from './check-machine-immutability.mjs'; + +const manifest = JSON.parse(await readFile(new URL('../generated/machine/v1.0.0/manifest.json', import.meta.url), 'utf8')); +const schema = JSON.parse(await readFile(new URL('../content/machine-manifest-v1.schema.json', import.meta.url), 'utf8')); + +test('published versions cannot change or disappear, but new versions may be added', () => { + const previous = new Map([['v1/file', Buffer.from('original')]]); + assertImmutable(previous, new Map([...previous, ['v2/file', Buffer.from('next')]])); + assert.throws(() => assertImmutable(previous, new Map()), /removed/); + assert.throws(() => assertImmutable(previous, new Map([['v1/file', Buffer.from('changed')]])), /changed/); +}); + +test('manifest schema rejects malformed hashes and unsupported envelopes', () => { + const validator = new Ajv2020({ strict: true }).compile(schema); + assert.ok(validator(manifest)); + const changed = structuredClone(manifest); + changed.resources[0].sha256 = 'not-a-hash'; + assert.equal(validator(changed), false); + assert.equal(validator({ ...manifest, schemaVersion: '2.0' }), false); +}); + +test('client detects unsupported reader and implementation capabilities', () => { + requireCapabilities(manifest, 'engine', ['completion', 'hover']); + requireCapabilities(manifest, 'cli', ['check', 'render']); + assert.throws(() => requireCapabilities(manifest, 'cli', ['check-json']), /Unsupported capability/); + assert.throws(() => requireCapabilities(manifest, 'engine', ['document-symbols']), /Unsupported capability/); + assert.throws(() => requireCapabilities(manifest, 'cli', [], []), /Unsupported reader feature/); +}); + +test('resource consumer rejects tampering, missing content, mutable URLs, and unexpected hosts', async () => { + const bytes = Buffer.from('valid'); + const item = { id: 'test', url: 'https://raw.githubusercontent.com/stack-sh/specification/' + 'a'.repeat(40) + '/SPECIFICATION.md', bytes: bytes.length, sha256: sha256(bytes) }; + assert.deepEqual(await retrieveResource(item, async () => new Response(bytes)), bytes); + await assert.rejects(retrieveResource(item, async () => new Response('other')), /integrity/); + await assert.rejects(retrieveResource(item, async () => new Response('', { status: 404 })), /HTTP 404/); + await assert.rejects(retrieveResource({ ...item, url: item.url.replace('a'.repeat(40), 'main') })); + await assert.rejects(retrieveResource({ ...item, url: 'https://example.com/resource' })); +}); diff --git a/scripts/validate-machine-resources.mjs b/scripts/validate-machine-resources.mjs new file mode 100644 index 0000000..71d7973 --- /dev/null +++ b/scripts/validate-machine-resources.mjs @@ -0,0 +1,90 @@ +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import Ajv2020 from 'ajv/dist/2020.js'; +import init, { check, render, completion, hover } from '@stack-sh/engine'; +import { requireCapabilities, retrieveResource, sha256 } from './machine-resources.mjs'; + +const root = fileURLToPath(new URL('../', import.meta.url)); +const manifest = JSON.parse(await readFile(path.join(root, 'generated/machine/v1.0.0/manifest.json'), 'utf8')); +const schema = JSON.parse(await readFile(path.join(root, 'generated/machine/v1.0.0/manifest.schema.json'), 'utf8')); +// Draft 2020-12 needs its own Ajv class: https://ajv.js.org/json-schema.html#draft-2020-12-breaking +const ajv = new Ajv2020({ allErrors: true, strict: false }); +const validateManifest = ajv.compile(schema); +assert.ok(validateManifest(manifest), ajv.errorsText(validateManifest.errors)); +assert.equal(new Set(manifest.resources.map(resource => resource.id)).size, manifest.resources.length); +const bytesById = new Map(); +for (let i = 0; i < manifest.resources.length; i += 8) { + await Promise.all(manifest.resources.slice(i, i + 8).map(async resource => { + const bytes = resource.url.startsWith('https://stack-diagram.com/') + ? await readFile(path.join(root, 'generated', new URL(resource.url).pathname.slice(1))) + : await retrieveResource(resource); + assert.equal(bytes.length, resource.bytes); + assert.equal(sha256(bytes), resource.sha256); + bytesById.set(resource.id, bytes); + })); +} +const resource = id => { + const bytes = bytesById.get(id); + assert.ok(bytes, `Missing resource: ${id}`); + return bytes; +}; +const json = id => JSON.parse(resource(id).toString('utf8')); +const sourceUrl = id => manifest.resources.find(item => item.id === id).url; +for (const entry of manifest.resources.filter(item => item.id.startsWith('schemas/'))) ajv.addSchema(json(entry.id), entry.url); +const validate = (id, value) => { + const validator = ajv.getSchema(sourceUrl(id)); + assert.ok(validator(value), `${id}: ${ajv.errorsText(validator.errors)}`); +}; + +const portable = [...resource('SPECIFICATION.md').toString('utf8').matchAll(/^\| `(STK\d{4})` \| (Error|Warning) \| (.+) \|$/gm)].map(m => ({ code: m[1], severity: m[2].toLowerCase(), meaning: m[3] })); +assert.ok(portable.length > 0); +assert.deepEqual(json('diagnostic-catalog').diagnostics, portable, 'Generated diagnostic catalog differs from the canonical specification'); + +requireCapabilities(manifest, 'engine', ['check', 'render', 'completion', 'hover']); +await init({ module_or_path: await readFile(path.join(root, 'node_modules/@stack-sh/engine/dist/stack_engine_bg.wasm')) }); +const catalog = json('examples/catalog.json'); +validate('schemas/example-catalog.schema.json', catalog); +for (const example of catalog.examples) { + const result = render(resource(`examples/${example.source}`)); + assert.ok(result.svg, `Example did not render: ${example.id}`); + assert.equal(result.diagnostics.filter(d => d.severity === 'error').length, 0); + for (const diagnostic of result.diagnostics) validate('schemas/diagnostic.schema.json', diagnostic); +} +let diagnosticCases = 0; +let intelligenceCases = 0; +for (const entry of manifest.resources) { + if (entry.id.endsWith('/expected.ir.json')) validate('schemas/normalized-ir.schema.json', json(entry.id)); + if (entry.id.endsWith('/expected.diagnostics.json')) { + const expected = json(entry.id); + validate('schemas/diagnostic-expectations.schema.json', expected); + const source = resource(entry.id.replace('expected.diagnostics.json', 'source.stack')); + const result = check(source); + for (const diagnostic of result.diagnostics) validate('schemas/diagnostic.schema.json', diagnostic); + const actual = result.diagnostics.filter(d => d.code.startsWith('STK')); + assert.equal(actual.length, expected.diagnostics.length, entry.id); + expected.diagnostics.forEach((item, i) => { + for (const key of Object.keys(item)) assert.deepEqual(actual[i][key], item[key], `${entry.id}: ${key}`); + }); + diagnosticCases++; + } + if (entry.id.startsWith('conformance/language-intelligence/') && entry.id.endsWith('/fixture.json')) { + const fixture = json(entry.id); + const source = resource(entry.id.replace('fixture.json', fixture.source)).toString('utf8'); + for (const operation of fixture.operations) { + validate('schemas/language-intelligence.schema.json', operation.request); + validate('schemas/language-intelligence.schema.json', operation.response); + const request = operation.request; + if (!['completion', 'hover'].includes(request.feature)) continue; + if (request.feature === 'completion' && request.completionCatalog.icons.length) continue; + const result = request.feature === 'completion' ? completion(source, request.documentVersion, request.position) : hover(source, request.documentVersion, request.position); + const envelope = { ...result, kind: 'response', feature: request.feature }; + validate('schemas/language-intelligence.schema.json', envelope); + assert.deepEqual(envelope, operation.response, `${entry.id}/${operation.id}`); + intelligenceCases++; + } + } +} +assert.ok(diagnosticCases > 0 && intelligenceCases > 0); +console.log(`Verified ${manifest.resources.length} resource hashes, ${portable.length} portable diagnostics, ${catalog.examples.length} rendered examples, ${diagnosticCases} diagnostic fixtures, and ${intelligenceCases} live WASM intelligence fixtures.`);