@warpgogol/forge 5.2.4 → 5.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.uk.md +8 -8
- package/bin/cli.ts +25 -33
- package/dist/bin/cli.js +21 -32
- package/dist/bin/cli.js.map +1 -1
- package/dist/os/adr/adr.module.d.ts.map +1 -1
- package/dist/os/adr/adr.module.js +8 -3
- package/dist/os/adr/adr.module.js.map +1 -1
- package/dist/os/adr/frontmatter-io.js +5 -5
- package/dist/os/adr/frontmatter-io.js.map +1 -1
- package/dist/os/adr/handlers/archive.d.ts.map +1 -1
- package/dist/os/adr/handlers/archive.js +10 -4
- package/dist/os/adr/handlers/archive.js.map +1 -1
- package/dist/os/adr/handlers/implement-stamp.d.ts.map +1 -1
- package/dist/os/adr/handlers/implement-stamp.js +10 -10
- package/dist/os/adr/handlers/implement-stamp.js.map +1 -1
- package/dist/os/adr/handlers/list-create.js +5 -5
- package/dist/os/adr/handlers/list-create.js.map +1 -1
- package/dist/os/adr/handlers/validate.js +1 -1
- package/dist/os/adr/handlers/validate.js.map +1 -1
- package/dist/os/audit/audit.module.js +3 -3
- package/dist/os/audit/audit.module.js.map +1 -1
- package/dist/os/audit/frontmatter-io.js +5 -5
- package/dist/os/audit/frontmatter-io.js.map +1 -1
- package/dist/os/audit/handlers/archive.d.ts.map +1 -1
- package/dist/os/audit/handlers/archive.js +10 -4
- package/dist/os/audit/handlers/archive.js.map +1 -1
- package/dist/os/compass/compass.module.d.ts.map +1 -1
- package/dist/os/compass/compass.module.js +17 -1
- package/dist/os/compass/compass.module.js.map +1 -1
- package/dist/os/compass/handlers/compass-audit-handler.d.ts.map +1 -1
- package/dist/os/compass/handlers/compass-audit-handler.js +12 -5
- package/dist/os/compass/handlers/compass-audit-handler.js.map +1 -1
- package/dist/os/compass/handlers/compass-change-summary-handler.d.ts.map +1 -1
- package/dist/os/compass/handlers/compass-change-summary-handler.js +3 -2
- package/dist/os/compass/handlers/compass-change-summary-handler.js.map +1 -1
- package/dist/os/compass/handlers/compass-inventory-handler.d.ts.map +1 -1
- package/dist/os/compass/handlers/compass-inventory-handler.js +6 -4
- package/dist/os/compass/handlers/compass-inventory-handler.js.map +1 -1
- package/dist/os/compass/handlers/compass-inventory.d.ts.map +1 -1
- package/dist/os/compass/handlers/compass-inventory.js +10 -8
- package/dist/os/compass/handlers/compass-inventory.js.map +1 -1
- package/dist/os/compass/handlers/compass-migrate-handler.js +1 -1
- package/dist/os/compass/handlers/compass-migrate-handler.js.map +1 -1
- package/dist/os/compass/handlers/compass-migrate.d.ts.map +1 -1
- package/dist/os/compass/handlers/compass-migrate.js +6 -3
- package/dist/os/compass/handlers/compass-migrate.js.map +1 -1
- package/dist/os/compass/handlers/git-revision.d.ts.map +1 -1
- package/dist/os/compass/handlers/git-revision.js +9 -6
- package/dist/os/compass/handlers/git-revision.js.map +1 -1
- package/dist/os/compass/handlers/resolve-scan-root.js +1 -1
- package/dist/os/compass/handlers/resolve-scan-root.js.map +1 -1
- package/dist/os/compass/handlers/summary-record.d.ts.map +1 -1
- package/dist/os/compass/handlers/summary-record.js +8 -4
- package/dist/os/compass/handlers/summary-record.js.map +1 -1
- package/dist/os/core/core.module.d.ts.map +1 -1
- package/dist/os/core/core.module.js +43 -4
- package/dist/os/core/core.module.js.map +1 -1
- package/dist/os/core/handlers/assets-helpers.d.ts.map +1 -1
- package/dist/os/core/handlers/assets-helpers.js +6 -3
- package/dist/os/core/handlers/assets-helpers.js.map +1 -1
- package/dist/os/core/handlers/build.js +1 -1
- package/dist/os/core/handlers/build.js.map +1 -1
- package/dist/os/core/handlers/determinism-check.d.ts.map +1 -1
- package/dist/os/core/handlers/determinism-check.js +10 -6
- package/dist/os/core/handlers/determinism-check.js.map +1 -1
- package/dist/os/core/handlers/dev.js +1 -1
- package/dist/os/core/handlers/dev.js.map +1 -1
- package/dist/os/core/handlers/file-size-lint.d.ts.map +1 -1
- package/dist/os/core/handlers/file-size-lint.js +11 -7
- package/dist/os/core/handlers/file-size-lint.js.map +1 -1
- package/dist/os/core/handlers/forge-autonomy-validate.d.ts.map +1 -1
- package/dist/os/core/handlers/forge-autonomy-validate.js +9 -5
- package/dist/os/core/handlers/forge-autonomy-validate.js.map +1 -1
- package/dist/os/core/handlers/knowledge-compact.js +1 -1
- package/dist/os/core/handlers/knowledge-compact.js.map +1 -1
- package/dist/os/core/handlers/package-health.js +1 -1
- package/dist/os/core/handlers/package-health.js.map +1 -1
- package/dist/os/core/handlers/pinned-check.js +2 -2
- package/dist/os/core/handlers/pinned-check.js.map +1 -1
- package/dist/os/core/handlers/pinned-init.d.ts.map +1 -1
- package/dist/os/core/handlers/pinned-init.js +9 -8
- package/dist/os/core/handlers/pinned-init.js.map +1 -1
- package/dist/os/core/handlers/pinned-validate.js +3 -3
- package/dist/os/core/handlers/pinned-validate.js.map +1 -1
- package/dist/os/core/handlers/profile-resolve.js +1 -1
- package/dist/os/core/handlers/profile-resolve.js.map +1 -1
- package/dist/os/core/handlers/public-surface.js +1 -1
- package/dist/os/core/handlers/public-surface.js.map +1 -1
- package/dist/os/core/handlers/release-prepare.d.ts.map +1 -1
- package/dist/os/core/handlers/release-prepare.js +10 -6
- package/dist/os/core/handlers/release-prepare.js.map +1 -1
- package/dist/os/core/handlers/release-publish.js +6 -6
- package/dist/os/core/handlers/release-publish.js.map +1 -1
- package/dist/os/core/handlers/validate.js +1 -1
- package/dist/os/core/handlers/validate.js.map +1 -1
- package/dist/os/exploration/exploration.module.d.ts.map +1 -1
- package/dist/os/exploration/exploration.module.js +1 -0
- package/dist/os/exploration/exploration.module.js.map +1 -1
- package/dist/os/exploration/frontmatter-io.js +4 -4
- package/dist/os/exploration/frontmatter-io.js.map +1 -1
- package/dist/os/exploration/handlers/archive.js +3 -3
- package/dist/os/exploration/handlers/archive.js.map +1 -1
- package/dist/os/mission/handlers/archive.d.ts.map +1 -1
- package/dist/os/mission/handlers/archive.js +44 -23
- package/dist/os/mission/handlers/archive.js.map +1 -1
- package/dist/os/mission/mission.module.js +3 -3
- package/dist/os/mission/mission.module.js.map +1 -1
- package/dist/os/naming/naming-convention.d.ts.map +1 -1
- package/dist/os/naming/naming-convention.js +7 -3
- package/dist/os/naming/naming-convention.js.map +1 -1
- package/dist/os/naming/naming.module.d.ts.map +1 -1
- package/dist/os/naming/naming.module.js +4 -3
- package/dist/os/naming/naming.module.js.map +1 -1
- package/dist/os/notes/notes.module.d.ts.map +1 -1
- package/dist/os/notes/notes.module.js +6 -3
- package/dist/os/notes/notes.module.js.map +1 -1
- package/dist/os/plan/frontmatter-io.js +5 -5
- package/dist/os/plan/frontmatter-io.js.map +1 -1
- package/dist/os/plan/handlers/archive.d.ts.map +1 -1
- package/dist/os/plan/handlers/archive.js +10 -4
- package/dist/os/plan/handlers/archive.js.map +1 -1
- package/dist/os/plan/plan.module.js +3 -3
- package/dist/os/plan/plan.module.js.map +1 -1
- package/dist/os/plugin/plugin.module.d.ts.map +1 -1
- package/dist/os/plugin/plugin.module.js +6 -3
- package/dist/os/plugin/plugin.module.js.map +1 -1
- package/dist/os/program/discovery.js +2 -2
- package/dist/os/program/discovery.js.map +1 -1
- package/dist/os/program/handlers/complete.js +1 -1
- package/dist/os/program/handlers/complete.js.map +1 -1
- package/dist/os/program/handlers/lease.js +1 -1
- package/dist/os/program/handlers/lease.js.map +1 -1
- package/dist/os/program/handlers/seal.js +1 -1
- package/dist/os/program/handlers/seal.js.map +1 -1
- package/dist/os/program/lease.js +1 -1
- package/dist/os/program/lease.js.map +1 -1
- package/dist/os/program/program.module.d.ts.map +1 -1
- package/dist/os/program/program.module.js +9 -3
- package/dist/os/program/program.module.js.map +1 -1
- package/dist/os/queue/index.js +1 -1
- package/dist/os/queue/manifest.d.ts.map +1 -1
- package/dist/os/queue/manifest.js +4 -8
- package/dist/os/queue/manifest.js.map +1 -1
- package/dist/os/rfc/acceptance.d.ts.map +1 -1
- package/dist/os/rfc/acceptance.js +10 -6
- package/dist/os/rfc/acceptance.js.map +1 -1
- package/dist/os/rfc/decision-log.d.ts.map +1 -1
- package/dist/os/rfc/decision-log.js +4 -3
- package/dist/os/rfc/decision-log.js.map +1 -1
- package/dist/os/rfc/dna-trace.d.ts.map +1 -1
- package/dist/os/rfc/dna-trace.js +7 -2
- package/dist/os/rfc/dna-trace.js.map +1 -1
- package/dist/os/rfc/frontmatter-io.js +5 -5
- package/dist/os/rfc/frontmatter-io.js.map +1 -1
- package/dist/os/rfc/handlers/archive.d.ts.map +1 -1
- package/dist/os/rfc/handlers/archive.js +11 -5
- package/dist/os/rfc/handlers/archive.js.map +1 -1
- package/dist/os/rfc/handlers/check.d.ts.map +1 -1
- package/dist/os/rfc/handlers/check.js +6 -3
- package/dist/os/rfc/handlers/check.js.map +1 -1
- package/dist/os/rfc/handlers/implement-stamp.d.ts.map +1 -1
- package/dist/os/rfc/handlers/implement-stamp.js +11 -10
- package/dist/os/rfc/handlers/implement-stamp.js.map +1 -1
- package/dist/os/rfc/handlers/index-graph.js +3 -3
- package/dist/os/rfc/handlers/index-graph.js.map +1 -1
- package/dist/os/rfc/handlers/lifecycle.d.ts.map +1 -1
- package/dist/os/rfc/handlers/lifecycle.js +6 -2
- package/dist/os/rfc/handlers/lifecycle.js.map +1 -1
- package/dist/os/rfc/handlers/list-create.d.ts.map +1 -1
- package/dist/os/rfc/handlers/list-create.js +7 -6
- package/dist/os/rfc/handlers/list-create.js.map +1 -1
- package/dist/os/rfc/handlers/shared.js +3 -3
- package/dist/os/rfc/handlers/shared.js.map +1 -1
- package/dist/os/rfc/handlers/supersede-propose.d.ts.map +1 -1
- package/dist/os/rfc/handlers/supersede-propose.js +7 -3
- package/dist/os/rfc/handlers/supersede-propose.js.map +1 -1
- package/dist/os/rfc/handlers/validate-rules.d.ts.map +1 -1
- package/dist/os/rfc/handlers/validate-rules.js +8 -5
- package/dist/os/rfc/handlers/validate-rules.js.map +1 -1
- package/dist/os/rfc/handlers/validate.d.ts.map +1 -1
- package/dist/os/rfc/handlers/validate.js +6 -1
- package/dist/os/rfc/handlers/validate.js.map +1 -1
- package/dist/os/rfc/rfc.module.d.ts.map +1 -1
- package/dist/os/rfc/rfc.module.js +44 -4
- package/dist/os/rfc/rfc.module.js.map +1 -1
- package/dist/os/rfc/verification-evidence.d.ts.map +1 -1
- package/dist/os/rfc/verification-evidence.js +9 -5
- package/dist/os/rfc/verification-evidence.js.map +1 -1
- package/dist/os/rfc/verification-refresh.d.ts.map +1 -1
- package/dist/os/rfc/verification-refresh.js +4 -3
- package/dist/os/rfc/verification-refresh.js.map +1 -1
- package/dist/os/session/frontmatter-io.js +12 -12
- package/dist/os/session/frontmatter-io.js.map +1 -1
- package/dist/os/session/handlers/archive.d.ts.map +1 -1
- package/dist/os/session/handlers/archive.js +10 -4
- package/dist/os/session/handlers/archive.js.map +1 -1
- package/dist/os/session/handlers/metrics-aggregate.d.ts.map +1 -1
- package/dist/os/session/handlers/metrics-aggregate.js +9 -5
- package/dist/os/session/handlers/metrics-aggregate.js.map +1 -1
- package/dist/os/session/handlers/metrics-rfc.d.ts.map +1 -1
- package/dist/os/session/handlers/metrics-rfc.js +11 -8
- package/dist/os/session/handlers/metrics-rfc.js.map +1 -1
- package/dist/os/session/handlers/metrics-session.d.ts.map +1 -1
- package/dist/os/session/handlers/metrics-session.js +6 -3
- package/dist/os/session/handlers/metrics-session.js.map +1 -1
- package/dist/os/session/handlers/save.d.ts.map +1 -1
- package/dist/os/session/handlers/save.js +14 -8
- package/dist/os/session/handlers/save.js.map +1 -1
- package/dist/os/session/session.module.d.ts.map +1 -1
- package/dist/os/session/session.module.js +6 -0
- package/dist/os/session/session.module.js.map +1 -1
- package/dist/os/spec/live-spec-list.js +4 -4
- package/dist/os/spec/live-spec-list.js.map +1 -1
- package/dist/os/spec/live-spec-merge.js +5 -5
- package/dist/os/spec/live-spec-merge.js.map +1 -1
- package/dist/os/spec/live-spec-show.js +3 -3
- package/dist/os/spec/live-spec-show.js.map +1 -1
- package/dist/os/spec/live-spec-validate.js +4 -4
- package/dist/os/spec/live-spec-validate.js.map +1 -1
- package/dist/os/spec/spec-materialize.js +9 -9
- package/dist/os/spec/spec-materialize.js.map +1 -1
- package/dist/os/spec/spec-status.js +9 -9
- package/dist/os/spec/spec-status.js.map +1 -1
- package/dist/os/spec/spec-validate.js +7 -7
- package/dist/os/spec/spec-validate.js.map +1 -1
- package/dist/os/spec/spec.module.d.ts.map +1 -1
- package/dist/os/spec/spec.module.js +8 -0
- package/dist/os/spec/spec.module.js.map +1 -1
- package/dist/os/werkstatt/handlers/lock.js +16 -16
- package/dist/os/werkstatt/handlers/lock.js.map +1 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js +3 -3
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js.map +1 -1
- package/dist/os/werkstatt/handlers/werkstatt-operation-validate.d.ts.map +1 -1
- package/dist/os/werkstatt/handlers/werkstatt-operation-validate.js +3 -2
- package/dist/os/werkstatt/handlers/werkstatt-operation-validate.js.map +1 -1
- package/dist/os/werkstatt/handlers/workspace-deps.d.ts.map +1 -1
- package/dist/os/werkstatt/handlers/workspace-deps.js +0 -1
- package/dist/os/werkstatt/handlers/workspace-deps.js.map +1 -1
- package/dist/os/werkstatt/werkstatt.module.d.ts.map +1 -1
- package/dist/os/werkstatt/werkstatt.module.js +6 -2
- package/dist/os/werkstatt/werkstatt.module.js.map +1 -1
- package/dist/os/workflow/handlers.d.ts.map +1 -1
- package/dist/os/workflow/handlers.js +8 -5
- package/dist/os/workflow/handlers.js.map +1 -1
- package/dist/os/workflow/workflow.module.d.ts.map +1 -1
- package/dist/os/workflow/workflow.module.js +6 -3
- package/dist/os/workflow/workflow.module.js.map +1 -1
- package/dist/src/cli-flags.d.ts +28 -0
- package/dist/src/cli-flags.d.ts.map +1 -0
- package/dist/src/cli-flags.js +232 -0
- package/dist/src/cli-flags.js.map +1 -0
- package/dist/src/compass/contract-registry.js +1 -1
- package/dist/src/compass/contract-registry.js.map +1 -1
- package/dist/src/config/forge-config.d.ts +1 -1
- package/dist/src/config/forge-config.js +1 -1
- package/dist/src/config/forge-config.js.map +1 -1
- package/dist/src/knowledge/budgets.js +1 -1
- package/dist/src/knowledge/budgets.js.map +1 -1
- package/dist/src/knowledge/compact.js +1 -1
- package/dist/src/knowledge/compact.js.map +1 -1
- package/dist/src/knowledge/parse.js +1 -1
- package/dist/src/knowledge/parse.js.map +1 -1
- package/dist/src/knowledge/sync.d.ts.map +1 -1
- package/dist/src/knowledge/sync.js +3 -5
- package/dist/src/knowledge/sync.js.map +1 -1
- package/dist/src/migration-adapters/git-utils.js +2 -2
- package/dist/src/migration-adapters/git-utils.js.map +1 -1
- package/dist/src/migration-adapters/ignored-files.js +2 -2
- package/dist/src/migration-adapters/ignored-files.js.map +1 -1
- package/dist/src/migration-adapters/node-typescript-pnpm/index.js +1 -1
- package/dist/src/migration-adapters/node-typescript-pnpm/index.js.map +1 -1
- package/dist/src/migration-adapters/phaser-pnpm/index.js +1 -1
- package/dist/src/migration-adapters/phaser-pnpm/index.js.map +1 -1
- package/dist/src/onboarding/agents-generate.d.ts.map +1 -1
- package/dist/src/onboarding/agents-generate.js +76 -34
- package/dist/src/onboarding/agents-generate.js.map +1 -1
- package/dist/src/onboarding/create.d.ts.map +1 -1
- package/dist/src/onboarding/create.js +10 -10
- package/dist/src/onboarding/create.js.map +1 -1
- package/dist/src/onboarding/doctor.d.ts.map +1 -1
- package/dist/src/onboarding/doctor.js +68 -59
- package/dist/src/onboarding/doctor.js.map +1 -1
- package/dist/src/onboarding/init.d.ts.map +1 -1
- package/dist/src/onboarding/init.js +30 -1
- package/dist/src/onboarding/init.js.map +1 -1
- package/dist/src/onboarding/invariant-engine.js +1 -1
- package/dist/src/onboarding/invariant-engine.js.map +1 -1
- package/dist/src/onboarding/memory-compact.d.ts.map +1 -1
- package/dist/src/onboarding/memory-compact.js +5 -4
- package/dist/src/onboarding/memory-compact.js.map +1 -1
- package/dist/src/onboarding/memory-scaffold.js +1 -1
- package/dist/src/onboarding/memory-scaffold.js.map +1 -1
- package/dist/src/onboarding/nested-agents-generate.d.ts +4 -1
- package/dist/src/onboarding/nested-agents-generate.d.ts.map +1 -1
- package/dist/src/onboarding/nested-agents-generate.js +34 -5
- package/dist/src/onboarding/nested-agents-generate.js.map +1 -1
- package/dist/src/onboarding/nested-agents-templates.d.ts.map +1 -1
- package/dist/src/onboarding/nested-agents-templates.js +8 -12
- package/dist/src/onboarding/nested-agents-templates.js.map +1 -1
- package/dist/src/onboarding/npm-token-check.js +2 -2
- package/dist/src/onboarding/npm-token-check.js.map +1 -1
- package/dist/src/onboarding/prettierignore.d.ts +29 -0
- package/dist/src/onboarding/prettierignore.d.ts.map +1 -0
- package/dist/src/onboarding/prettierignore.js +231 -0
- package/dist/src/onboarding/prettierignore.js.map +1 -0
- package/dist/src/onboarding/profile-validate.d.ts.map +1 -1
- package/dist/src/onboarding/profile-validate.js +5 -4
- package/dist/src/onboarding/profile-validate.js.map +1 -1
- package/dist/src/onboarding/scaffold-project.d.ts.map +1 -1
- package/dist/src/onboarding/scaffold-project.js +35 -27
- package/dist/src/onboarding/scaffold-project.js.map +1 -1
- package/dist/src/onboarding/scaffold.js +1 -1
- package/dist/src/onboarding/scaffold.js.map +1 -1
- package/dist/src/onboarding/skill-markers.d.ts +27 -0
- package/dist/src/onboarding/skill-markers.d.ts.map +1 -0
- package/dist/src/onboarding/skill-markers.js +131 -0
- package/dist/src/onboarding/skill-markers.js.map +1 -0
- package/dist/src/onboarding/upgrade.d.ts +10 -0
- package/dist/src/onboarding/upgrade.d.ts.map +1 -1
- package/dist/src/onboarding/upgrade.js +215 -74
- package/dist/src/onboarding/upgrade.js.map +1 -1
- package/dist/src/onboarding/workspace-discovery.js +1 -1
- package/dist/src/onboarding/workspace-discovery.js.map +1 -1
- package/dist/src/pipeline-status.d.ts +6 -5
- package/dist/src/pipeline-status.d.ts.map +1 -1
- package/dist/src/pipeline-status.js +24 -19
- package/dist/src/pipeline-status.js.map +1 -1
- package/dist/src/profiles/stack-profile.js +1 -1
- package/dist/src/profiles/stack-profile.js.map +1 -1
- package/dist/src/registry.d.ts +1 -1
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +3 -3
- package/dist/src/registry.js.map +1 -1
- package/dist/src/skill-schema.d.ts +1 -1
- package/dist/src/skill-schema.d.ts.map +1 -1
- package/dist/src/skill-schema.js +4 -1
- package/dist/src/skill-schema.js.map +1 -1
- package/dist/src/types.d.ts +116 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/editable-region.d.ts +46 -0
- package/dist/src/utils/editable-region.d.ts.map +1 -0
- package/dist/src/utils/editable-region.js +125 -0
- package/dist/src/utils/editable-region.js.map +1 -0
- package/dist/src/utils/fs-idempotent.d.ts +2 -1
- package/dist/src/utils/fs-idempotent.d.ts.map +1 -1
- package/dist/src/utils/fs-idempotent.js +11 -7
- package/dist/src/utils/fs-idempotent.js.map +1 -1
- package/dist/src/utils/generated-marker.d.ts +17 -0
- package/dist/src/utils/generated-marker.d.ts.map +1 -1
- package/dist/src/utils/generated-marker.js +29 -1
- package/dist/src/utils/generated-marker.js.map +1 -1
- package/dist/src/utils/index.d.ts +3 -1
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +3 -1
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/utils/io.d.ts +9 -0
- package/dist/src/utils/io.d.ts.map +1 -0
- package/dist/src/utils/io.js +130 -0
- package/dist/src/utils/io.js.map +1 -0
- package/dist/src/utils/markdown-table.d.ts +21 -0
- package/dist/src/utils/markdown-table.d.ts.map +1 -0
- package/dist/src/utils/markdown-table.js +116 -0
- package/dist/src/utils/markdown-table.js.map +1 -0
- package/dist/src/utils/sync-fs.d.ts +5 -0
- package/dist/src/utils/sync-fs.d.ts.map +1 -0
- package/dist/src/utils/sync-fs.js +26 -0
- package/dist/src/utils/sync-fs.js.map +1 -0
- package/dist/src/validators/note-frontmatter-validate.js +1 -1
- package/dist/src/validators/note-frontmatter-validate.js.map +1 -1
- package/dist/src/validators/note-link-validate.js +1 -1
- package/dist/src/validators/note-link-validate.js.map +1 -1
- package/dist/src/validators/note-orphan-detect.js +1 -1
- package/dist/src/validators/note-orphan-detect.js.map +1 -1
- package/dist/src/validators/port-validate.js +1 -1
- package/dist/src/validators/port-validate.js.map +1 -1
- package/dist/src/validators/skill-validate.d.ts.map +1 -1
- package/dist/src/validators/skill-validate.js +34 -13
- package/dist/src/validators/skill-validate.js.map +1 -1
- package/os/adr/adr.module.ts +136 -132
- package/os/adr/frontmatter-io.ts +5 -5
- package/os/adr/handlers/archive.ts +8 -4
- package/os/adr/handlers/implement-stamp.ts +14 -10
- package/os/adr/handlers/list-create.ts +5 -5
- package/os/adr/handlers/validate.ts +1 -1
- package/os/audit/audit.module.ts +33 -34
- package/os/audit/frontmatter-io.ts +5 -5
- package/os/audit/handlers/archive.ts +8 -4
- package/os/compass/compass.module.ts +17 -1
- package/os/compass/handlers/compass-audit-handler.ts +13 -5
- package/os/compass/handlers/compass-change-summary-handler.ts +4 -2
- package/os/compass/handlers/compass-inventory-handler.ts +7 -4
- package/os/compass/handlers/compass-inventory.ts +11 -8
- package/os/compass/handlers/compass-migrate-handler.ts +1 -1
- package/os/compass/handlers/compass-migrate.ts +7 -3
- package/os/compass/handlers/git-revision.ts +11 -6
- package/os/compass/handlers/resolve-scan-root.ts +1 -1
- package/os/compass/handlers/summary-record.ts +10 -4
- package/os/compass/handlers/tests/compass-audit-plan.test.ts +2 -1
- package/os/core/core.module.ts +43 -4
- package/os/core/handlers/assets-helpers.ts +7 -3
- package/os/core/handlers/build.ts +1 -1
- package/os/core/handlers/determinism-check.ts +12 -6
- package/os/core/handlers/dev.ts +1 -1
- package/os/core/handlers/file-size-lint.ts +16 -9
- package/os/core/handlers/forge-autonomy-validate.ts +10 -5
- package/os/core/handlers/knowledge-compact.ts +1 -1
- package/os/core/handlers/package-health.ts +1 -1
- package/os/core/handlers/pinned-check.ts +2 -2
- package/os/core/handlers/pinned-init.ts +9 -8
- package/os/core/handlers/pinned-validate.ts +3 -3
- package/os/core/handlers/profile-resolve.ts +1 -1
- package/os/core/handlers/public-surface.ts +1 -1
- package/os/core/handlers/release-prepare.ts +11 -6
- package/os/core/handlers/release-publish.ts +6 -6
- package/os/core/handlers/validate.ts +1 -1
- package/os/exploration/exploration.module.ts +1 -0
- package/os/exploration/frontmatter-io.ts +4 -4
- package/os/exploration/handlers/archive.ts +3 -3
- package/os/mission/handlers/archive.test.ts +38 -1
- package/os/mission/handlers/archive.ts +54 -23
- package/os/mission/mission.module.ts +38 -39
- package/os/naming/naming-convention.ts +9 -3
- package/os/naming/naming.module.ts +25 -25
- package/os/notes/notes.module.ts +87 -85
- package/os/plan/frontmatter-io.ts +5 -5
- package/os/plan/handlers/archive.ts +8 -4
- package/os/plan/plan.module.ts +33 -34
- package/os/plugin/plugin.module.ts +8 -6
- package/os/program/discovery.ts +2 -2
- package/os/program/handlers/complete.ts +1 -1
- package/os/program/handlers/lease.ts +1 -1
- package/os/program/handlers/seal.ts +1 -1
- package/os/program/lease.ts +1 -1
- package/os/program/program.module.ts +198 -193
- package/os/queue/index.ts +1 -1
- package/os/queue/manifest.ts +10 -9
- package/os/queue/queue-validate.test.ts +6 -15
- package/os/rfc/acceptance.ts +12 -6
- package/os/rfc/decision-log.ts +4 -3
- package/os/rfc/dna-trace.ts +8 -2
- package/os/rfc/frontmatter-io.ts +5 -5
- package/os/rfc/handlers/archive.ts +9 -5
- package/os/rfc/handlers/check.ts +5 -3
- package/os/rfc/handlers/implement-stamp.ts +15 -10
- package/os/rfc/handlers/index-graph.ts +3 -3
- package/os/rfc/handlers/lifecycle.ts +7 -2
- package/os/rfc/handlers/list-create.ts +7 -6
- package/os/rfc/handlers/shared.ts +3 -3
- package/os/rfc/handlers/supersede-propose.ts +8 -3
- package/os/rfc/handlers/validate-rules-rfc1006.test.ts +18 -6
- package/os/rfc/handlers/validate-rules.ts +10 -5
- package/os/rfc/handlers/validate.test.ts +71 -0
- package/os/rfc/handlers/validate.ts +6 -1
- package/os/rfc/rfc-create-concurrent.test.ts +11 -3
- package/os/rfc/rfc.module.ts +413 -374
- package/os/rfc/verification-evidence.ts +11 -5
- package/os/rfc/verification-refresh.ts +4 -3
- package/os/session/frontmatter-io.ts +14 -14
- package/os/session/handlers/archive.ts +8 -4
- package/os/session/handlers/metrics-aggregate.ts +34 -13
- package/os/session/handlers/metrics-rfc.ts +13 -8
- package/os/session/handlers/metrics-session.ts +7 -3
- package/os/session/handlers/save.ts +12 -8
- package/os/session/session.module.ts +6 -0
- package/os/spec/live-spec-list.ts +4 -4
- package/os/spec/live-spec-merge.ts +5 -5
- package/os/spec/live-spec-show.ts +3 -3
- package/os/spec/live-spec-validate.ts +4 -4
- package/os/spec/spec-materialize.ts +9 -9
- package/os/spec/spec-status.ts +9 -9
- package/os/spec/spec-validate.ts +7 -7
- package/os/spec/spec.module.ts +8 -0
- package/os/werkstatt/handlers/lock.ts +16 -16
- package/os/werkstatt/handlers/werkstatt-lock-recover.ts +3 -3
- package/os/werkstatt/handlers/werkstatt-operation-validate.ts +4 -2
- package/os/werkstatt/handlers/workspace-deps.ts +0 -1
- package/os/werkstatt/werkstatt.module.ts +8 -5
- package/os/workflow/handlers.ts +7 -5
- package/os/workflow/workflow.module.ts +45 -44
- package/package.json +1 -1
- package/profiles/forge-shell.yaml +1 -1
- package/profiles/godot-game.yaml +1 -1
- package/profiles/knowledge.yaml +1 -1
- package/profiles/phaser-game.yaml +1 -1
- package/profiles/site-workshop.yaml +1 -1
- package/profiles/typescript.yaml +1 -1
- package/skills/fo/fo-add-tests/SKILL.md +2 -2
- package/skills/fo/fo-architecture/SKILL.md +2 -2
- package/skills/fo/fo-compass-annotate/SKILL.md +2 -2
- package/skills/fo/fo-design-summit/SKILL.md +2 -2
- package/skills/fo/fo-doc-audit/SKILL.md +2 -2
- package/skills/fo/fo-explore/SKILL.md +2 -2
- package/skills/fo/fo-extract-dna/SKILL.md +2 -2
- package/skills/fo/fo-fix/SKILL.md +2 -2
- package/skills/fo/fo-handoff/SKILL.md +2 -2
- package/skills/fo/fo-harvest/SKILL.md +2 -2
- package/skills/fo/fo-idea/SKILL.md +2 -2
- package/skills/fo/fo-idea-audit/SKILL.md +2 -2
- package/skills/fo/fo-idea-create-adr/SKILL.md +3 -3
- package/skills/fo/fo-idea-create-rfc/SKILL.md +3 -3
- package/skills/fo/fo-idea-enhance/SKILL.md +2 -2
- package/skills/fo/fo-idea-i-just-want-to-see-the-plan/SKILL.md +2 -2
- package/skills/fo/fo-idea-i-just-want-to-see-the-result/SKILL.md +1 -1
- package/skills/fo/fo-idea-implement/SKILL.md +2 -2
- package/skills/fo/fo-idea-plan/SKILL.md +2 -2
- package/skills/fo/fo-idea-status/SKILL.md +2 -2
- package/skills/fo/fo-knowledge-distill/SKILL.md +2 -2
- package/skills/fo/fo-memory-sync/SKILL.md +2 -2
- package/skills/fo/fo-qa/SKILL.md +2 -2
- package/skills/fo/fo-review/SKILL.md +2 -2
- package/skills/fo/fo-session-retro/SKILL.md +2 -2
- package/skills/fo/fo-session-save/SKILL.md +2 -2
- package/skills/fo/fo-spec-ingest/SKILL.md +2 -2
- package/skills/fo/fo-step-commit/SKILL.md +1 -1
- package/skills/fo/fo-triage/SKILL.md +2 -2
- package/skills/meta/forge-bootstrap/SKILL.md +1 -1
- package/skills/meta/port-to-forge/SKILL.md +1 -1
- package/skills/meta/skill-create/SKILL.md +1 -1
- package/skills/shared/grilling/SKILL.md +1 -1
- package/skills/shared/grilling/learned-principles.archive.md +17 -0
- package/skills/shared/grilling/learned-principles.md +0 -1
- package/skills/shared/knowledge/learned-principles.md +6 -0
- package/skills/shared/my-preferences/SKILL.md +1 -1
- package/skills/shared/windows-ai-tooling/SKILL.md +1 -1
- package/skills/shared/writing-great-skills/SKILL.md +1 -1
- package/src/cli-flags.ts +285 -0
- package/src/compass/contract-registry.ts +1 -1
- package/src/config/forge-config.ts +1 -1
- package/src/knowledge/__tests__/sync.test.ts +2 -7
- package/src/knowledge/budgets.ts +1 -1
- package/src/knowledge/compact.ts +1 -1
- package/src/knowledge/parse.ts +1 -1
- package/src/knowledge/sync.ts +3 -5
- package/src/migration-adapters/git-utils.ts +2 -2
- package/src/migration-adapters/ignored-files.ts +2 -2
- package/src/migration-adapters/node-typescript-pnpm/index.ts +1 -1
- package/src/migration-adapters/phaser-pnpm/index.ts +1 -1
- package/src/onboarding/agents-generate.ts +92 -36
- package/src/onboarding/create.ts +10 -10
- package/src/onboarding/doctor.ts +70 -55
- package/src/onboarding/init.ts +38 -1
- package/src/onboarding/invariant-engine.ts +1 -1
- package/src/onboarding/memory-compact.ts +5 -4
- package/src/onboarding/memory-scaffold.ts +1 -1
- package/src/onboarding/nested-agents-generate.ts +45 -4
- package/src/onboarding/nested-agents-templates.ts +19 -13
- package/src/onboarding/npm-token-check.ts +2 -2
- package/src/onboarding/prettierignore.ts +263 -0
- package/src/onboarding/profile-validate.ts +5 -4
- package/src/onboarding/scaffold-project.ts +38 -27
- package/src/onboarding/scaffold.ts +1 -1
- package/src/onboarding/skill-markers.ts +162 -0
- package/src/onboarding/templates/behavioral-layer-core.md +2 -4
- package/src/onboarding/upgrade.ts +285 -89
- package/src/onboarding/workspace-discovery.ts +1 -1
- package/src/pipeline-status.test.ts +1 -4
- package/src/pipeline-status.ts +30 -13
- package/src/profiles/stack-profile.ts +1 -1
- package/src/registry.ts +4 -4
- package/src/skill-schema.ts +4 -1
- package/src/tests/acceptance-probe-kinds.test.ts +5 -15
- package/src/tests/agents-generate.test.ts +28 -5
- package/src/tests/cli-flags.test.ts +169 -0
- package/src/tests/contract-registry.test.ts +12 -6
- package/src/tests/doctor-fix.test.ts +1 -4
- package/src/tests/doctor-nested-agents.test.ts +53 -1
- package/src/tests/editable-generated-region.test.ts +231 -0
- package/src/tests/file-size-lint.test.ts +8 -12
- package/src/tests/fixtures/agents-generate-business-before.txt +85 -56
- package/src/tests/markdown-table.test.ts +107 -0
- package/src/tests/prettierignore-manage.test.ts +134 -0
- package/src/tests/skill-agents-sync.test.ts +168 -0
- package/src/tests/skill-sync-marker.test.ts +134 -0
- package/src/tests/skill-validate.test.ts +12 -5
- package/src/tests/upgrade.test.ts +87 -41
- package/src/types.ts +123 -0
- package/src/utils/editable-region.ts +156 -0
- package/src/utils/fs-idempotent.ts +12 -6
- package/src/utils/generated-marker.ts +36 -2
- package/src/utils/index.ts +17 -0
- package/src/utils/io.ts +143 -0
- package/src/utils/markdown-table.ts +121 -0
- package/src/utils/sync-fs.ts +43 -0
- package/src/validators/note-frontmatter-validate.ts +1 -1
- package/src/validators/note-link-validate.ts +1 -1
- package/src/validators/note-orphan-detect.ts +1 -1
- package/src/validators/port-validate.ts +1 -1
- package/src/validators/skill-validate.ts +38 -13
- package/AGENTS.md +0 -502
package/os/rfc/dna-trace.ts
CHANGED
|
@@ -15,14 +15,18 @@ entries from all RFCs, and builds a bidirectional trace matrix.
|
|
|
15
15
|
</CHANGE_SUMMARY>
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { readFile } from "node:fs/promises";
|
|
19
18
|
import { join } from "node:path";
|
|
19
|
+
import { ambientIo, resolveIo } from "../../src/utils/io.ts";
|
|
20
20
|
|
|
21
21
|
import { writeFileAtomic } from "../../src/utils/fs-atomic.ts";
|
|
22
22
|
import { buildGeneratedHeader } from "../../src/utils/generated-marker.ts";
|
|
23
23
|
import { stringify as yamlStringify } from "yaml";
|
|
24
24
|
import { listRfcFiles, readAndParseRfc } from "./frontmatter-io.ts";
|
|
25
25
|
import { RFC_DIR } from "./types.ts";
|
|
26
|
+
|
|
27
|
+
// Ambient default for helper fns without a context param — handlers override
|
|
28
|
+
// with `const io = resolveIo(context.io)` inside their own scope.
|
|
29
|
+
const io = ambientIo;
|
|
26
30
|
import type {
|
|
27
31
|
Diagnostic,
|
|
28
32
|
ForgeCommandInput,
|
|
@@ -56,7 +60,7 @@ export interface DnaTraceResult {
|
|
|
56
60
|
async function parseDnaRegistry(workspaceRoot: string): Promise<Set<string>> {
|
|
57
61
|
const ids = new Set<string>();
|
|
58
62
|
try {
|
|
59
|
-
const src = await readFile(join(workspaceRoot, DNA_REGISTRY_PATH)
|
|
63
|
+
const src = await io.readFile(join(workspaceRoot, DNA_REGISTRY_PATH));
|
|
60
64
|
for (const m of src.matchAll(DNA_HEADING_RE)) {
|
|
61
65
|
ids.add(`DNA-${m[1]}`);
|
|
62
66
|
}
|
|
@@ -186,6 +190,7 @@ export async function runRfcDnaTraceValidate(
|
|
|
186
190
|
input: ForgeCommandInput,
|
|
187
191
|
context: ForgeRuntimeContext,
|
|
188
192
|
): Promise<ForgeCommandResult<DnaTraceResult>> {
|
|
193
|
+
const _io = resolveIo(context.io);
|
|
189
194
|
const { workspaceRoot, logger, outputFormat } = context;
|
|
190
195
|
const dnaFilter = input.flags["dna"] as string | undefined;
|
|
191
196
|
|
|
@@ -241,6 +246,7 @@ export async function runRfcDnaTraceGenerate(
|
|
|
241
246
|
_input: ForgeCommandInput,
|
|
242
247
|
context: ForgeRuntimeContext,
|
|
243
248
|
): Promise<ForgeCommandResult<DnaTraceResult>> {
|
|
249
|
+
const _io = resolveIo(context.io);
|
|
244
250
|
const { workspaceRoot, logger, outputFormat } = context;
|
|
245
251
|
|
|
246
252
|
const { entries, diagnostics, registryIds } = await buildDnaTrace(workspaceRoot);
|
package/os/rfc/frontmatter-io.ts
CHANGED
|
@@ -22,7 +22,7 @@ Sweep batch 4: 73 Compass headers on headerless engine files (certification, com
|
|
|
22
22
|
</CHANGE_SUMMARY>
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import fs from "
|
|
25
|
+
import { ambientIo as fs } from "../../src/utils/io.ts";
|
|
26
26
|
import path from "node:path";
|
|
27
27
|
import YAML from "yaml";
|
|
28
28
|
|
|
@@ -47,13 +47,13 @@ export async function listRfcFiles(rfcDirPath: string): Promise<string[]> {
|
|
|
47
47
|
|
|
48
48
|
async function scanDir(dirPath: string, relativePrefix: string): Promise<void> {
|
|
49
49
|
try {
|
|
50
|
-
const entries = await fs.readdir(dirPath
|
|
50
|
+
const entries = await fs.readdir(dirPath);
|
|
51
51
|
for (const entry of entries) {
|
|
52
52
|
const relativePath = relativePrefix ? `${relativePrefix}/${entry.name}` : entry.name;
|
|
53
|
-
if (entry.isDirectory
|
|
53
|
+
if (entry.isDirectory) {
|
|
54
54
|
await scanDir(path.join(dirPath, entry.name), relativePath);
|
|
55
55
|
} else if (
|
|
56
|
-
entry.isFile
|
|
56
|
+
entry.isFile &&
|
|
57
57
|
entry.name.endsWith(".md") &&
|
|
58
58
|
!entry.name.startsWith("rfc-0000") &&
|
|
59
59
|
!entry.name.endsWith(".generated.md") &&
|
|
@@ -84,7 +84,7 @@ export async function readAndParseRfc(
|
|
|
84
84
|
): Promise<ReadAndParseRfcResult | undefined> {
|
|
85
85
|
try {
|
|
86
86
|
const filePath = path.join(rfcDirPath, fileName);
|
|
87
|
-
const content = await fs.readFile(filePath
|
|
87
|
+
const content = await fs.readFile(filePath);
|
|
88
88
|
return { fileName, parsed: parseRfcFile(content) };
|
|
89
89
|
} catch (e) {
|
|
90
90
|
if (e instanceof Error) {
|
|
@@ -22,7 +22,7 @@ Sweep batch 4: 73 Compass headers on headerless engine files (certification, com
|
|
|
22
22
|
</CHANGE_SUMMARY>
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import fs from "
|
|
25
|
+
import { ambientIo as fs } from "../../../src/utils/io.ts";
|
|
26
26
|
import path from "node:path";
|
|
27
27
|
import { stringify as yamlStringify } from "yaml";
|
|
28
28
|
import { listRfcFiles, readAndParseRfc } from "../frontmatter-io.ts";
|
|
@@ -137,7 +137,9 @@ export async function runRfcArchive(
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
try {
|
|
140
|
-
await fs.
|
|
140
|
+
await fs.exists(targetPath).then((ok) => {
|
|
141
|
+
if (!ok) throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
|
|
142
|
+
});
|
|
141
143
|
skipped.push({ id, file: relFile, reason: "destination exists" });
|
|
142
144
|
continue;
|
|
143
145
|
} catch {
|
|
@@ -145,7 +147,7 @@ export async function runRfcArchive(
|
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
if (!dryRun) {
|
|
148
|
-
await fs.mkdir(targetDir
|
|
150
|
+
await fs.mkdir(targetDir);
|
|
149
151
|
try {
|
|
150
152
|
await fs.rename(path.join(rfcDirPath, fileName), targetPath);
|
|
151
153
|
} catch (err) {
|
|
@@ -184,7 +186,9 @@ export async function runRfcArchive(
|
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
try {
|
|
187
|
-
await fs.
|
|
189
|
+
await fs.exists(targetPath).then((ok) => {
|
|
190
|
+
if (!ok) throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
|
|
191
|
+
});
|
|
188
192
|
skipped.push({ id, file: relFile, reason: "destination exists" });
|
|
189
193
|
continue;
|
|
190
194
|
} catch {
|
|
@@ -269,7 +273,7 @@ export async function runRfcArchive(
|
|
|
269
273
|
count: entries.length,
|
|
270
274
|
entries,
|
|
271
275
|
};
|
|
272
|
-
await fs.writeFile(path.join(workspaceRoot, outRel), `${yamlStringify(payload)}
|
|
276
|
+
await fs.writeFile(path.join(workspaceRoot, outRel), `${yamlStringify(payload)}`);
|
|
273
277
|
indexRefreshed = true;
|
|
274
278
|
if (outputFormat === "pretty") {
|
|
275
279
|
logger.info(`rfc.archive: refreshed ${outRel} (${entries.length} entries)`);
|
package/os/rfc/handlers/check.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
</CHANGE_SUMMARY>
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import fs from "
|
|
13
|
+
import { ambientIo as fs } from "../../../src/utils/io.ts";
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
|
|
16
16
|
import { listRfcFiles, readAndParseRfc } from "../frontmatter-io.ts";
|
|
@@ -117,7 +117,7 @@ async function loadFeatureKeysForApps(
|
|
|
117
117
|
"features.ts",
|
|
118
118
|
);
|
|
119
119
|
try {
|
|
120
|
-
const source = await fs.readFile(featuresPath
|
|
120
|
+
const source = await fs.readFile(featuresPath);
|
|
121
121
|
result.set(siteName, extractDefinedFeatureKeysFromSource(source));
|
|
122
122
|
} catch {
|
|
123
123
|
// features.ts not found for this app — skip
|
|
@@ -165,7 +165,9 @@ export async function runRfcCheck(
|
|
|
165
165
|
if (!isLiteralFsPath(declaredPath)) continue;
|
|
166
166
|
const absPath = path.join(workspaceRoot, declaredPath);
|
|
167
167
|
try {
|
|
168
|
-
await fs.
|
|
168
|
+
await fs.exists(absPath).then((ok) => {
|
|
169
|
+
if (!ok) throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
|
|
170
|
+
});
|
|
169
171
|
} catch {
|
|
170
172
|
violations.push({
|
|
171
173
|
rfcId,
|
|
@@ -25,8 +25,9 @@ Sweep batch 2: real KEY_DECISIONS on 10 files, expanded purposes (CONTRACT-02/PU
|
|
|
25
25
|
</CHANGE_SUMMARY>
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
import { execFile } from "
|
|
29
|
-
import {
|
|
28
|
+
import { execFile, writeFileSync } from "../../../src/utils/sync-fs.ts";
|
|
29
|
+
import { ambientIo, resolveIo } from "../../../src/utils/io.ts";
|
|
30
|
+
|
|
30
31
|
import { join, dirname } from "node:path";
|
|
31
32
|
|
|
32
33
|
import { writeFileAtomic } from "../../../src/utils/fs-atomic.ts";
|
|
@@ -43,6 +44,10 @@ import { evaluateAcceptanceCriteria } from "./validate-rules.ts";
|
|
|
43
44
|
import { toIsoDate } from "./shared.ts";
|
|
44
45
|
import { RFC_DIR, RFC_METADATA_CUTOFF, RFC_PROBE_BINDING_CUTOFF } from "../types.ts";
|
|
45
46
|
import type { RfcStatus, RfcImplementStampViolation, RfcImplementStampResult } from "../types.ts";
|
|
47
|
+
|
|
48
|
+
// Ambient default for helper fns without a context param — handlers override
|
|
49
|
+
// with `const io = resolveIo(context.io)` inside their own scope.
|
|
50
|
+
const io = ambientIo;
|
|
46
51
|
import type {
|
|
47
52
|
ForgeCommandInput,
|
|
48
53
|
ForgeCommandResult,
|
|
@@ -162,16 +167,15 @@ async function acquireRfcLock(
|
|
|
162
167
|
): Promise<{ acquired: boolean; lockPath: string }> {
|
|
163
168
|
const lockPath = lockFilePath(workspaceRoot, rfcId);
|
|
164
169
|
const lockDir = dirname(lockPath);
|
|
165
|
-
await mkdir(lockDir
|
|
170
|
+
await io.mkdir(lockDir);
|
|
166
171
|
|
|
167
172
|
// Atomic lock acquisition via O_EXCL file creation
|
|
168
|
-
const { open } = await import("node:fs/promises");
|
|
169
173
|
try {
|
|
170
|
-
|
|
171
|
-
|
|
174
|
+
writeFileSync(
|
|
175
|
+
lockPath,
|
|
172
176
|
JSON.stringify({ pid: process.pid, acquiredAt: new Date().toISOString() }),
|
|
177
|
+
{ flag: "wx" },
|
|
173
178
|
);
|
|
174
|
-
await handle.close();
|
|
175
179
|
return { acquired: true, lockPath };
|
|
176
180
|
} catch {
|
|
177
181
|
return { acquired: false, lockPath };
|
|
@@ -180,7 +184,7 @@ async function acquireRfcLock(
|
|
|
180
184
|
|
|
181
185
|
async function releaseRfcLock(lockPath: string): Promise<void> {
|
|
182
186
|
try {
|
|
183
|
-
await
|
|
187
|
+
await io.rm(lockPath);
|
|
184
188
|
} catch {
|
|
185
189
|
// Lock file already removed — safe
|
|
186
190
|
}
|
|
@@ -195,7 +199,7 @@ async function checkExistingEvidence(
|
|
|
195
199
|
const slug = rfcId.toLowerCase();
|
|
196
200
|
const evidencePath = join(workspaceRoot, VERIFICATION_DIR, `${slug}.generated.yaml`);
|
|
197
201
|
try {
|
|
198
|
-
const content = await readFile(evidencePath
|
|
202
|
+
const content = await io.readFile(evidencePath);
|
|
199
203
|
const evidence = yamlParse(content) as { overall?: string };
|
|
200
204
|
return { exists: true, overall: String(evidence.overall ?? "") };
|
|
201
205
|
} catch {
|
|
@@ -239,6 +243,7 @@ export async function runRfcImplementStamp(
|
|
|
239
243
|
input: ForgeCommandInput,
|
|
240
244
|
context: ForgeRuntimeContext,
|
|
241
245
|
): Promise<ForgeCommandResult<RfcImplementStampResult>> {
|
|
246
|
+
const io = resolveIo(context.io);
|
|
242
247
|
const { workspaceRoot, logger, outputFormat, dryRun } = context;
|
|
243
248
|
const rfcDirPath = join(workspaceRoot, RFC_DIR);
|
|
244
249
|
|
|
@@ -437,7 +442,7 @@ export async function runRfcImplementStamp(
|
|
|
437
442
|
try {
|
|
438
443
|
// ── Atomic mutation ──────────────────────────────────────────────────────
|
|
439
444
|
const rfcFilePath = join(rfcDirPath, targetFile);
|
|
440
|
-
const rfcSource = await readFile(rfcFilePath
|
|
445
|
+
const rfcSource = await io.readFile(rfcFilePath);
|
|
441
446
|
|
|
442
447
|
const today = toIsoDate(new Date());
|
|
443
448
|
const stampedAt = new Date().toISOString();
|
|
@@ -16,7 +16,7 @@ Sweep batch 4: 73 Compass headers on headerless engine files (certification, com
|
|
|
16
16
|
</CHANGE_SUMMARY>
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import fs from "
|
|
19
|
+
import { ambientIo as fs } from "../../../src/utils/io.ts";
|
|
20
20
|
import path from "node:path";
|
|
21
21
|
import { parse as yamlParse, stringify as yamlStringify } from "yaml";
|
|
22
22
|
|
|
@@ -78,7 +78,7 @@ export async function runRfcIndexGenerate(
|
|
|
78
78
|
count: entries.length,
|
|
79
79
|
entries,
|
|
80
80
|
};
|
|
81
|
-
await fs.writeFile(path.join(workspaceRoot, outRel), `${yamlStringify(payload)}
|
|
81
|
+
await fs.writeFile(path.join(workspaceRoot, outRel), `${yamlStringify(payload)}`);
|
|
82
82
|
written = outRel;
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -166,7 +166,7 @@ export async function runRfcIndexValidate(
|
|
|
166
166
|
// RFC-IDX-01: missing index file
|
|
167
167
|
let indexContent: string;
|
|
168
168
|
try {
|
|
169
|
-
indexContent = await fs.readFile(indexPath
|
|
169
|
+
indexContent = await fs.readFile(indexPath);
|
|
170
170
|
} catch {
|
|
171
171
|
violations.push({
|
|
172
172
|
rule: "RFC-IDX-01",
|
|
@@ -18,8 +18,8 @@ Sweep batch 4: 73 Compass headers on headerless engine files (certification, com
|
|
|
18
18
|
</CHANGE_SUMMARY>
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import { readFile } from "node:fs/promises";
|
|
22
21
|
import path from "node:path";
|
|
22
|
+
import { ambientIo, resolveIo } from "../../../src/utils/io.ts";
|
|
23
23
|
import { parse as yamlParse } from "yaml";
|
|
24
24
|
|
|
25
25
|
import type { CommandRegistry } from "../../../src/types.ts";
|
|
@@ -42,10 +42,14 @@ import type {
|
|
|
42
42
|
import { RFC_DIR, RFC_METADATA_CUTOFF } from "../types.ts";
|
|
43
43
|
import { commandBuckets } from "./shared.ts";
|
|
44
44
|
|
|
45
|
+
// Ambient default for helper fns without a context param — handlers override
|
|
46
|
+
// with `const io = resolveIo(context.io)` inside their own scope.
|
|
47
|
+
const io = ambientIo;
|
|
48
|
+
|
|
45
49
|
async function loadManifestCommandNames(workspaceRoot: string): Promise<Set<string>> {
|
|
46
50
|
const manifestPath = path.join(workspaceRoot, "docs", "command-manifest.generated.yaml");
|
|
47
51
|
try {
|
|
48
|
-
const raw = await readFile(manifestPath
|
|
52
|
+
const raw = await io.readFile(manifestPath);
|
|
49
53
|
const manifest = yamlParse(raw) as { commands?: Array<{ name: string }> };
|
|
50
54
|
return new Set((manifest.commands ?? []).map((c) => c.name));
|
|
51
55
|
} catch {
|
|
@@ -195,6 +199,7 @@ export async function runRfcCommandLifecycleValidate(
|
|
|
195
199
|
input: ForgeCommandInput,
|
|
196
200
|
context: ForgeRuntimeContext,
|
|
197
201
|
): Promise<ForgeCommandResult<RfcCommandLifecycleValidationResult>> {
|
|
202
|
+
const _io = resolveIo(context.io);
|
|
198
203
|
const { workspaceRoot, logger, outputFormat } = context;
|
|
199
204
|
const rfcDirPath = path.join(workspaceRoot, RFC_DIR);
|
|
200
205
|
const targetId = input.flags["id"] as string | undefined;
|
|
@@ -19,7 +19,8 @@ Sweep batch 4: 73 Compass headers on headerless engine files (certification, com
|
|
|
19
19
|
</CHANGE_SUMMARY>
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import fs from "
|
|
22
|
+
import { ambientIo as fs } from "../../../src/utils/io.ts";
|
|
23
|
+
import { writeFileSync } from "../../../src/utils/sync-fs.ts";
|
|
23
24
|
import path from "node:path";
|
|
24
25
|
import { toKebabCase } from "../../../src/utils/string-utils.ts";
|
|
25
26
|
import { listRfcFiles, readAndParseRfc } from "../frontmatter-io.ts";
|
|
@@ -190,7 +191,7 @@ export async function runRfcCreate(
|
|
|
190
191
|
const templatePath = resolveRfcTemplate(workspaceRoot);
|
|
191
192
|
let templateContent: string;
|
|
192
193
|
try {
|
|
193
|
-
templateContent = await fs.readFile(templatePath
|
|
194
|
+
templateContent = await fs.readFile(templatePath);
|
|
194
195
|
} catch {
|
|
195
196
|
throw new Error(`RFC template not found at ${templatePath}.`);
|
|
196
197
|
}
|
|
@@ -250,14 +251,14 @@ export async function runRfcCreate(
|
|
|
250
251
|
const claimPath = path.join(rfcDirPath, `${nextSlug}.claim`);
|
|
251
252
|
|
|
252
253
|
try {
|
|
253
|
-
|
|
254
|
+
writeFileSync(claimPath, `${process.pid}\n`, { flag: "wx" });
|
|
254
255
|
} catch (err) {
|
|
255
256
|
if ((err as NodeJS.ErrnoException).code === "EEXIST") {
|
|
256
257
|
// Stale claim (crashed create) → reclaim and retry the same id.
|
|
257
258
|
// Live claim → another create holds this id — move to the next.
|
|
258
259
|
const st = await fs.stat(claimPath).catch(() => null);
|
|
259
260
|
if (st && Date.now() - st.mtimeMs > CLAIM_STALE_MS) {
|
|
260
|
-
await fs.rm(claimPath
|
|
261
|
+
await fs.rm(claimPath);
|
|
261
262
|
} else {
|
|
262
263
|
candidate++;
|
|
263
264
|
}
|
|
@@ -283,11 +284,11 @@ export async function runRfcCreate(
|
|
|
283
284
|
content = content.replace(/^# RFC-0000: .+$/m, `# ${nextId}: ${title}`);
|
|
284
285
|
|
|
285
286
|
const targetPath = path.join(rfcDirPath, fileName);
|
|
286
|
-
|
|
287
|
+
writeFileSync(targetPath, content, { flag: "wx" });
|
|
287
288
|
relativeFile = path.join(RFC_DIR, fileName);
|
|
288
289
|
allocated = true;
|
|
289
290
|
} finally {
|
|
290
|
-
await fs.rm(claimPath
|
|
291
|
+
await fs.rm(claimPath);
|
|
291
292
|
}
|
|
292
293
|
if (allocated) break;
|
|
293
294
|
}
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
</CHANGE_SUMMARY>
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import fs from "
|
|
14
|
-
import { existsSync } from "
|
|
13
|
+
import { ambientIo as fs } from "../../../src/utils/io.ts";
|
|
14
|
+
import { existsSync } from "../../../src/utils/sync-fs.ts";
|
|
15
15
|
import path from "node:path";
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
17
17
|
|
|
@@ -38,7 +38,7 @@ export async function loadInvariantIds(
|
|
|
38
38
|
const re = new RegExp(`^##\\s+${prefix}-(\\d+)\\b`, "gm");
|
|
39
39
|
for (const rel of relPaths) {
|
|
40
40
|
try {
|
|
41
|
-
const src = await fs.readFile(path.join(workspaceRoot, rel)
|
|
41
|
+
const src = await fs.readFile(path.join(workspaceRoot, rel));
|
|
42
42
|
for (const m of src.matchAll(re)) ids.add(parseInt(m[1]!, 10));
|
|
43
43
|
} catch {
|
|
44
44
|
// Doc not present at this path — try the next candidate.
|
|
@@ -20,8 +20,8 @@ Sweep batch 4: 73 Compass headers on headerless engine files (certification, com
|
|
|
20
20
|
</CHANGE_SUMMARY>
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
import { readFile } from "node:fs/promises";
|
|
24
23
|
import { join, basename } from "node:path";
|
|
24
|
+
import { ambientIo, resolveIo } from "../../../src/utils/io.ts";
|
|
25
25
|
|
|
26
26
|
import { toKebabCase } from "../../../src/utils/string-utils.ts";
|
|
27
27
|
import { writeFileAtomic } from "../../../src/utils/fs-atomic.ts";
|
|
@@ -37,12 +37,16 @@ import type {
|
|
|
37
37
|
} from "../../../src/types.ts";
|
|
38
38
|
import { toIsoDate } from "./shared.ts";
|
|
39
39
|
|
|
40
|
+
// Ambient default for helper fns without a context param — handlers override
|
|
41
|
+
// with `const io = resolveIo(context.io)` inside their own scope.
|
|
42
|
+
const io = ambientIo;
|
|
43
|
+
|
|
40
44
|
const DNA_REGISTRY_PATH = "docs/architecture-dna.md";
|
|
41
45
|
const DNA_HEADING_RE = /^##\s+DNA-(\d+)\b/gm;
|
|
42
46
|
|
|
43
47
|
async function validateDnaIds(workspaceRoot: string, ids: string[]): Promise<string[]> {
|
|
44
48
|
const errors: string[] = [];
|
|
45
|
-
const registrySrc = await readFile(join(workspaceRoot, DNA_REGISTRY_PATH)
|
|
49
|
+
const registrySrc = await io.readFile(join(workspaceRoot, DNA_REGISTRY_PATH));
|
|
46
50
|
const knownDna = new Set<string>();
|
|
47
51
|
for (const m of registrySrc.matchAll(DNA_HEADING_RE)) {
|
|
48
52
|
knownDna.add(`DNA-${m[1]}`);
|
|
@@ -68,6 +72,7 @@ export async function runRfcSupersedePropose(
|
|
|
68
72
|
input: ForgeCommandInput,
|
|
69
73
|
context: ForgeRuntimeContext,
|
|
70
74
|
): Promise<ForgeCommandResult<RfcSupersedeProposeResult>> {
|
|
75
|
+
const io = resolveIo(context.io);
|
|
71
76
|
const { workspaceRoot, logger, outputFormat } = context;
|
|
72
77
|
const rfcDirPath = join(workspaceRoot, RFC_DIR);
|
|
73
78
|
|
|
@@ -147,7 +152,7 @@ export async function runRfcSupersedePropose(
|
|
|
147
152
|
const templatePath = resolveRfcTemplate(workspaceRoot);
|
|
148
153
|
let templateContent: string;
|
|
149
154
|
try {
|
|
150
|
-
templateContent = await readFile(templatePath
|
|
155
|
+
templateContent = await io.readFile(templatePath);
|
|
151
156
|
} catch {
|
|
152
157
|
throw new Error(`RFC template not found at ${templatePath}.`);
|
|
153
158
|
}
|
|
@@ -168,7 +168,10 @@ describe("V-38: document readiness completeness (RFC-1006)", () => {
|
|
|
168
168
|
const body = BASE_BODY.replace(
|
|
169
169
|
"DOCUMENT_READINESS_HERE",
|
|
170
170
|
"## Document readiness\n\n- [ ] DR-1: alternatives listed",
|
|
171
|
-
).replace(
|
|
171
|
+
).replace(
|
|
172
|
+
"ACCEPTANCE_HERE",
|
|
173
|
+
"- [x] AC-1: test (evidence: test.ts:1)\n- [x] AC-2: test2 (evidence: test.ts:2)\n- [x] AC-3: test3 (evidence: test.ts:3)",
|
|
174
|
+
);
|
|
172
175
|
const parsed = makeParsed("accepted", body);
|
|
173
176
|
const violations = await runValidate(parsed);
|
|
174
177
|
const v38 = filterRule(violations, "V-38");
|
|
@@ -180,7 +183,10 @@ describe("V-38: document readiness completeness (RFC-1006)", () => {
|
|
|
180
183
|
const body = BASE_BODY.replace(
|
|
181
184
|
"DOCUMENT_READINESS_HERE",
|
|
182
185
|
"## Document readiness\n\n- [x] DR-1: alternatives listed (evidence: file: test.md:1)",
|
|
183
|
-
).replace(
|
|
186
|
+
).replace(
|
|
187
|
+
"ACCEPTANCE_HERE",
|
|
188
|
+
"- [x] AC-1: test (evidence: test.ts:1)\n- [x] AC-2: test2 (evidence: test.ts:2)\n- [x] AC-3: test3 (evidence: test.ts:3)",
|
|
189
|
+
);
|
|
184
190
|
const parsed = makeParsed("accepted", body);
|
|
185
191
|
const violations = await runValidate(parsed);
|
|
186
192
|
const v38 = filterRule(violations, "V-38");
|
|
@@ -191,7 +197,10 @@ describe("V-38: document readiness completeness (RFC-1006)", () => {
|
|
|
191
197
|
const body = BASE_BODY.replace(
|
|
192
198
|
"DOCUMENT_READINESS_HERE",
|
|
193
199
|
"## Document readiness\n\n- [ ] DR-1: alternatives listed",
|
|
194
|
-
).replace(
|
|
200
|
+
).replace(
|
|
201
|
+
"ACCEPTANCE_HERE",
|
|
202
|
+
"- [x] AC-1: test (evidence: test.ts:1)\n- [x] AC-2: test2 (evidence: test.ts:2)\n- [x] AC-3: test3 (evidence: test.ts:3)",
|
|
203
|
+
);
|
|
195
204
|
const parsed = makeParsed("accepted", body, { createdAt: "2026-08-01" });
|
|
196
205
|
const violations = await runValidate(parsed);
|
|
197
206
|
const v38 = filterRule(violations, "V-38");
|
|
@@ -202,7 +211,10 @@ describe("V-38: document readiness completeness (RFC-1006)", () => {
|
|
|
202
211
|
const body = BASE_BODY.replace(
|
|
203
212
|
"DOCUMENT_READINESS_HERE",
|
|
204
213
|
"## Document readiness\n\n- [ ] DR-1: alternatives listed",
|
|
205
|
-
).replace(
|
|
214
|
+
).replace(
|
|
215
|
+
"ACCEPTANCE_HERE",
|
|
216
|
+
"- [x] AC-1: test (evidence: test.ts:1)\n- [x] AC-2: test2 (evidence: test.ts:2)\n- [x] AC-3: test3 (evidence: test.ts:3)",
|
|
217
|
+
);
|
|
206
218
|
const parsed = makeParsed("draft", body);
|
|
207
219
|
const violations = await runValidate(parsed);
|
|
208
220
|
const v38 = filterRule(violations, "V-38");
|
|
@@ -470,8 +482,8 @@ describe("Pre-cutoff exemption (RFC-1006)", () => {
|
|
|
470
482
|
);
|
|
471
483
|
const parsed = makeParsed("accepted", body, { createdAt: "2026-08-01" });
|
|
472
484
|
const violations = await runValidate(parsed);
|
|
473
|
-
const newRules = violations.filter(
|
|
474
|
-
|
|
485
|
+
const newRules = violations.filter((v) =>
|
|
486
|
+
["V-38", "V-39", "V-40", "V-41", "V-42"].includes(v.rule),
|
|
475
487
|
);
|
|
476
488
|
expect(newRules).toHaveLength(0);
|
|
477
489
|
});
|
|
@@ -20,8 +20,9 @@ Sweep batch 2: real KEY_DECISIONS on 10 files, expanded purposes (CONTRACT-02/PU
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import path from "node:path";
|
|
23
|
-
import {
|
|
24
|
-
|
|
23
|
+
import { ambientIo } from "../../../src/utils/io.ts";
|
|
24
|
+
|
|
25
|
+
import { execFile } from "../../../src/utils/sync-fs.ts";
|
|
25
26
|
|
|
26
27
|
import { parse as yamlParse } from "yaml";
|
|
27
28
|
import { validateAcceptanceShape } from "../acceptance.ts";
|
|
@@ -43,6 +44,10 @@ import {
|
|
|
43
44
|
import type { ProbeCoverageReport, AcceptanceProbe } from "../types.ts";
|
|
44
45
|
import { DNA_DOCS, AP_DOCS } from "./shared.ts";
|
|
45
46
|
|
|
47
|
+
// Ambient default for helper fns without a context param — handlers override
|
|
48
|
+
// with `const io = resolveIo(context.io)` inside their own scope.
|
|
49
|
+
const io = ambientIo;
|
|
50
|
+
|
|
46
51
|
const DNA_DOC = DNA_DOCS[0]!;
|
|
47
52
|
const AP_DOC = AP_DOCS[0]!;
|
|
48
53
|
|
|
@@ -831,7 +836,7 @@ export async function validateSingleRfc(
|
|
|
831
836
|
} else if (evidence.startsWith("test:")) {
|
|
832
837
|
const testPath = evidence.slice("test:".length).trim();
|
|
833
838
|
try {
|
|
834
|
-
await stat(path.join(workspaceRoot, testPath));
|
|
839
|
+
await io.stat(path.join(workspaceRoot, testPath));
|
|
835
840
|
} catch {
|
|
836
841
|
addViolation(
|
|
837
842
|
rfcId,
|
|
@@ -844,7 +849,7 @@ export async function validateSingleRfc(
|
|
|
844
849
|
const lastColon = evidence.lastIndexOf(":");
|
|
845
850
|
const filePath = evidence.slice(0, lastColon).trim();
|
|
846
851
|
try {
|
|
847
|
-
await stat(path.join(workspaceRoot, filePath));
|
|
852
|
+
await io.stat(path.join(workspaceRoot, filePath));
|
|
848
853
|
} catch {
|
|
849
854
|
addViolation(
|
|
850
855
|
rfcId,
|
|
@@ -1110,7 +1115,7 @@ export async function validateSingleRfc(
|
|
|
1110
1115
|
let evidenceOk = false;
|
|
1111
1116
|
let evidenceOverall = "";
|
|
1112
1117
|
try {
|
|
1113
|
-
const evidenceContent = await readFile(evidenceAbsPath
|
|
1118
|
+
const evidenceContent = await io.readFile(evidenceAbsPath);
|
|
1114
1119
|
const evidence = yamlParse(evidenceContent) as { overall?: string };
|
|
1115
1120
|
evidenceOverall = String(evidence.overall ?? "");
|
|
1116
1121
|
evidenceOk = evidenceOverall === "pass";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>Unit tests for runRfcValidate flag handling — the --id guard that
|
|
4
|
+
rejects non-string values before file scanning.</purpose>
|
|
5
|
+
<non-goals>
|
|
6
|
+
<item>Do not duplicate validate-rules coverage — V-rule behavior lives in validate-rules*.test.ts.</item>
|
|
7
|
+
</non-goals>
|
|
8
|
+
</MODULE_CONTRACT>
|
|
9
|
+
<CHANGE_SUMMARY>
|
|
10
|
+
<item>Initial test — non-string --id (boolean/array from unvalidated flag input) throws a clear flag error instead of TypeError in rfcFileMatchesId.</item>
|
|
11
|
+
</CHANGE_SUMMARY>
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { test, expect, describe } from "vitest";
|
|
15
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { tmpdir } from "node:os";
|
|
18
|
+
import { runRfcValidate } from "./validate.ts";
|
|
19
|
+
import type {
|
|
20
|
+
ForgeCommandInput,
|
|
21
|
+
ForgeFlagValue,
|
|
22
|
+
ForgeRuntimeContext,
|
|
23
|
+
} from "../../../src/types.ts";
|
|
24
|
+
|
|
25
|
+
function makeContext(workspaceRoot: string): ForgeRuntimeContext {
|
|
26
|
+
return {
|
|
27
|
+
workspaceRoot,
|
|
28
|
+
logger: {
|
|
29
|
+
info: () => {},
|
|
30
|
+
success: () => {},
|
|
31
|
+
warn: () => {},
|
|
32
|
+
error: () => {},
|
|
33
|
+
section: () => {},
|
|
34
|
+
},
|
|
35
|
+
dryRun: false,
|
|
36
|
+
outputFormat: "json",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe("runRfcValidate --id flag guard", () => {
|
|
41
|
+
test.each([
|
|
42
|
+
["boolean true", true],
|
|
43
|
+
["string array", ["rfc-0001", "rfc-0002"]],
|
|
44
|
+
])("non-string --id (%s) throws a clear error", async (_label, id) => {
|
|
45
|
+
const dir = mkdtempSync(join(tmpdir(), "rfc-validate-id-"));
|
|
46
|
+
try {
|
|
47
|
+
const input: ForgeCommandInput = {
|
|
48
|
+
argv: [],
|
|
49
|
+
flags: { id: id as ForgeFlagValue },
|
|
50
|
+
};
|
|
51
|
+
await expect(runRfcValidate(input, makeContext(dir))).rejects.toThrow(
|
|
52
|
+
'Flag "--id" for command "rfc.validate" requires a single string value.',
|
|
53
|
+
);
|
|
54
|
+
} finally {
|
|
55
|
+
rmSync(dir, { recursive: true, force: true });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("missing --id runs the all-files path without throwing the guard", async () => {
|
|
60
|
+
const dir = mkdtempSync(join(tmpdir(), "rfc-validate-noid-"));
|
|
61
|
+
try {
|
|
62
|
+
const result = await runRfcValidate(
|
|
63
|
+
{ argv: [], flags: {} },
|
|
64
|
+
makeContext(dir),
|
|
65
|
+
);
|
|
66
|
+
expect(result.data?.status).toBe("pass");
|
|
67
|
+
} finally {
|
|
68
|
+
rmSync(dir, { recursive: true, force: true });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -13,6 +13,7 @@ Mechanical v1 to v2 header migration across the workspace: 942 files rewritten
|
|
|
13
13
|
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
14
14
|
|
|
15
15
|
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.</item>
|
|
16
|
+
<item>Guard --id against non-string values (boolean/array from unvalidated flag input) — throws a clear flag error instead of TypeError in rfcFileMatchesId.</item>
|
|
16
17
|
</CHANGE_SUMMARY>
|
|
17
18
|
*/
|
|
18
19
|
|
|
@@ -48,7 +49,11 @@ export async function runRfcValidate(
|
|
|
48
49
|
const { workspaceRoot, logger, outputFormat } = context;
|
|
49
50
|
const rfcDirPath = path.join(workspaceRoot, RFC_DIR);
|
|
50
51
|
|
|
51
|
-
const
|
|
52
|
+
const rawId = input.flags["id"];
|
|
53
|
+
if (rawId !== undefined && typeof rawId !== "string") {
|
|
54
|
+
throw new Error(`Flag "--id" for command "rfc.validate" requires a single string value.`);
|
|
55
|
+
}
|
|
56
|
+
const targetId = rawId as string | undefined;
|
|
52
57
|
|
|
53
58
|
const allFiles = await listRfcFiles(rfcDirPath);
|
|
54
59
|
const filesToValidate = targetId
|
|
@@ -77,7 +77,9 @@ describe("rfc.create — RFC-1138 concurrent id allocation", () => {
|
|
|
77
77
|
const ids = results.map((r) => (r.data as { id: string }).id);
|
|
78
78
|
expect(new Set(ids).size).toBe(5);
|
|
79
79
|
|
|
80
|
-
const files = (await fs.readdir(rfcDir)).filter(
|
|
80
|
+
const files = (await fs.readdir(rfcDir)).filter(
|
|
81
|
+
(f) => f.startsWith("rfc-") && f !== "rfc-0000-template.md",
|
|
82
|
+
);
|
|
81
83
|
expect(files).toHaveLength(5);
|
|
82
84
|
});
|
|
83
85
|
|
|
@@ -94,7 +96,11 @@ describe("rfc.create — RFC-1138 concurrent id allocation", () => {
|
|
|
94
96
|
test("AC-5: pre-existing highest id is respected after a collision", async () => {
|
|
95
97
|
// Seed rfc-0001 so the first create takes 0002; a file racing in at 0002
|
|
96
98
|
// forces the retry path to land on 0003.
|
|
97
|
-
await fs.writeFile(
|
|
99
|
+
await fs.writeFile(
|
|
100
|
+
path.join(rfcDir, "rfc-0001-seeded.md"),
|
|
101
|
+
"---\nid: RFC-0001\n---\n",
|
|
102
|
+
"utf-8",
|
|
103
|
+
);
|
|
98
104
|
const winner = runRfcCreate(makeInput("Winner"), makeContext(tmpDir));
|
|
99
105
|
// Interleave a manual claim at the id the scan will compute.
|
|
100
106
|
const claim = (async () => {
|
|
@@ -111,7 +117,9 @@ describe("rfc.create — RFC-1138 concurrent id allocation", () => {
|
|
|
111
117
|
const id = (result.data as { id: string }).id;
|
|
112
118
|
// Either the create won 0002 (interloper lost the wx race) or it retried to 0003.
|
|
113
119
|
expect(["RFC-0002", "RFC-0003"]).toContain(id);
|
|
114
|
-
const files = (await fs.readdir(rfcDir)).filter(
|
|
120
|
+
const files = (await fs.readdir(rfcDir)).filter(
|
|
121
|
+
(f) => f.startsWith("rfc-") && f !== "rfc-0000-template.md",
|
|
122
|
+
);
|
|
115
123
|
// Seeded + interloper (if it won) + create output — never a silent overwrite.
|
|
116
124
|
expect(files.length).toBeGreaterThanOrEqual(2);
|
|
117
125
|
});
|