@warpgogol/forge 4.2.4 → 5.1.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/AGENTS.md +14 -6
- package/CHANGELOG.md +72 -0
- package/README.md +8 -8
- package/README.uk.md +5 -5
- package/dist/os/adr/handlers/list-create.d.ts.map +1 -1
- package/dist/os/adr/handlers/list-create.js +4 -1
- package/dist/os/adr/handlers/list-create.js.map +1 -1
- package/dist/os/adr/handlers/validate.d.ts.map +1 -1
- package/dist/os/adr/handlers/validate.js +6 -1
- package/dist/os/adr/handlers/validate.js.map +1 -1
- package/dist/os/adr/types.d.ts.map +1 -1
- package/dist/os/adr/types.js +7 -3
- package/dist/os/adr/types.js.map +1 -1
- package/dist/os/compass/compass.module.d.ts.map +1 -1
- package/dist/os/compass/compass.module.js +76 -10
- 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 +7 -3
- package/dist/os/compass/handlers/compass-audit-handler.js.map +1 -1
- package/dist/os/compass/handlers/compass-change-summary-handler.d.ts +1 -9
- package/dist/os/compass/handlers/compass-change-summary-handler.d.ts.map +1 -1
- package/dist/os/compass/handlers/compass-change-summary-handler.js +44 -186
- package/dist/os/compass/handlers/compass-change-summary-handler.js.map +1 -1
- package/dist/os/compass/handlers/compass-inventory-handler.d.ts +2 -0
- package/dist/os/compass/handlers/compass-inventory-handler.d.ts.map +1 -1
- package/dist/os/compass/handlers/compass-inventory-handler.js +24 -12
- package/dist/os/compass/handlers/compass-inventory-handler.js.map +1 -1
- package/dist/os/compass/handlers/compass-inventory.d.ts +7 -5
- package/dist/os/compass/handlers/compass-inventory.d.ts.map +1 -1
- package/dist/os/compass/handlers/compass-inventory.js +84 -241
- package/dist/os/compass/handlers/compass-inventory.js.map +1 -1
- package/dist/os/compass/handlers/compass-migrate-handler.d.ts +4 -0
- package/dist/os/compass/handlers/compass-migrate-handler.d.ts.map +1 -0
- package/dist/os/compass/handlers/compass-migrate-handler.js +100 -0
- package/dist/os/compass/handlers/compass-migrate-handler.js.map +1 -0
- package/dist/os/compass/handlers/compass-migrate.d.ts +34 -0
- package/dist/os/compass/handlers/compass-migrate.d.ts.map +1 -0
- package/dist/os/compass/handlers/compass-migrate.js +273 -0
- package/dist/os/compass/handlers/compass-migrate.js.map +1 -0
- package/dist/os/compass/handlers/resolve-scan-root.d.ts.map +1 -1
- package/dist/os/compass/handlers/resolve-scan-root.js +15 -8
- package/dist/os/compass/handlers/resolve-scan-root.js.map +1 -1
- package/dist/os/compass/handlers/summary-record.d.ts +46 -0
- package/dist/os/compass/handlers/summary-record.d.ts.map +1 -0
- package/dist/os/compass/handlers/summary-record.js +233 -0
- package/dist/os/compass/handlers/summary-record.js.map +1 -0
- package/dist/os/compass/index.d.ts +4 -1
- package/dist/os/compass/index.d.ts.map +1 -1
- package/dist/os/compass/index.js +9 -1
- package/dist/os/compass/index.js.map +1 -1
- package/dist/os/compass/policy.d.ts +65 -0
- package/dist/os/compass/policy.d.ts.map +1 -0
- package/dist/os/compass/policy.js +241 -0
- package/dist/os/compass/policy.js.map +1 -0
- package/dist/os/core/core.module.d.ts.map +1 -1
- package/dist/os/core/core.module.js +11 -23
- package/dist/os/core/core.module.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 +7 -1
- package/dist/os/core/handlers/forge-autonomy-validate.js.map +1 -1
- package/dist/os/core/handlers/package-health.d.ts.map +1 -1
- package/dist/os/core/handlers/package-health.js +6 -1
- package/dist/os/core/handlers/package-health.js.map +1 -1
- package/dist/os/core/handlers/pinned-check.d.ts.map +1 -1
- package/dist/os/core/handlers/pinned-check.js +6 -1
- package/dist/os/core/handlers/pinned-check.js.map +1 -1
- package/dist/os/core/handlers/pinned-validate.d.ts.map +1 -1
- package/dist/os/core/handlers/pinned-validate.js +6 -1
- package/dist/os/core/handlers/pinned-validate.js.map +1 -1
- package/dist/os/core/handlers/validate.d.ts.map +1 -1
- package/dist/os/core/handlers/validate.js +6 -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 +6 -4
- package/dist/os/exploration/exploration.module.js.map +1 -1
- package/dist/os/exploration/handlers/list.d.ts.map +1 -1
- package/dist/os/exploration/handlers/list.js +4 -1
- package/dist/os/exploration/handlers/list.js.map +1 -1
- package/dist/os/mission/handlers/archive.d.ts.map +1 -1
- package/dist/os/mission/handlers/archive.js +7 -3
- package/dist/os/mission/handlers/archive.js.map +1 -1
- package/dist/os/mission/index.d.ts.map +1 -1
- package/dist/os/mission/index.js +13 -0
- package/dist/os/mission/index.js.map +1 -1
- package/dist/os/notes/index.d.ts.map +1 -1
- package/dist/os/notes/index.js +7 -1
- package/dist/os/notes/index.js.map +1 -1
- package/dist/os/rfc/frontmatter-io.d.ts.map +1 -1
- package/dist/os/rfc/frontmatter-io.js +6 -1
- 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 +6 -1
- package/dist/os/rfc/handlers/archive.js.map +1 -1
- package/dist/os/rfc/handlers/implement-stamp.d.ts.map +1 -1
- package/dist/os/rfc/handlers/implement-stamp.js +7 -3
- package/dist/os/rfc/handlers/implement-stamp.js.map +1 -1
- package/dist/os/rfc/handlers/index-graph.d.ts.map +1 -1
- package/dist/os/rfc/handlers/index-graph.js +6 -1
- 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 -1
- 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 +6 -1
- package/dist/os/rfc/handlers/list-create.js.map +1 -1
- package/dist/os/rfc/handlers/pipeline-status.d.ts.map +1 -1
- package/dist/os/rfc/handlers/pipeline-status.js +6 -1
- package/dist/os/rfc/handlers/pipeline-status.js.map +1 -1
- package/dist/os/rfc/handlers/supersede-propose.d.ts.map +1 -1
- package/dist/os/rfc/handlers/supersede-propose.js +6 -1
- 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 +7 -3
- 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/index.d.ts.map +1 -1
- package/dist/os/rfc/index.js +6 -1
- package/dist/os/rfc/index.js.map +1 -1
- package/dist/os/rfc/rfc.module.d.ts.map +1 -1
- package/dist/os/rfc/rfc.module.js +6 -1
- package/dist/os/rfc/rfc.module.js.map +1 -1
- package/dist/os/rfc/types.d.ts +7 -4
- package/dist/os/rfc/types.d.ts.map +1 -1
- package/dist/os/rfc/types.js +7 -4
- package/dist/os/rfc/types.js.map +1 -1
- package/dist/os/session/handlers/save.d.ts.map +1 -1
- package/dist/os/session/handlers/save.js +6 -1
- package/dist/os/session/handlers/save.js.map +1 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.d.ts.map +1 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js +6 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js.map +1 -1
- package/dist/os/werkstatt/handlers/workspace-deps.js +3 -3
- package/dist/os/werkstatt/handlers/workspace-deps.js.map +1 -1
- package/dist/os/workflow/index.d.ts.map +1 -1
- package/dist/os/workflow/index.js +6 -1
- package/dist/os/workflow/index.js.map +1 -1
- package/dist/src/config/forge-config.d.ts +62 -4
- package/dist/src/config/forge-config.d.ts.map +1 -1
- package/dist/src/config/forge-config.js +35 -19
- package/dist/src/config/forge-config.js.map +1 -1
- package/dist/src/forge-module.d.ts.map +1 -1
- package/dist/src/forge-module.js +6 -1
- package/dist/src/forge-module.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +10 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/migration-adapters/git-utils.d.ts.map +1 -1
- package/dist/src/migration-adapters/git-utils.js +6 -2
- package/dist/src/migration-adapters/git-utils.js.map +1 -1
- package/dist/src/migration-adapters/ignored-files.d.ts.map +1 -1
- package/dist/src/migration-adapters/ignored-files.js +6 -1
- package/dist/src/migration-adapters/ignored-files.js.map +1 -1
- package/dist/src/migration-adapters/index.d.ts.map +1 -1
- package/dist/src/migration-adapters/index.js +4 -1
- package/dist/src/migration-adapters/index.js.map +1 -1
- package/dist/src/migration-adapters/types.d.ts.map +1 -1
- package/dist/src/migration-adapters/types.js +6 -2
- package/dist/src/migration-adapters/types.js.map +1 -1
- package/dist/src/onboarding/agents-generate.d.ts.map +1 -1
- package/dist/src/onboarding/agents-generate.js +18 -14
- 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 +7 -6
- 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 +7 -13
- 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 +7 -12
- package/dist/src/onboarding/init.js.map +1 -1
- package/dist/src/onboarding/invariant-engine.d.ts.map +1 -1
- package/dist/src/onboarding/invariant-engine.js +7 -2
- package/dist/src/onboarding/invariant-engine.js.map +1 -1
- package/dist/src/onboarding/nested-agents-generate.d.ts.map +1 -1
- package/dist/src/onboarding/nested-agents-generate.js +7 -2
- 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 +11 -3
- package/dist/src/onboarding/nested-agents-templates.js.map +1 -1
- package/dist/src/onboarding/scaffold-project.d.ts.map +1 -1
- package/dist/src/onboarding/scaffold-project.js +6 -1
- package/dist/src/onboarding/scaffold-project.js.map +1 -1
- package/dist/src/onboarding/upgrade.d.ts.map +1 -1
- package/dist/src/onboarding/upgrade.js +7 -3
- package/dist/src/onboarding/upgrade.js.map +1 -1
- package/dist/src/profiles/profile-schema.d.ts +54 -4
- package/dist/src/profiles/profile-schema.d.ts.map +1 -1
- package/dist/src/profiles/profile-schema.js +34 -14
- package/dist/src/profiles/profile-schema.js.map +1 -1
- package/dist/src/profiles/stack-profile.d.ts +24 -0
- package/dist/src/profiles/stack-profile.d.ts.map +1 -1
- package/dist/src/profiles/stack-profile.js +7 -3
- package/dist/src/profiles/stack-profile.js.map +1 -1
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +7 -9
- package/dist/src/registry.js.map +1 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +6 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils/fs-atomic.d.ts.map +1 -1
- package/dist/src/utils/fs-atomic.js +13 -1
- package/dist/src/utils/fs-atomic.js.map +1 -1
- package/dist/src/utils/fs-idempotent.d.ts.map +1 -1
- package/dist/src/utils/fs-idempotent.js +13 -0
- package/dist/src/utils/fs-idempotent.js.map +1 -1
- package/dist/src/utils/fs-trash-sync.d.ts.map +1 -1
- package/dist/src/utils/fs-trash-sync.js +13 -1
- package/dist/src/utils/fs-trash-sync.js.map +1 -1
- package/dist/src/utils/fs-trash.d.ts.map +1 -1
- package/dist/src/utils/fs-trash.js +13 -1
- package/dist/src/utils/fs-trash.js.map +1 -1
- package/dist/src/utils/fs.d.ts.map +1 -1
- package/dist/src/utils/fs.js +14 -3
- package/dist/src/utils/fs.js.map +1 -1
- package/dist/src/utils/hash.d.ts.map +1 -1
- package/dist/src/utils/hash.js +12 -1
- package/dist/src/utils/hash.js.map +1 -1
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +13 -2
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/utils/string-utils.d.ts.map +1 -1
- package/dist/src/utils/string-utils.js +12 -1
- package/dist/src/utils/string-utils.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 +7 -8
- package/dist/src/validators/skill-validate.js.map +1 -1
- package/docs/getting-started.md +1 -1
- package/docs/reference/forge-yaml.md +38 -9
- package/docs/reference/profiles.md +8 -8
- package/os/adr/handlers/list-create.ts +4 -1
- package/os/adr/handlers/validate.ts +6 -1
- package/os/adr/types.ts +7 -3
- package/os/compass/compass.module.ts +79 -13
- package/os/compass/handlers/compass-audit-handler.ts +22 -3
- package/os/compass/handlers/compass-change-summary-handler.ts +55 -227
- package/os/compass/handlers/compass-inventory-handler.ts +30 -12
- package/os/compass/handlers/compass-inventory.ts +103 -240
- package/os/compass/handlers/compass-migrate-handler.ts +122 -0
- package/os/compass/handlers/compass-migrate.ts +361 -0
- package/os/compass/handlers/resolve-scan-root-package.test.ts +70 -0
- package/os/compass/handlers/resolve-scan-root.ts +15 -8
- package/os/compass/handlers/summary-record.ts +313 -0
- package/os/compass/handlers/tests/compass-migrate.test.ts +291 -0
- package/os/compass/handlers/tests/compass-policy.test.ts +249 -0
- package/os/compass/handlers/tests/compass-v2-contract.test.ts +9 -9
- package/os/compass/handlers/tests/summary-record.test.ts +224 -0
- package/os/compass/index.ts +23 -5
- package/os/compass/policy.ts +350 -0
- package/os/core/core.module.ts +11 -23
- package/os/core/handlers/forge-autonomy-validate.ts +7 -1
- package/os/core/handlers/package-health.ts +6 -1
- package/os/core/handlers/pinned-check.ts +6 -1
- package/os/core/handlers/pinned-validate.ts +6 -1
- package/os/core/handlers/validate.ts +6 -1
- package/os/exploration/exploration.module.ts +72 -71
- package/os/exploration/handlers/list.ts +4 -1
- package/os/mission/handlers/archive.ts +7 -3
- package/os/mission/index.ts +14 -0
- package/os/notes/index.ts +7 -1
- package/os/rfc/frontmatter-io.ts +6 -1
- package/os/rfc/handlers/archive.ts +6 -1
- package/os/rfc/handlers/implement-stamp.ts +7 -3
- package/os/rfc/handlers/index-graph.ts +6 -1
- package/os/rfc/handlers/lifecycle.ts +6 -1
- package/os/rfc/handlers/list-create.ts +6 -1
- package/os/rfc/handlers/pipeline-status.ts +6 -1
- package/os/rfc/handlers/supersede-propose.ts +6 -1
- package/os/rfc/handlers/validate-rules.ts +7 -3
- package/os/rfc/handlers/validate.ts +6 -1
- package/os/rfc/index.ts +6 -1
- package/os/rfc/rfc.module.ts +6 -1
- package/os/rfc/types.ts +7 -4
- package/os/session/handlers/save.ts +6 -1
- package/os/werkstatt/handlers/werkstatt-lock-recover.ts +6 -1
- package/os/werkstatt/handlers/workspace-deps.ts +3 -3
- package/os/workflow/index.ts +6 -1
- package/package.json +1 -1
- package/profiles/{godot-csharp.yaml → godot-game.yaml} +2 -2
- package/profiles/{knowledge-typescript-turborepo.yaml → knowledge.yaml} +1 -1
- package/profiles/{phaser-turborepo.yaml → phaser-game.yaml} +2 -2
- package/profiles/{typescript-turborepo.yaml → typescript.yaml} +2 -2
- package/skills/fo/fo-add-tests/SKILL.md +14 -0
- package/skills/fo/fo-architecture/SKILL.md +14 -0
- package/skills/fo/fo-compass-annotate/SKILL.md +14 -0
- package/skills/fo/fo-design-summit/SKILL.md +14 -0
- package/skills/fo/fo-doc-audit/SKILL.md +14 -0
- package/skills/fo/fo-explore/SKILL.md +14 -0
- package/skills/fo/fo-extract-dna/SKILL.md +14 -0
- package/skills/fo/fo-fix/SKILL.md +14 -0
- package/skills/fo/fo-handoff/SKILL.md +14 -0
- package/skills/fo/fo-harvest/SKILL.md +14 -0
- package/skills/fo/fo-idea/SKILL.md +14 -0
- package/skills/fo/fo-idea-audit/SKILL.md +14 -0
- package/skills/fo/fo-idea-create-adr/SKILL.md +14 -0
- package/skills/fo/fo-idea-create-rfc/SKILL.md +14 -0
- package/skills/fo/fo-idea-enhance/SKILL.md +14 -0
- package/skills/fo/fo-idea-i-just-want-to-see-the-plan/SKILL.md +14 -0
- package/skills/fo/fo-idea-i-just-want-to-see-the-result/SKILL.md +14 -0
- package/skills/fo/fo-idea-implement/SKILL.md +14 -0
- package/skills/fo/fo-idea-plan/SKILL.md +14 -0
- package/skills/fo/fo-idea-status/SKILL.md +14 -0
- package/skills/fo/fo-knowledge-distill/SKILL.md +14 -0
- package/skills/fo/fo-memory-sync/SKILL.md +14 -0
- package/skills/fo/fo-qa/SKILL.md +14 -0
- package/skills/fo/fo-review/SKILL.md +14 -0
- package/skills/fo/fo-session-retro/SKILL.md +14 -0
- package/skills/fo/fo-session-save/SKILL.md +14 -0
- package/skills/fo/fo-spec-ingest/SKILL.md +14 -0
- package/skills/fo/fo-step-commit/SKILL.md +14 -0
- package/skills/fo/fo-triage/SKILL.md +14 -0
- package/skills/meta/forge-bootstrap/SKILL.md +14 -0
- package/skills/meta/port-to-forge/SKILL.md +14 -0
- package/skills/meta/skill-create/SKILL.md +14 -0
- package/skills/shared/grilling/SKILL.md +14 -0
- package/skills/shared/my-preferences/SKILL.md +14 -0
- package/skills/shared/windows-ai-tooling/SKILL.md +14 -0
- package/skills/shared/writing-great-skills/SKILL.md +14 -0
- package/src/config/forge-config.ts +40 -23
- package/src/forge-module.ts +6 -1
- package/src/index.ts +10 -2
- package/src/migration-adapters/git-utils.ts +6 -2
- package/src/migration-adapters/ignored-files.ts +6 -1
- package/src/migration-adapters/index.ts +4 -1
- package/src/migration-adapters/types.ts +6 -2
- package/src/onboarding/agents-generate.ts +23 -14
- package/src/onboarding/create.ts +7 -6
- package/src/onboarding/doctor.ts +7 -13
- package/src/onboarding/init.ts +7 -12
- package/src/onboarding/invariant-engine.ts +7 -2
- package/src/onboarding/nested-agents-generate.ts +7 -2
- package/src/onboarding/nested-agents-templates.ts +11 -3
- package/src/onboarding/scaffold-project.ts +6 -1
- package/src/onboarding/upgrade.ts +7 -3
- package/src/profiles/profile-schema.ts +42 -18
- package/src/profiles/stack-profile.ts +7 -3
- package/src/registry.ts +7 -9
- package/src/tests/agents-generate-domain.test.ts +3 -3
- package/src/tests/agents-generate.test.ts +2 -2
- package/src/tests/create.test.ts +4 -4
- package/src/tests/forge-autonomy-validate.test.ts +1 -1
- package/src/tests/package-files.test.ts +53 -1
- package/src/tests/profile-schema.test.ts +4 -4
- package/src/tests/scaffold-project.test.ts +3 -3
- package/src/tests/stack-profile.test.ts +12 -12
- package/src/types.ts +6 -1
- package/src/utils/fs-atomic.ts +13 -1
- package/src/utils/fs-idempotent.ts +13 -0
- package/src/utils/fs-trash-sync.ts +13 -1
- package/src/utils/fs-trash.ts +13 -1
- package/src/utils/fs.ts +14 -3
- package/src/utils/hash.ts +12 -1
- package/src/utils/index.ts +13 -2
- package/src/utils/string-utils.ts +12 -1
- package/src/validators/port-validate.ts +1 -1
- package/src/validators/skill-validate.ts +7 -8
- package/skills/shared/extension-e2e-mitm/SKILL.md +0 -53
- package/skills/shared/extension-e2e-mitm/fixture-proxy.ts +0 -113
- package/src/types/werkstatt-engine-shims.d.ts +0 -1416
- package/src/types/werkstatt-shared-shims.d.ts +0 -5686
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
<MODULE_CONTRACT>
|
|
3
|
-
<purpose>Canonical Compass inventory scanning logic. Moved from
|
|
4
|
-
to @warpgogol/forge for full autonomous mode (RFC-0556). Provides file collection,
|
|
3
|
+
<purpose>Canonical Compass inventory scanning logic. Moved from the legacy site
|
|
4
|
+
kernel package to @warpgogol/forge for full autonomous mode (RFC-0556). Provides file collection,
|
|
5
5
|
workspace detection, layer classification, risk assessment, and compliance checking
|
|
6
6
|
for Compass source-file inventory.</purpose>
|
|
7
7
|
<non-goals>
|
|
@@ -9,82 +9,37 @@ for Compass source-file inventory.</purpose>
|
|
|
9
9
|
<item>Do not register commands — this is a pure utility module.</item>
|
|
10
10
|
</non-goals>
|
|
11
11
|
</MODULE_CONTRACT>
|
|
12
|
+
<KEY_DECISIONS>
|
|
13
|
+
<item>Authoring status is classified before compliance — generated, test, and excluded files never reach rule evaluation.</item>
|
|
14
|
+
<item>Risk class derives from layer rules plus high-risk globs — KEY_DECISIONS is required only on medium and high.</item>
|
|
15
|
+
<item>Policy literals come from resolveCompassPolicy — no stack- or consumer-specific values live in this module.</item>
|
|
16
|
+
</KEY_DECISIONS>
|
|
12
17
|
<CHANGE_SUMMARY>
|
|
13
|
-
<item>RFC-0348: collapsed to two-block contract (MODULE_CONTRACT + CHANGE_SUMMARY); removed MODULE_MAP, keywords, responsibilities, COMPASS_BLOCK anchors; coverage modes collapsed to standard/none.</item>
|
|
14
|
-
<item>Post-refactor hardening: exclude src/templates generation inputs from authored Compass requirements.</item>
|
|
15
|
-
<item>Post-refactor hardening: detect nested packages/os workspaces before deriving Compass layer and workspace name.</item>
|
|
16
|
-
<item>RFC-0556: moved canonical implementation from @warpgogol/site-kernel to @warpgogol/forge for autonomous mode.</item>
|
|
17
|
-
<item>Game extensions: added .cs, .tscn, .tres, .gd to SOURCE_EXTENSIONS; createCompassInventoryEntries now reads forge.yaml compass.fileExtensions at runtime and merges with hardcoded set.</item>
|
|
18
|
-
<item>Added .md to SOURCE_EXTENSIONS for SKILL.md Compass coverage; detectAuthoringStatus excludes non-SKILL.md markdown files.</item>
|
|
19
18
|
<item>RFC-1094: v2 contract — KEY_DECISIONS/history parsing, new inventory fields, evaluateV2Rules, deriveFileTokens, resolveCompassMode, shared GOVERNANCE_ID_RE.</item>
|
|
19
|
+
<item>RFC-1095: compass.summary.record, trim repair rewrite, commit integration</item>
|
|
20
|
+
<item>RFC-1096: all policy literals externalized to resolveCompassPolicy — scan roots, extensions, ignored dirs/paths, layer/risk rules, governance-ID and boilerplate patterns come from generic defaults + profile + bindings.compass.</item>
|
|
21
|
+
<item>RFC-1097: sweep — SKILL.md headers + classification fixes
|
|
22
|
+
|
|
23
|
+
Sweep batch 1: add Compass v2 headers to 45 SKILL.md files (purpose derived from frontmatter description). Fix non-skill-markdown exclusion to check filename not workspace-relative path (packages/AGENTS.md escaped it). Add .coverage to ignoredDirs.</item>
|
|
24
|
+
<item>RFC-1097: sweep — packages/forge + services clean
|
|
25
|
+
|
|
26
|
+
Sweep batch 2: real KEY_DECISIONS on 10 files, expanded purposes (CONTRACT-02/PURPOSE-02), headers on mission/index + gen-upstreams, sanitizeItemText in summary.record (literal Compass tags corrupted history), excludedPaths for wrangler types, test-fixtures testPattern. forge+services now 0 diagnostics under --mode error.</item>
|
|
27
|
+
<history>RFC-0348, RFC-0556</history>
|
|
20
28
|
</CHANGE_SUMMARY>
|
|
21
29
|
*/
|
|
22
30
|
|
|
23
31
|
import { readdir, readFile } from "node:fs/promises";
|
|
24
|
-
import { readFileSync, existsSync } from "node:fs";
|
|
25
32
|
import { join, relative, resolve } from "node:path";
|
|
26
|
-
import { parse as parseYaml } from "yaml";
|
|
27
33
|
import type { ForgeCommandInput } from "../../../src/types.ts";
|
|
28
34
|
import { hasGeneratedMarker } from "../../../src/utils/generated-marker.ts";
|
|
35
|
+
import {
|
|
36
|
+
parseGovernanceIdParts,
|
|
37
|
+
resolveCompassPolicy,
|
|
38
|
+
type CompassPolicy,
|
|
39
|
+
type CompassRiskClass,
|
|
40
|
+
type CompassWorkspaceKind,
|
|
41
|
+
} from "../policy.ts";
|
|
29
42
|
|
|
30
|
-
function loadCompassExtensionsFromForgeYaml(workspaceRoot: string): Set<string> {
|
|
31
|
-
const forgeYamlPath = join(workspaceRoot, "forge.yaml");
|
|
32
|
-
if (!existsSync(forgeYamlPath)) {
|
|
33
|
-
return new Set();
|
|
34
|
-
}
|
|
35
|
-
try {
|
|
36
|
-
const raw = readFileSync(forgeYamlPath, "utf8");
|
|
37
|
-
const parsed = parseYaml(raw) as Record<string, unknown> | null;
|
|
38
|
-
const bindings = parsed?.bindings as Record<string, unknown> | undefined;
|
|
39
|
-
const compass = bindings?.compass as Record<string, unknown> | undefined;
|
|
40
|
-
const extensions = compass?.fileExtensions;
|
|
41
|
-
if (Array.isArray(extensions)) {
|
|
42
|
-
return new Set(extensions.filter((e: unknown) => typeof e === "string"));
|
|
43
|
-
}
|
|
44
|
-
} catch {
|
|
45
|
-
// forge.yaml not parseable or missing compass section — fall back to hardcoded set
|
|
46
|
-
}
|
|
47
|
-
return new Set();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const SOURCE_EXTENSIONS = new Set([
|
|
51
|
-
".ts",
|
|
52
|
-
".tsx",
|
|
53
|
-
".astro",
|
|
54
|
-
".js",
|
|
55
|
-
".jsx",
|
|
56
|
-
".mjs",
|
|
57
|
-
".mts",
|
|
58
|
-
".css",
|
|
59
|
-
".cs",
|
|
60
|
-
".tscn",
|
|
61
|
-
".tres",
|
|
62
|
-
".gd",
|
|
63
|
-
".md",
|
|
64
|
-
]);
|
|
65
|
-
const IGNORED_DIRECTORY_NAMES = new Set([
|
|
66
|
-
".git",
|
|
67
|
-
".turbo",
|
|
68
|
-
".astro",
|
|
69
|
-
".wrangler",
|
|
70
|
-
".vscode",
|
|
71
|
-
".cache",
|
|
72
|
-
"coverage",
|
|
73
|
-
"dist",
|
|
74
|
-
"node_modules",
|
|
75
|
-
"spec",
|
|
76
|
-
"todo",
|
|
77
|
-
]);
|
|
78
|
-
const DEFAULT_SCAN_ROOTS = ["apps", "packages", "services"];
|
|
79
|
-
const HIGH_RISK_EXACT_RELATIVE_PATHS = new Set([
|
|
80
|
-
"apps/main/src/content/config.ts",
|
|
81
|
-
"apps/main/src/middleware.ts",
|
|
82
|
-
"packages/os/site-kernel/src/cli/index.ts",
|
|
83
|
-
"packages/os/site-kernel/src/discovery.ts",
|
|
84
|
-
"packages/os/site-kernel/src/registry.ts",
|
|
85
|
-
"packages/os/site-kernel/src/runtime.ts",
|
|
86
|
-
"packages/os/site-kernel/src/types.ts",
|
|
87
|
-
]);
|
|
88
43
|
function forbiddenMarkerPattern(tagName: string): RegExp {
|
|
89
44
|
return new RegExp(`<${tagName}\\b`);
|
|
90
45
|
}
|
|
@@ -96,12 +51,7 @@ const FORBIDDEN_PATTERNS: Array<{ name: string; regex: RegExp }> = [
|
|
|
96
51
|
{ name: "COMPASS_BLOCK", regex: new RegExp(`</?${"COMPASS_BLOCK"}\\b`) },
|
|
97
52
|
];
|
|
98
53
|
|
|
99
|
-
// RFC-
|
|
100
|
-
// governance-ID pattern shared with the change-summary handler.
|
|
101
|
-
export const GOVERNANCE_ID_RE = /\b([A-Z][A-Z0-9]*-)+\d+\b/;
|
|
102
|
-
const GOVERNANCE_ID_PREFIX_RE = /^([A-Z][A-Z0-9]*-)+\d+\b/;
|
|
103
|
-
const HISTORY_ID_RE = /^([A-Z][A-Z0-9]*-)+\d+$/;
|
|
104
|
-
const HISTORY_ID_PARTS_RE = /^(([A-Z][A-Z0-9]*-)+)(\d+)$/;
|
|
54
|
+
// RFC-1096: governance-ID regexes are policy-derived (policy.idPattern*).
|
|
105
55
|
const TODO_PLACEHOLDER_RE = /^TODO\b/i;
|
|
106
56
|
|
|
107
57
|
const GENERIC_STEMS = new Set([
|
|
@@ -120,12 +70,6 @@ const SYMBOL_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".mts"]
|
|
|
120
70
|
const EXPORTED_SYMBOL_RE =
|
|
121
71
|
/export\s+(?:async\s+)?(?:function|const|let|class|interface|type|enum)\s+(\w+)/g;
|
|
122
72
|
|
|
123
|
-
const PURPOSE_BOILERPLATE_PATTERNS: RegExp[] = [
|
|
124
|
-
/^(this file|the file|a file|this module|a module)\b/i,
|
|
125
|
-
/^(utility|utilities|helper|helpers|misc)\b/i,
|
|
126
|
-
/^(todo|placeholder|fixme)\b/i,
|
|
127
|
-
];
|
|
128
|
-
|
|
129
73
|
const KEY_DECISIONS_MAX_ITEMS = 7;
|
|
130
74
|
const KEY_DECISIONS_MAX_WORDS = 20;
|
|
131
75
|
const CHANGE_SUMMARY_MAX_ITEMS = 5;
|
|
@@ -145,8 +89,6 @@ export function resolveCompassMode(input: ForgeCommandInput): CompassValidationM
|
|
|
145
89
|
throw new Error(`--mode must be "warning" or "error", got "${String(raw)}"`);
|
|
146
90
|
}
|
|
147
91
|
|
|
148
|
-
type CompassWorkspaceKind = "app" | "package" | "service";
|
|
149
|
-
type CompassRiskClass = "high" | "medium" | "low";
|
|
150
92
|
type CompassComplexity = "non-trivial" | "trivial";
|
|
151
93
|
type CompassScaffoldingMode = "standard" | "none";
|
|
152
94
|
type CompassAuthoringStatus = "authored" | "excluded";
|
|
@@ -186,45 +128,33 @@ function getFlagValues(input: ForgeCommandInput, key: string): string[] {
|
|
|
186
128
|
return typeof value === "string" ? [value] : [];
|
|
187
129
|
}
|
|
188
130
|
|
|
189
|
-
function resolveScanRoots(
|
|
131
|
+
function resolveScanRoots(
|
|
132
|
+
workspaceRoot: string,
|
|
133
|
+
input: ForgeCommandInput,
|
|
134
|
+
policy: CompassPolicy,
|
|
135
|
+
): string[] {
|
|
190
136
|
const values = getFlagValues(input, "root");
|
|
191
|
-
const roots = values.length > 0 ? values :
|
|
137
|
+
const roots = values.length > 0 ? values : policy.scanRoots;
|
|
192
138
|
return roots.map((value) => resolve(workspaceRoot, value));
|
|
193
139
|
}
|
|
194
140
|
|
|
195
|
-
function shouldIgnoreDirectory(name: string): boolean {
|
|
196
|
-
if (
|
|
141
|
+
function shouldIgnoreDirectory(name: string, policy: CompassPolicy): boolean {
|
|
142
|
+
if (policy.ignoredDirs.has(name)) {
|
|
197
143
|
return true;
|
|
198
144
|
}
|
|
199
|
-
|
|
200
|
-
return true;
|
|
201
|
-
}
|
|
202
|
-
if (name.startsWith("-")) {
|
|
203
|
-
return true;
|
|
204
|
-
}
|
|
205
|
-
return false;
|
|
145
|
+
return policy.ignoredDirPrefixes.some((prefix) => name.startsWith(prefix));
|
|
206
146
|
}
|
|
207
147
|
|
|
208
|
-
function hasRelevantExtension(filePath: string,
|
|
209
|
-
for (const extension of
|
|
148
|
+
function hasRelevantExtension(filePath: string, policy: CompassPolicy): boolean {
|
|
149
|
+
for (const extension of policy.fileExtensions) {
|
|
210
150
|
if (filePath.endsWith(extension)) {
|
|
211
151
|
return true;
|
|
212
152
|
}
|
|
213
153
|
}
|
|
214
|
-
if (extraExtensions) {
|
|
215
|
-
for (const extension of extraExtensions) {
|
|
216
|
-
if (filePath.endsWith(extension)) {
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
154
|
return false;
|
|
222
155
|
}
|
|
223
156
|
|
|
224
|
-
async function collectSourceFiles(
|
|
225
|
-
targetPath: string,
|
|
226
|
-
extraExtensions?: Set<string>,
|
|
227
|
-
): Promise<string[]> {
|
|
157
|
+
async function collectSourceFiles(targetPath: string, policy: CompassPolicy): Promise<string[]> {
|
|
228
158
|
let stat;
|
|
229
159
|
try {
|
|
230
160
|
const { stat: fsStat } = await import("node:fs/promises");
|
|
@@ -234,7 +164,7 @@ async function collectSourceFiles(
|
|
|
234
164
|
}
|
|
235
165
|
|
|
236
166
|
if (stat.isFile()) {
|
|
237
|
-
return hasRelevantExtension(targetPath,
|
|
167
|
+
return hasRelevantExtension(targetPath, policy) ? [targetPath] : [];
|
|
238
168
|
}
|
|
239
169
|
|
|
240
170
|
let entries;
|
|
@@ -249,25 +179,15 @@ async function collectSourceFiles(
|
|
|
249
179
|
const absolutePath = join(targetPath, entry.name);
|
|
250
180
|
|
|
251
181
|
if (entry.isDirectory()) {
|
|
252
|
-
if (shouldIgnoreDirectory(entry.name)) {
|
|
182
|
+
if (shouldIgnoreDirectory(entry.name, policy)) {
|
|
253
183
|
continue;
|
|
254
184
|
}
|
|
255
185
|
|
|
256
|
-
|
|
257
|
-
if (
|
|
258
|
-
normalizedPath.endsWith("/src/assets") ||
|
|
259
|
-
normalizedPath.endsWith("/src/icons/gen") ||
|
|
260
|
-
normalizedPath.includes("/public/_video") ||
|
|
261
|
-
normalizedPath.includes("/public/_img")
|
|
262
|
-
) {
|
|
263
|
-
continue;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
files.push(...(await collectSourceFiles(absolutePath, extraExtensions)));
|
|
186
|
+
files.push(...(await collectSourceFiles(absolutePath, policy)));
|
|
267
187
|
continue;
|
|
268
188
|
}
|
|
269
189
|
|
|
270
|
-
if (entry.isFile() && hasRelevantExtension(absolutePath,
|
|
190
|
+
if (entry.isFile() && hasRelevantExtension(absolutePath, policy)) {
|
|
271
191
|
files.push(absolutePath);
|
|
272
192
|
}
|
|
273
193
|
}
|
|
@@ -275,77 +195,48 @@ async function collectSourceFiles(
|
|
|
275
195
|
return files;
|
|
276
196
|
}
|
|
277
197
|
|
|
278
|
-
function getRelativeSegments(filePath: string, workspaceRoot: string): string[] {
|
|
198
|
+
export function getRelativeSegments(filePath: string, workspaceRoot: string): string[] {
|
|
279
199
|
return relative(workspaceRoot, filePath).replace(/\\/g, "/").split("/").filter(Boolean);
|
|
280
200
|
}
|
|
281
201
|
|
|
282
|
-
function
|
|
283
|
-
|
|
284
|
-
return segments[0] === "packages" ? "package" : "app";
|
|
202
|
+
function isWorkspaceDir(segment: string | undefined, policy: CompassPolicy): boolean {
|
|
203
|
+
return segment !== undefined && segment in policy.workspaceKinds;
|
|
285
204
|
}
|
|
286
205
|
|
|
287
|
-
function
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
return segments[1] ?? "unknown";
|
|
206
|
+
function detectWorkspaceKind(segments: string[], policy: CompassPolicy): CompassWorkspaceKind {
|
|
207
|
+
const first = segments[0];
|
|
208
|
+
return (first !== undefined && policy.workspaceKinds[first]) || "app";
|
|
292
209
|
}
|
|
293
210
|
|
|
294
|
-
function
|
|
295
|
-
if (segments[0]
|
|
296
|
-
return segments
|
|
211
|
+
function detectWorkspaceName(segments: string[], policy: CompassPolicy): string {
|
|
212
|
+
if (isWorkspaceDir(segments[0], policy)) {
|
|
213
|
+
return segments[1] ?? "unknown";
|
|
297
214
|
}
|
|
298
|
-
|
|
215
|
+
// Files outside any workspace dir (e.g. tools/*) report "root" rather than
|
|
216
|
+
// leaking a filename into the workspace-name slot.
|
|
217
|
+
return "root";
|
|
299
218
|
}
|
|
300
219
|
|
|
301
|
-
function
|
|
302
|
-
if (
|
|
303
|
-
|
|
304
|
-
if (relativePath.startsWith("tools/modules/")) return "tool-module";
|
|
305
|
-
if (relativePath.startsWith("tools/runtime/")) return "tool-runtime";
|
|
306
|
-
if (relativePath.startsWith("src/middleware/")) return "middleware";
|
|
307
|
-
if (relativePath === "src/middleware.ts") return "middleware";
|
|
308
|
-
if (relativePath.startsWith("src/pages/")) return "page";
|
|
309
|
-
if (relativePath.startsWith("src/components/")) return "component";
|
|
310
|
-
if (relativePath.startsWith("src/content/schemas/")) return "schema";
|
|
311
|
-
if (relativePath.startsWith("src/content/")) return "content";
|
|
312
|
-
if (relativePath.startsWith("src/styles/")) return "style";
|
|
313
|
-
if (relativePath.startsWith("src/scripts/")) return "script";
|
|
314
|
-
if (relativePath.startsWith("src/layouts/")) return "layout";
|
|
315
|
-
if (relativePath.startsWith("src/utils/")) return "utility";
|
|
316
|
-
if (relativePath.startsWith("src/configure/")) return "config";
|
|
317
|
-
if (
|
|
318
|
-
relativePath.startsWith("test/") ||
|
|
319
|
-
relativePath.startsWith("src/tests/") ||
|
|
320
|
-
relativePath.endsWith(".test.ts") ||
|
|
321
|
-
relativePath.endsWith(".spec.ts")
|
|
322
|
-
)
|
|
323
|
-
return "test";
|
|
324
|
-
if (relativePath.startsWith("src/")) return "source";
|
|
325
|
-
if (relativePath.endsWith("SKILL.md")) return "skill";
|
|
326
|
-
return "other";
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
function detectRiskClass(pathFromRoot: string, layer: string): CompassRiskClass {
|
|
330
|
-
if (HIGH_RISK_EXACT_RELATIVE_PATHS.has(pathFromRoot)) {
|
|
331
|
-
return "high";
|
|
332
|
-
}
|
|
333
|
-
if (pathFromRoot.includes("/src/scripts/layout-scroll/")) {
|
|
334
|
-
return "high";
|
|
335
|
-
}
|
|
336
|
-
if (pathFromRoot.includes("/src/layouts/")) {
|
|
337
|
-
return "high";
|
|
220
|
+
export function getWorkspaceRelativeSegments(segments: string[], policy: CompassPolicy): string[] {
|
|
221
|
+
if (isWorkspaceDir(segments[0], policy)) {
|
|
222
|
+
return segments.slice(2);
|
|
338
223
|
}
|
|
339
|
-
|
|
224
|
+
return segments;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export function detectLayer(relativePath: string, policy: CompassPolicy): string {
|
|
228
|
+
return policy.matchLayer(relativePath)?.layer ?? "other";
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function detectRiskClass(
|
|
232
|
+
pathFromRoot: string,
|
|
233
|
+
workspaceRelativePath: string,
|
|
234
|
+
policy: CompassPolicy,
|
|
235
|
+
): CompassRiskClass {
|
|
236
|
+
if (policy.isHighRisk(pathFromRoot)) {
|
|
340
237
|
return "high";
|
|
341
238
|
}
|
|
342
|
-
|
|
343
|
-
return "medium";
|
|
344
|
-
}
|
|
345
|
-
if (layer === "page" || layer === "component" || layer === "utility" || layer === "script") {
|
|
346
|
-
return "medium";
|
|
347
|
-
}
|
|
348
|
-
return "low";
|
|
239
|
+
return policy.matchLayer(workspaceRelativePath)?.risk ?? "low";
|
|
349
240
|
}
|
|
350
241
|
|
|
351
242
|
function detectComplexity(source: string): CompassComplexity {
|
|
@@ -356,20 +247,11 @@ function detectComplexity(source: string): CompassComplexity {
|
|
|
356
247
|
return "non-trivial";
|
|
357
248
|
}
|
|
358
249
|
|
|
359
|
-
function isSimpleSvgLogoComponent(segments: string[]): boolean {
|
|
360
|
-
return (
|
|
361
|
-
segments.length >= 4 &&
|
|
362
|
-
segments[0] === "apps" &&
|
|
363
|
-
segments[2] === "src" &&
|
|
364
|
-
segments[3] === "components" &&
|
|
365
|
-
segments[4] === "logo"
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
250
|
function detectAuthoringStatus(
|
|
370
251
|
segments: string[],
|
|
371
252
|
relativePath: string,
|
|
372
253
|
source: string,
|
|
254
|
+
policy: CompassPolicy,
|
|
373
255
|
): {
|
|
374
256
|
authoringStatus: CompassAuthoringStatus;
|
|
375
257
|
exclusionReason?: string;
|
|
@@ -381,24 +263,11 @@ function detectAuthoringStatus(
|
|
|
381
263
|
};
|
|
382
264
|
}
|
|
383
265
|
|
|
384
|
-
|
|
266
|
+
const policyExclusion = policy.excludedReason(relativePath);
|
|
267
|
+
if (policyExclusion !== undefined) {
|
|
385
268
|
return {
|
|
386
269
|
authoringStatus: "excluded",
|
|
387
|
-
exclusionReason:
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
if (relativePath.startsWith("src/assets/")) {
|
|
392
|
-
return {
|
|
393
|
-
authoringStatus: "excluded",
|
|
394
|
-
exclusionReason: "assets-directory",
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
if (isSimpleSvgLogoComponent(segments)) {
|
|
399
|
-
return {
|
|
400
|
-
authoringStatus: "excluded",
|
|
401
|
-
exclusionReason: "svg-component",
|
|
270
|
+
exclusionReason: policyExclusion,
|
|
402
271
|
};
|
|
403
272
|
}
|
|
404
273
|
|
|
@@ -416,20 +285,7 @@ function detectAuthoringStatus(
|
|
|
416
285
|
};
|
|
417
286
|
}
|
|
418
287
|
|
|
419
|
-
if (
|
|
420
|
-
return {
|
|
421
|
-
authoringStatus: "excluded",
|
|
422
|
-
exclusionReason: "template-source",
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
if (
|
|
427
|
-
relativePath.startsWith("test/") ||
|
|
428
|
-
relativePath.endsWith(".test.ts") ||
|
|
429
|
-
relativePath.endsWith(".test.js") ||
|
|
430
|
-
relativePath.endsWith(".spec.ts") ||
|
|
431
|
-
relativePath.endsWith(".spec.js")
|
|
432
|
-
) {
|
|
288
|
+
if (policy.isTestPath(relativePath)) {
|
|
433
289
|
return {
|
|
434
290
|
authoringStatus: "excluded",
|
|
435
291
|
exclusionReason: "test-file",
|
|
@@ -443,7 +299,11 @@ function detectAuthoringStatus(
|
|
|
443
299
|
};
|
|
444
300
|
}
|
|
445
301
|
|
|
446
|
-
|
|
302
|
+
// Check the filename, not the workspace-relative path: files directly under
|
|
303
|
+
// a workspace dir (packages/AGENTS.md) get an empty workspace-relative path
|
|
304
|
+
// and would otherwise escape the markdown exclusion.
|
|
305
|
+
const fileName = segments[segments.length - 1] ?? relativePath;
|
|
306
|
+
if (fileName.endsWith(".md") && !fileName.endsWith("SKILL.md")) {
|
|
447
307
|
return {
|
|
448
308
|
authoringStatus: "excluded",
|
|
449
309
|
exclusionReason: "non-skill-markdown",
|
|
@@ -642,9 +502,9 @@ export function deriveFileTokens(pathFromRoot: string, source: string): Set<stri
|
|
|
642
502
|
return tokens;
|
|
643
503
|
}
|
|
644
504
|
|
|
645
|
-
function validateHistoryIds(historyIds: string[]): string | null {
|
|
505
|
+
function validateHistoryIds(historyIds: string[], policy: CompassPolicy): string | null {
|
|
646
506
|
for (const token of historyIds) {
|
|
647
|
-
if (!
|
|
507
|
+
if (!policy.idPatternFull.test(token)) {
|
|
648
508
|
return `<history> contains a non-ID token: "${token}"`;
|
|
649
509
|
}
|
|
650
510
|
}
|
|
@@ -653,14 +513,12 @@ function validateHistoryIds(historyIds: string[]): string | null {
|
|
|
653
513
|
}
|
|
654
514
|
const lastSeenByNamespace = new Map<string, number>();
|
|
655
515
|
for (const token of historyIds) {
|
|
656
|
-
const parts = token
|
|
657
|
-
const
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
if (last !== undefined && numeric <= last) {
|
|
661
|
-
return `<history> IDs are not in per-namespace ascending numeric order (${token} after ${namespace}-${last})`;
|
|
516
|
+
const parts = parseGovernanceIdParts(token)!;
|
|
517
|
+
const last = lastSeenByNamespace.get(parts.namespace);
|
|
518
|
+
if (last !== undefined && parts.numeric <= last) {
|
|
519
|
+
return `<history> IDs are not in per-namespace ascending numeric order (${token} after ${parts.namespace}-${last})`;
|
|
662
520
|
}
|
|
663
|
-
lastSeenByNamespace.set(namespace, numeric);
|
|
521
|
+
lastSeenByNamespace.set(parts.namespace, parts.numeric);
|
|
664
522
|
}
|
|
665
523
|
return null;
|
|
666
524
|
}
|
|
@@ -668,6 +526,7 @@ function validateHistoryIds(historyIds: string[]): string | null {
|
|
|
668
526
|
export function evaluateV2Rules(
|
|
669
527
|
entry: Pick<CompassInventoryEntry, "path" | "keyDecisionsRequired">,
|
|
670
528
|
source: string,
|
|
529
|
+
policy: CompassPolicy,
|
|
671
530
|
): CompassV2Diagnostic[] {
|
|
672
531
|
const parse = parseCompassBlocks(source);
|
|
673
532
|
const diagnostics: CompassV2Diagnostic[] = [];
|
|
@@ -715,7 +574,7 @@ export function evaluateV2Rules(
|
|
|
715
574
|
fix: "fix: compress the item to a single decision statement",
|
|
716
575
|
});
|
|
717
576
|
}
|
|
718
|
-
if (
|
|
577
|
+
if (policy.idPatternPrefix.test(item)) {
|
|
719
578
|
diagnostics.push({
|
|
720
579
|
ruleId: "COMPASS-KD-05",
|
|
721
580
|
message:
|
|
@@ -734,7 +593,7 @@ export function evaluateV2Rules(
|
|
|
734
593
|
}
|
|
735
594
|
|
|
736
595
|
if (parse.purposeText.length > 0) {
|
|
737
|
-
if (
|
|
596
|
+
if (policy.purposeBoilerplatePatterns.some((pattern) => pattern.test(parse.purposeText))) {
|
|
738
597
|
diagnostics.push({
|
|
739
598
|
ruleId: "COMPASS-PURPOSE-01",
|
|
740
599
|
message: "<purpose> matches a boilerplate pattern",
|
|
@@ -767,7 +626,7 @@ export function evaluateV2Rules(
|
|
|
767
626
|
});
|
|
768
627
|
}
|
|
769
628
|
for (const item of parse.changeSummaryItems) {
|
|
770
|
-
if (!
|
|
629
|
+
if (!policy.idPattern.test(item)) {
|
|
771
630
|
diagnostics.push({
|
|
772
631
|
ruleId: "COMPASS-CS-06",
|
|
773
632
|
message: `CHANGE_SUMMARY item lacks a governance-ID reference: "${item.slice(0, 60)}"`,
|
|
@@ -776,7 +635,7 @@ export function evaluateV2Rules(
|
|
|
776
635
|
}
|
|
777
636
|
}
|
|
778
637
|
if (parse.historyRaw !== null) {
|
|
779
|
-
const historyError = validateHistoryIds(parse.historyIds);
|
|
638
|
+
const historyError = validateHistoryIds(parse.historyIds, policy);
|
|
780
639
|
if (historyError) {
|
|
781
640
|
diagnostics.push({
|
|
782
641
|
ruleId: "COMPASS-CS-07",
|
|
@@ -839,11 +698,12 @@ export async function createCompassInventoryEntries(
|
|
|
839
698
|
workspaceRoot: string,
|
|
840
699
|
input: ForgeCommandInput,
|
|
841
700
|
scanRoot?: string,
|
|
701
|
+
policy?: CompassPolicy,
|
|
842
702
|
): Promise<CompassInventoryEntry[]> {
|
|
843
|
-
const
|
|
844
|
-
const
|
|
703
|
+
const resolvedPolicy = policy ?? resolveCompassPolicy(workspaceRoot);
|
|
704
|
+
const roots = scanRoot ? [scanRoot] : resolveScanRoots(workspaceRoot, input, resolvedPolicy);
|
|
845
705
|
const files = (
|
|
846
|
-
await Promise.all(roots.map((root) => collectSourceFiles(root,
|
|
706
|
+
await Promise.all(roots.map((root) => collectSourceFiles(root, resolvedPolicy)))
|
|
847
707
|
).flat();
|
|
848
708
|
const entries: CompassInventoryEntry[] = [];
|
|
849
709
|
|
|
@@ -851,14 +711,17 @@ export async function createCompassInventoryEntries(
|
|
|
851
711
|
const source = await readFile(filePath, "utf8");
|
|
852
712
|
const pathFromRoot = relative(workspaceRoot, filePath).replace(/\\/g, "/");
|
|
853
713
|
const segments = getRelativeSegments(filePath, workspaceRoot);
|
|
854
|
-
const relativePathWithinWorkspace = getWorkspaceRelativeSegments(segments).join(
|
|
855
|
-
|
|
856
|
-
|
|
714
|
+
const relativePathWithinWorkspace = getWorkspaceRelativeSegments(segments, resolvedPolicy).join(
|
|
715
|
+
"/",
|
|
716
|
+
);
|
|
717
|
+
const layer = detectLayer(relativePathWithinWorkspace, resolvedPolicy);
|
|
718
|
+
const riskClass = detectRiskClass(pathFromRoot, relativePathWithinWorkspace, resolvedPolicy);
|
|
857
719
|
const complexity = detectComplexity(source);
|
|
858
720
|
const { authoringStatus, exclusionReason } = detectAuthoringStatus(
|
|
859
721
|
segments,
|
|
860
722
|
relativePathWithinWorkspace,
|
|
861
723
|
source,
|
|
724
|
+
resolvedPolicy,
|
|
862
725
|
);
|
|
863
726
|
const requiredScaffolding = detectRequiredScaffolding(authoringStatus);
|
|
864
727
|
const markup = detectMarkup(source);
|
|
@@ -869,8 +732,8 @@ export async function createCompassInventoryEntries(
|
|
|
869
732
|
const nonEmptyLineCount = source.split(/\r?\n/).filter((line) => line.trim().length > 0).length;
|
|
870
733
|
const candidate: CompassInventoryEntry = {
|
|
871
734
|
path: pathFromRoot,
|
|
872
|
-
workspaceKind: detectWorkspaceKind(segments),
|
|
873
|
-
workspaceName: detectWorkspaceName(segments),
|
|
735
|
+
workspaceKind: detectWorkspaceKind(segments, resolvedPolicy),
|
|
736
|
+
workspaceName: detectWorkspaceName(segments, resolvedPolicy),
|
|
874
737
|
layer,
|
|
875
738
|
extension:
|
|
876
739
|
segments.length > 0
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>compass.migrate kernel handler (RFC-1097). Resolves scan root and
|
|
4
|
+
policy, enforces the dirty-tree refusal before any write, then delegates to
|
|
5
|
+
the migrateWorkspace codemod and returns the per-file action manifest.</purpose>
|
|
6
|
+
<non-goals>
|
|
7
|
+
<item>Do not implement transform logic — that lives in compass-migrate.ts.</item>
|
|
8
|
+
<item>Do not scaffold headers — no-header files are reported, not written.</item>
|
|
9
|
+
</non-goals>
|
|
10
|
+
</MODULE_CONTRACT>
|
|
11
|
+
<CHANGE_SUMMARY>
|
|
12
|
+
<item>RFC-1097: initial handler — dirty-tree refusal with --force, --files bypass, dry-run manifest.</item>
|
|
13
|
+
<item>RFC-1097: steps 1-4 — compass.migrate codemod
|
|
14
|
+
|
|
15
|
+
Add the v1 to v2 Compass header codemod: migrateFile pure transform (collapse, strip, seed, reorder, purpose-flag actions), migrateWorkspace walker, runCompassMigrate handler with dirty-tree refusal and --force/--files/--dry-run flags, module registration, and 15 unit tests.</item>
|
|
16
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
17
|
+
|
|
18
|
+
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.</item>
|
|
19
|
+
<item>RFC-1097: sweep — engine package clean
|
|
20
|
+
|
|
21
|
+
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. engine package now 0 diagnostics.</item>
|
|
22
|
+
<item>RFC-1097: AC-4 banned literal in os/compass handlers
|
|
23
|
+
|
|
24
|
+
compass-migrate-handler hint used a consumer-specific run command — switched to generic 'pnpm exec forge run' convention. Reworded recorded CHANGE_SUMMARY items in 3 handlers to drop the consumer-specific literal. compass-policy AC-4 test green (65/65).</item>
|
|
25
|
+
</CHANGE_SUMMARY>
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { execFileSync } from "node:child_process";
|
|
29
|
+
import { migrateWorkspace, type MigrateResult } from "./compass-migrate.ts";
|
|
30
|
+
import { resolveCompassScanRoot } from "./resolve-scan-root.ts";
|
|
31
|
+
import { resolveCompassPolicy } from "../policy.ts";
|
|
32
|
+
import type {
|
|
33
|
+
ForgeCommandInput,
|
|
34
|
+
ForgeCommandResult,
|
|
35
|
+
ForgeRuntimeContext,
|
|
36
|
+
} from "../../../src/types.ts";
|
|
37
|
+
|
|
38
|
+
const DIRTY_LIST_CAP = 20;
|
|
39
|
+
|
|
40
|
+
function listDirtyPaths(repoRoot: string): string[] | null {
|
|
41
|
+
try {
|
|
42
|
+
const out = execFileSync("git", ["-C", repoRoot, "status", "--porcelain"], {
|
|
43
|
+
encoding: "utf8",
|
|
44
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
45
|
+
timeout: 15000,
|
|
46
|
+
});
|
|
47
|
+
return out
|
|
48
|
+
.split("\n")
|
|
49
|
+
.map((line) => line.trim())
|
|
50
|
+
.filter(Boolean)
|
|
51
|
+
.map((line) => line.slice(3));
|
|
52
|
+
} catch {
|
|
53
|
+
// Not a git repository — nothing to protect, skip the check.
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function runCompassMigrate(
|
|
59
|
+
input: ForgeCommandInput,
|
|
60
|
+
context: ForgeRuntimeContext,
|
|
61
|
+
): Promise<ForgeCommandResult<MigrateResult>> {
|
|
62
|
+
const scanRoot = resolveCompassScanRoot(input, context);
|
|
63
|
+
const baseRoot = scanRoot ?? context.workspaceRoot;
|
|
64
|
+
const policy = resolveCompassPolicy(baseRoot, context.forgeRoot);
|
|
65
|
+
|
|
66
|
+
const dryRun = context.dryRun || input.flags["dry-run"] === true;
|
|
67
|
+
const force = input.flags["force"] === true;
|
|
68
|
+
|
|
69
|
+
const rawFiles = input.flags["files"];
|
|
70
|
+
const files = (
|
|
71
|
+
Array.isArray(rawFiles)
|
|
72
|
+
? rawFiles.filter((entry): entry is string => typeof entry === "string")
|
|
73
|
+
: typeof rawFiles === "string"
|
|
74
|
+
? [rawFiles]
|
|
75
|
+
: []
|
|
76
|
+
)
|
|
77
|
+
.flatMap((entry) => entry.split(","))
|
|
78
|
+
.map((entry) => entry.trim())
|
|
79
|
+
.filter(Boolean);
|
|
80
|
+
const explicitFiles = files.length > 0 ? files : undefined;
|
|
81
|
+
|
|
82
|
+
// Dirty-tree refusal guards the write only — a dry-run writes nothing and
|
|
83
|
+
// stays useful as a pre-commit preview on a dirty tree.
|
|
84
|
+
if (!dryRun && !force) {
|
|
85
|
+
const dirty = listDirtyPaths(baseRoot);
|
|
86
|
+
if (dirty && dirty.length > 0) {
|
|
87
|
+
const shown = dirty.slice(0, DIRTY_LIST_CAP);
|
|
88
|
+
const suffix =
|
|
89
|
+
dirty.length > shown.length ? ` … and ${dirty.length - shown.length} more` : "";
|
|
90
|
+
context.logger.error(
|
|
91
|
+
`[compass.migrate] refusing to run on a dirty git tree (${dirty.length} uncommitted path(s)):\n${shown.map((p) => ` ${p}`).join("\n")}${suffix}\nCommit or stash first, or pass --force to override.`,
|
|
92
|
+
);
|
|
93
|
+
return { exitCode: 1, summary: "dirty git tree — refused" };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const result = await migrateWorkspace(context.workspaceRoot, input, scanRoot, policy, {
|
|
98
|
+
files: explicitFiles,
|
|
99
|
+
dryRun,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const counts = new Map<string, number>();
|
|
103
|
+
for (const file of result.files) {
|
|
104
|
+
for (const action of file.actions) {
|
|
105
|
+
counts.set(action, (counts.get(action) ?? 0) + 1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const tally = [...counts.entries()].map(([k, v]) => `${k}=${v}`).join(", ");
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
data: result,
|
|
112
|
+
exitCode: 0,
|
|
113
|
+
summary: `[compass.migrate] scanned=${result.scanned} ${tally}${dryRun ? " (dry-run)" : ""}`,
|
|
114
|
+
nextSteps: [
|
|
115
|
+
{
|
|
116
|
+
action:
|
|
117
|
+
"Run `pnpm exec forge run compass.inventory --json` to list todo/purpose-flagged files for the agent sweep.",
|
|
118
|
+
kind: "optional",
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
}
|