3 open 003-npm-release-docs-site
First npm Release, Safe Release Automation, and Documentation Site with Live Project Dashboard
48 / 51 tasks · 7 of 8 phases
Width = task count · Selected: Phase 8: Polish & Cross-Cutting Concerns
Phase 1Setup (Shared Infrastructure)4/4
T001Update package.json: add "repository": {"type": "git", "url": "git+https://github.com/SerafAC/speckit-eye.git"}, "homepage": "https://serafac.github.io/speckit-eye/", "bugs": {"url": "https://github.com/SerafAC/speckit-eye/issues"}, "author": "SerafAC", "keywords": ["spec-kit", "speckit", "github-spec-kit", "spec-driven-development", "dashboard", "progress", "tasks", "cli", "static-site"], "publishConfig": {"access": "public", "provenance": true}; add script "prepublishOnly": "node -e \"if(!process.env.GITHUB_ACTIONS){console.error('Publish only from the Release workflow: see docs/releasing.md');process.exit(1)}\"" (research R8); keep version 1.0.0, files, engines unchanged
Update package.json: add "repository": {"type": "git", "url": "git+https://github.com/SerafAC/speckit-eye.git"}, "homepage": "https://serafac.github.io/speckit-eye/", "bugs": {"url": "https://github.com/SerafAC/speckit-eye/issues"}, "author": "SerafAC", "keywords": ["spec-kit", "speckit", "github-spec-kit", "spec-driven-development", "dashboard", "progress", "tasks", "cli", "static-site"], "publishConfig": {"access": "public", "provenance": true}; add script "prepublishOnly": "node -e \"if(!process.env.GITHUB_ACTIONS){console.error('Publish only from the Release workflow: see docs/releasing.md');process.exit(1)}\"" (research R8); keep version 1.0.0, files, engines unchanged
T002Add dev dependency @docmd/core pinned exactly ("0.9.7", no caret) with pnpm add -D -E @docmd/core@0.9.7; in pnpm-workspace.yaml add esbuild: false and '@docmd/engine-rust': false under allowBuilds with a comment that docmd falls back to its JS engine (research R2); commit the updated pnpm-lock.yaml; verify pnpm exec docmd --version prints 0.9.7
Add dev dependency @docmd/core pinned exactly ("0.9.7", no caret) with pnpm add -D -E @docmd/core@0.9.7; in pnpm-workspace.yaml add esbuild: false and '@docmd/engine-rust': false under allowBuilds with a comment that docmd falls back to its JS engine (research R2); commit the updated pnpm-lock.yaml; verify pnpm exec docmd --version prints 0.9.7
T003Add site/ and *.tgz to .gitignore
Add site/ and *.tgz to .gitignore
- Parallel
T004Update playwright.config.js: add a project tooling (Desktop Chrome, viewport 1440 × 900) with testMatch: /(release-.*|site|repo-health)\.spec\.js/; add the same pattern to DESKTOP_IGNORE so chromium, firefox, webkit do not run the 003 suites; update the header comment (the tooling suites test packaging, scripts and the docs site, not browser engines, research R14). The project runs wherever pnpm run test:e2e runs, i.e. in the CI E2E job on Linux, macOS and Windows; this is intended (the package and the docs build must work on every supported OS). If a suite proves OS-specific, fix it rather than skipping an OS
Update playwright.config.js: add a project tooling (Desktop Chrome, viewport 1440 × 900) with testMatch: /(release-.*|site|repo-health)\.spec\.js/; add the same pattern to DESKTOP_IGNORE so chromium, firefox, webkit do not run the 003 suites; update the header comment (the tooling suites test packaging, scripts and the docs site, not browser engines, research R14). The project runs wherever pnpm run test:e2e runs, i.e. in the CI E2E job on Linux, macOS and Windows; this is intended (the package and the docs build must work on every supported OS). If a suite proves OS-specific, fix it rather than skipping an OS
- Parallel
Phase 2Foundational (Blocking Prerequisites)2/2
T005Create scripts/release/release.js with the command dispatcher only: main(argv, io) parses <command> and options with util.parseArgs (strict), dispatches to bump, verify, notes, release-commit, pack-check (each a stub returning exit 1 "not implemented" until its story task), prints usage and exits 2 on an unknown command or bad options; exports parseVersion(text) → {major, minor, patch, pre: {id, n} | null} or null, accepting only MAJOR.MINOR.PATCH with optional -<id>.<n> (no build metadata, data-model Version), and formatVersion(v); one-line entry point at the end. Unit tests for dispatch, usage/exit codes and parseVersion/formatVersion (valid, 1.0, 01.0.0, 1.0.0+build, 1.0.0-rc, 1.0.0-rc.1) in tests/unit/release.test.jsJavaScript2 files
Create scripts/release/release.js with the command dispatcher only: main(argv, io) parses <command> and options with util.parseArgs (strict), dispatches to bump, verify, notes, release-commit, pack-check (each a stub returning exit 1 "not implemented" until its story task), prints usage and exits 2 on an unknown command or bad options; exports parseVersion(text) → {major, minor, patch, pre: {id, n} | null} or null, accepting only MAJOR.MINOR.PATCH with optional -<id>.<n> (no build metadata, data-model Version), and formatVersion(v); one-line entry point at the end. Unit tests for dispatch, usage/exit codes and parseVersion/formatVersion (valid, 1.0, 01.0.0, 1.0.0+build, 1.0.0-rc, 1.0.0-rc.1) in tests/unit/release.test.js
T006Update .github/workflows/ci.yml (contracts/workflows.md "ci.yml"): add triggers workflow_call and workflow_dispatch; add permissions: {} at the top and permissions: contents: read per job; pin actions/checkout, pnpm/action-setup, actions/setup-node, actions/upload-artifact, Vampire/setup-wsl to full commit SHAs with version comments; add persist-credentials: false to every checkout; in the e2e job's test command keep pnpm run test:e2e (the tooling project runs with it). Keep the job names, matrices and the macOS App Nap step unchangedYAMLci.yml
Update .github/workflows/ci.yml (contracts/workflows.md "ci.yml"): add triggers workflow_call and workflow_dispatch; add permissions: {} at the top and permissions: contents: read per job; pin actions/checkout, pnpm/action-setup, actions/setup-node, actions/upload-artifact, Vampire/setup-wsl to full commit SHAs with version comments; add persist-credentials: false to every checkout; in the e2e job's test command keep pnpm run test:e2e (the tooling project runs with it). Keep the job names, matrices and the macOS App Nap step unchanged
Phase 3User Story 1 - Install speckit-eye from npm (Priority: P1) 🎯 MVPP13/3
T007Implement pack-check <file-list.json> in scripts/release/release.js (contracts/release-cli.md): export pure checkPackFiles(paths) → {unexpected: string[], missing: string[]} where allowed = package.json, README.md, CHANGELOG.md, LICENSE, bin/speckit-eye.js, src/**/*.js except src/styles/**, dist/styles.css, dist/fonts/*.woff2, dist/fonts/OFL-*.txt, and required = each fixed file plus at least one src/ file and at least one .woff2; main reads the JSON (accepting both the npm pack --dry-run --json array form [{files:[{path}]}] and the pnpm pack --json object form {files:[{path}]}), prints each unexpected and missing path to stderr and exits 1 if any, else 0. Unit tests (exact allowed set passes; tests/…, specs/…, src/styles/input.css, docs/x.md, .github/… rejected; missing LICENSE and no .woff2 reported; both JSON forms) in tests/unit/release.test.jsJavaScript6 files
Implement pack-check <file-list.json> in scripts/release/release.js (contracts/release-cli.md): export pure checkPackFiles(paths) → {unexpected: string[], missing: string[]} where allowed = package.json, README.md, CHANGELOG.md, LICENSE, bin/speckit-eye.js, src/**/*.js except src/styles/**, dist/styles.css, dist/fonts/*.woff2, dist/fonts/OFL-*.txt, and required = each fixed file plus at least one src/ file and at least one .woff2; main reads the JSON (accepting both the npm pack --dry-run --json array form [{files:[{path}]}] and the pnpm pack --json object form {files:[{path}]}), prints each unexpected and missing path to stderr and exits 1 if any, else 0. Unit tests (exact allowed set passes; tests/…, specs/…, src/styles/input.css, docs/x.md, .github/… rejected; missing LICENSE and no .woff2 reported; both JSON forms) in tests/unit/release.test.js
- US1
T008Create E2E suite tests/e2e/release-package.spec.js (tooling project): in a temp folder run pnpm pack --json --pack-destination <tmp> from the repo root, run node scripts/release/release.js pack-check on its output (exit 0) — 003 US1 FR-002 the package contains only runtime files, README, CHANGELOG and LICENSE; check the packed package.json has description, license, repository, homepage, bugs, keywords, engines — 003 US1 FR-001 the package carries complete metadata; npm install <tgz> into an empty temp folder, spawn npx speckit-eye --serve <copy of tests/fixtures/projects/mixed> from there, wait for the Local: line, open it in the page and expect 40 / 65 tasks (62 %) — 003 US1 FR-001 the installed tarball serves a project's overview; stop the server; reuse helpers from tests/e2e/helpers.js (fixture copy, spawn, port 4747)JavaScript test2 files
Create E2E suite tests/e2e/release-package.spec.js (tooling project): in a temp folder run pnpm pack --json --pack-destination <tmp> from the repo root, run node scripts/release/release.js pack-check on its output (exit 0) — 003 US1 FR-002 the package contains only runtime files, README, CHANGELOG and LICENSE; check the packed package.json has description, license, repository, homepage, bugs, keywords, engines — 003 US1 FR-001 the package carries complete metadata; npm install <tgz> into an empty temp folder, spawn npx speckit-eye --serve <copy of tests/fixtures/projects/mixed> from there, wait for the Local: line, open it in the page and expect 40 / 65 tasks (62 %) — 003 US1 FR-001 the installed tarball serves a project's overview; stop the server; reuse helpers from tests/e2e/helpers.js (fixture copy, spawn, port 4747)
- US1
- FR-002
- FR-001
T009In DEVELOPMENT.md's release checklist, replace the manual "Package contents" and "Installed tarball runs" items with one line saying both are now automated by release.js pack-check and tests/e2e/release-package.spec.js (the release section is rewritten in T019)JavaScript testrelease-package.spec.js
In DEVELOPMENT.md's release checklist, replace the manual "Package contents" and "Installed tarball runs" items with one line saying both are now automated by release.js pack-check and tests/e2e/release-package.spec.js (the release section is rewritten in T019)
- US1
Phase 4User Story 2 - Cut a release safely by following one guide (Priority: P1)P111/11
T010Implement pure nextVersion(current, kind, preid = "rc") in scripts/release/release.js following the data-model "Next version" table exactly (kinds patch, minor, major, prepatch, preminor, premajor, prerelease; from a pre-release, patch/minor/major finish it when the base already matches, e.g. 1.3.0-rc.1 + patch → 1.3.0; prerelease from a stable version behaves as prepatch; prerelease with the same id increments n, with a different id starts at 0); throws on an unknown kind. Unit tests covering every cell of the table plus 1.0.0-beta.2 + prerelease --preid rc → 1.0.0-rc.0 in tests/unit/release.test.jsJavaScript2 files
Implement pure nextVersion(current, kind, preid = "rc") in scripts/release/release.js following the data-model "Next version" table exactly (kinds patch, minor, major, prepatch, preminor, premajor, prerelease; from a pre-release, patch/minor/major finish it when the base already matches, e.g. 1.3.0-rc.1 + patch → 1.3.0; prerelease from a stable version behaves as prepatch; prerelease with the same id increments n, with a different id starts at 0); throws on an unknown kind. Unit tests covering every cell of the table plus 1.0.0-beta.2 + prerelease --preid rc → 1.0.0-rc.0 in tests/unit/release.test.js
- US2
T011Implement changelog functions in scripts/release/release.js (data-model "Changelog section"): parseChangelog(text) → {head, unreleased: {body}, sections: [{version, date, body}], links} (throws malformed changelog without # Changelog or ## [Unreleased]); hasEntries(body) (at least one line starting - ); releaseChangelog(text, {version, date, repoUrl}) → new text with an empty ## [Unreleased] followed by ## [X.Y.Z] - YYYY-MM-DD holding the former Unreleased body (sub-headings kept), then the older sections unchanged, then rewritten link definitions: [Unreleased]: <repo>/compare/vX.Y.Z...HEAD, and per released version [V]: <repo>/compare/v<previous>...vV or, for the oldest, [V]: <repo>/releases/tag/vV; sectionNotes(text, version) → the section body trimmed, or throws; repoUrlFrom(pkg) → repository.url without git+ and .git. Unit tests with sample changelogs (first release from the real shape of CHANGELOG.md, second release, sub-headings preserved, empty Unreleased, malformed input, notes of a missing version) in tests/unit/release.test.jsJavaScript2 files
Implement changelog functions in scripts/release/release.js (data-model "Changelog section"): parseChangelog(text) → {head, unreleased: {body}, sections: [{version, date, body}], links} (throws malformed changelog without # Changelog or ## [Unreleased]); hasEntries(body) (at least one line starting - ); releaseChangelog(text, {version, date, repoUrl}) → new text with an empty ## [Unreleased] followed by ## [X.Y.Z] - YYYY-MM-DD holding the former Unreleased body (sub-headings kept), then the older sections unchanged, then rewritten link definitions: [Unreleased]: <repo>/compare/vX.Y.Z...HEAD, and per released version [V]: <repo>/compare/v<previous>...vV or, for the oldest, [V]: <repo>/releases/tag/vV; sectionNotes(text, version) → the section body trimmed, or throws; repoUrlFrom(pkg) → repository.url without git+ and .git. Unit tests with sample changelogs (first release from the real shape of CHANGELOG.md, second release, sub-headings preserved, empty Unreleased, malformed input, notes of a missing version) in tests/unit/release.test.js
- US2
T012Implement the bump command in scripts/release/release.js (contracts/release-cli.md): bump <kind> [--preid rc] or bump --version X.Y.Z (exactly one); reads package.json and CHANGELOG.md; refuses (exit 1, nothing written, stderr message) when Unreleased has no entries (FR-008), when the version is invalid, or when the changelog already has a ## [X.Y.Z] section; --version equal to the current version is allowed (first release 1.0.0); writes package.json with only version changed (JSON.stringify(pkg, null, 2) + "\n", key order kept) and the released changelog with today's UTC date from io.now(); prints the new version. Unit tests with fake I/O (writes both files, first-release --version 1.0.0, empty Unreleased writes nothing, duplicate section refused, both <kind> and --version rejected) in tests/unit/release.test.jsJavaScript2 files
Implement the bump command in scripts/release/release.js (contracts/release-cli.md): bump <kind> [--preid rc] or bump --version X.Y.Z (exactly one); reads package.json and CHANGELOG.md; refuses (exit 1, nothing written, stderr message) when Unreleased has no entries (FR-008), when the version is invalid, or when the changelog already has a ## [X.Y.Z] section; --version equal to the current version is allowed (first release 1.0.0); writes package.json with only version changed (JSON.stringify(pkg, null, 2) + "\n", key order kept) and the released changelog with today's UTC date from io.now(); prints the new version. Unit tests with fake I/O (writes both files, first-release --version 1.0.0, empty Unreleased writes nothing, duplicate section refused, both <kind> and --version rejected) in tests/unit/release.test.js
- US2
- FR-008
T013Implement verify --tag vX.Y.Z and notes --version X.Y.Z in scripts/release/release.js (contracts/release-cli.md): verifyRelease({tag, pkg, changelog}) → {version, tag, prerelease, distTag} or throws with the failed check named (tag v1.2.0 does not match package.json version 1.1.0, newest changelog section is 1.1.0, not 1.2.0, changelog section 1.2.0 has no entries, invalid tag); distTag = next when the version contains -, else latest (FR-016); verify prints version=, tag=, prerelease=, dist-tag= lines; notes prints sectionNotes. Unit tests for each check and both dist-tags in tests/unit/release.test.jsJavaScript2 files
Implement verify --tag vX.Y.Z and notes --version X.Y.Z in scripts/release/release.js (contracts/release-cli.md): verifyRelease({tag, pkg, changelog}) → {version, tag, prerelease, distTag} or throws with the failed check named (tag v1.2.0 does not match package.json version 1.1.0, newest changelog section is 1.1.0, not 1.2.0, changelog section 1.2.0 has no entries, invalid tag); distTag = next when the version contains -, else latest (FR-016); verify prints version=, tag=, prerelease=, dist-tag= lines; notes prints sectionNotes. Unit tests for each check and both dist-tags in tests/unit/release.test.js
- US2
- FR-016
T014Implement release-commit --version X.Y.Z --head-ref <ref> --tag-exists <true|false> in scripts/release/release.js: pure releaseCommitDecision({version, headRef, tagExists, changelog}) → {release: true} only when headRef === "release/next", tagExists === false and the changelog has ## [X.Y.Z]; otherwise {release: false, reason} (not merged from release/next, tag vX.Y.Z already exists, no changelog section for X.Y.Z); prints release= and reason= lines, always exit 0 (research R10, edge case "hand-edited version"). Unit tests for all four outcomes in tests/unit/release.test.jsJavaScript2 files
Implement release-commit --version X.Y.Z --head-ref <ref> --tag-exists <true|false> in scripts/release/release.js: pure releaseCommitDecision({version, headRef, tagExists, changelog}) → {release: true} only when headRef === "release/next", tagExists === false and the changelog has ## [X.Y.Z]; otherwise {release: false, reason} (not merged from release/next, tag vX.Y.Z already exists, no changelog section for X.Y.Z); prints release= and reason= lines, always exit 0 (research R10, edge case "hand-edited version"). Unit tests for all four outcomes in tests/unit/release.test.js
- US2
T015Create .github/workflows/bump.yml (contracts/workflows.md "bump.yml"): workflow_dispatch inputs kind (choice patch, minor, major, prepatch, preminor, premajor, prerelease, explicit), version (string), preid (string, default rc); fail unless github.ref == 'refs/heads/main'; permissions: {} then job contents: write, pull-requests: write, actions: write; concurrency: bump; steps: checkout main, setup pnpm/node 22, run node scripts/release/release.js bump … (--version ${{ inputs.version }} when kind == explicit, else ${{ inputs.kind }} --preid ${{ inputs.preid }}), capture the version, commit chore(release): vX.Y.Z as github-actions[bot], git push --force origin HEAD:release/next, write the PR body (release notes from release.js notes + "Merging this PR tags vX.Y.Z and starts the Release workflow, which waits for the repository owner's approval"), then gh pr create --base main --head release/next --title "Release vX.Y.Z" or, when a PR from release/next is open, gh pr edit it (edge case "previous bump still open"), then gh workflow run ci.yml --ref release/next (research R9). Pass inputs through env:, never interpolate ${{ inputs.* }} directly into run: scripts (script injection)YAMLbump.yml
Create .github/workflows/bump.yml (contracts/workflows.md "bump.yml"): workflow_dispatch inputs kind (choice patch, minor, major, prepatch, preminor, premajor, prerelease, explicit), version (string), preid (string, default rc); fail unless github.ref == 'refs/heads/main'; permissions: {} then job contents: write, pull-requests: write, actions: write; concurrency: bump; steps: checkout main, setup pnpm/node 22, run node scripts/release/release.js bump … (--version ${{ inputs.version }} when kind == explicit, else ${{ inputs.kind }} --preid ${{ inputs.preid }}), capture the version, commit chore(release): vX.Y.Z as github-actions[bot], git push --force origin HEAD:release/next, write the PR body (release notes from release.js notes + "Merging this PR tags vX.Y.Z and starts the Release workflow, which waits for the repository owner's approval"), then gh pr create --base main --head release/next --title "Release vX.Y.Z" or, when a PR from release/next is open, gh pr edit it (edge case "previous bump still open"), then gh workflow run ci.yml --ref release/next (research R9). Pass inputs through env:, never interpolate ${{ inputs.* }} directly into run: scripts (script injection)
- US2
T016Create .github/workflows/release.yml (contracts/workflows.md "release.yml", research R10): triggers push to main with paths package.json, CHANGELOG.md; push tags v*; workflow_dispatch without inputs (re-run for an existing tag; there is no dry-run mode — the rehearsal is the real run reviewed at the approval step); permissions: {}; concurrency: {group: release, cancel-in-progress: false}. Job prepare (contents: read, pull-requests: read): on a push to main, get the head ref of the PR for github.sha with gh api repos/${{ github.repository }}/commits/${{ github.sha }}/pulls --jq '.[0].head.ref // ""', check the remote tag with git ls-remote --tags origin, run release.js release-commit; on a tag push or dispatch, require github.ref_type == 'tag' (dispatch on a branch fails with "run this workflow on a tag"); outputs release, version, tag, sha. Jobs ci (uses: ./.github/workflows/ci.yml, contents: read) and verify (contents: read; checkout with fetch-depth: 0; git merge-base --is-ancestor <sha> origin/main (FR-009); release.js verify --tag; fail if npm view speckit-eye@<version> version succeeds (FR-010); pnpm pack --json; release.js pack-check; release.js notes > notes.md; upload artifact release with the .tgz and notes.md) both only when prepare.outputs.release == 'true'. Job publish needs ci + verify, environment: npm, permissions contents: write, id-token: write: checkout with credentials, download the artifact, create and push the annotated tag vX.Y.Z on sha if it does not exist, setup-node 24 with registry-url: https://registry.npmjs.org, npm publish ./speckit-eye-<version>.tgz --access public --provenance --tag <dist-tag>, env NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} (research R7). Job github-release needs publish, contents: write: download the artifact and run gh release create <tag> --verify-tag --title <tag> --notes-file notes.md plus --prerelease when prerelease (FR-015). All values reach shell steps through env:YAMLrelease.yml
Create .github/workflows/release.yml (contracts/workflows.md "release.yml", research R10): triggers push to main with paths package.json, CHANGELOG.md; push tags v*; workflow_dispatch without inputs (re-run for an existing tag; there is no dry-run mode — the rehearsal is the real run reviewed at the approval step); permissions: {}; concurrency: {group: release, cancel-in-progress: false}. Job prepare (contents: read, pull-requests: read): on a push to main, get the head ref of the PR for github.sha with gh api repos/${{ github.repository }}/commits/${{ github.sha }}/pulls --jq '.[0].head.ref // ""', check the remote tag with git ls-remote --tags origin, run release.js release-commit; on a tag push or dispatch, require github.ref_type == 'tag' (dispatch on a branch fails with "run this workflow on a tag"); outputs release, version, tag, sha. Jobs ci (uses: ./.github/workflows/ci.yml, contents: read) and verify (contents: read; checkout with fetch-depth: 0; git merge-base --is-ancestor <sha> origin/main (FR-009); release.js verify --tag; fail if npm view speckit-eye@<version> version succeeds (FR-010); pnpm pack --json; release.js pack-check; release.js notes > notes.md; upload artifact release with the .tgz and notes.md) both only when prepare.outputs.release == 'true'. Job publish needs ci + verify, environment: npm, permissions contents: write, id-token: write: checkout with credentials, download the artifact, create and push the annotated tag vX.Y.Z on sha if it does not exist, setup-node 24 with registry-url: https://registry.npmjs.org, npm publish ./speckit-eye-<version>.tgz --access public --provenance --tag <dist-tag>, env NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} (research R7). Job github-release needs publish, contents: write: download the artifact and run gh release create <tag> --verify-tag --title <tag> --notes-file notes.md plus --prerelease when prerelease (FR-015). All values reach shell steps through env:
- US2
- FR-009
- FR-010
- FR-015
T017Create fixture files tests/fixtures/release/package.json ({"name": "speckit-eye", "version": "1.0.0", "repository": {"type": "git", "url": "git+https://github.com/SerafAC/speckit-eye.git"}}) and tests/fixtures/release/CHANGELOG.md (the Keep a Changelog head of the real file, an ## [Unreleased] section with ### Added and two entries, and the [Unreleased]: …/commits/main link line) — a frozen sample, never the repository's live files, so the suite keeps passing after real releases. Create E2E suite tests/e2e/release-flow.spec.js (tooling project): copy the two fixture files into a temp folder, run node <repo>/scripts/release/release.js there with cwd = temp. Tests: 003 US2 FR-006 bump moves Unreleased under the new dated version (bump --version 1.0.0 → stdout 1.0.0, empty Unreleased, ## [1.0.0] - <today UTC> with the former entries, link lines); 003 US2 FR-008 bump refuses an empty Unreleased section (second run exits 1, files unchanged by hash); 003 US2 FR-010 verify accepts a matching tag and names latest; 003 US2 FR-010 verify rejects a tag that does not match package.json (exit 1, stderr names the mismatch, SC-003); 003 US2 FR-016 a pre-release verifies with the next dist-tag (add an entry, bump preminor → 1.1.0-rc.0, verify → dist-tag=next); 003 US2 FR-015 notes print the version's changelog section; 003 US2 FR-002 pack-check rejects an unexpected file (hand-made list with tests/x.js → exit 1); 003 US2 FR-009 release-commit ignores a version change not merged from release/nextJSON test4 files
Create fixture files tests/fixtures/release/package.json ({"name": "speckit-eye", "version": "1.0.0", "repository": {"type": "git", "url": "git+https://github.com/SerafAC/speckit-eye.git"}}) and tests/fixtures/release/CHANGELOG.md (the Keep a Changelog head of the real file, an ## [Unreleased] section with ### Added and two entries, and the [Unreleased]: …/commits/main link line) — a frozen sample, never the repository's live files, so the suite keeps passing after real releases. Create E2E suite tests/e2e/release-flow.spec.js (tooling project): copy the two fixture files into a temp folder, run node <repo>/scripts/release/release.js there with cwd = temp. Tests: 003 US2 FR-006 bump moves Unreleased under the new dated version (bump --version 1.0.0 → stdout 1.0.0, empty Unreleased, ## [1.0.0] - <today UTC> with the former entries, link lines); 003 US2 FR-008 bump refuses an empty Unreleased section (second run exits 1, files unchanged by hash); 003 US2 FR-010 verify accepts a matching tag and names latest; 003 US2 FR-010 verify rejects a tag that does not match package.json (exit 1, stderr names the mismatch, SC-003); 003 US2 FR-016 a pre-release verifies with the next dist-tag (add an entry, bump preminor → 1.1.0-rc.0, verify → dist-tag=next); 003 US2 FR-015 notes print the version's changelog section; 003 US2 FR-002 pack-check rejects an unexpected file (hand-made list with tests/x.js → exit 1); 003 US2 FR-009 release-commit ignores a version change not merged from release/next
- US2
- FR-006
- FR-008
- FR-010
- SC-003
- FR-016
- FR-015
- FR-002
- FR-009
T018Write docs/releasing.md (FR-018): overview diagram (bump → PR → merge → Release: prepare, ci, verify, approval, tag, publish, GitHub release); One-time setup (claim/confirm the npm name; create the npm environment with the repository owner as the only required reviewer, self-review allowed, deployment refs main and v*; first-release granular npm token with write access and 1-day expiry as environment secret NPM_TOKEN; Settings → Actions → "Allow GitHub Actions to create and approve pull requests"; Settings → Pages → Source "GitHub Actions"; tag ruleset protecting v* from update and deletion; immutable releases; private vulnerability reporting); Cutting a release; Cutting a pre-release (prepatch/preminor/premajor/prerelease, next dist-tag, how users install it); The first release (explicit + 1.0.0, then switch to trusted publishing: configure the trusted publisher for SerafAC/speckit-eye, workflow release.yml, environment npm; set "Require two-factor authentication and disallow tokens"; revoke the token; delete NPM_TOKEN); Verifying a release (npm view, provenance on npmjs.com, npm audit signatures, tag, GitHub release, changelog); When something goes wrong (a check failed; approval rejected; publish succeeded but the GitHub release failed → re-run failed jobs; a tag pushed by hand; re-running a release by dispatching Release on its tag; there is no dry-run mode — to rehearse, review the pending run at the approval step and reject it; a broken version → npm deprecate speckit-eye@X "<reason>" and ship a patch, never unpublish/reuse; name taken); Why it is safe (the checks of FR-009–FR-017 in one list)Markdownreleasing.md
Write docs/releasing.md (FR-018): overview diagram (bump → PR → merge → Release: prepare, ci, verify, approval, tag, publish, GitHub release); One-time setup (claim/confirm the npm name; create the npm environment with the repository owner as the only required reviewer, self-review allowed, deployment refs main and v*; first-release granular npm token with write access and 1-day expiry as environment secret NPM_TOKEN; Settings → Actions → "Allow GitHub Actions to create and approve pull requests"; Settings → Pages → Source "GitHub Actions"; tag ruleset protecting v* from update and deletion; immutable releases; private vulnerability reporting); Cutting a release; Cutting a pre-release (prepatch/preminor/premajor/prerelease, next dist-tag, how users install it); The first release (explicit + 1.0.0, then switch to trusted publishing: configure the trusted publisher for SerafAC/speckit-eye, workflow release.yml, environment npm; set "Require two-factor authentication and disallow tokens"; revoke the token; delete NPM_TOKEN); Verifying a release (npm view, provenance on npmjs.com, npm audit signatures, tag, GitHub release, changelog); When something goes wrong (a check failed; approval rejected; publish succeeded but the GitHub release failed → re-run failed jobs; a tag pushed by hand; re-running a release by dispatching Release on its tag; there is no dry-run mode — to rehearse, review the pending run at the approval step and reject it; a broken version → npm deprecate speckit-eye@X "<reason>" and ship a patch, never unpublish/reuse; name taken); Why it is safe (the checks of FR-009–FR-017 in one list)
- US2
- FR-018
- FR-009
- FR-017
T019Update DEVELOPMENT.md "Release process": replace the manual steps and the release checklist with a short summary (the three maintainer actions: start Bump version, merge the PR, approve the release) and a link to docs/releasing.md (FR-019); mention scripts/release/release.js in "Project structure" and that npm publish from a working copy is refused by prepublishOnlyMarkdown2 files
Update DEVELOPMENT.md "Release process": replace the manual steps and the release checklist with a short summary (the three maintainer actions: start Bump version, merge the PR, approve the release) and a link to docs/releasing.md (FR-019); mention scripts/release/release.js in "Project structure" and that npm publish from a working copy is refused by prepublishOnly
- US2
- FR-019
T020Prepare CHANGELOG.md for the first bump: add, at the bottom, the link definition [Unreleased]: https://github.com/SerafAC/speckit-eye/commits/main (rewritten by bump on release); add a unit test in tests/unit/release.test.js that runs parseChangelog and releaseChangelog on an inline copy of the file's head, first entries and link line, so the real file's shape is covered without reading itJavaScript testrelease.test.js
Prepare CHANGELOG.md for the first bump: add, at the bottom, the link definition [Unreleased]: https://github.com/SerafAC/speckit-eye/commits/main (rewritten by bump on release); add a unit test in tests/unit/release.test.js that runs parseChangelog and releaseChangelog on an inline copy of the file's head, first entries and link line, so the real file's shape is covered without reading it
- US2
Phase 5User Story 3 - Read the documentation on a website (Priority: P2)P28/8
T021Create docmd.config.js (research R3): import pkg from "./package.json" with { type: "json" }; export default { title: "speckit-eye", url: pkg.homepage (as-is: docmd strips the trailing slash itself, so the config holds no logic to unit-test, §IV), src: "docs", out: "site", markdown: { breaks: false, linkify: false }, navigation: [Home "/", Usage "/usage", Hosting a snapshot "/hosting", Architecture "/architecture", Releasing "/releasing", external "Contributing" → https://github.com/SerafAC/speckit-eye/blob/main/CONTRIBUTING.md, external "Development" → https://github.com/SerafAC/speckit-eye/blob/main/DEVELOPMENT.md(FR-021), external "Project status & live demo" →${pkg.homepage}status/, external "npm" → https://www.npmjs.com/package/speckit-eye, external "GitHub" → repository URL], plugins: { ai: false, analytics: false } } — confirm the exact key names for navigation entries and external links against node_modules/@docmd/core/dist/utils/config-schema.js and @docmd/parser's normalizeNavPathsJavaScriptconfig-schema.js
Create docmd.config.js (research R3): import pkg from "./package.json" with { type: "json" }; export default { title: "speckit-eye", url: pkg.homepage (as-is: docmd strips the trailing slash itself, so the config holds no logic to unit-test, §IV), src: "docs", out: "site", markdown: { breaks: false, linkify: false }, navigation: [Home "/", Usage "/usage", Hosting a snapshot "/hosting", Architecture "/architecture", Releasing "/releasing", external "Contributing" → https://github.com/SerafAC/speckit-eye/blob/main/CONTRIBUTING.md, external "Development" → https://github.com/SerafAC/speckit-eye/blob/main/DEVELOPMENT.md(FR-021), external "Project status & live demo" →${pkg.homepage}status/, external "npm" → https://www.npmjs.com/package/speckit-eye, external "GitHub" → repository URL], plugins: { ai: false, analytics: false } } — confirm the exact key names for navigation entries and external links against node_modules/@docmd/core/dist/utils/config-schema.js and @docmd/parser's normalizeNavPaths
- US3
- Parallel
- FR-021
T022Move docs/screenshot.png and docs/screenshot-dark.png to docs/assets/ with git mv (docmd copies only docs/assets/, research R4); update the <picture> sources in README.md to docs/assets/screenshot-dark.png and docs/assets/screenshot.png; grep the repository for other references to the old paths (tests, docs) and update themPNG4 files
Move docs/screenshot.png and docs/screenshot-dark.png to docs/assets/ with git mv (docmd copies only docs/assets/, research R4); update the <picture> sources in README.md to docs/assets/screenshot-dark.png and docs/assets/screenshot.png; grep the repository for other references to the old paths (tests, docs) and update them
- US3
- Parallel
T023In docs/architecture.md and docs/usage.md, replace every relative link into specs/ (../specs/…) with the absolute URL https://github.com/SerafAC/speckit-eye/blob/main/specs/… (directories: …/tree/main/specs/…); in docs/usage.md rephrase the "Links to other documents" bullet so the example paths ./plan.md and contracts/cli.md#synopsis are not written in Markdown link syntax (research R4)Markdown3 files
In docs/architecture.md and docs/usage.md, replace every relative link into specs/ (../specs/…) with the absolute URL https://github.com/SerafAC/speckit-eye/blob/main/specs/… (directories: …/tree/main/specs/…); in docs/usage.md rephrase the "Links to other documents" bullet so the example paths ./plan.md and contracts/cli.md#synopsis are not written in Markdown link syntax (research R4)
- US3
- Parallel
T024Create docs/index.md (contracts/site.md "Home page"): front matter title: speckit-eye; one-paragraph description; the screenshot  with the README's alt text; "Install and run" with npx speckit-eye --serve . and Node ≥ 22; a prominent link "Project status & live demo" to https://serafac.github.io/speckit-eye/status/ (FR-026) with one sentence explaining it is this repository's own specs shown by speckit-eye; links to the npm package and the repository; a "Guides" list linking Usage, Hosting a snapshot, Architecture, Releasing; "Project" links to CONTRIBUTING.md, DEVELOPMENT.md, CHANGELOG.md, SECURITY.md on GitHub (absolute URLs, blob/main). Do not copy README sections (§III)Markdownindex.md
Create docs/index.md (contracts/site.md "Home page"): front matter title: speckit-eye; one-paragraph description; the screenshot  with the README's alt text; "Install and run" with npx speckit-eye --serve . and Node ≥ 22; a prominent link "Project status & live demo" to https://serafac.github.io/speckit-eye/status/ (FR-026) with one sentence explaining it is this repository's own specs shown by speckit-eye; links to the npm package and the repository; a "Guides" list linking Usage, Hosting a snapshot, Architecture, Releasing; "Project" links to CONTRIBUTING.md, DEVELOPMENT.md, CHANGELOG.md, SECURITY.md on GitHub (absolute URLs, blob/main). Do not copy README sections (§III)
- US3
- FR-026
T025Create scripts/build-site.js (contracts/site.md "Build command"), docs part: export pure sitePaths(homepage) → {home: "<homepage with trailing />", base: "<URL path of homepage>", statusBase: "<base>status/", statusUrl: "<home>status/"} (throws unless https:/http:); main(argv, io) removes site/ (io.rm), runs docmd build through io.run (the local binary node_modules/.bin/docmd), and returns its exit code (the dashboard step is added in T031); add script "docs:build": "node scripts/build-site.js" to package.json. Unit tests for sitePaths (https://serafac.github.io/speckit-eye/ and without trailing slash → base /speckit-eye/, statusBase /speckit-eye/status/; root domain → base /; ftp: throws) and for main with fake rm/run (order of calls, non-zero exit propagated) in tests/unit/build-site.test.jsJavaScript2 files
Create scripts/build-site.js (contracts/site.md "Build command"), docs part: export pure sitePaths(homepage) → {home: "<homepage with trailing />", base: "<URL path of homepage>", statusBase: "<base>status/", statusUrl: "<home>status/"} (throws unless https:/http:); main(argv, io) removes site/ (io.rm), runs docmd build through io.run (the local binary node_modules/.bin/docmd), and returns its exit code (the dashboard step is added in T031); add script "docs:build": "node scripts/build-site.js" to package.json. Unit tests for sitePaths (https://serafac.github.io/speckit-eye/ and without trailing slash → base /speckit-eye/, statusBase /speckit-eye/status/; root domain → base /; ftp: throws) and for main with fake rm/run (order of calls, non-zero exit propagated) in tests/unit/build-site.test.js
- US3
T026Create .github/workflows/pages.yml (contracts/workflows.md "pages.yml", research R12): triggers push to main and pull_request with paths docs/**, docmd.config.js, scripts/build-site.js, src/**, bin/**, specs/**, .specify/**, package.json, pnpm-lock.yaml, .github/workflows/pages.yml, plus workflow_dispatch; permissions: {}; concurrency: {group: pages, cancel-in-progress: false}; job build (contents: read): checkout, pnpm, node 22, pnpm install --frozen-lockfile, pnpm run docs:build, pnpm exec docmd validate, actions/upload-pages-artifact with path: site; job deploy (if: github.event_name != 'pull_request', needs build, pages: write, id-token: write, environment: {name: github-pages, url: ${{ steps.deployment.outputs.page_url }}}): actions/deploy-pages. Pin all actions by SHAYAML2 files
Create .github/workflows/pages.yml (contracts/workflows.md "pages.yml", research R12): triggers push to main and pull_request with paths docs/**, docmd.config.js, scripts/build-site.js, src/**, bin/**, specs/**, .specify/**, package.json, pnpm-lock.yaml, .github/workflows/pages.yml, plus workflow_dispatch; permissions: {}; concurrency: {group: pages, cancel-in-progress: false}; job build (contents: read): checkout, pnpm, node 22, pnpm install --frozen-lockfile, pnpm run docs:build, pnpm exec docmd validate, actions/upload-pages-artifact with path: site; job deploy (if: github.event_name != 'pull_request', needs build, pages: write, id-token: write, environment: {name: github-pages, url: ${{ steps.deployment.outputs.page_url }}}): actions/deploy-pages. Pin all actions by SHA
- US3
T027Create E2E suite tests/e2e/site.spec.js (tooling project), docs part: in beforeAll run pnpm run docs:build and start a small static file server (Node http, in tests/e2e/helpers.js as serveStatic(root, prefix)) that serves site/ under /speckit-eye/ on port 4747 and returns 404 elsewhere. Tests: 003 US3 FR-021 the home page links to every guide, npm, GitHub and the dashboard (Usage, Hosting a snapshot, Architecture, Releasing reachable in ≤ 2 clicks, SC-006); 003 US3 FR-021 the navigation lists every guide plus Contributing and Development; 003 US3 FR-023 the site has no broken internal links (crawl every same-origin href/src under /speckit-eye/, excluding /speckit-eye/status/ which the US4 part covers, and expect 200 for each); 003 US3 FR-020 a guide page shows the text of its docs/ file (a heading from docs/usage.md appears on /speckit-eye/usage/); 003 US3 FR-023 docmd validate passes (spawn pnpm exec docmd validate, exit 0)JavaScript test3 files
Create E2E suite tests/e2e/site.spec.js (tooling project), docs part: in beforeAll run pnpm run docs:build and start a small static file server (Node http, in tests/e2e/helpers.js as serveStatic(root, prefix)) that serves site/ under /speckit-eye/ on port 4747 and returns 404 elsewhere. Tests: 003 US3 FR-021 the home page links to every guide, npm, GitHub and the dashboard (Usage, Hosting a snapshot, Architecture, Releasing reachable in ≤ 2 clicks, SC-006); 003 US3 FR-021 the navigation lists every guide plus Contributing and Development; 003 US3 FR-023 the site has no broken internal links (crawl every same-origin href/src under /speckit-eye/, excluding /speckit-eye/status/ which the US4 part covers, and expect 200 for each); 003 US3 FR-020 a guide page shows the text of its docs/ file (a heading from docs/usage.md appears on /speckit-eye/usage/); 003 US3 FR-023 docmd validate passes (spawn pnpm exec docmd validate, exit 0)
- US3
- FR-021
- SC-006
- FR-023
- FR-020
T028Update README.md "Documentation" section: add a first bullet linking the documentation website https://serafac.github.io/speckit-eye/ (US3 acceptance scenario 5); keep the links to the files under docs/, adding docs/releasing.mdMarkdownreleasing.md
Update README.md "Documentation" section: add a first bullet linking the documentation website https://serafac.github.io/speckit-eye/ (US3 acceptance scenario 5); keep the links to the files under docs/, adding docs/releasing.md
- US3
Phase 6User Story 4 - See the project's own status and a live demo (Priority: P2)P28/8
T029Add the --home <url> option to src/cli/args.js (contracts/cli-home.md): new home string option; CliArgs.home (string | null, null by default and for serve/help/version); --home with --serve → {error: "--home can only be used with --build"}; a value that is not a URL with protocol http: or https: → {error: "--home must be an http or https URL"}; update USAGE with --home <url> Link back to <url> from every page, for --build (for example your docs site). Unit tests (accepted https URL, rejected javascript:alert(1), /relative, ftp://x; serve + home rejected; default null; usage text) in tests/unit/args.test.jsJavaScript2 files
Add the --home <url> option to src/cli/args.js (contracts/cli-home.md): new home string option; CliArgs.home (string | null, null by default and for serve/help/version); --home with --serve → {error: "--home can only be used with --build"}; a value that is not a URL with protocol http: or https: → {error: "--home must be an http or https URL"}; update USAGE with --home <url> Link back to <url> from every page, for --build (for example your docs site). Unit tests (accepted https URL, rejected javascript:alert(1), /relative, ftp://x; serve + home rejected; default null; usage text) in tests/unit/args.test.js
- US4
- Parallel
T030Add the Lucide house icon to src/render/icons.js (same format and ISC notice as the other icons) and a test that it renders in tests/unit/icons.test.jsJavaScript2 files
Add the Lucide house icon to src/render/icons.js (same format and ISC notice as the other icons) and a test that it renders in tests/unit/icons.test.js
- US4
- Parallel
T031Render the Home link (contracts/cli-home.md "Rendering"): renderPage in src/render/layout.js takes home = null; when set, the sidebar gets <a href="<home>" data-part="home">${icon("house")}<span>Home</span></a> directly after <p data-part="project-name">, the mobile menu gets the same link after its <summary>, and the document-page rail gets <a href="<home>" data-part="home" aria-label="Home" title="Home">${icon("house")}</a> directly after the brand; when home is null the output is unchanged. Thread home through renderSite in src/render/site.js (every renderPage call) and pass args.home from the build branch of src/cli/main.js (serve passes nothing). Add the data-part="home" link style to src/styles/input.css next to the brand style (tokens only, no inline styles). Unit tests: with home the three placements exist with the escaped URL; without home the HTML of every page type equals the output before this change (snapshot the current output in the test first) in tests/unit/layout.test.js and tests/unit/site.test.js; main passes home only in build mode in tests/unit/main.test.jsJavaScript7 files
Render the Home link (contracts/cli-home.md "Rendering"): renderPage in src/render/layout.js takes home = null; when set, the sidebar gets <a href="<home>" data-part="home">${icon("house")}<span>Home</span></a> directly after <p data-part="project-name">, the mobile menu gets the same link after its <summary>, and the document-page rail gets <a href="<home>" data-part="home" aria-label="Home" title="Home">${icon("house")}</a> directly after the brand; when home is null the output is unchanged. Thread home through renderSite in src/render/site.js (every renderPage call) and pass args.home from the build branch of src/cli/main.js (serve passes nothing). Add the data-part="home" link style to src/styles/input.css next to the brand style (tokens only, no inline styles). Unit tests: with home the three placements exist with the escaped URL; without home the HTML of every page type equals the output before this change (snapshot the current output in the test first) in tests/unit/layout.test.js and tests/unit/site.test.js; main passes home only in build mode in tests/unit/main.test.js
- US4
T032Extend scripts/build-site.js: after docmd build, run node bin/speckit-eye.js --build . --out site/status --base <statusBase> --home <home> through io.run; return the first non-zero exit code (FR-024: a failing dashboard build fails the whole build). Unit tests for the second call's arguments and failure propagation in tests/unit/build-site.test.jsJavaScript2 files
Extend scripts/build-site.js: after docmd build, run node bin/speckit-eye.js --build . --out site/status --base <statusBase> --home <home> through io.run; return the first non-zero exit code (FR-024: a failing dashboard build fails the whole build). Unit tests for the second call's arguments and failure propagation in tests/unit/build-site.test.js
- US4
- FR-024
T033Update README.md: directly under the intro paragraph add a line with the links "Documentation" → https://serafac.github.io/speckit-eye/ and "Project status & live demo" → https://serafac.github.io/speckit-eye/status/ (this repository's own specs shown by speckit-eye) (FR-026)
Update README.md: directly under the intro paragraph add a line with the links "Documentation" → https://serafac.github.io/speckit-eye/ and "Project status & live demo" → https://serafac.github.io/speckit-eye/status/ (this repository's own specs shown by speckit-eye) (FR-026)
- US4
- FR-026
T034Document --home: add the option to docs/usage.md (build mode) and docs/hosting.md (options list, with an example linking back to a docs site), and add the --home row and synopsis to specs/001-speckit-eye-dashboard/contracts/cli.md as described in contracts/cli-home.mdMarkdown4 files
Document --home: add the option to docs/usage.md (build mode) and docs/hosting.md (options list, with an example linking back to a docs site), and add the --home row and synopsis to specs/001-speckit-eye-dashboard/contracts/cli.md as described in contracts/cli-home.md
- US4
T035Extend tests/e2e/site.spec.js, status part: 003 US4 FR-025 the dashboard of this repository is served at /status/ (open /speckit-eye/status/, overview heading and sidebar present); 003 US4 FR-025 the dashboard counts match this repository's tasks.md checkboxes (count - [x]/- [X] and - [ ] task lines in specs/*/tasks.md the same way tests/e2e/self-counts.spec.js does — reuse its helper, moving it into tests/e2e/helpers.js if needed — and compare with the stats card, SC-007); 003 US4 FR-027 every link, style, font and script of the dashboard loads under /status/ (crawl same-origin URLs from the overview, one feature page and one document page; all 200; the search dialog opens and finds a task; the theme switch changes the theme); 003 US4 FR-027 the Home link returns to the documentation home; 003 US4 FR-026 the docs home and README link to the dashboard (home page link resolves to /speckit-eye/status/; README.md contains https://serafac.github.io/speckit-eye/status/)JavaScript test4 files
Extend tests/e2e/site.spec.js, status part: 003 US4 FR-025 the dashboard of this repository is served at /status/ (open /speckit-eye/status/, overview heading and sidebar present); 003 US4 FR-025 the dashboard counts match this repository's tasks.md checkboxes (count - [x]/- [X] and - [ ] task lines in specs/*/tasks.md the same way tests/e2e/self-counts.spec.js does — reuse its helper, moving it into tests/e2e/helpers.js if needed — and compare with the stats card, SC-007); 003 US4 FR-027 every link, style, font and script of the dashboard loads under /status/ (crawl same-origin URLs from the overview, one feature page and one document page; all 200; the search dialog opens and finds a task; the theme switch changes the theme); 003 US4 FR-027 the Home link returns to the documentation home; 003 US4 FR-026 the docs home and README link to the dashboard (home page link resolves to /speckit-eye/status/; README.md contains https://serafac.github.io/speckit-eye/status/)
- US4
- FR-025
- SC-007
- FR-027
- FR-026
T036Add a build-mode E2E test to tests/e2e/us4-build.spec.js: 003 US4 FR-027 --home adds a Home link to every page of a build (build the mixed fixture with --home https://example.com/docs/, check overview, a feature page and a document page) and 003 US4 FR-027 a build without --home has no Home linkJavaScript testus4-build.spec.js
Add a build-mode E2E test to tests/e2e/us4-build.spec.js: 003 US4 FR-027 --home adds a Home link to every page of a build (build the mixed fixture with --home https://example.com/docs/, check overview, a feature page and a document page) and 003 US4 FR-027 a build without --home has no Home link
- US4
- Parallel
- FR-027
Phase 7User Story 5 - Contribute to an open-source project with clear rules (Priority: P3)P38/8
T037Create CONTRIBUTING.md: how to report a bug or propose a feature (issue templates), the Spec Kit flow used by this project (specify → clarify → plan → tasks → implement, specs/), the constitution's Quality Gates in short with a link to .specify/memory/constitution.md, "Development setup, tests and conventions: see DEVELOPMENT.md" (no duplication, §III), commit messages in the existing style (docs(…), chore: …), and that releases are cut by maintainers (link docs/releasing.md)Markdown2 files
Create CONTRIBUTING.md: how to report a bug or propose a feature (issue templates), the Spec Kit flow used by this project (specify → clarify → plan → tasks → implement, specs/), the constitution's Quality Gates in short with a link to .specify/memory/constitution.md, "Development setup, tests and conventions: see DEVELOPMENT.md" (no duplication, §III), commit messages in the existing style (docs(…), chore: …), and that releases are cut by maintainers (link docs/releasing.md)
- US5
- Parallel
T038Create CODE_OF_CONDUCT.md from the Contributor Covenant 2.1 text; leave the enforcement contact as the literal placeholder [INSERT CONTACT METHOD] and leave it for the maintainer task T049 — do not invent or insert any personal address (research R13)
Create CODE_OF_CONDUCT.md from the Contributor Covenant 2.1 text; leave the enforcement contact as the literal placeholder [INSERT CONTACT METHOD] and leave it for the maintainer task T049 — do not invent or insert any personal address (research R13)
- US5
- Parallel
T039Create SECURITY.md: supported versions table (latest 1.x minor: supported; older: not), how to report — GitHub private vulnerability reporting (https://github.com/SerafAC/speckit-eye/security/advisories/new), what to include, expected first response within 7 days, coordinated disclosure; scope notes (serve mode listens on loopback only, the tool is read-only)
Create SECURITY.md: supported versions table (latest 1.x minor: supported; older: not), how to report — GitHub private vulnerability reporting (https://github.com/SerafAC/speckit-eye/security/advisories/new), what to include, expected first response within 7 days, coordinated disclosure; scope notes (serve mode listens on loopback only, the tool is read-only)
- US5
- Parallel
T040Create .github/ISSUE_TEMPLATE/bug_report.yml (fields: speckit-eye version, Node.js version, OS, command run, what happened, expected, tasks.md/spec excerpt if relevant), .github/ISSUE_TEMPLATE/feature_request.yml (problem, proposed solution, alternatives), and .github/ISSUE_TEMPLATE/config.yml (blank_issues_enabled: false; contact link "Report a security vulnerability" → the private advisory URL; contact link "Documentation" → https://serafac.github.io/speckit-eye/)YAML3 files
Create .github/ISSUE_TEMPLATE/bug_report.yml (fields: speckit-eye version, Node.js version, OS, command run, what happened, expected, tasks.md/spec excerpt if relevant), .github/ISSUE_TEMPLATE/feature_request.yml (problem, proposed solution, alternatives), and .github/ISSUE_TEMPLATE/config.yml (blank_issues_enabled: false; contact link "Report a security vulnerability" → the private advisory URL; contact link "Documentation" → https://serafac.github.io/speckit-eye/)
- US5
- Parallel
T041Create .github/pull_request_template.md: summary, linked spec/issue, and a checklist of the Quality Gates — unit tests (§IV), E2E tests with USn FR-xxx names (§V), CHANGELOG.md Unreleased entry for user-visible changes (§VI), docs/ / README.md / DEVELOPMENT.md updated where affected (§VII–IX), no unjustified complexity (§I–III)Markdownpull_request_template.md
Create .github/pull_request_template.md: summary, linked spec/issue, and a checklist of the Quality Gates — unit tests (§IV), E2E tests with USn FR-xxx names (§V), CHANGELOG.md Unreleased entry for user-visible changes (§VI), docs/ / README.md / DEVELOPMENT.md updated where affected (§VII–IX), no unjustified complexity (§I–III)
- US5
- Parallel
T042Create .github/dependabot.yml (contracts/workflows.md): version: 2; ecosystems npm (directory /) and github-actions (directory /), schedule.interval: weekly, one group per ecosystem for minor and patch updates (FR-031)YAMLdependabot.yml
Create .github/dependabot.yml (contracts/workflows.md): version: 2; ecosystems npm (directory /) and github-actions (directory /), schedule.interval: weekly, one group per ecosystem for minor and patch updates (FR-031)
- US5
- Parallel
- FR-031
T043Add badges to the top of README.md under the title: CI (https://github.com/SerafAC/speckit-eye/actions/workflows/ci.yml/badge.svg → the workflow page), npm version (https://img.shields.io/npm/v/speckit-eye → https://www.npmjs.com/package/speckit-eye), license (https://img.shields.io/npm/l/speckit-eye → LICENSE); add a "Contributing" section at the end linking CONTRIBUTING.md, CODE_OF_CONDUCT.md and SECURITY.md (FR-030; user-facing, §VIII)SVGbadge.svg
Add badges to the top of README.md under the title: CI (https://github.com/SerafAC/speckit-eye/actions/workflows/ci.yml/badge.svg → the workflow page), npm version (https://img.shields.io/npm/v/speckit-eye → https://www.npmjs.com/package/speckit-eye), license (https://img.shields.io/npm/l/speckit-eye → LICENSE); add a "Contributing" section at the end linking CONTRIBUTING.md, CODE_OF_CONDUCT.md and SECURITY.md (FR-030; user-facing, §VIII)
- US5
- FR-030
T044Create E2E suite tests/e2e/repo-health.spec.js (tooling project, file checks only): 003 US5 FR-028 contribution guidelines, code of conduct and security policy exist and are linked from README; 003 US5 FR-029 issue templates for bugs and features and a PR template with the quality gates exist (parse the YAML templates' name/body; PR template mentions CHANGELOG and tests); 003 US5 FR-030 README shows CI, npm and license badges; 003 US5 FR-031 Dependabot watches npm and GitHub Actions; 003 US5 FR-014 every third-party action in .github/workflows is pinned to a commit SHA (regex over uses: lines, allowing only local ./ paths and 40-hex SHAs) and every workflow sets top-level permissionsJavaScript testrepo-health.spec.js
Create E2E suite tests/e2e/repo-health.spec.js (tooling project, file checks only): 003 US5 FR-028 contribution guidelines, code of conduct and security policy exist and are linked from README; 003 US5 FR-029 issue templates for bugs and features and a PR template with the quality gates exist (parse the YAML templates' name/body; PR template mentions CHANGELOG and tests); 003 US5 FR-030 README shows CI, npm and license badges; 003 US5 FR-031 Dependabot watches npm and GitHub Actions; 003 US5 FR-014 every third-party action in .github/workflows is pinned to a commit SHA (regex over uses: lines, allowing only local ./ paths and 40-hex SHAs) and every workflow sets top-level permissions
- US5
- FR-028
- FR-029
- FR-030
- FR-031
- FR-014
Phase 8Polish & Cross-Cutting Concerns4/7
T045Add entries under ## [Unreleased] in CHANGELOG.md (FR-032): Added — speckit-eye is published on npm (npx speckit-eye); the --home <url> build option; a documentation website with this project's live status dashboard; contributing guide, code of conduct, security policy. Changed — screenshots moved to docs/assets/
Add entries under ## [Unreleased] in CHANGELOG.md (FR-032): Added — speckit-eye is published on npm (npx speckit-eye); the --home <url> build option; a documentation website with this project's live status dashboard; contributing guide, code of conduct, security policy. Changed — screenshots moved to docs/assets/
- FR-032
T046Update docs/architecture.md: new sections "Release automation" (bump → PR → release run; scripts/release/release.js commands; where each FR-009–FR-017 check happens; link docs/releasing.md) and "Documentation site" (docmd from docs/, scripts/build-site.js, /status/ dashboard, pages.yml); --home in the CLI sectionMarkdown4 files
Update docs/architecture.md: new sections "Release automation" (bump → PR → release run; scripts/release/release.js commands; where each FR-009–FR-017 check happens; link docs/releasing.md) and "Documentation site" (docmd from docs/, scripts/build-site.js, /status/ dashboard, pages.yml); --home in the CLI section
- Parallel
- FR-009
- FR-017
T047Update DEVELOPMENT.md: pnpm run docs:build and pnpm exec docmd dev for previewing docs, site/ output, the tooling Playwright project and the 003 USn FR-xxx test naming for this feature, scripts/build-site.js and docmd.config.js in "Project structure"; note that the tooling suites need registry access (release-package.spec.js installs the packed tarball with npm install, which fetches markdown-it)JavaScriptbuild-site.js
Update DEVELOPMENT.md: pnpm run docs:build and pnpm exec docmd dev for previewing docs, site/ output, the tooling Playwright project and the 003 USn FR-xxx test naming for this feature, scripts/build-site.js and docmd.config.js in "Project structure"; note that the tooling suites need registry access (release-package.spec.js installs the packed tarball with npm install, which fetches markdown-it)
- Parallel
T048Run the full local validation (quickstart §1–4): pnpm test, pnpm run test:e2e --project tooling, pnpm run test:e2e --project chromium --project chromium-nojs --project chromium-mobile, pnpm run docs:build && pnpm exec docmd validate, pnpm pack + pack-check; fix any failure; run actionlint on .github/workflows/*.yml if available
Run the full local validation (quickstart §1–4): pnpm test, pnpm run test:e2e --project tooling, pnpm run test:e2e --project chromium --project chromium-nojs --project chromium-mobile, pnpm run docs:build && pnpm exec docmd validate, pnpm pack + pack-check; fix any failure; run actionlint on .github/workflows/*.yml if available
T049Maintainer (outside the repository, cannot be automated): provide the Code of Conduct contact and replace [INSERT CONTACT METHOD] in CODE_OF_CONDUCT.md; then perform the one-time setup of docs/releasing.md "One-time setup" (quickstart §5)Markdownreleasing.md
Maintainer (outside the repository, cannot be automated): provide the Code of Conduct contact and replace [INSERT CONTACT METHOD] in CODE_OF_CONDUCT.md; then perform the one-time setup of docs/releasing.md "One-time setup" (quickstart §5)
T050Maintainer: after this feature is merged to main, confirm the Pages deploy published https://serafac.github.io/speckit-eye/ and /status/ (SC-005), then cut the first release following docs/releasing.md "The first release" — Bump version with explicit / 1.0.0, merge the PR, review and approve the Release run — and verify (quickstart §6): npm view speckit-eye version → 1.0.0, provenance shown on npmjs.com, tag v1.0.0, GitHub release notes = changelog section (SC-004); then switch to trusted publishing and delete NPM_TOKENMarkdownreleasing.md
Maintainer: after this feature is merged to main, confirm the Pages deploy published https://serafac.github.io/speckit-eye/ and /status/ (SC-005), then cut the first release following docs/releasing.md "The first release" — Bump version with explicit / 1.0.0, merge the PR, review and approve the Release run — and verify (quickstart §6): npm view speckit-eye version → 1.0.0, provenance shown on npmjs.com, tag v1.0.0, GitHub release notes = changelog section (SC-004); then switch to trusted publishing and delete NPM_TOKEN
- SC-005
- SC-004
T051Maintainer: run the negative checks of quickstart §7 — hand-pushed mismatching tag, re-dispatch on v1.0.0 (already on npm), bump with empty Unreleased, and a tag on a scratch-branch commit with a deliberately failing unit test (fails both ci and the "on main" check) — and confirm nothing is published in any of them (SC-003); delete the scratch tag and branch
Maintainer: run the negative checks of quickstart §7 — hand-pushed mismatching tag, re-dispatch on v1.0.0 (already on npm), bump with empty Unreleased, and a tag on a scratch-branch commit with a deliberately failing unit test (fails both ci and the "on main" check) — and confirm nothing is published in any of them (SC-003); delete the scratch tag and branch
- SC-003
No tasks match the filters.
tasks.md