@warpgogol/forge 5.2.3 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +34 -2
- package/README.md +1 -1
- package/README.uk.md +8 -8
- package/bin/cli.ts +1 -0
- package/dist/bin/cli.js +1 -0
- 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 -9
- 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 +57 -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 +22 -19
- 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/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/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/compass/contract-registry.js +1 -1
- package/dist/src/compass/contract-registry.js.map +1 -1
- package/dist/src/config/forge-config.d.ts +10 -1
- package/dist/src/config/forge-config.d.ts.map +1 -1
- package/dist/src/config/forge-config.js +8 -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 +2 -0
- package/dist/src/onboarding/agents-generate.d.ts.map +1 -1
- package/dist/src/onboarding/agents-generate.js +73 -48
- 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 +6 -0
- package/dist/src/onboarding/doctor.d.ts.map +1 -1
- package/dist/src/onboarding/doctor.js +179 -61
- 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 +22 -0
- package/dist/src/onboarding/memory-compact.d.ts.map +1 -0
- package/dist/src/onboarding/memory-compact.js +148 -0
- package/dist/src/onboarding/memory-compact.js.map +1 -0
- package/dist/src/onboarding/memory-scaffold.d.ts +1 -0
- package/dist/src/onboarding/memory-scaffold.d.ts.map +1 -1
- package/dist/src/onboarding/memory-scaffold.js +2 -2
- 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 +35 -6
- 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.d.ts +1 -1
- package/dist/src/onboarding/workspace-discovery.d.ts.map +1 -1
- package/dist/src/onboarding/workspace-discovery.js +15 -3
- 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/docs/reference/forge-yaml.md +12 -0
- 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 -9
- 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 +58 -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.ts +27 -19
- 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/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/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 +3 -0
- package/profiles/godot-game.yaml +3 -0
- package/profiles/phaser-game.yaml +3 -0
- package/profiles/site-workshop.yaml +567 -564
- 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/compass/contract-registry.ts +1 -1
- package/src/config/forge-config.ts +12 -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 +91 -50
- package/src/onboarding/create.ts +10 -10
- package/src/onboarding/doctor.ts +199 -59
- package/src/onboarding/init.ts +38 -1
- package/src/onboarding/invariant-engine.ts +1 -1
- package/src/onboarding/memory-compact.ts +189 -0
- package/src/onboarding/memory-scaffold.ts +2 -2
- package/src/onboarding/nested-agents-generate.ts +50 -5
- 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 +16 -2
- 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 +32 -7
- package/src/tests/contract-registry.test.ts +12 -6
- package/src/tests/doctor-dist-freshness.test.ts +110 -0
- package/src/tests/doctor-fix.test.ts +142 -0
- package/src/tests/doctor-nested-agents.test.ts +160 -0
- 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 +54 -54
- package/src/tests/markdown-table.test.ts +107 -0
- package/src/tests/memory-compact.test.ts +143 -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/tests/workspace-discovery.test.ts +28 -0
- 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
|
@@ -15,7 +15,7 @@ workspace type (app, service, package) by content markers.</purpose>
|
|
|
15
15
|
</CHANGE_SUMMARY>
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import fs from "
|
|
18
|
+
import * as fs from "../utils/sync-fs.ts";
|
|
19
19
|
import path from "node:path";
|
|
20
20
|
import { hasGeneratedMarker } from "../utils/index.ts";
|
|
21
21
|
import type { ProfileWorkspaceType } from "../profiles/profile-schema.ts";
|
|
@@ -36,6 +36,13 @@ const SKIP_DIRS = new Set([
|
|
|
36
36
|
".turbo",
|
|
37
37
|
".cache",
|
|
38
38
|
".agents",
|
|
39
|
+
// Pipeline-managed mission workpieces and archives — their AGENTS.md is
|
|
40
|
+
// generated by the site pipeline, not by forge.agents.generate.
|
|
41
|
+
"missions",
|
|
42
|
+
// Test fixture workshops — not real project workspaces.
|
|
43
|
+
"test-fixtures",
|
|
44
|
+
// Stryker mutation-testing sandboxes — transient temp dirs.
|
|
45
|
+
".stryker-tmp",
|
|
39
46
|
]);
|
|
40
47
|
|
|
41
48
|
export function detectWorkspaceType(
|
|
@@ -110,8 +117,15 @@ function matchesWorkspaceType(dirPath: string, wt: ProfileWorkspaceType): boolea
|
|
|
110
117
|
export function discoverWorkspaces(
|
|
111
118
|
workspaceRoot: string,
|
|
112
119
|
workspaceTypes?: ProfileWorkspaceType[],
|
|
120
|
+
extraSkipDirs?: readonly string[],
|
|
113
121
|
): WorkspaceDir[] {
|
|
114
122
|
const results: WorkspaceDir[] = [];
|
|
123
|
+
// RFC-1150: consumer-declared exclusions (bindings.workspaces.skipDirs)
|
|
124
|
+
// merge over the SKIP_DIRS defaults.
|
|
125
|
+
const skipDirs =
|
|
126
|
+
extraSkipDirs && extraSkipDirs.length > 0
|
|
127
|
+
? new Set([...SKIP_DIRS, ...extraSkipDirs])
|
|
128
|
+
: SKIP_DIRS;
|
|
115
129
|
|
|
116
130
|
function scanDir(dirPath: string, depth: number): void {
|
|
117
131
|
if (depth > 5) return;
|
|
@@ -125,7 +139,7 @@ export function discoverWorkspaces(
|
|
|
125
139
|
|
|
126
140
|
for (const entry of entries) {
|
|
127
141
|
if (!entry.isDirectory()) continue;
|
|
128
|
-
if (
|
|
142
|
+
if (skipDirs.has(entry.name)) continue;
|
|
129
143
|
|
|
130
144
|
const childPath = path.join(dirPath, entry.name);
|
|
131
145
|
const type = detectWorkspaceType(childPath, workspaceTypes);
|
|
@@ -116,10 +116,7 @@ describe("deriveQueueItemStatus — derivation matrix (RFC-1140)", () => {
|
|
|
116
116
|
|
|
117
117
|
test("audit file only → in-progress/enhance", async () => {
|
|
118
118
|
await writeRfc("RFC-1107", "status: draft\n");
|
|
119
|
-
await fs.writeFile(
|
|
120
|
-
path.join(tmpDir, "docs/audits/audit-rfc-1107-test.md"),
|
|
121
|
-
"# audit\n",
|
|
122
|
-
);
|
|
119
|
+
await fs.writeFile(path.join(tmpDir, "docs/audits/audit-rfc-1107-test.md"), "# audit\n");
|
|
123
120
|
const r = await deriveQueueItemStatus(tmpDir, "RFC-1107");
|
|
124
121
|
expect(r?.status).toBe("in-progress");
|
|
125
122
|
expect(r?.pipelineStep).toBe("enhance");
|
package/src/pipeline-status.ts
CHANGED
|
@@ -25,8 +25,9 @@ Add pipeline-status.test.ts (derivation matrix, order, next selection, ADR, skip
|
|
|
25
25
|
</CHANGE_SUMMARY>
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
import fs from "node:fs/promises";
|
|
29
28
|
import path from "node:path";
|
|
29
|
+
import type { WorkspaceIO } from "./types.ts";
|
|
30
|
+
import { resolveIo } from "./utils/io.ts";
|
|
30
31
|
import YAML from "yaml";
|
|
31
32
|
|
|
32
33
|
// ---------------------------------------------------------------------------
|
|
@@ -75,10 +76,12 @@ export function parseFrontmatter(source: string): ParsedDocument {
|
|
|
75
76
|
export async function findAuditFile(
|
|
76
77
|
workspaceRoot: string,
|
|
77
78
|
docId: string,
|
|
79
|
+
io?: WorkspaceIO,
|
|
78
80
|
): Promise<string | undefined> {
|
|
81
|
+
const fio = resolveIo(io);
|
|
79
82
|
const auditsDir = path.join(workspaceRoot, "docs/audits");
|
|
80
83
|
try {
|
|
81
|
-
const entries = await
|
|
84
|
+
const entries = (await fio.readdir(auditsDir)).map((e) => e.name);
|
|
82
85
|
const prefix = `audit-${docId.toLowerCase()}`;
|
|
83
86
|
const match = entries.find((e) => e.toLowerCase().startsWith(prefix) && e.endsWith(".md"));
|
|
84
87
|
return match ? path.join("docs/audits", match) : undefined;
|
|
@@ -90,10 +93,12 @@ export async function findAuditFile(
|
|
|
90
93
|
export async function findPlanFile(
|
|
91
94
|
workspaceRoot: string,
|
|
92
95
|
docId: string,
|
|
96
|
+
io?: WorkspaceIO,
|
|
93
97
|
): Promise<string | undefined> {
|
|
98
|
+
const fio = resolveIo(io);
|
|
94
99
|
const plansDir = path.join(workspaceRoot, "docs/plans");
|
|
95
100
|
try {
|
|
96
|
-
const entries = await
|
|
101
|
+
const entries = (await fio.readdir(plansDir)).map((e) => e.name);
|
|
97
102
|
const prefix = `plan-${docId.toLowerCase()}`;
|
|
98
103
|
const match = entries.find((e) => e.toLowerCase().startsWith(prefix) && e.endsWith(".md"));
|
|
99
104
|
return match ? path.join("docs/plans", match) : undefined;
|
|
@@ -122,20 +127,26 @@ async function scanForDocument(
|
|
|
122
127
|
dirPath: string,
|
|
123
128
|
relativePrefix: string,
|
|
124
129
|
idLower: string,
|
|
130
|
+
io: WorkspaceIO,
|
|
125
131
|
): Promise<string | undefined> {
|
|
126
132
|
let entries;
|
|
127
133
|
try {
|
|
128
|
-
entries = await
|
|
134
|
+
entries = await io.readdir(dirPath);
|
|
129
135
|
} catch {
|
|
130
136
|
return undefined;
|
|
131
137
|
}
|
|
132
138
|
for (const entry of entries) {
|
|
133
139
|
const relativePath = relativePrefix ? `${relativePrefix}/${entry.name}` : entry.name;
|
|
134
|
-
if (entry.isDirectory
|
|
135
|
-
const found = await scanForDocument(
|
|
140
|
+
if (entry.isDirectory) {
|
|
141
|
+
const found = await scanForDocument(
|
|
142
|
+
path.join(dirPath, entry.name),
|
|
143
|
+
relativePath,
|
|
144
|
+
idLower,
|
|
145
|
+
io,
|
|
146
|
+
);
|
|
136
147
|
if (found) return found;
|
|
137
148
|
} else if (
|
|
138
|
-
entry.isFile
|
|
149
|
+
entry.isFile &&
|
|
139
150
|
entry.name.endsWith(".md") &&
|
|
140
151
|
entry.name.toLowerCase().startsWith(idLower)
|
|
141
152
|
) {
|
|
@@ -153,19 +164,21 @@ async function scanForDocument(
|
|
|
153
164
|
export async function resolveDocument(
|
|
154
165
|
workspaceRoot: string,
|
|
155
166
|
docId: string,
|
|
167
|
+
io?: WorkspaceIO,
|
|
156
168
|
): Promise<ResolvedDocument | undefined> {
|
|
169
|
+
const fio = resolveIo(io);
|
|
157
170
|
const idMatch = DOC_ID_PATTERN.exec(docId.trim());
|
|
158
171
|
if (!idMatch) return undefined;
|
|
159
172
|
const kind: QueueDocumentKind = idMatch[1]!.toUpperCase() === "ADR" ? "adr" : "rfc";
|
|
160
173
|
const baseDir = kind === "adr" ? "docs/adrs" : "docs/rfcs";
|
|
161
174
|
const idLower = docId.toLowerCase();
|
|
162
175
|
|
|
163
|
-
const found = await scanForDocument(path.join(workspaceRoot, baseDir), "", idLower);
|
|
176
|
+
const found = await scanForDocument(path.join(workspaceRoot, baseDir), "", idLower, fio);
|
|
164
177
|
if (!found) return undefined;
|
|
165
178
|
|
|
166
179
|
let source: string;
|
|
167
180
|
try {
|
|
168
|
-
source = await
|
|
181
|
+
source = await fio.readFile(path.join(workspaceRoot, baseDir, found));
|
|
169
182
|
} catch {
|
|
170
183
|
return undefined;
|
|
171
184
|
}
|
|
@@ -242,8 +255,10 @@ export interface QueueItemReport {
|
|
|
242
255
|
export async function deriveQueueItemStatus(
|
|
243
256
|
workspaceRoot: string,
|
|
244
257
|
docId: string,
|
|
258
|
+
io?: WorkspaceIO,
|
|
245
259
|
): Promise<QueueItemReport | undefined> {
|
|
246
|
-
const
|
|
260
|
+
const fio = resolveIo(io);
|
|
261
|
+
const doc = await resolveDocument(workspaceRoot, docId, fio);
|
|
247
262
|
if (!doc) return undefined;
|
|
248
263
|
|
|
249
264
|
const fm = doc.frontmatter;
|
|
@@ -268,8 +283,8 @@ export async function deriveQueueItemStatus(
|
|
|
268
283
|
}
|
|
269
284
|
|
|
270
285
|
const enhancedAt = fm["enhancedAt"] ? String(fm["enhancedAt"]) : undefined;
|
|
271
|
-
const auditFile = await findAuditFile(workspaceRoot, doc.id);
|
|
272
|
-
const planFile = await findPlanFile(workspaceRoot, doc.id);
|
|
286
|
+
const auditFile = await findAuditFile(workspaceRoot, doc.id, fio);
|
|
287
|
+
const planFile = await findPlanFile(workspaceRoot, doc.id, fio);
|
|
273
288
|
|
|
274
289
|
const stages = computeRfcPipelineStages({
|
|
275
290
|
status,
|
|
@@ -306,10 +321,12 @@ export interface QueueReport {
|
|
|
306
321
|
export async function deriveQueueReport(
|
|
307
322
|
workspaceRoot: string,
|
|
308
323
|
itemIds: string[],
|
|
324
|
+
io?: WorkspaceIO,
|
|
309
325
|
): Promise<QueueReport> {
|
|
326
|
+
const fio = resolveIo(io);
|
|
310
327
|
const items: QueueItemReport[] = [];
|
|
311
328
|
for (const id of itemIds) {
|
|
312
|
-
const report = await deriveQueueItemStatus(workspaceRoot, id);
|
|
329
|
+
const report = await deriveQueueItemStatus(workspaceRoot, id, fio);
|
|
313
330
|
// Unresolvable ids are reported by the manifest validator; the resolver
|
|
314
331
|
// skips them here so a partial report stays usable.
|
|
315
332
|
if (report) items.push(report);
|
|
@@ -20,7 +20,7 @@ Sweep batch 2: real KEY_DECISIONS on 10 files, expanded purposes (CONTRACT-02/PU
|
|
|
20
20
|
</CHANGE_SUMMARY>
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
import fs from "
|
|
23
|
+
import * as fs from "../utils/sync-fs.ts";
|
|
24
24
|
import path from "node:path";
|
|
25
25
|
import { z } from "zod";
|
|
26
26
|
import { parse as parseYaml } from "yaml";
|
package/src/registry.ts
CHANGED
|
@@ -19,7 +19,7 @@ Sweep batch 2: real KEY_DECISIONS on 10 files, expanded purposes (CONTRACT-02/PU
|
|
|
19
19
|
</CHANGE_SUMMARY>
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import fs from "
|
|
22
|
+
import * as fs from "./utils/sync-fs.ts";
|
|
23
23
|
import path from "node:path";
|
|
24
24
|
import { parse as parseYaml } from "yaml";
|
|
25
25
|
import type { ForgeConfig } from "./config/forge-config.ts";
|
|
@@ -38,7 +38,7 @@ export interface ForgeSkillEntry {
|
|
|
38
38
|
dependsOn: string[];
|
|
39
39
|
path: string;
|
|
40
40
|
knowledge?: string[];
|
|
41
|
-
|
|
41
|
+
triggerPhrases?: string[];
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -191,9 +191,9 @@ function discoverForgeSkills(skillsRoot: string): ForgeSkillEntry[] {
|
|
|
191
191
|
),
|
|
192
192
|
}
|
|
193
193
|
: {}),
|
|
194
|
-
...(Array.isArray(fm["
|
|
194
|
+
...(Array.isArray(fm["triggerPhrases"])
|
|
195
195
|
? {
|
|
196
|
-
|
|
196
|
+
triggerPhrases: (fm["triggerPhrases"] as unknown[]).filter(
|
|
197
197
|
(v): v is string => typeof v === "string",
|
|
198
198
|
),
|
|
199
199
|
}
|
package/src/skill-schema.ts
CHANGED
|
@@ -31,7 +31,10 @@ export const skillFrontmatterSchema = z.object({
|
|
|
31
31
|
})
|
|
32
32
|
.optional(),
|
|
33
33
|
knowledge: z.array(z.string()).optional(),
|
|
34
|
-
triggers
|
|
34
|
+
// Named triggerPhrases, not triggers — agent-IDE skill loaders (Devin CLI,
|
|
35
|
+
// Windsurf) reserve `triggers` for invocation modes (user/model); a list of
|
|
36
|
+
// phrases parses to zero valid modes and the skill is dropped entirely.
|
|
37
|
+
triggerPhrases: z.array(z.string().min(5).max(100)).max(5).optional(),
|
|
35
38
|
});
|
|
36
39
|
|
|
37
40
|
export type SkillFrontmatter = z.infer<typeof skillFrontmatterSchema>;
|
|
@@ -36,17 +36,13 @@ describe("validateAcceptanceShape — test probe", () => {
|
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
it("rejects a test probe missing file", () => {
|
|
39
|
-
const issues = validateAcceptanceShape([
|
|
40
|
-
{ probe: "test", expect: { exitCode: 0 } },
|
|
41
|
-
]);
|
|
39
|
+
const issues = validateAcceptanceShape([{ probe: "test", expect: { exitCode: 0 } }]);
|
|
42
40
|
expect(issues).toHaveLength(1);
|
|
43
41
|
expect(issues[0].message).toContain('requires a string "file"');
|
|
44
42
|
});
|
|
45
43
|
|
|
46
44
|
it("rejects a test probe missing expect.exitCode", () => {
|
|
47
|
-
const issues = validateAcceptanceShape([
|
|
48
|
-
{ probe: "test", file: "src/test.ts" },
|
|
49
|
-
]);
|
|
45
|
+
const issues = validateAcceptanceShape([{ probe: "test", file: "src/test.ts" }]);
|
|
50
46
|
expect(issues).toHaveLength(1);
|
|
51
47
|
expect(issues[0].message).toContain("requires expect: { exitCode");
|
|
52
48
|
});
|
|
@@ -108,9 +104,7 @@ describe("validateAcceptanceShape — existing probe kinds (regression)", () =>
|
|
|
108
104
|
});
|
|
109
105
|
|
|
110
106
|
it("accepts well-formed file-exists probe", () => {
|
|
111
|
-
const issues = validateAcceptanceShape([
|
|
112
|
-
{ probe: "file-exists", path: "src/index.ts" },
|
|
113
|
-
]);
|
|
107
|
+
const issues = validateAcceptanceShape([{ probe: "file-exists", path: "src/index.ts" }]);
|
|
114
108
|
expect(issues).toEqual([]);
|
|
115
109
|
});
|
|
116
110
|
|
|
@@ -122,16 +116,12 @@ describe("validateAcceptanceShape — existing probe kinds (regression)", () =>
|
|
|
122
116
|
});
|
|
123
117
|
|
|
124
118
|
it("accepts well-formed command-registered probe", () => {
|
|
125
|
-
const issues = validateAcceptanceShape([
|
|
126
|
-
{ probe: "command-registered", name: "rfc.validate" },
|
|
127
|
-
]);
|
|
119
|
+
const issues = validateAcceptanceShape([{ probe: "command-registered", name: "rfc.validate" }]);
|
|
128
120
|
expect(issues).toEqual([]);
|
|
129
121
|
});
|
|
130
122
|
|
|
131
123
|
it("accepts well-formed page probe", () => {
|
|
132
|
-
const issues = validateAcceptanceShape([
|
|
133
|
-
{ probe: "page", path: "/about" },
|
|
134
|
-
]);
|
|
124
|
+
const issues = validateAcceptanceShape([{ probe: "page", path: "/about" }]);
|
|
135
125
|
expect(issues).toEqual([]);
|
|
136
126
|
});
|
|
137
127
|
});
|
|
@@ -102,7 +102,8 @@ test("agents-generate includes intent-to-skill routing table", async () => {
|
|
|
102
102
|
|
|
103
103
|
const agentsMd = await readFile(join(tempDir, "AGENTS.md"), "utf8");
|
|
104
104
|
expect(agentsMd).toContain("### Intent-to-skill routing");
|
|
105
|
-
|
|
105
|
+
// RFC-1154: header cells are padded to column width — match via regex
|
|
106
|
+
expect(agentsMd).toMatch(/\| Operator says something like +\| Skill +\|/);
|
|
106
107
|
// Should contain at least one skill name from the registry
|
|
107
108
|
expect(agentsMd).toContain("fo-");
|
|
108
109
|
});
|
|
@@ -224,13 +225,36 @@ test("agents-generate is idempotent — running twice produces the same content"
|
|
|
224
225
|
expect(second).toBe(first);
|
|
225
226
|
});
|
|
226
227
|
|
|
227
|
-
|
|
228
|
+
// RFC-1150: hand-written root guard is non-fatal — skip root, continue nested
|
|
229
|
+
|
|
230
|
+
test("agents-generate skips hand-written root and still generates nested", async () => {
|
|
228
231
|
await makeForgeYaml(tempDir);
|
|
229
232
|
await writeFile(join(tempDir, "AGENTS.md"), "# Hand-written\nNo marker.\n", "utf8");
|
|
233
|
+
await mkdir(join(tempDir, "packages", "my-pkg"), { recursive: true });
|
|
234
|
+
await writeFile(
|
|
235
|
+
join(tempDir, "packages", "my-pkg", "package.json"),
|
|
236
|
+
JSON.stringify({ name: "@test/my-pkg" }),
|
|
237
|
+
);
|
|
230
238
|
|
|
231
239
|
const result = await runAgentsGenerate({ argv: [], flags: {} }, makeContext(tempDir));
|
|
232
|
-
expect(result.exitCode).toBe(
|
|
233
|
-
expect(result.data?.status).toBe("
|
|
240
|
+
expect(result.exitCode).toBe(0);
|
|
241
|
+
expect(result.data?.status).toBe("pass");
|
|
242
|
+
expect(result.data?.rootSkipped).toBe(true);
|
|
243
|
+
expect(result.data?.rootSkipReason).toBe("hand-written");
|
|
244
|
+
expect(result.data?.skipped).toContain("AGENTS.md (hand-written)");
|
|
245
|
+
expect(result.data?.generated).toContain("packages/my-pkg/AGENTS.md");
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test("agents-generate does not modify hand-written root AGENTS.md", async () => {
|
|
249
|
+
await makeForgeYaml(tempDir);
|
|
250
|
+
const original = "# Hand-written\nNo marker.\n";
|
|
251
|
+
await writeFile(join(tempDir, "AGENTS.md"), original, "utf8");
|
|
252
|
+
|
|
253
|
+
const result = await runAgentsGenerate({ argv: [], flags: {} }, makeContext(tempDir));
|
|
254
|
+
expect(result.exitCode).toBe(0);
|
|
255
|
+
|
|
256
|
+
const after = await readFile(join(tempDir, "AGENTS.md"), "utf8");
|
|
257
|
+
expect(after).toBe(original);
|
|
234
258
|
});
|
|
235
259
|
|
|
236
260
|
// RFC-0611: nested AGENTS.md generation tests
|
|
@@ -404,9 +428,10 @@ test("agents-generate nested renders entry points from exports map", async () =>
|
|
|
404
428
|
|
|
405
429
|
const nested = await readFile(join(tempDir, "packages", "my-pkg", "AGENTS.md"), "utf8");
|
|
406
430
|
expect(nested).toContain("## Entry points");
|
|
407
|
-
|
|
408
|
-
expect(nested).
|
|
409
|
-
expect(nested).
|
|
431
|
+
// RFC-1154: cells are padded to column width — match via regex
|
|
432
|
+
expect(nested).toMatch(/\| `@test\/my-pkg` +\| `\.\/src\/index\.ts` +\|/);
|
|
433
|
+
expect(nested).toMatch(/\| `@test\/my-pkg\/port` +\| `\.\/src\/port\.ts` +\|/);
|
|
434
|
+
expect(nested).toMatch(/\| `@test\/my-pkg\/client` +\| `\.\/src\/client\.ts` +\|/);
|
|
410
435
|
});
|
|
411
436
|
|
|
412
437
|
test("agents-generate nested separates workspace and external dependencies", async () => {
|
|
@@ -41,11 +41,15 @@ describe("contract-registry (RFC-0943)", () => {
|
|
|
41
41
|
|
|
42
42
|
describe("fileMatchesGlobs", () => {
|
|
43
43
|
test("matches a simple glob pattern", () => {
|
|
44
|
-
expect(fileMatchesGlobs("packages/my-pack/src/index.ts", ["packages/my-pack/**/*.ts"])).toBe(
|
|
44
|
+
expect(fileMatchesGlobs("packages/my-pack/src/index.ts", ["packages/my-pack/**/*.ts"])).toBe(
|
|
45
|
+
true,
|
|
46
|
+
);
|
|
45
47
|
});
|
|
46
48
|
|
|
47
49
|
test("does not match when glob does not match", () => {
|
|
48
|
-
expect(
|
|
50
|
+
expect(
|
|
51
|
+
fileMatchesGlobs("packages/other-pack/src/index.ts", ["packages/my-pack/**/*.ts"]),
|
|
52
|
+
).toBe(false);
|
|
49
53
|
});
|
|
50
54
|
|
|
51
55
|
test("matches any of multiple globs", () => {
|
|
@@ -58,7 +62,9 @@ describe("contract-registry (RFC-0943)", () => {
|
|
|
58
62
|
});
|
|
59
63
|
|
|
60
64
|
test("handles dot files with dot option", () => {
|
|
61
|
-
expect(fileMatchesGlobs("packages/my-pack/.env.example", ["packages/**/*.example"])).toBe(
|
|
65
|
+
expect(fileMatchesGlobs("packages/my-pack/.env.example", ["packages/**/*.example"])).toBe(
|
|
66
|
+
true,
|
|
67
|
+
);
|
|
62
68
|
});
|
|
63
69
|
});
|
|
64
70
|
|
|
@@ -86,7 +92,7 @@ describe("contract-registry (RFC-0943)", () => {
|
|
|
86
92
|
const packDir = join(ws, "my-pack");
|
|
87
93
|
writeManifest(
|
|
88
94
|
packDir,
|
|
89
|
-
|
|
95
|
+
'id: my-pack\nversion: 1.0.0\nextensionPoints:\n compass:\n contract:\n blocks:\n - blockId: api-contract\n requiredFor:\n - "packages/my-pack/**/*.ts"\n requiredTags:\n - name: endpoints\n minWords: 5\n',
|
|
90
96
|
);
|
|
91
97
|
|
|
92
98
|
const config: ForgeConfig = {
|
|
@@ -111,11 +117,11 @@ describe("contract-registry (RFC-0943)", () => {
|
|
|
111
117
|
try {
|
|
112
118
|
writeManifest(
|
|
113
119
|
join(ws, "pack-a"),
|
|
114
|
-
|
|
120
|
+
'id: pack-a\nversion: 1.0.0\nextensionPoints:\n compass:\n contract:\n blocks:\n - blockId: shared-block\n requiredFor:\n - "packages/**/*.ts"\n',
|
|
115
121
|
);
|
|
116
122
|
writeManifest(
|
|
117
123
|
join(ws, "pack-b"),
|
|
118
|
-
|
|
124
|
+
'id: pack-b\nversion: 1.0.0\nextensionPoints:\n compass:\n contract:\n blocks:\n - blockId: shared-block\n requiredFor:\n - "services/**/*.ts"\n',
|
|
119
125
|
);
|
|
120
126
|
|
|
121
127
|
const config: ForgeConfig = {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>Unit tests for the dist-freshness doctor check — warns when a forge
|
|
4
|
+
source checkout's dist/ is older than the newest src/ file (RFC-1151).</purpose>
|
|
5
|
+
</MODULE_CONTRACT>
|
|
6
|
+
<CHANGE_SUMMARY>
|
|
7
|
+
<item>RFC-1151: initial dist-freshness tests.</item>
|
|
8
|
+
</CHANGE_SUMMARY>
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { test, expect, beforeEach, afterEach } from "vitest";
|
|
12
|
+
import { mkdtemp, rm, mkdir, writeFile, utimes } from "node:fs/promises";
|
|
13
|
+
import { tmpdir } from "node:os";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { runDoctor } from "../onboarding/doctor.ts";
|
|
16
|
+
import type { ForgeCommandInput, ForgeRuntimeContext } from "../types.ts";
|
|
17
|
+
|
|
18
|
+
let tempDir: string;
|
|
19
|
+
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
tempDir = await mkdtemp(join(tmpdir(), "doctor-dist-test-"));
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
function makeContext(): ForgeRuntimeContext {
|
|
29
|
+
return {
|
|
30
|
+
workspaceRoot: tempDir,
|
|
31
|
+
// forgeRoot falls back to <workspaceRoot>/packages/forge when unresolvable
|
|
32
|
+
forgeRoot: join(tempDir, "packages", "forge"),
|
|
33
|
+
logger: {
|
|
34
|
+
section: () => {},
|
|
35
|
+
success: () => {},
|
|
36
|
+
warn: () => {},
|
|
37
|
+
error: () => {},
|
|
38
|
+
info: () => {},
|
|
39
|
+
},
|
|
40
|
+
dryRun: false,
|
|
41
|
+
outputFormat: "json",
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const FORGE_YAML = `schema: "forge/config@1"
|
|
46
|
+
project:
|
|
47
|
+
name: test-project
|
|
48
|
+
stack: []
|
|
49
|
+
packageManager: pnpm
|
|
50
|
+
paths:
|
|
51
|
+
rfcsDir: docs/rfcs
|
|
52
|
+
adrsDir: docs/adrs
|
|
53
|
+
plansDir: docs/plans
|
|
54
|
+
auditsDir: docs/audits
|
|
55
|
+
specsDir: docs/specs
|
|
56
|
+
skillsDir: .agents/skills
|
|
57
|
+
sessionsDir: docs/sessions
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
async function makeForgeCheckout(srcMtime: Date, distMtime: Date): Promise<void> {
|
|
61
|
+
const forgeRoot = join(tempDir, "packages", "forge");
|
|
62
|
+
await mkdir(join(forgeRoot, "src"), { recursive: true });
|
|
63
|
+
await mkdir(join(forgeRoot, "dist"), { recursive: true });
|
|
64
|
+
await writeFile(join(forgeRoot, "package.json"), JSON.stringify({ name: "@warpgogol/forge" }));
|
|
65
|
+
await writeFile(join(forgeRoot, "src", "index.ts"), "export {};\n");
|
|
66
|
+
await writeFile(join(forgeRoot, "dist", "index.js"), "export {};\n");
|
|
67
|
+
await utimes(join(forgeRoot, "src", "index.ts"), srcMtime, srcMtime);
|
|
68
|
+
await utimes(join(forgeRoot, "dist"), distMtime, distMtime);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
test("dist-freshness warns when dist is older than newest src file", async () => {
|
|
72
|
+
await writeFile(join(tempDir, "forge.yaml"), FORGE_YAML, "utf8");
|
|
73
|
+
const old = new Date("2026-01-01T00:00:00Z");
|
|
74
|
+
const recent = new Date("2026-09-01T00:00:00Z");
|
|
75
|
+
await makeForgeCheckout(recent, old);
|
|
76
|
+
|
|
77
|
+
const input: ForgeCommandInput = { argv: [], flags: {} };
|
|
78
|
+
const result = await runDoctor(input, makeContext());
|
|
79
|
+
|
|
80
|
+
const check = result.data!.checks.find((c) => c.name === "dist-freshness");
|
|
81
|
+
expect(check).toBeDefined();
|
|
82
|
+
expect(check!.status).toBe("warn");
|
|
83
|
+
expect(check!.message).toContain("pnpm run build");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("dist-freshness passes when dist is absent (npm consumer layout)", async () => {
|
|
87
|
+
await writeFile(join(tempDir, "forge.yaml"), FORGE_YAML, "utf8");
|
|
88
|
+
// No packages/forge at all — forgeRoot fallback dir doesn't exist
|
|
89
|
+
const input: ForgeCommandInput = { argv: [], flags: {} };
|
|
90
|
+
const result = await runDoctor(input, makeContext());
|
|
91
|
+
|
|
92
|
+
const check = result.data!.checks.find((c) => c.name === "dist-freshness");
|
|
93
|
+
expect(check).toBeDefined();
|
|
94
|
+
expect(check!.status).toBe("pass");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("dist-freshness passes when dist is newer than src", async () => {
|
|
98
|
+
await writeFile(join(tempDir, "forge.yaml"), FORGE_YAML, "utf8");
|
|
99
|
+
const old = new Date("2026-01-01T00:00:00Z");
|
|
100
|
+
const recent = new Date("2026-09-01T00:00:00Z");
|
|
101
|
+
await makeForgeCheckout(old, recent);
|
|
102
|
+
|
|
103
|
+
const input: ForgeCommandInput = { argv: [], flags: {} };
|
|
104
|
+
const result = await runDoctor(input, makeContext());
|
|
105
|
+
|
|
106
|
+
const check = result.data!.checks.find((c) => c.name === "dist-freshness");
|
|
107
|
+
expect(check).toBeDefined();
|
|
108
|
+
expect(check!.status).toBe("pass");
|
|
109
|
+
expect(check!.message).toContain("fresh");
|
|
110
|
+
});
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>Unit tests for forge doctor --fix — safe remediations for warn/fail
|
|
4
|
+
checks: nested-AGENTS.md regeneration and memory-layer compaction (RFC-1151).</purpose>
|
|
5
|
+
</MODULE_CONTRACT>
|
|
6
|
+
<CHANGE_SUMMARY>
|
|
7
|
+
<item>RFC-1151: initial doctor --fix tests.</item>
|
|
8
|
+
</CHANGE_SUMMARY>
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { test, expect, beforeEach, afterEach } from "vitest";
|
|
12
|
+
import { mkdtemp, rm, mkdir, writeFile, readFile } from "node:fs/promises";
|
|
13
|
+
import { tmpdir } from "node:os";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { runDoctor } from "../onboarding/doctor.ts";
|
|
16
|
+
import type { ForgeCommandInput, ForgeRuntimeContext } from "../types.ts";
|
|
17
|
+
|
|
18
|
+
let tempDir: string;
|
|
19
|
+
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
tempDir = await mkdtemp(join(tmpdir(), "doctor-fix-test-"));
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
function makeContext(dryRun = false): ForgeRuntimeContext {
|
|
29
|
+
return {
|
|
30
|
+
workspaceRoot: tempDir,
|
|
31
|
+
logger: {
|
|
32
|
+
section: () => {},
|
|
33
|
+
success: () => {},
|
|
34
|
+
warn: () => {},
|
|
35
|
+
error: () => {},
|
|
36
|
+
info: () => {},
|
|
37
|
+
},
|
|
38
|
+
dryRun,
|
|
39
|
+
outputFormat: "json",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const FORGE_YAML = `schema: "forge/config@1"
|
|
44
|
+
project:
|
|
45
|
+
name: test-project
|
|
46
|
+
stack: []
|
|
47
|
+
packageManager: pnpm
|
|
48
|
+
paths:
|
|
49
|
+
rfcsDir: docs/rfcs
|
|
50
|
+
adrsDir: docs/adrs
|
|
51
|
+
plansDir: docs/plans
|
|
52
|
+
auditsDir: docs/audits
|
|
53
|
+
specsDir: docs/specs
|
|
54
|
+
skillsDir: .agents/skills
|
|
55
|
+
sessionsDir: docs/sessions
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
const GENERATED_MARKER =
|
|
59
|
+
"<!--\n GENERATED. Do not change this line unless the file contains project specific changes.\n-->\n";
|
|
60
|
+
|
|
61
|
+
async function makeStaleWorkspace(): Promise<void> {
|
|
62
|
+
await mkdir(join(tempDir, "packages", "my-pkg"), { recursive: true });
|
|
63
|
+
await writeFile(
|
|
64
|
+
join(tempDir, "packages", "my-pkg", "package.json"),
|
|
65
|
+
JSON.stringify({ name: "@test/my-pkg" }),
|
|
66
|
+
);
|
|
67
|
+
// Generated marker + outdated content → stale
|
|
68
|
+
await writeFile(
|
|
69
|
+
join(tempDir, "packages", "my-pkg", "AGENTS.md"),
|
|
70
|
+
`${GENERATED_MARKER}# Old content\n`,
|
|
71
|
+
"utf8",
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
test("doctor --fix regenerates stale nested AGENTS.md and subsequent run passes", async () => {
|
|
76
|
+
await writeFile(join(tempDir, "forge.yaml"), FORGE_YAML, "utf8");
|
|
77
|
+
await makeStaleWorkspace();
|
|
78
|
+
|
|
79
|
+
const fixInput: ForgeCommandInput = { argv: [], flags: { fix: true } };
|
|
80
|
+
const fixResult = await runDoctor(fixInput, makeContext());
|
|
81
|
+
|
|
82
|
+
const fixEntry = fixResult.data!.fixes?.find((f) => f.check === "nested-AGENTS.md");
|
|
83
|
+
expect(fixEntry).toBeDefined();
|
|
84
|
+
expect(fixEntry!.action).toBe("fixed");
|
|
85
|
+
|
|
86
|
+
const regenerated = await readFile(join(tempDir, "packages", "my-pkg", "AGENTS.md"), "utf8");
|
|
87
|
+
expect(regenerated).toContain("`@test/my-pkg` — Agent Guide");
|
|
88
|
+
expect(regenerated).not.toContain("Old content");
|
|
89
|
+
|
|
90
|
+
// Subsequent doctor run: nested-AGENTS.md no longer reports this file stale
|
|
91
|
+
const verifyResult = await runDoctor({ argv: [], flags: {} }, makeContext());
|
|
92
|
+
const check = verifyResult.data!.checks.find((c) => c.name === "nested-AGENTS.md");
|
|
93
|
+
expect(check!.message).not.toContain("my-pkg/AGENTS.md stale");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("doctor --fix does not modify hand-written nested AGENTS.md", async () => {
|
|
97
|
+
await writeFile(join(tempDir, "forge.yaml"), FORGE_YAML, "utf8");
|
|
98
|
+
await mkdir(join(tempDir, "packages", "my-pkg"), { recursive: true });
|
|
99
|
+
await writeFile(
|
|
100
|
+
join(tempDir, "packages", "my-pkg", "package.json"),
|
|
101
|
+
JSON.stringify({ name: "@test/my-pkg" }),
|
|
102
|
+
);
|
|
103
|
+
const handwritten = "# Custom\nNo marker.\n";
|
|
104
|
+
await writeFile(join(tempDir, "packages", "my-pkg", "AGENTS.md"), handwritten, "utf8");
|
|
105
|
+
|
|
106
|
+
const result = await runDoctor({ argv: [], flags: { fix: true } }, makeContext());
|
|
107
|
+
expect(result.data!.fixes).toBeDefined();
|
|
108
|
+
|
|
109
|
+
const after = await readFile(join(tempDir, "packages", "my-pkg", "AGENTS.md"), "utf8");
|
|
110
|
+
expect(after).toBe(handwritten);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("doctor --fix compacts over-budget MEMORY.md", async () => {
|
|
114
|
+
await writeFile(join(tempDir, "forge.yaml"), FORGE_YAML, "utf8");
|
|
115
|
+
await mkdir(join(tempDir, ".agents", "memory"), { recursive: true });
|
|
116
|
+
const env = Array.from({ length: 30 }, (_, i) => `- env ${i} ${"x".repeat(200)}`).join("\n");
|
|
117
|
+
await writeFile(
|
|
118
|
+
join(tempDir, ".agents", "memory", "MEMORY.md"),
|
|
119
|
+
`# Project Memory\n\n## Current focus\n\n- keep\n\n## Environment notes\n\n${env}\n`,
|
|
120
|
+
"utf8",
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const result = await runDoctor({ argv: [], flags: { fix: true } }, makeContext());
|
|
124
|
+
const fixEntry = result.data!.fixes?.find((f) => f.check === "memory-layer");
|
|
125
|
+
expect(fixEntry).toBeDefined();
|
|
126
|
+
expect(fixEntry!.action).toBe("fixed");
|
|
127
|
+
|
|
128
|
+
const after = await readFile(join(tempDir, ".agents", "memory", "MEMORY.md"), "utf8");
|
|
129
|
+
expect(after.length).toBeLessThanOrEqual(4096);
|
|
130
|
+
expect(after).toContain("- keep");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("doctor without --fix produces no fixes array and does not mutate", async () => {
|
|
134
|
+
await writeFile(join(tempDir, "forge.yaml"), FORGE_YAML, "utf8");
|
|
135
|
+
await makeStaleWorkspace();
|
|
136
|
+
|
|
137
|
+
const result = await runDoctor({ argv: [], flags: {} }, makeContext());
|
|
138
|
+
expect(result.data!.fixes).toBeUndefined();
|
|
139
|
+
|
|
140
|
+
const after = await readFile(join(tempDir, "packages", "my-pkg", "AGENTS.md"), "utf8");
|
|
141
|
+
expect(after).toContain("Old content");
|
|
142
|
+
});
|