@warpgogol/forge 1.2.2 → 2.1.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 +1 -0
- package/README.md +33 -19
- package/README.uk.md +33 -19
- package/package.json +1 -1
- package/profiles/astro-typescript-turborepo.yaml +147 -0
- package/profiles/forge-shell.yaml +120 -1
- package/profiles/godot-csharp.yaml +280 -6
- package/profiles/phaser-turborepo.yaml +134 -0
- package/skills/_shared/fo-pipeline-conventions.md +55 -0
- package/skills/fo/fo-doc-audit/SKILL.md +2 -2
- package/skills/fo/fo-idea-i-just-want-to-see-the-plan/SKILL.md +2 -0
- package/skills/fo/fo-idea-i-just-want-to-see-the-result/SKILL.md +7 -3
- package/skills/fo/fo-idea-implement/SKILL.md +50 -46
- package/skills/fo/fo-session-retro/SKILL.md +2 -2
- package/dist/bin/cli.d.ts +0 -3
- package/dist/bin/cli.d.ts.map +0 -1
- package/dist/bin/cli.js +0 -292
- package/dist/bin/cli.js.map +0 -1
- package/dist/os/adr/adr.module.d.ts +0 -3
- package/dist/os/adr/adr.module.d.ts.map +0 -1
- package/dist/os/adr/adr.module.js +0 -145
- package/dist/os/adr/adr.module.js.map +0 -1
- package/dist/os/adr/frontmatter-io.d.ts +0 -12
- package/dist/os/adr/frontmatter-io.d.ts.map +0 -1
- package/dist/os/adr/frontmatter-io.js +0 -67
- package/dist/os/adr/frontmatter-io.js.map +0 -1
- package/dist/os/adr/handlers/archive.d.ts +0 -24
- package/dist/os/adr/handlers/archive.d.ts.map +0 -1
- package/dist/os/adr/handlers/archive.js +0 -194
- package/dist/os/adr/handlers/archive.js.map +0 -1
- package/dist/os/adr/handlers/implement-stamp.d.ts +0 -4
- package/dist/os/adr/handlers/implement-stamp.d.ts.map +0 -1
- package/dist/os/adr/handlers/implement-stamp.js +0 -258
- package/dist/os/adr/handlers/implement-stamp.js.map +0 -1
- package/dist/os/adr/handlers/list-create.d.ts +0 -5
- package/dist/os/adr/handlers/list-create.d.ts.map +0 -1
- package/dist/os/adr/handlers/list-create.js +0 -165
- package/dist/os/adr/handlers/list-create.js.map +0 -1
- package/dist/os/adr/handlers/validate.d.ts +0 -4
- package/dist/os/adr/handlers/validate.d.ts.map +0 -1
- package/dist/os/adr/handlers/validate.js +0 -265
- package/dist/os/adr/handlers/validate.js.map +0 -1
- package/dist/os/adr/index.d.ts +0 -8
- package/dist/os/adr/index.d.ts.map +0 -1
- package/dist/os/adr/index.js +0 -18
- package/dist/os/adr/index.js.map +0 -1
- package/dist/os/adr/types.d.ts +0 -75
- package/dist/os/adr/types.d.ts.map +0 -1
- package/dist/os/adr/types.js +0 -55
- package/dist/os/adr/types.js.map +0 -1
- package/dist/os/audit/audit.module.d.ts +0 -3
- package/dist/os/audit/audit.module.d.ts.map +0 -1
- package/dist/os/audit/audit.module.js +0 -44
- package/dist/os/audit/audit.module.js.map +0 -1
- package/dist/os/audit/frontmatter-io.d.ts +0 -12
- package/dist/os/audit/frontmatter-io.d.ts.map +0 -1
- package/dist/os/audit/frontmatter-io.js +0 -71
- package/dist/os/audit/frontmatter-io.js.map +0 -1
- package/dist/os/audit/handlers/archive.d.ts +0 -4
- package/dist/os/audit/handlers/archive.d.ts.map +0 -1
- package/dist/os/audit/handlers/archive.js +0 -207
- package/dist/os/audit/handlers/archive.js.map +0 -1
- package/dist/os/audit/index.d.ts +0 -6
- package/dist/os/audit/index.d.ts.map +0 -1
- package/dist/os/audit/index.js +0 -16
- package/dist/os/audit/index.js.map +0 -1
- package/dist/os/audit/types.d.ts +0 -12
- package/dist/os/audit/types.d.ts.map +0 -1
- package/dist/os/audit/types.js +0 -17
- package/dist/os/audit/types.js.map +0 -1
- package/dist/os/compass/compass.module.d.ts +0 -3
- package/dist/os/compass/compass.module.d.ts.map +0 -1
- package/dist/os/compass/compass.module.js +0 -166
- package/dist/os/compass/compass.module.js.map +0 -1
- package/dist/os/compass/handlers/compass-audit-handler.d.ts +0 -36
- package/dist/os/compass/handlers/compass-audit-handler.d.ts.map +0 -1
- package/dist/os/compass/handlers/compass-audit-handler.js +0 -238
- package/dist/os/compass/handlers/compass-audit-handler.js.map +0 -1
- package/dist/os/compass/handlers/compass-change-summary-handler.d.ts +0 -19
- package/dist/os/compass/handlers/compass-change-summary-handler.d.ts.map +0 -1
- package/dist/os/compass/handlers/compass-change-summary-handler.js +0 -205
- package/dist/os/compass/handlers/compass-change-summary-handler.js.map +0 -1
- package/dist/os/compass/handlers/compass-inventory-handler.d.ts +0 -28
- package/dist/os/compass/handlers/compass-inventory-handler.d.ts.map +0 -1
- package/dist/os/compass/handlers/compass-inventory-handler.js +0 -213
- package/dist/os/compass/handlers/compass-inventory-handler.js.map +0 -1
- package/dist/os/compass/handlers/compass-inventory.d.ts +0 -30
- package/dist/os/compass/handlers/compass-inventory.d.ts.map +0 -1
- package/dist/os/compass/handlers/compass-inventory.js +0 -418
- package/dist/os/compass/handlers/compass-inventory.js.map +0 -1
- package/dist/os/compass/handlers/git-revision.d.ts +0 -8
- package/dist/os/compass/handlers/git-revision.d.ts.map +0 -1
- package/dist/os/compass/handlers/git-revision.js +0 -99
- package/dist/os/compass/handlers/git-revision.js.map +0 -1
- package/dist/os/compass/handlers/resolve-scan-root.d.ts +0 -3
- package/dist/os/compass/handlers/resolve-scan-root.d.ts.map +0 -1
- package/dist/os/compass/handlers/resolve-scan-root.js +0 -57
- package/dist/os/compass/handlers/resolve-scan-root.js.map +0 -1
- package/dist/os/compass/index.d.ts +0 -8
- package/dist/os/compass/index.d.ts.map +0 -1
- package/dist/os/compass/index.js +0 -19
- package/dist/os/compass/index.js.map +0 -1
- package/dist/os/core/core.module.d.ts +0 -3
- package/dist/os/core/core.module.d.ts.map +0 -1
- package/dist/os/core/core.module.js +0 -758
- package/dist/os/core/core.module.js.map +0 -1
- package/dist/os/core/handlers/assets-check.d.ts +0 -19
- package/dist/os/core/handlers/assets-check.d.ts.map +0 -1
- package/dist/os/core/handlers/assets-check.js +0 -89
- package/dist/os/core/handlers/assets-check.js.map +0 -1
- package/dist/os/core/handlers/assets-helpers.d.ts +0 -28
- package/dist/os/core/handlers/assets-helpers.d.ts.map +0 -1
- package/dist/os/core/handlers/assets-helpers.js +0 -128
- package/dist/os/core/handlers/assets-helpers.js.map +0 -1
- package/dist/os/core/handlers/assets-list.d.ts +0 -9
- package/dist/os/core/handlers/assets-list.d.ts.map +0 -1
- package/dist/os/core/handlers/assets-list.js +0 -72
- package/dist/os/core/handlers/assets-list.js.map +0 -1
- package/dist/os/core/handlers/build.d.ts +0 -16
- package/dist/os/core/handlers/build.d.ts.map +0 -1
- package/dist/os/core/handlers/build.js +0 -123
- package/dist/os/core/handlers/build.js.map +0 -1
- package/dist/os/core/handlers/determinism-check.d.ts +0 -20
- package/dist/os/core/handlers/determinism-check.d.ts.map +0 -1
- package/dist/os/core/handlers/determinism-check.js +0 -289
- package/dist/os/core/handlers/determinism-check.js.map +0 -1
- package/dist/os/core/handlers/dev.d.ts +0 -10
- package/dist/os/core/handlers/dev.d.ts.map +0 -1
- package/dist/os/core/handlers/dev.js +0 -102
- package/dist/os/core/handlers/dev.js.map +0 -1
- package/dist/os/core/handlers/knowledge-compact.d.ts +0 -4
- package/dist/os/core/handlers/knowledge-compact.d.ts.map +0 -1
- package/dist/os/core/handlers/knowledge-compact.js +0 -198
- package/dist/os/core/handlers/knowledge-compact.js.map +0 -1
- package/dist/os/core/handlers/pinned-check.d.ts +0 -49
- package/dist/os/core/handlers/pinned-check.d.ts.map +0 -1
- package/dist/os/core/handlers/pinned-check.js +0 -159
- package/dist/os/core/handlers/pinned-check.js.map +0 -1
- package/dist/os/core/handlers/pinned-init.d.ts +0 -19
- package/dist/os/core/handlers/pinned-init.d.ts.map +0 -1
- package/dist/os/core/handlers/pinned-init.js +0 -283
- package/dist/os/core/handlers/pinned-init.js.map +0 -1
- package/dist/os/core/handlers/pinned-types.d.ts +0 -29
- package/dist/os/core/handlers/pinned-types.d.ts.map +0 -1
- package/dist/os/core/handlers/pinned-types.js +0 -16
- package/dist/os/core/handlers/pinned-types.js.map +0 -1
- package/dist/os/core/handlers/pinned-validate.d.ts +0 -4
- package/dist/os/core/handlers/pinned-validate.d.ts.map +0 -1
- package/dist/os/core/handlers/pinned-validate.js +0 -248
- package/dist/os/core/handlers/pinned-validate.js.map +0 -1
- package/dist/os/core/handlers/profile-resolve.d.ts +0 -13
- package/dist/os/core/handlers/profile-resolve.d.ts.map +0 -1
- package/dist/os/core/handlers/profile-resolve.js +0 -65
- package/dist/os/core/handlers/profile-resolve.js.map +0 -1
- package/dist/os/core/handlers/release-prepare.d.ts +0 -25
- package/dist/os/core/handlers/release-prepare.d.ts.map +0 -1
- package/dist/os/core/handlers/release-prepare.js +0 -228
- package/dist/os/core/handlers/release-prepare.js.map +0 -1
- package/dist/os/core/handlers/release-publish.d.ts +0 -13
- package/dist/os/core/handlers/release-publish.d.ts.map +0 -1
- package/dist/os/core/handlers/release-publish.js +0 -173
- package/dist/os/core/handlers/release-publish.js.map +0 -1
- package/dist/os/core/handlers/validate.d.ts +0 -26
- package/dist/os/core/handlers/validate.d.ts.map +0 -1
- package/dist/os/core/handlers/validate.js +0 -208
- package/dist/os/core/handlers/validate.js.map +0 -1
- package/dist/os/core/handlers/workspace-deps.d.ts +0 -12
- package/dist/os/core/handlers/workspace-deps.d.ts.map +0 -1
- package/dist/os/core/handlers/workspace-deps.js +0 -39
- package/dist/os/core/handlers/workspace-deps.js.map +0 -1
- package/dist/os/core/index.d.ts +0 -2
- package/dist/os/core/index.d.ts.map +0 -1
- package/dist/os/core/index.js +0 -13
- package/dist/os/core/index.js.map +0 -1
- package/dist/os/exploration/exploration.module.d.ts +0 -3
- package/dist/os/exploration/exploration.module.d.ts.map +0 -1
- package/dist/os/exploration/exploration.module.js +0 -82
- package/dist/os/exploration/exploration.module.js.map +0 -1
- package/dist/os/exploration/frontmatter-io.d.ts +0 -13
- package/dist/os/exploration/frontmatter-io.d.ts.map +0 -1
- package/dist/os/exploration/frontmatter-io.js +0 -61
- package/dist/os/exploration/frontmatter-io.js.map +0 -1
- package/dist/os/exploration/handlers/archive.d.ts +0 -4
- package/dist/os/exploration/handlers/archive.d.ts.map +0 -1
- package/dist/os/exploration/handlers/archive.js +0 -135
- package/dist/os/exploration/handlers/archive.js.map +0 -1
- package/dist/os/exploration/handlers/list.d.ts +0 -4
- package/dist/os/exploration/handlers/list.d.ts.map +0 -1
- package/dist/os/exploration/handlers/list.js +0 -56
- package/dist/os/exploration/handlers/list.js.map +0 -1
- package/dist/os/exploration/handlers/show.d.ts +0 -4
- package/dist/os/exploration/handlers/show.d.ts.map +0 -1
- package/dist/os/exploration/handlers/show.js +0 -91
- package/dist/os/exploration/handlers/show.js.map +0 -1
- package/dist/os/exploration/index.d.ts +0 -7
- package/dist/os/exploration/index.d.ts.map +0 -1
- package/dist/os/exploration/index.js +0 -17
- package/dist/os/exploration/index.js.map +0 -1
- package/dist/os/exploration/types.d.ts +0 -38
- package/dist/os/exploration/types.d.ts.map +0 -1
- package/dist/os/exploration/types.js +0 -23
- package/dist/os/exploration/types.js.map +0 -1
- package/dist/os/mission/handlers/archive.d.ts +0 -4
- package/dist/os/mission/handlers/archive.d.ts.map +0 -1
- package/dist/os/mission/handlers/archive.js +0 -356
- package/dist/os/mission/handlers/archive.js.map +0 -1
- package/dist/os/mission/index.d.ts +0 -2
- package/dist/os/mission/index.d.ts.map +0 -1
- package/dist/os/mission/index.js +0 -2
- package/dist/os/mission/index.js.map +0 -1
- package/dist/os/mission/mission.module.d.ts +0 -3
- package/dist/os/mission/mission.module.d.ts.map +0 -1
- package/dist/os/mission/mission.module.js +0 -44
- package/dist/os/mission/mission.module.js.map +0 -1
- package/dist/os/mission/types.d.ts +0 -23
- package/dist/os/mission/types.d.ts.map +0 -1
- package/dist/os/mission/types.js +0 -18
- package/dist/os/mission/types.js.map +0 -1
- package/dist/os/naming/index.d.ts +0 -3
- package/dist/os/naming/index.d.ts.map +0 -1
- package/dist/os/naming/index.js +0 -14
- package/dist/os/naming/index.js.map +0 -1
- package/dist/os/naming/naming-convention.d.ts +0 -25
- package/dist/os/naming/naming-convention.d.ts.map +0 -1
- package/dist/os/naming/naming-convention.js +0 -324
- package/dist/os/naming/naming-convention.js.map +0 -1
- package/dist/os/naming/naming.module.d.ts +0 -3
- package/dist/os/naming/naming.module.d.ts.map +0 -1
- package/dist/os/naming/naming.module.js +0 -33
- package/dist/os/naming/naming.module.js.map +0 -1
- package/dist/os/notes/index.d.ts +0 -2
- package/dist/os/notes/index.d.ts.map +0 -1
- package/dist/os/notes/index.js +0 -10
- package/dist/os/notes/index.js.map +0 -1
- package/dist/os/notes/notes.module.d.ts +0 -3
- package/dist/os/notes/notes.module.d.ts.map +0 -1
- package/dist/os/notes/notes.module.js +0 -83
- package/dist/os/notes/notes.module.js.map +0 -1
- package/dist/os/plan/frontmatter-io.d.ts +0 -12
- package/dist/os/plan/frontmatter-io.d.ts.map +0 -1
- package/dist/os/plan/frontmatter-io.js +0 -69
- package/dist/os/plan/frontmatter-io.js.map +0 -1
- package/dist/os/plan/handlers/archive.d.ts +0 -4
- package/dist/os/plan/handlers/archive.d.ts.map +0 -1
- package/dist/os/plan/handlers/archive.js +0 -206
- package/dist/os/plan/handlers/archive.js.map +0 -1
- package/dist/os/plan/index.d.ts +0 -6
- package/dist/os/plan/index.d.ts.map +0 -1
- package/dist/os/plan/index.js +0 -16
- package/dist/os/plan/index.js.map +0 -1
- package/dist/os/plan/plan.module.d.ts +0 -3
- package/dist/os/plan/plan.module.d.ts.map +0 -1
- package/dist/os/plan/plan.module.js +0 -44
- package/dist/os/plan/plan.module.js.map +0 -1
- package/dist/os/plan/types.d.ts +0 -12
- package/dist/os/plan/types.d.ts.map +0 -1
- package/dist/os/plan/types.js +0 -17
- package/dist/os/plan/types.js.map +0 -1
- package/dist/os/program/discovery.d.ts +0 -61
- package/dist/os/program/discovery.d.ts.map +0 -1
- package/dist/os/program/discovery.js +0 -236
- package/dist/os/program/discovery.js.map +0 -1
- package/dist/os/program/handlers/complete.d.ts +0 -12
- package/dist/os/program/handlers/complete.d.ts.map +0 -1
- package/dist/os/program/handlers/complete.js +0 -344
- package/dist/os/program/handlers/complete.js.map +0 -1
- package/dist/os/program/handlers/lease.d.ts +0 -13
- package/dist/os/program/handlers/lease.d.ts.map +0 -1
- package/dist/os/program/handlers/lease.js +0 -322
- package/dist/os/program/handlers/lease.js.map +0 -1
- package/dist/os/program/handlers/seal.d.ts +0 -12
- package/dist/os/program/handlers/seal.d.ts.map +0 -1
- package/dist/os/program/handlers/seal.js +0 -265
- package/dist/os/program/handlers/seal.js.map +0 -1
- package/dist/os/program/handlers/validate.d.ts +0 -14
- package/dist/os/program/handlers/validate.d.ts.map +0 -1
- package/dist/os/program/handlers/validate.js +0 -164
- package/dist/os/program/handlers/validate.js.map +0 -1
- package/dist/os/program/lease.d.ts +0 -39
- package/dist/os/program/lease.d.ts.map +0 -1
- package/dist/os/program/lease.js +0 -129
- package/dist/os/program/lease.js.map +0 -1
- package/dist/os/program/program.module.d.ts +0 -3
- package/dist/os/program/program.module.d.ts.map +0 -1
- package/dist/os/program/program.module.js +0 -201
- package/dist/os/program/program.module.js.map +0 -1
- package/dist/os/program/schemas.d.ts +0 -225
- package/dist/os/program/schemas.d.ts.map +0 -1
- package/dist/os/program/schemas.js +0 -174
- package/dist/os/program/schemas.js.map +0 -1
- package/dist/os/program/state.d.ts +0 -38
- package/dist/os/program/state.d.ts.map +0 -1
- package/dist/os/program/state.js +0 -189
- package/dist/os/program/state.js.map +0 -1
- package/dist/os/rfc/acceptance.d.ts +0 -15
- package/dist/os/rfc/acceptance.d.ts.map +0 -1
- package/dist/os/rfc/acceptance.js +0 -310
- package/dist/os/rfc/acceptance.js.map +0 -1
- package/dist/os/rfc/decision-log.d.ts +0 -6
- package/dist/os/rfc/decision-log.d.ts.map +0 -1
- package/dist/os/rfc/decision-log.js +0 -269
- package/dist/os/rfc/decision-log.js.map +0 -1
- package/dist/os/rfc/dna-trace.d.ts +0 -27
- package/dist/os/rfc/dna-trace.d.ts.map +0 -1
- package/dist/os/rfc/dna-trace.js +0 -214
- package/dist/os/rfc/dna-trace.js.map +0 -1
- package/dist/os/rfc/frontmatter-io.d.ts +0 -18
- package/dist/os/rfc/frontmatter-io.d.ts.map +0 -1
- package/dist/os/rfc/frontmatter-io.js +0 -110
- package/dist/os/rfc/frontmatter-io.js.map +0 -1
- package/dist/os/rfc/handlers/archive.d.ts +0 -25
- package/dist/os/rfc/handlers/archive.d.ts.map +0 -1
- package/dist/os/rfc/handlers/archive.js +0 -247
- package/dist/os/rfc/handlers/archive.js.map +0 -1
- package/dist/os/rfc/handlers/check.d.ts +0 -4
- package/dist/os/rfc/handlers/check.d.ts.map +0 -1
- package/dist/os/rfc/handlers/check.js +0 -195
- package/dist/os/rfc/handlers/check.js.map +0 -1
- package/dist/os/rfc/handlers/implement-stamp.d.ts +0 -4
- package/dist/os/rfc/handlers/implement-stamp.d.ts.map +0 -1
- package/dist/os/rfc/handlers/implement-stamp.js +0 -420
- package/dist/os/rfc/handlers/implement-stamp.js.map +0 -1
- package/dist/os/rfc/handlers/index-graph.d.ts +0 -13
- package/dist/os/rfc/handlers/index-graph.d.ts.map +0 -1
- package/dist/os/rfc/handlers/index-graph.js +0 -192
- package/dist/os/rfc/handlers/index-graph.js.map +0 -1
- package/dist/os/rfc/handlers/lifecycle.d.ts +0 -13
- package/dist/os/rfc/handlers/lifecycle.d.ts.map +0 -1
- package/dist/os/rfc/handlers/lifecycle.js +0 -155
- package/dist/os/rfc/handlers/lifecycle.js.map +0 -1
- package/dist/os/rfc/handlers/list-create.d.ts +0 -6
- package/dist/os/rfc/handlers/list-create.d.ts.map +0 -1
- package/dist/os/rfc/handlers/list-create.js +0 -240
- package/dist/os/rfc/handlers/list-create.js.map +0 -1
- package/dist/os/rfc/handlers/pipeline-status.d.ts +0 -26
- package/dist/os/rfc/handlers/pipeline-status.d.ts.map +0 -1
- package/dist/os/rfc/handlers/pipeline-status.js +0 -124
- package/dist/os/rfc/handlers/pipeline-status.js.map +0 -1
- package/dist/os/rfc/handlers/shared.d.ts +0 -22
- package/dist/os/rfc/handlers/shared.d.ts.map +0 -1
- package/dist/os/rfc/handlers/shared.js +0 -105
- package/dist/os/rfc/handlers/shared.js.map +0 -1
- package/dist/os/rfc/handlers/supersede-propose.d.ts +0 -4
- package/dist/os/rfc/handlers/supersede-propose.d.ts.map +0 -1
- package/dist/os/rfc/handlers/supersede-propose.js +0 -203
- package/dist/os/rfc/handlers/supersede-propose.js.map +0 -1
- package/dist/os/rfc/handlers/validate-rules.d.ts +0 -32
- package/dist/os/rfc/handlers/validate-rules.d.ts.map +0 -1
- package/dist/os/rfc/handlers/validate-rules.js +0 -590
- package/dist/os/rfc/handlers/validate-rules.js.map +0 -1
- package/dist/os/rfc/handlers/validate.d.ts +0 -4
- package/dist/os/rfc/handlers/validate.d.ts.map +0 -1
- package/dist/os/rfc/handlers/validate.js +0 -108
- package/dist/os/rfc/handlers/validate.js.map +0 -1
- package/dist/os/rfc/handlers.d.ts +0 -7
- package/dist/os/rfc/handlers.d.ts.map +0 -1
- package/dist/os/rfc/handlers.js +0 -19
- package/dist/os/rfc/handlers.js.map +0 -1
- package/dist/os/rfc/index.d.ts +0 -18
- package/dist/os/rfc/index.d.ts.map +0 -1
- package/dist/os/rfc/index.js +0 -24
- package/dist/os/rfc/index.js.map +0 -1
- package/dist/os/rfc/rfc.module.d.ts +0 -3
- package/dist/os/rfc/rfc.module.d.ts.map +0 -1
- package/dist/os/rfc/rfc.module.js +0 -366
- package/dist/os/rfc/rfc.module.js.map +0 -1
- package/dist/os/rfc/types.d.ts +0 -483
- package/dist/os/rfc/types.d.ts.map +0 -1
- package/dist/os/rfc/types.js +0 -100
- package/dist/os/rfc/types.js.map +0 -1
- package/dist/os/rfc/verification-evidence.d.ts +0 -8
- package/dist/os/rfc/verification-evidence.d.ts.map +0 -1
- package/dist/os/rfc/verification-evidence.js +0 -184
- package/dist/os/rfc/verification-evidence.js.map +0 -1
- package/dist/os/session/atif-parser.d.ts +0 -29
- package/dist/os/session/atif-parser.d.ts.map +0 -1
- package/dist/os/session/atif-parser.js +0 -140
- package/dist/os/session/atif-parser.js.map +0 -1
- package/dist/os/session/frontmatter-io.d.ts +0 -31
- package/dist/os/session/frontmatter-io.d.ts.map +0 -1
- package/dist/os/session/frontmatter-io.js +0 -146
- package/dist/os/session/frontmatter-io.js.map +0 -1
- package/dist/os/session/handlers/archive.d.ts +0 -4
- package/dist/os/session/handlers/archive.d.ts.map +0 -1
- package/dist/os/session/handlers/archive.js +0 -241
- package/dist/os/session/handlers/archive.js.map +0 -1
- package/dist/os/session/handlers/list.d.ts +0 -4
- package/dist/os/session/handlers/list.d.ts.map +0 -1
- package/dist/os/session/handlers/list.js +0 -147
- package/dist/os/session/handlers/list.js.map +0 -1
- package/dist/os/session/handlers/save.d.ts +0 -6
- package/dist/os/session/handlers/save.d.ts.map +0 -1
- package/dist/os/session/handlers/save.js +0 -297
- package/dist/os/session/handlers/save.js.map +0 -1
- package/dist/os/session/handlers/validate.d.ts +0 -4
- package/dist/os/session/handlers/validate.d.ts.map +0 -1
- package/dist/os/session/handlers/validate.js +0 -188
- package/dist/os/session/handlers/validate.js.map +0 -1
- package/dist/os/session/index.d.ts +0 -9
- package/dist/os/session/index.d.ts.map +0 -1
- package/dist/os/session/index.js +0 -20
- package/dist/os/session/index.js.map +0 -1
- package/dist/os/session/session.module.d.ts +0 -3
- package/dist/os/session/session.module.d.ts.map +0 -1
- package/dist/os/session/session.module.js +0 -115
- package/dist/os/session/session.module.js.map +0 -1
- package/dist/os/session/types.d.ts +0 -101
- package/dist/os/session/types.d.ts.map +0 -1
- package/dist/os/session/types.js +0 -52
- package/dist/os/session/types.js.map +0 -1
- package/dist/os/spec/live-spec-list.d.ts +0 -4
- package/dist/os/spec/live-spec-list.d.ts.map +0 -1
- package/dist/os/spec/live-spec-list.js +0 -64
- package/dist/os/spec/live-spec-list.js.map +0 -1
- package/dist/os/spec/live-spec-merge.d.ts +0 -4
- package/dist/os/spec/live-spec-merge.d.ts.map +0 -1
- package/dist/os/spec/live-spec-merge.js +0 -345
- package/dist/os/spec/live-spec-merge.js.map +0 -1
- package/dist/os/spec/live-spec-show.d.ts +0 -4
- package/dist/os/spec/live-spec-show.d.ts.map +0 -1
- package/dist/os/spec/live-spec-show.js +0 -99
- package/dist/os/spec/live-spec-show.js.map +0 -1
- package/dist/os/spec/live-spec-types.d.ts +0 -71
- package/dist/os/spec/live-spec-types.d.ts.map +0 -1
- package/dist/os/spec/live-spec-types.js +0 -14
- package/dist/os/spec/live-spec-types.js.map +0 -1
- package/dist/os/spec/live-spec-validate.d.ts +0 -4
- package/dist/os/spec/live-spec-validate.d.ts.map +0 -1
- package/dist/os/spec/live-spec-validate.js +0 -140
- package/dist/os/spec/live-spec-validate.js.map +0 -1
- package/dist/os/spec/spec-materialize.d.ts +0 -21
- package/dist/os/spec/spec-materialize.d.ts.map +0 -1
- package/dist/os/spec/spec-materialize.js +0 -336
- package/dist/os/spec/spec-materialize.js.map +0 -1
- package/dist/os/spec/spec-schema.d.ts +0 -126
- package/dist/os/spec/spec-schema.d.ts.map +0 -1
- package/dist/os/spec/spec-schema.js +0 -118
- package/dist/os/spec/spec-schema.js.map +0 -1
- package/dist/os/spec/spec-status.d.ts +0 -33
- package/dist/os/spec/spec-status.d.ts.map +0 -1
- package/dist/os/spec/spec-status.js +0 -222
- package/dist/os/spec/spec-status.js.map +0 -1
- package/dist/os/spec/spec-validate.d.ts +0 -4
- package/dist/os/spec/spec-validate.d.ts.map +0 -1
- package/dist/os/spec/spec-validate.js +0 -435
- package/dist/os/spec/spec-validate.js.map +0 -1
- package/dist/os/spec/spec.module.d.ts +0 -3
- package/dist/os/spec/spec.module.d.ts.map +0 -1
- package/dist/os/spec/spec.module.js +0 -119
- package/dist/os/spec/spec.module.js.map +0 -1
- package/dist/os/werkstatt/handlers/lock.d.ts +0 -10
- package/dist/os/werkstatt/handlers/lock.d.ts.map +0 -1
- package/dist/os/werkstatt/handlers/lock.js +0 -153
- package/dist/os/werkstatt/handlers/lock.js.map +0 -1
- package/dist/os/werkstatt/handlers/schema.d.ts +0 -33
- package/dist/os/werkstatt/handlers/schema.d.ts.map +0 -1
- package/dist/os/werkstatt/handlers/schema.js +0 -42
- package/dist/os/werkstatt/handlers/schema.js.map +0 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.d.ts +0 -15
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.d.ts.map +0 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js +0 -144
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js.map +0 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-status.d.ts +0 -18
- package/dist/os/werkstatt/handlers/werkstatt-lock-status.d.ts.map +0 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-status.js +0 -43
- package/dist/os/werkstatt/handlers/werkstatt-lock-status.js.map +0 -1
- package/dist/os/werkstatt/handlers/werkstatt-operation-validate.d.ts +0 -11
- package/dist/os/werkstatt/handlers/werkstatt-operation-validate.d.ts.map +0 -1
- package/dist/os/werkstatt/handlers/werkstatt-operation-validate.js +0 -79
- package/dist/os/werkstatt/handlers/werkstatt-operation-validate.js.map +0 -1
- package/dist/os/werkstatt/index.d.ts +0 -7
- package/dist/os/werkstatt/index.d.ts.map +0 -1
- package/dist/os/werkstatt/index.js +0 -18
- package/dist/os/werkstatt/index.js.map +0 -1
- package/dist/os/werkstatt/werkstatt.module.d.ts +0 -3
- package/dist/os/werkstatt/werkstatt.module.d.ts.map +0 -1
- package/dist/os/werkstatt/werkstatt.module.js +0 -58
- package/dist/os/werkstatt/werkstatt.module.js.map +0 -1
- package/dist/os/workflow/handlers.d.ts +0 -12
- package/dist/os/workflow/handlers.d.ts.map +0 -1
- package/dist/os/workflow/handlers.js +0 -254
- package/dist/os/workflow/handlers.js.map +0 -1
- package/dist/os/workflow/index.d.ts +0 -4
- package/dist/os/workflow/index.d.ts.map +0 -1
- package/dist/os/workflow/index.js +0 -18
- package/dist/os/workflow/index.js.map +0 -1
- package/dist/os/workflow/types.d.ts +0 -69
- package/dist/os/workflow/types.d.ts.map +0 -1
- package/dist/os/workflow/types.js +0 -23
- package/dist/os/workflow/types.js.map +0 -1
- package/dist/os/workflow/workflow.module.d.ts +0 -3
- package/dist/os/workflow/workflow.module.d.ts.map +0 -1
- package/dist/os/workflow/workflow.module.js +0 -48
- package/dist/os/workflow/workflow.module.js.map +0 -1
- package/dist/src/cli-output.d.ts +0 -5
- package/dist/src/cli-output.d.ts.map +0 -1
- package/dist/src/cli-output.js +0 -53
- package/dist/src/cli-output.js.map +0 -1
- package/dist/src/config/forge-config.d.ts +0 -242
- package/dist/src/config/forge-config.d.ts.map +0 -1
- package/dist/src/config/forge-config.js +0 -359
- package/dist/src/config/forge-config.js.map +0 -1
- package/dist/src/forge-module.d.ts +0 -16
- package/dist/src/forge-module.d.ts.map +0 -1
- package/dist/src/forge-module.js +0 -15
- package/dist/src/forge-module.js.map +0 -1
- package/dist/src/index.d.ts +0 -36
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -56
- package/dist/src/index.js.map +0 -1
- package/dist/src/knowledge/budgets.d.ts +0 -38
- package/dist/src/knowledge/budgets.d.ts.map +0 -1
- package/dist/src/knowledge/budgets.js +0 -157
- package/dist/src/knowledge/budgets.js.map +0 -1
- package/dist/src/knowledge/compact.d.ts +0 -47
- package/dist/src/knowledge/compact.d.ts.map +0 -1
- package/dist/src/knowledge/compact.js +0 -320
- package/dist/src/knowledge/compact.js.map +0 -1
- package/dist/src/knowledge/index.d.ts +0 -7
- package/dist/src/knowledge/index.d.ts.map +0 -1
- package/dist/src/knowledge/index.js +0 -19
- package/dist/src/knowledge/index.js.map +0 -1
- package/dist/src/knowledge/parse.d.ts +0 -3
- package/dist/src/knowledge/parse.d.ts.map +0 -1
- package/dist/src/knowledge/parse.js +0 -205
- package/dist/src/knowledge/parse.js.map +0 -1
- package/dist/src/knowledge/promote.d.ts +0 -37
- package/dist/src/knowledge/promote.d.ts.map +0 -1
- package/dist/src/knowledge/promote.js +0 -120
- package/dist/src/knowledge/promote.js.map +0 -1
- package/dist/src/knowledge/schema.d.ts +0 -61
- package/dist/src/knowledge/schema.d.ts.map +0 -1
- package/dist/src/knowledge/schema.js +0 -64
- package/dist/src/knowledge/schema.js.map +0 -1
- package/dist/src/knowledge/serialize.d.ts +0 -3
- package/dist/src/knowledge/serialize.d.ts.map +0 -1
- package/dist/src/knowledge/serialize.js +0 -67
- package/dist/src/knowledge/serialize.js.map +0 -1
- package/dist/src/migration-adapters/git-utils.d.ts +0 -3
- package/dist/src/migration-adapters/git-utils.d.ts.map +0 -1
- package/dist/src/migration-adapters/git-utils.js +0 -56
- package/dist/src/migration-adapters/git-utils.js.map +0 -1
- package/dist/src/migration-adapters/ignored-files.d.ts +0 -12
- package/dist/src/migration-adapters/ignored-files.d.ts.map +0 -1
- package/dist/src/migration-adapters/ignored-files.js +0 -190
- package/dist/src/migration-adapters/ignored-files.js.map +0 -1
- package/dist/src/migration-adapters/index.d.ts +0 -8
- package/dist/src/migration-adapters/index.d.ts.map +0 -1
- package/dist/src/migration-adapters/index.js +0 -17
- package/dist/src/migration-adapters/index.js.map +0 -1
- package/dist/src/migration-adapters/node-typescript-pnpm/index.d.ts +0 -3
- package/dist/src/migration-adapters/node-typescript-pnpm/index.d.ts.map +0 -1
- package/dist/src/migration-adapters/node-typescript-pnpm/index.js +0 -141
- package/dist/src/migration-adapters/node-typescript-pnpm/index.js.map +0 -1
- package/dist/src/migration-adapters/phaser-pnpm/index.d.ts +0 -3
- package/dist/src/migration-adapters/phaser-pnpm/index.d.ts.map +0 -1
- package/dist/src/migration-adapters/phaser-pnpm/index.js +0 -142
- package/dist/src/migration-adapters/phaser-pnpm/index.js.map +0 -1
- package/dist/src/migration-adapters/registry.d.ts +0 -6
- package/dist/src/migration-adapters/registry.d.ts.map +0 -1
- package/dist/src/migration-adapters/registry.js +0 -55
- package/dist/src/migration-adapters/registry.js.map +0 -1
- package/dist/src/migration-adapters/types.d.ts +0 -35
- package/dist/src/migration-adapters/types.d.ts.map +0 -1
- package/dist/src/migration-adapters/types.js +0 -31
- package/dist/src/migration-adapters/types.js.map +0 -1
- package/dist/src/onboarding/agents-generate.d.ts +0 -30
- package/dist/src/onboarding/agents-generate.d.ts.map +0 -1
- package/dist/src/onboarding/agents-generate.js +0 -352
- package/dist/src/onboarding/agents-generate.js.map +0 -1
- package/dist/src/onboarding/create.d.ts +0 -12
- package/dist/src/onboarding/create.d.ts.map +0 -1
- package/dist/src/onboarding/create.js +0 -318
- package/dist/src/onboarding/create.js.map +0 -1
- package/dist/src/onboarding/doctor.d.ts +0 -45
- package/dist/src/onboarding/doctor.d.ts.map +0 -1
- package/dist/src/onboarding/doctor.js +0 -1108
- package/dist/src/onboarding/doctor.js.map +0 -1
- package/dist/src/onboarding/init.d.ts +0 -32
- package/dist/src/onboarding/init.d.ts.map +0 -1
- package/dist/src/onboarding/init.js +0 -291
- package/dist/src/onboarding/init.js.map +0 -1
- package/dist/src/onboarding/invariant-engine.d.ts +0 -17
- package/dist/src/onboarding/invariant-engine.d.ts.map +0 -1
- package/dist/src/onboarding/invariant-engine.js +0 -416
- package/dist/src/onboarding/invariant-engine.js.map +0 -1
- package/dist/src/onboarding/memory-scaffold.d.ts +0 -18
- package/dist/src/onboarding/memory-scaffold.d.ts.map +0 -1
- package/dist/src/onboarding/memory-scaffold.js +0 -151
- package/dist/src/onboarding/memory-scaffold.js.map +0 -1
- package/dist/src/onboarding/nested-agents-generate.d.ts +0 -18
- package/dist/src/onboarding/nested-agents-generate.d.ts.map +0 -1
- package/dist/src/onboarding/nested-agents-generate.js +0 -69
- package/dist/src/onboarding/nested-agents-generate.js.map +0 -1
- package/dist/src/onboarding/nested-agents-templates.d.ts +0 -26
- package/dist/src/onboarding/nested-agents-templates.d.ts.map +0 -1
- package/dist/src/onboarding/nested-agents-templates.js +0 -178
- package/dist/src/onboarding/nested-agents-templates.js.map +0 -1
- package/dist/src/onboarding/profile-validate.d.ts +0 -13
- package/dist/src/onboarding/profile-validate.d.ts.map +0 -1
- package/dist/src/onboarding/profile-validate.js +0 -109
- package/dist/src/onboarding/profile-validate.js.map +0 -1
- package/dist/src/onboarding/scaffold-project.d.ts +0 -12
- package/dist/src/onboarding/scaffold-project.d.ts.map +0 -1
- package/dist/src/onboarding/scaffold-project.js +0 -248
- package/dist/src/onboarding/scaffold-project.js.map +0 -1
- package/dist/src/onboarding/scaffold.d.ts +0 -15
- package/dist/src/onboarding/scaffold.d.ts.map +0 -1
- package/dist/src/onboarding/scaffold.js +0 -120
- package/dist/src/onboarding/scaffold.js.map +0 -1
- package/dist/src/onboarding/upgrade.d.ts +0 -25
- package/dist/src/onboarding/upgrade.d.ts.map +0 -1
- package/dist/src/onboarding/upgrade.js +0 -391
- package/dist/src/onboarding/upgrade.js.map +0 -1
- package/dist/src/onboarding/workspace-discovery.d.ts +0 -11
- package/dist/src/onboarding/workspace-discovery.d.ts.map +0 -1
- package/dist/src/onboarding/workspace-discovery.js +0 -138
- package/dist/src/onboarding/workspace-discovery.js.map +0 -1
- package/dist/src/profiles/profile-schema.d.ts +0 -351
- package/dist/src/profiles/profile-schema.d.ts.map +0 -1
- package/dist/src/profiles/profile-schema.js +0 -201
- package/dist/src/profiles/profile-schema.js.map +0 -1
- package/dist/src/profiles/stack-profile.d.ts +0 -168
- package/dist/src/profiles/stack-profile.d.ts.map +0 -1
- package/dist/src/profiles/stack-profile.js +0 -144
- package/dist/src/profiles/stack-profile.js.map +0 -1
- package/dist/src/profiles/terminology-utils.d.ts +0 -8
- package/dist/src/profiles/terminology-utils.d.ts.map +0 -1
- package/dist/src/profiles/terminology-utils.js +0 -31
- package/dist/src/profiles/terminology-utils.js.map +0 -1
- package/dist/src/registry.d.ts +0 -38
- package/dist/src/registry.d.ts.map +0 -1
- package/dist/src/registry.js +0 -135
- package/dist/src/registry.js.map +0 -1
- package/dist/src/skill-schema.d.ts +0 -30
- package/dist/src/skill-schema.d.ts.map +0 -1
- package/dist/src/skill-schema.js +0 -34
- package/dist/src/skill-schema.js.map +0 -1
- package/dist/src/types.d.ts +0 -152
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/types.js +0 -17
- package/dist/src/types.js.map +0 -1
- package/dist/src/utils/fs-atomic.d.ts +0 -7
- package/dist/src/utils/fs-atomic.d.ts.map +0 -1
- package/dist/src/utils/fs-atomic.js +0 -81
- package/dist/src/utils/fs-atomic.js.map +0 -1
- package/dist/src/utils/fs-idempotent.d.ts +0 -2
- package/dist/src/utils/fs-idempotent.d.ts.map +0 -1
- package/dist/src/utils/fs-idempotent.js +0 -39
- package/dist/src/utils/fs-idempotent.js.map +0 -1
- package/dist/src/utils/fs-trash-sync.d.ts +0 -2
- package/dist/src/utils/fs-trash-sync.d.ts.map +0 -1
- package/dist/src/utils/fs-trash-sync.js +0 -34
- package/dist/src/utils/fs-trash-sync.js.map +0 -1
- package/dist/src/utils/fs-trash.d.ts +0 -2
- package/dist/src/utils/fs-trash.d.ts.map +0 -1
- package/dist/src/utils/fs-trash.js +0 -24
- package/dist/src/utils/fs-trash.js.map +0 -1
- package/dist/src/utils/fs.d.ts +0 -8
- package/dist/src/utils/fs.d.ts.map +0 -1
- package/dist/src/utils/fs.js +0 -60
- package/dist/src/utils/fs.js.map +0 -1
- package/dist/src/utils/generated-marker.d.ts +0 -21
- package/dist/src/utils/generated-marker.d.ts.map +0 -1
- package/dist/src/utils/generated-marker.js +0 -128
- package/dist/src/utils/generated-marker.js.map +0 -1
- package/dist/src/utils/hash.d.ts +0 -2
- package/dist/src/utils/hash.d.ts.map +0 -1
- package/dist/src/utils/hash.js +0 -18
- package/dist/src/utils/hash.js.map +0 -1
- package/dist/src/utils/index.d.ts +0 -9
- package/dist/src/utils/index.d.ts.map +0 -1
- package/dist/src/utils/index.js +0 -21
- package/dist/src/utils/index.js.map +0 -1
- package/dist/src/utils/string-utils.d.ts +0 -2
- package/dist/src/utils/string-utils.d.ts.map +0 -1
- package/dist/src/utils/string-utils.js +0 -19
- package/dist/src/utils/string-utils.js.map +0 -1
- package/dist/src/validators/note-frontmatter-validate.d.ts +0 -20
- package/dist/src/validators/note-frontmatter-validate.d.ts.map +0 -1
- package/dist/src/validators/note-frontmatter-validate.js +0 -117
- package/dist/src/validators/note-frontmatter-validate.js.map +0 -1
- package/dist/src/validators/note-link-validate.d.ts +0 -21
- package/dist/src/validators/note-link-validate.d.ts.map +0 -1
- package/dist/src/validators/note-link-validate.js +0 -121
- package/dist/src/validators/note-link-validate.js.map +0 -1
- package/dist/src/validators/note-orphan-detect.d.ts +0 -19
- package/dist/src/validators/note-orphan-detect.d.ts.map +0 -1
- package/dist/src/validators/note-orphan-detect.js +0 -123
- package/dist/src/validators/note-orphan-detect.js.map +0 -1
- package/dist/src/validators/port-validate.d.ts +0 -12
- package/dist/src/validators/port-validate.d.ts.map +0 -1
- package/dist/src/validators/port-validate.js +0 -78
- package/dist/src/validators/port-validate.js.map +0 -1
- package/dist/src/validators/skill-validate.d.ts +0 -29
- package/dist/src/validators/skill-validate.d.ts.map +0 -1
- package/dist/src/validators/skill-validate.js +0 -689
- package/dist/src/validators/skill-validate.js.map +0 -1
|
@@ -1,1108 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
<MODULE_CONTRACT>
|
|
3
|
-
<purpose>forge.doctor — diagnoses forge state in an existing project.
|
|
4
|
-
Checks for forge.yaml, AGENTS.md, PREFERENCES.md, .agents/skills/, docs/rfcs/,
|
|
5
|
-
@warpgogol/* import autonomy guard, and bindings contract (RFC-0393).</purpose>
|
|
6
|
-
<non-goals>
|
|
7
|
-
<item>Do not modify files — doctor is read-only diagnostics.</item>
|
|
8
|
-
</non-goals>
|
|
9
|
-
</MODULE_CONTRACT>
|
|
10
|
-
<CHANGE_SUMMARY>
|
|
11
|
-
<item>Initial forge.doctor handler for autonomy refactor.</item>
|
|
12
|
-
<item>RFC-0391: added @warpgogol/* forbidden-imports autonomy guard.</item>
|
|
13
|
-
<item>RFC-0393: added bindings validation — resolved/absent/invalid reporting.</item>
|
|
14
|
-
<item>RFC-0524: added stale knowledge file detection — compares source and .agents/ copies.</item>
|
|
15
|
-
<item>RFC-0539: extended knowledge file check to iterate pack skills via discoverPackSkills. Added pack-skills check for stale/missing copies and skillPacks config validation.</item>
|
|
16
|
-
<item>RFC-0540: added defaultable-binding-null notices for forge-CLI-backed bindings.</item>
|
|
17
|
-
<item>RFC-0611: added nested AGENTS.md checks — missing, stale (dryRun comparison), hand-written improvement.</item>
|
|
18
|
-
<item>RFC-0640: added domain reporting, invariant listing (reported-only), terminology resolution, --strict flag, and software-specific check skipping for non-software domains.</item>
|
|
19
|
-
<item>RFC-0675: upgraded domain-invariants check from advisory to enforcement using invariant engine.</item>
|
|
20
|
-
<item>RFC-0660: added legacy-section count reporting for structured knowledge files.</item>
|
|
21
|
-
<item>RFC-0661: added knowledge-budgets check — validates override shape, computes per-skill budget reports, reports summary with headroom %.</item>
|
|
22
|
-
<item>RFC-0663: added knowledge-duplicates check (cross-skill L2 duplicate detection) and shared-knowledge-file check (schema/id uniqueness for the shared layer).</item>
|
|
23
|
-
<item>RFC-0664: added memory-layer health check (budget usage, gitignore coverage, daily-file leak risk).</item>
|
|
24
|
-
<item>RFC-0704: added independent-version-packages check — validates that paths in independentVersionPackages exist and contain package.json.</item>
|
|
25
|
-
</CHANGE_SUMMARY>
|
|
26
|
-
*/
|
|
27
|
-
import { readFile, readdir, stat } from "node:fs/promises";
|
|
28
|
-
import { readFileSync } from "node:fs";
|
|
29
|
-
import { join, relative, dirname } from "node:path";
|
|
30
|
-
import { parse as parseYaml } from "yaml";
|
|
31
|
-
import { resolveForgeRoot, loadForgeConfig, resolveBinding, resolveTerminology, FORGE_CLI_BINDING_DEFAULTS, resolvePmRunner } from "../config/forge-config.js";
|
|
32
|
-
import { FORGE_SKILLS, discoverPackSkills } from "../registry.js";
|
|
33
|
-
import { discoverWorkspaces } from "./workspace-discovery.js";
|
|
34
|
-
import { buildNestedAgentsMd, selectNestedTemplate } from "./nested-agents-templates.js";
|
|
35
|
-
import { readPackageInfo } from "./nested-agents-generate.js";
|
|
36
|
-
import { listStackProfiles } from "../profiles/stack-profile.js";
|
|
37
|
-
import { resolveAllTerminology } from "../profiles/terminology-utils.js";
|
|
38
|
-
import { TERMINOLOGY_DEFAULTS } from "../profiles/profile-schema.js";
|
|
39
|
-
import { runProfileValidate } from "./profile-validate.js";
|
|
40
|
-
import { parseKnowledgeFile } from "../knowledge/index.js";
|
|
41
|
-
import { computeLayerBudgets, resolveKnowledgeBudgets, DEFAULT_KNOWLEDGE_BUDGETS } from "../knowledge/budgets.js";
|
|
42
|
-
import { detectDuplicatePrinciples } from "../knowledge/index.js";
|
|
43
|
-
import { checkMemoryLayerHealth } from "./memory-scaffold.js";
|
|
44
|
-
import { checkInvariants } from "./invariant-engine.js";
|
|
45
|
-
import { execSync } from "node:child_process";
|
|
46
|
-
async function pathExists(target) {
|
|
47
|
-
try {
|
|
48
|
-
await stat(target);
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
const FORBIDDEN_IMPORT_PATTERN = /(?:^|\n)\s*(?:import\s+[^;]+?\s+from\s+|require\s*\(\s*)["'`](@warpgogol\/[^"'`]+)["'`]/g;
|
|
56
|
-
async function scanForForbiddenImports(dir, workspaceRoot) {
|
|
57
|
-
const violations = [];
|
|
58
|
-
const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
59
|
-
for (const entry of entries) {
|
|
60
|
-
const fullPath = join(dir, entry.name);
|
|
61
|
-
if (entry.isDirectory()) {
|
|
62
|
-
if (entry.name === "node_modules" || entry.name === "tests")
|
|
63
|
-
continue;
|
|
64
|
-
const sub = await scanForForbiddenImports(fullPath, workspaceRoot);
|
|
65
|
-
violations.push(...sub);
|
|
66
|
-
}
|
|
67
|
-
else if (entry.name.endsWith(".ts")) {
|
|
68
|
-
const content = await readFile(fullPath, "utf8").catch(() => "");
|
|
69
|
-
let match;
|
|
70
|
-
const pattern = new RegExp(FORBIDDEN_IMPORT_PATTERN.source, "g");
|
|
71
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
72
|
-
violations.push({
|
|
73
|
-
file: relative(workspaceRoot, fullPath),
|
|
74
|
-
specifier: match[1],
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return violations;
|
|
80
|
-
}
|
|
81
|
-
// ---------------------------------------------------------------------------
|
|
82
|
-
// Bindings validation (RFC-0393)
|
|
83
|
-
// ---------------------------------------------------------------------------
|
|
84
|
-
const BINDING_PATH_KEYS = [
|
|
85
|
-
"paths.invariantsFile",
|
|
86
|
-
"paths.reviewsDir",
|
|
87
|
-
"paths.handoffsDir",
|
|
88
|
-
"paths.sessionsDir",
|
|
89
|
-
];
|
|
90
|
-
const BINDING_COMMAND_KEYS = [
|
|
91
|
-
"commands.validateRfc",
|
|
92
|
-
"commands.validateAdr",
|
|
93
|
-
"commands.implementStamp",
|
|
94
|
-
"commands.typecheck",
|
|
95
|
-
"commands.test",
|
|
96
|
-
"commands.scopedBuild",
|
|
97
|
-
"commands.specValidate",
|
|
98
|
-
"commands.sessionSave",
|
|
99
|
-
];
|
|
100
|
-
async function validateBindings(workspaceRoot) {
|
|
101
|
-
const result = { resolved: [], absent: [], invalid: [], notices: [] };
|
|
102
|
-
let config;
|
|
103
|
-
try {
|
|
104
|
-
config = loadForgeConfig(workspaceRoot);
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
return result;
|
|
108
|
-
}
|
|
109
|
-
if (!config.bindings) {
|
|
110
|
-
return result;
|
|
111
|
-
}
|
|
112
|
-
for (const key of BINDING_PATH_KEYS) {
|
|
113
|
-
const value = resolveBinding(config, key);
|
|
114
|
-
if (value === null) {
|
|
115
|
-
result.absent.push(key);
|
|
116
|
-
}
|
|
117
|
-
else if (typeof value === "string") {
|
|
118
|
-
const exists = await pathExists(join(workspaceRoot, value));
|
|
119
|
-
if (exists) {
|
|
120
|
-
result.resolved.push(key);
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
result.invalid.push(`${key} (path not found: ${value})`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
const compassDocs = resolveBinding(config, "paths.compassDocs");
|
|
128
|
-
if (Array.isArray(compassDocs) && compassDocs.length > 0) {
|
|
129
|
-
for (const docPath of compassDocs) {
|
|
130
|
-
const exists = await pathExists(join(workspaceRoot, docPath));
|
|
131
|
-
if (exists) {
|
|
132
|
-
result.resolved.push(`paths.compassDocs[${docPath}]`);
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
result.invalid.push(`paths.compassDocs[${docPath}] (path not found)`);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
result.absent.push("paths.compassDocs");
|
|
141
|
-
}
|
|
142
|
-
for (const key of BINDING_COMMAND_KEYS) {
|
|
143
|
-
const value = resolveBinding(config, key);
|
|
144
|
-
if (value === null) {
|
|
145
|
-
result.absent.push(key);
|
|
146
|
-
}
|
|
147
|
-
else if (typeof value === "string") {
|
|
148
|
-
result.resolved.push(key);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
// RFC-0540: Emit defaultable-binding-null notices for forge-CLI-backed bindings
|
|
152
|
-
const pm = config.project.packageManager;
|
|
153
|
-
const runner = resolvePmRunner(pm);
|
|
154
|
-
for (const entry of FORGE_CLI_BINDING_DEFAULTS) {
|
|
155
|
-
const value = resolveBinding(config, entry.key);
|
|
156
|
-
if (value === null) {
|
|
157
|
-
result.notices.push({
|
|
158
|
-
key: entry.key,
|
|
159
|
-
rule: "defaultable-binding-null",
|
|
160
|
-
suggestion: `${runner} ${entry.template}`,
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return result;
|
|
165
|
-
}
|
|
166
|
-
// ---------------------------------------------------------------------------
|
|
167
|
-
// Stale knowledge file detection (RFC-0524)
|
|
168
|
-
// ---------------------------------------------------------------------------
|
|
169
|
-
async function checkStaleKnowledgeFiles(workspaceRoot, forgeRoot) {
|
|
170
|
-
const stale = [];
|
|
171
|
-
let config;
|
|
172
|
-
try {
|
|
173
|
-
config = loadForgeConfig(workspaceRoot);
|
|
174
|
-
}
|
|
175
|
-
catch {
|
|
176
|
-
return { name: "knowledge-files", status: "pass", message: "No forge.yaml — knowledge file check skipped" };
|
|
177
|
-
}
|
|
178
|
-
const agentsSkillsDir = join(workspaceRoot, config.paths.skillsDir);
|
|
179
|
-
for (const skill of FORGE_SKILLS) {
|
|
180
|
-
if (!skill.knowledge || skill.knowledge.length === 0)
|
|
181
|
-
continue;
|
|
182
|
-
const skillSrcDir = dirname(join(forgeRoot, skill.path));
|
|
183
|
-
for (const kf of skill.knowledge) {
|
|
184
|
-
const srcPath = join(skillSrcDir, kf);
|
|
185
|
-
const destPath = join(agentsSkillsDir, skill.name, kf);
|
|
186
|
-
const srcExists = await pathExists(srcPath);
|
|
187
|
-
const destExists = await pathExists(destPath);
|
|
188
|
-
if (srcExists && destExists) {
|
|
189
|
-
const srcContent = await readFile(srcPath, "utf8").catch(() => "");
|
|
190
|
-
const destContent = await readFile(destPath, "utf8").catch(() => "");
|
|
191
|
-
if (srcContent !== destContent) {
|
|
192
|
-
stale.push(`${skill.name}/${kf}`);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
// If source exists but dest doesn't, skip — expected on first install
|
|
196
|
-
// If source doesn't exist, SKILL-13 in forge.skill.validate catches it
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
// RFC-0539: Check pack skill knowledge files
|
|
200
|
-
const packSkills = discoverPackSkills(workspaceRoot, config);
|
|
201
|
-
for (const skill of packSkills) {
|
|
202
|
-
if (!skill.knowledge || skill.knowledge.length === 0)
|
|
203
|
-
continue;
|
|
204
|
-
const skillSrcDir = dirname(join(workspaceRoot, skill.dir, skill.path));
|
|
205
|
-
for (const kf of skill.knowledge) {
|
|
206
|
-
const srcPath = join(skillSrcDir, kf);
|
|
207
|
-
const destPath = join(agentsSkillsDir, skill.name, kf);
|
|
208
|
-
const srcExists = await pathExists(srcPath);
|
|
209
|
-
const destExists = await pathExists(destPath);
|
|
210
|
-
if (srcExists && destExists) {
|
|
211
|
-
const srcContent = await readFile(srcPath, "utf8").catch(() => "");
|
|
212
|
-
const destContent = await readFile(destPath, "utf8").catch(() => "");
|
|
213
|
-
if (srcContent !== destContent) {
|
|
214
|
-
stale.push(`${skill.name}/${kf}`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return {
|
|
220
|
-
name: "knowledge-files",
|
|
221
|
-
status: stale.length === 0 ? "pass" : "warn",
|
|
222
|
-
message: stale.length === 0
|
|
223
|
-
? "All knowledge files in sync"
|
|
224
|
-
: `${stale.length} stale knowledge file(s): ${stale.join(", ")} — run 'forge create' to sync`,
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
// ---------------------------------------------------------------------------
|
|
228
|
-
// Legacy section detection (RFC-0660)
|
|
229
|
-
// ---------------------------------------------------------------------------
|
|
230
|
-
function checkLegacyKnowledgeSections(workspaceRoot, forgeRoot) {
|
|
231
|
-
let config;
|
|
232
|
-
try {
|
|
233
|
-
config = loadForgeConfig(workspaceRoot);
|
|
234
|
-
}
|
|
235
|
-
catch {
|
|
236
|
-
return { name: "knowledge-legacy", status: "pass", message: "No forge.yaml — legacy section check skipped" };
|
|
237
|
-
}
|
|
238
|
-
let totalLegacy = 0;
|
|
239
|
-
let filesWithLegacy = 0;
|
|
240
|
-
// Check forge skills
|
|
241
|
-
for (const skill of FORGE_SKILLS) {
|
|
242
|
-
if (!skill.knowledge || skill.knowledge.length === 0)
|
|
243
|
-
continue;
|
|
244
|
-
const skillDir = join(forgeRoot, dirname(skill.path));
|
|
245
|
-
for (const kf of skill.knowledge) {
|
|
246
|
-
const kfPath = join(skillDir, kf);
|
|
247
|
-
try {
|
|
248
|
-
const parsed = parseKnowledgeFile(kfPath);
|
|
249
|
-
if (parsed.isKnowledgeAdjacent)
|
|
250
|
-
continue;
|
|
251
|
-
if (parsed.legacySections.length > 0) {
|
|
252
|
-
totalLegacy += parsed.legacySections.length;
|
|
253
|
-
filesWithLegacy++;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
catch {
|
|
257
|
-
// File read errors are handled by stale knowledge check
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
// Check pack skills
|
|
262
|
-
const packSkills = discoverPackSkills(workspaceRoot, config);
|
|
263
|
-
for (const skill of packSkills) {
|
|
264
|
-
if (!skill.knowledge || skill.knowledge.length === 0)
|
|
265
|
-
continue;
|
|
266
|
-
const skillDir = join(workspaceRoot, skill.dir, dirname(skill.path));
|
|
267
|
-
for (const kf of skill.knowledge) {
|
|
268
|
-
const kfPath = join(skillDir, kf);
|
|
269
|
-
try {
|
|
270
|
-
const parsed = parseKnowledgeFile(kfPath);
|
|
271
|
-
if (parsed.isKnowledgeAdjacent)
|
|
272
|
-
continue;
|
|
273
|
-
if (parsed.legacySections.length > 0) {
|
|
274
|
-
totalLegacy += parsed.legacySections.length;
|
|
275
|
-
filesWithLegacy++;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
catch {
|
|
279
|
-
// File read errors are handled by stale knowledge check
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
return {
|
|
284
|
-
name: "knowledge-legacy",
|
|
285
|
-
status: totalLegacy === 0 ? "pass" : "warn",
|
|
286
|
-
message: totalLegacy === 0
|
|
287
|
-
? "No legacy knowledge sections"
|
|
288
|
-
: `${totalLegacy} legacy section${totalLegacy === 1 ? "" : "s"} across ${filesWithLegacy} knowledge file${filesWithLegacy === 1 ? "" : "s"} — run the knowledge compaction command to migrate`,
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
// ---------------------------------------------------------------------------
|
|
292
|
-
// Knowledge budget check (RFC-0661)
|
|
293
|
-
// ---------------------------------------------------------------------------
|
|
294
|
-
function checkKnowledgeBudgets(workspaceRoot, forgeRoot) {
|
|
295
|
-
let config;
|
|
296
|
-
try {
|
|
297
|
-
config = loadForgeConfig(workspaceRoot);
|
|
298
|
-
}
|
|
299
|
-
catch {
|
|
300
|
-
return { name: "knowledge-budgets", status: "pass", message: "No forge.yaml — budget check skipped" };
|
|
301
|
-
}
|
|
302
|
-
// Validate override shape if present
|
|
303
|
-
const overrideWarnings = [];
|
|
304
|
-
const effectiveBudgets = resolveKnowledgeBudgets(workspaceRoot);
|
|
305
|
-
let usingDefaults = true;
|
|
306
|
-
try {
|
|
307
|
-
const forgeYamlPath = join(workspaceRoot, "forge.yaml");
|
|
308
|
-
const content = readFileSync(forgeYamlPath, "utf8");
|
|
309
|
-
const parsed = parseYaml(content);
|
|
310
|
-
const bindings = parsed?.bindings;
|
|
311
|
-
const knowledge = bindings?.knowledge;
|
|
312
|
-
const budgets = knowledge?.budgets;
|
|
313
|
-
if (budgets) {
|
|
314
|
-
usingDefaults = false;
|
|
315
|
-
if (typeof budgets.hot !== "number" || budgets.hot <= 0 || !Number.isInteger(budgets.hot)) {
|
|
316
|
-
overrideWarnings.push(`bindings.knowledge.budgets.hot invalid (got ${String(budgets.hot)}), using default ${DEFAULT_KNOWLEDGE_BUDGETS.hot}`);
|
|
317
|
-
}
|
|
318
|
-
if (typeof budgets.warm !== "number" || budgets.warm <= 0 || !Number.isInteger(budgets.warm)) {
|
|
319
|
-
overrideWarnings.push(`bindings.knowledge.budgets.warm invalid (got ${String(budgets.warm)}), using default ${DEFAULT_KNOWLEDGE_BUDGETS.warm}`);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
catch {
|
|
324
|
-
// forge.yaml not readable — defaults already applied
|
|
325
|
-
}
|
|
326
|
-
// Collect all parsed knowledge files from forge skills and pack skills
|
|
327
|
-
const parsedFiles = [];
|
|
328
|
-
for (const skill of FORGE_SKILLS) {
|
|
329
|
-
if (!skill.knowledge || skill.knowledge.length === 0)
|
|
330
|
-
continue;
|
|
331
|
-
const skillDir = join(forgeRoot, dirname(skill.path));
|
|
332
|
-
for (const kf of skill.knowledge) {
|
|
333
|
-
const kfPath = join(skillDir, kf);
|
|
334
|
-
try {
|
|
335
|
-
const parsed = parseKnowledgeFile(kfPath);
|
|
336
|
-
if (parsed.layer !== null && parsed.layer !== "L0" && !parsed.isKnowledgeAdjacent && parsed.parseIssues.length === 0) {
|
|
337
|
-
parsedFiles.push({ file: parsed, skillName: skill.name });
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
catch {
|
|
341
|
-
// File read errors are handled by stale knowledge check
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
const packSkills = discoverPackSkills(workspaceRoot, config);
|
|
346
|
-
for (const skill of packSkills) {
|
|
347
|
-
if (!skill.knowledge || skill.knowledge.length === 0)
|
|
348
|
-
continue;
|
|
349
|
-
const skillDir = join(workspaceRoot, skill.dir, dirname(skill.path));
|
|
350
|
-
for (const kf of skill.knowledge) {
|
|
351
|
-
const kfPath = join(skillDir, kf);
|
|
352
|
-
try {
|
|
353
|
-
const parsed = parseKnowledgeFile(kfPath);
|
|
354
|
-
if (parsed.layer !== null && parsed.layer !== "L0" && !parsed.isKnowledgeAdjacent && parsed.parseIssues.length === 0) {
|
|
355
|
-
parsedFiles.push({ file: parsed, skillName: skill.name, pack: skill.pack });
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
catch {
|
|
359
|
-
// File read errors are handled by stale knowledge check
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
// Compute budget reports
|
|
364
|
-
const filesForBudget = parsedFiles.map((p) => p.file);
|
|
365
|
-
const skillNames = new Map();
|
|
366
|
-
for (const p of parsedFiles) {
|
|
367
|
-
skillNames.set(p.file.path, p.skillName);
|
|
368
|
-
}
|
|
369
|
-
const reports = computeLayerBudgets(filesForBudget, effectiveBudgets, skillNames);
|
|
370
|
-
// Build summary
|
|
371
|
-
const budgetSource = usingDefaults ? "defaults" : "override";
|
|
372
|
-
const parts = [`budgets: hot=${effectiveBudgets.hot} warm=${effectiveBudgets.warm} (${budgetSource})`];
|
|
373
|
-
if (reports.length > 0) {
|
|
374
|
-
const summary = reports.map((r) => {
|
|
375
|
-
const pct = Math.round((r.activeChars / r.budget) * 100);
|
|
376
|
-
return `${r.skill}/${r.file}[${r.layer}]: ${r.activeChars}/${r.budget} (${pct}%)`;
|
|
377
|
-
});
|
|
378
|
-
parts.push(`${reports.length} file${reports.length === 1 ? "" : "s"}: ${summary.join(", ")}`);
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
parts.push("no hot/warm knowledge files to check");
|
|
382
|
-
}
|
|
383
|
-
if (overrideWarnings.length > 0) {
|
|
384
|
-
parts.push(overrideWarnings.join("; "));
|
|
385
|
-
}
|
|
386
|
-
const status = overrideWarnings.length > 0 ? "warn" : "pass";
|
|
387
|
-
return {
|
|
388
|
-
name: "knowledge-budgets",
|
|
389
|
-
status,
|
|
390
|
-
message: parts.join(" | "),
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
// ---------------------------------------------------------------------------
|
|
394
|
-
// Knowledge duplicate detection (RFC-0663)
|
|
395
|
-
// ---------------------------------------------------------------------------
|
|
396
|
-
function collectL2Files(workspaceRoot, forgeRoot) {
|
|
397
|
-
let config;
|
|
398
|
-
try {
|
|
399
|
-
config = loadForgeConfig(workspaceRoot);
|
|
400
|
-
}
|
|
401
|
-
catch {
|
|
402
|
-
return [];
|
|
403
|
-
}
|
|
404
|
-
const files = [];
|
|
405
|
-
for (const skill of FORGE_SKILLS) {
|
|
406
|
-
if (!skill.knowledge || skill.knowledge.length === 0)
|
|
407
|
-
continue;
|
|
408
|
-
const skillDir = join(forgeRoot, dirname(skill.path));
|
|
409
|
-
for (const kf of skill.knowledge) {
|
|
410
|
-
if (kf !== "learned-principles.md")
|
|
411
|
-
continue;
|
|
412
|
-
const kfPath = join(skillDir, kf);
|
|
413
|
-
try {
|
|
414
|
-
const parsed = parseKnowledgeFile(kfPath);
|
|
415
|
-
if (parsed.isKnowledgeAdjacent)
|
|
416
|
-
continue;
|
|
417
|
-
if (parsed.parseIssues.length > 0)
|
|
418
|
-
continue;
|
|
419
|
-
files.push({ skill: skill.name, parsed });
|
|
420
|
-
}
|
|
421
|
-
catch {
|
|
422
|
-
// File read errors are handled by stale knowledge check
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
const packSkills = discoverPackSkills(workspaceRoot, config);
|
|
427
|
-
for (const skill of packSkills) {
|
|
428
|
-
if (!skill.knowledge || skill.knowledge.length === 0)
|
|
429
|
-
continue;
|
|
430
|
-
const skillDir = join(workspaceRoot, skill.dir, dirname(skill.path));
|
|
431
|
-
for (const kf of skill.knowledge) {
|
|
432
|
-
if (kf !== "learned-principles.md")
|
|
433
|
-
continue;
|
|
434
|
-
const kfPath = join(skillDir, kf);
|
|
435
|
-
try {
|
|
436
|
-
const parsed = parseKnowledgeFile(kfPath);
|
|
437
|
-
if (parsed.isKnowledgeAdjacent)
|
|
438
|
-
continue;
|
|
439
|
-
if (parsed.parseIssues.length > 0)
|
|
440
|
-
continue;
|
|
441
|
-
files.push({ skill: skill.name, parsed });
|
|
442
|
-
}
|
|
443
|
-
catch {
|
|
444
|
-
// File read errors are handled by stale knowledge check
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
const sharedPath = join(forgeRoot, "skills", "shared", "knowledge", "learned-principles.md");
|
|
449
|
-
try {
|
|
450
|
-
const parsed = parseKnowledgeFile(sharedPath);
|
|
451
|
-
if (!parsed.isKnowledgeAdjacent && parsed.parseIssues.length === 0 && parsed.entries.length > 0) {
|
|
452
|
-
files.push({ skill: "shared", parsed });
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
catch {
|
|
456
|
-
// Shared layer not initialized — not an error
|
|
457
|
-
}
|
|
458
|
-
return files;
|
|
459
|
-
}
|
|
460
|
-
function checkKnowledgeDuplicates(workspaceRoot, forgeRoot) {
|
|
461
|
-
const l2Files = collectL2Files(workspaceRoot, forgeRoot);
|
|
462
|
-
if (l2Files.length === 0) {
|
|
463
|
-
return { name: "knowledge-duplicates", status: "pass", message: "No L2 knowledge files to check" };
|
|
464
|
-
}
|
|
465
|
-
const pairs = detectDuplicatePrinciples(l2Files);
|
|
466
|
-
if (pairs.length === 0) {
|
|
467
|
-
return { name: "knowledge-duplicates", status: "pass", message: "No cross-skill duplicate principles detected" };
|
|
468
|
-
}
|
|
469
|
-
const pairSummaries = pairs.map((p) => `${p.a.skill}/${p.a.entryId} ↔ ${p.b.skill}/${p.b.entryId} (${p.kind})`);
|
|
470
|
-
return {
|
|
471
|
-
name: "knowledge-duplicates",
|
|
472
|
-
status: "warn",
|
|
473
|
-
message: `${pairs.length} duplicate pair${pairs.length === 1 ? "" : "s"} detected — run fo-knowledge-distill to promote: ${pairSummaries.join("; ")}`,
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
// ---------------------------------------------------------------------------
|
|
477
|
-
// Shared knowledge file validation (RFC-0663)
|
|
478
|
-
// ---------------------------------------------------------------------------
|
|
479
|
-
function checkSharedKnowledgeFile(workspaceRoot, forgeRoot) {
|
|
480
|
-
const sharedPath = join(forgeRoot, "skills", "shared", "knowledge", "learned-principles.md");
|
|
481
|
-
let parsed;
|
|
482
|
-
try {
|
|
483
|
-
parsed = parseKnowledgeFile(sharedPath);
|
|
484
|
-
}
|
|
485
|
-
catch {
|
|
486
|
-
return { name: "shared-knowledge-file", status: "pass", message: "Shared knowledge layer not initialized — created on first promotion" };
|
|
487
|
-
}
|
|
488
|
-
if (parsed.isKnowledgeAdjacent) {
|
|
489
|
-
return { name: "shared-knowledge-file", status: "pass", message: "Shared knowledge layer is empty (no structured entries)" };
|
|
490
|
-
}
|
|
491
|
-
const issues = [];
|
|
492
|
-
for (const issue of parsed.parseIssues) {
|
|
493
|
-
issues.push(`line ${issue.line}: ${issue.message}`);
|
|
494
|
-
}
|
|
495
|
-
const seenIds = new Set();
|
|
496
|
-
for (const entry of parsed.entries) {
|
|
497
|
-
if (seenIds.has(entry.meta.id)) {
|
|
498
|
-
issues.push(`duplicate entry id: ${entry.meta.id}`);
|
|
499
|
-
}
|
|
500
|
-
seenIds.add(entry.meta.id);
|
|
501
|
-
}
|
|
502
|
-
if (issues.length > 0) {
|
|
503
|
-
return {
|
|
504
|
-
name: "shared-knowledge-file",
|
|
505
|
-
status: "fail",
|
|
506
|
-
message: `${issues.length} issue${issues.length === 1 ? "" : "s"}: ${issues.join("; ")}`,
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
return {
|
|
510
|
-
name: "shared-knowledge-file",
|
|
511
|
-
status: "pass",
|
|
512
|
-
message: `Shared knowledge layer: ${parsed.entries.length} entr${parsed.entries.length === 1 ? "y" : "ies"}`,
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
// ---------------------------------------------------------------------------
|
|
516
|
-
// Independent version packages diagnostics (RFC-0704)
|
|
517
|
-
// ---------------------------------------------------------------------------
|
|
518
|
-
async function checkIndependentVersionPackages(workspaceRoot) {
|
|
519
|
-
let config;
|
|
520
|
-
try {
|
|
521
|
-
config = loadForgeConfig(workspaceRoot);
|
|
522
|
-
}
|
|
523
|
-
catch {
|
|
524
|
-
return { name: "independent-version-packages", status: "pass", message: "No forge.yaml — independent version packages check skipped" };
|
|
525
|
-
}
|
|
526
|
-
if (!config.independentVersionPackages || config.independentVersionPackages.length === 0) {
|
|
527
|
-
return { name: "independent-version-packages", status: "pass", message: "No independent version packages declared" };
|
|
528
|
-
}
|
|
529
|
-
const issues = [];
|
|
530
|
-
let validCount = 0;
|
|
531
|
-
for (const pkgPath of config.independentVersionPackages) {
|
|
532
|
-
const dirExists = await pathExists(join(workspaceRoot, pkgPath));
|
|
533
|
-
const pkgJsonExists = await pathExists(join(workspaceRoot, pkgPath, "package.json"));
|
|
534
|
-
if (!dirExists) {
|
|
535
|
-
issues.push(`path '${pkgPath}' does not exist`);
|
|
536
|
-
}
|
|
537
|
-
else if (!pkgJsonExists) {
|
|
538
|
-
issues.push(`path '${pkgPath}' has no package.json`);
|
|
539
|
-
}
|
|
540
|
-
else {
|
|
541
|
-
validCount++;
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
if (issues.length === 0) {
|
|
545
|
-
return {
|
|
546
|
-
name: "independent-version-packages",
|
|
547
|
-
status: "pass",
|
|
548
|
-
message: `${validCount} independent version package${validCount === 1 ? "" : "s"} declared`,
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
return {
|
|
552
|
-
name: "independent-version-packages",
|
|
553
|
-
status: "warn",
|
|
554
|
-
message: `${issues.length} issue${issues.length === 1 ? "" : "s"}: ${issues.join(", ")}`,
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
// ---------------------------------------------------------------------------
|
|
558
|
-
// Pack skill diagnostics (RFC-0539)
|
|
559
|
-
// ---------------------------------------------------------------------------
|
|
560
|
-
async function checkPackSkills(workspaceRoot) {
|
|
561
|
-
let config;
|
|
562
|
-
try {
|
|
563
|
-
config = loadForgeConfig(workspaceRoot);
|
|
564
|
-
}
|
|
565
|
-
catch {
|
|
566
|
-
return { name: "pack-skills", status: "pass", message: "No forge.yaml — pack skill check skipped" };
|
|
567
|
-
}
|
|
568
|
-
if (!config.skillPacks || config.skillPacks.length === 0) {
|
|
569
|
-
return { name: "pack-skills", status: "pass", message: "No skill packs declared" };
|
|
570
|
-
}
|
|
571
|
-
const issues = [];
|
|
572
|
-
// Validate skillPacks config: unique prefixes, unique dirs, no 'fo' prefix, dir exists
|
|
573
|
-
const prefixes = new Set();
|
|
574
|
-
const dirs = new Set();
|
|
575
|
-
for (const pack of config.skillPacks) {
|
|
576
|
-
if (prefixes.has(pack.prefix)) {
|
|
577
|
-
issues.push(`duplicate prefix '${pack.prefix}'`);
|
|
578
|
-
}
|
|
579
|
-
prefixes.add(pack.prefix);
|
|
580
|
-
if (pack.prefix === "fo") {
|
|
581
|
-
issues.push(`prefix 'fo' is reserved for forge`);
|
|
582
|
-
}
|
|
583
|
-
if (dirs.has(pack.dir)) {
|
|
584
|
-
issues.push(`duplicate dir '${pack.dir}'`);
|
|
585
|
-
}
|
|
586
|
-
dirs.add(pack.dir);
|
|
587
|
-
const packDirExists = await pathExists(join(workspaceRoot, pack.dir));
|
|
588
|
-
if (!packDirExists) {
|
|
589
|
-
issues.push(`pack dir '${pack.dir}' does not exist`);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
// Check for stale/missing pack skill copies
|
|
593
|
-
const packSkills = discoverPackSkills(workspaceRoot, config);
|
|
594
|
-
const agentsSkillsDir = join(workspaceRoot, config.paths.skillsDir);
|
|
595
|
-
for (const skill of packSkills) {
|
|
596
|
-
const srcPath = join(workspaceRoot, skill.dir, skill.path);
|
|
597
|
-
const destPath = join(agentsSkillsDir, skill.name, "SKILL.md");
|
|
598
|
-
const srcExists = await pathExists(srcPath);
|
|
599
|
-
const destExists = await pathExists(destPath);
|
|
600
|
-
if (srcExists && destExists) {
|
|
601
|
-
const srcContent = await readFile(srcPath, "utf8").catch(() => "");
|
|
602
|
-
const destContent = await readFile(destPath, "utf8").catch(() => "");
|
|
603
|
-
if (srcContent !== destContent) {
|
|
604
|
-
issues.push(`stale copy of '${skill.name}'`);
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
else if (srcExists && !destExists) {
|
|
608
|
-
issues.push(`missing copy of '${skill.name}'`);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
return {
|
|
612
|
-
name: "pack-skills",
|
|
613
|
-
status: issues.length === 0 ? "pass" : "warn",
|
|
614
|
-
message: issues.length === 0
|
|
615
|
-
? `${packSkills.length} pack skill(s) in sync`
|
|
616
|
-
: `${issues.length} issue(s): ${issues.join(", ")} — run 'forge create' to sync`,
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
// ---------------------------------------------------------------------------
|
|
620
|
-
// Nested AGENTS.md diagnostics (RFC-0611)
|
|
621
|
-
// ---------------------------------------------------------------------------
|
|
622
|
-
async function checkNestedAgentsMd(workspaceRoot, workspaceTypes) {
|
|
623
|
-
let config;
|
|
624
|
-
try {
|
|
625
|
-
config = loadForgeConfig(workspaceRoot);
|
|
626
|
-
}
|
|
627
|
-
catch {
|
|
628
|
-
return {
|
|
629
|
-
name: "nested-AGENTS.md",
|
|
630
|
-
status: "pass",
|
|
631
|
-
message: "forge.yaml not loadable — nested AGENTS.md check skipped",
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
const workspaces = discoverWorkspaces(workspaceRoot, workspaceTypes);
|
|
635
|
-
if (workspaces.length === 0) {
|
|
636
|
-
return {
|
|
637
|
-
name: "nested-AGENTS.md",
|
|
638
|
-
status: "pass",
|
|
639
|
-
message: "no workspace directories found",
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
const issues = [];
|
|
643
|
-
let missing = 0;
|
|
644
|
-
let stale = 0;
|
|
645
|
-
let handwritten = 0;
|
|
646
|
-
for (const ws of workspaces) {
|
|
647
|
-
if (!ws.hasAgentsMd) {
|
|
648
|
-
missing++;
|
|
649
|
-
issues.push(`${ws.path}/AGENTS.md missing`);
|
|
650
|
-
continue;
|
|
651
|
-
}
|
|
652
|
-
if (!ws.isGenerated) {
|
|
653
|
-
handwritten++;
|
|
654
|
-
const suggestions = [];
|
|
655
|
-
try {
|
|
656
|
-
const content = await readFile(join(workspaceRoot, ws.path, "AGENTS.md"), "utf8");
|
|
657
|
-
if (!content.includes("AGENTS.md")) {
|
|
658
|
-
suggestions.push("reference root AGENTS.md");
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
catch {
|
|
662
|
-
// unreadable — skip
|
|
663
|
-
}
|
|
664
|
-
if (suggestions.length > 0) {
|
|
665
|
-
issues.push(`${ws.path}/AGENTS.md hand-written — consider: ${suggestions.join(", ")}`);
|
|
666
|
-
}
|
|
667
|
-
continue;
|
|
668
|
-
}
|
|
669
|
-
// Stale check: compare in-memory render to committed file
|
|
670
|
-
// Must match the generate pipeline: readPackageInfo + buildNestedAgentsMd + selectNestedTemplate
|
|
671
|
-
try {
|
|
672
|
-
const packageInfo = readPackageInfo(workspaceRoot, ws.path);
|
|
673
|
-
const fallback = buildNestedAgentsMd(ws, config, packageInfo);
|
|
674
|
-
const profile = config.profile;
|
|
675
|
-
const terminology = resolveAllTerminology(config, profile);
|
|
676
|
-
const wsType = workspaceTypes?.find((wt) => wt.id === ws.type);
|
|
677
|
-
const expected = selectNestedTemplate(wsType, profile, terminology, fallback);
|
|
678
|
-
const actual = await readFile(join(workspaceRoot, ws.path, "AGENTS.md"), "utf8");
|
|
679
|
-
if (expected !== actual) {
|
|
680
|
-
stale++;
|
|
681
|
-
issues.push(`${ws.path}/AGENTS.md stale — run 'forge agents generate'`);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
catch {
|
|
685
|
-
// unreadable — skip
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
if (issues.length === 0) {
|
|
689
|
-
return {
|
|
690
|
-
name: "nested-AGENTS.md",
|
|
691
|
-
status: "pass",
|
|
692
|
-
message: `${workspaces.length} workspace(s) — all AGENTS.md in sync`,
|
|
693
|
-
};
|
|
694
|
-
}
|
|
695
|
-
const parts = [];
|
|
696
|
-
if (missing > 0)
|
|
697
|
-
parts.push(`${missing} missing`);
|
|
698
|
-
if (stale > 0)
|
|
699
|
-
parts.push(`${stale} stale`);
|
|
700
|
-
if (handwritten > 0)
|
|
701
|
-
parts.push(`${handwritten} hand-written`);
|
|
702
|
-
return {
|
|
703
|
-
name: "nested-AGENTS.md",
|
|
704
|
-
status: stale > 0 ? "warn" : "pass",
|
|
705
|
-
message: `${parts.join(", ")} — ${issues.slice(0, 3).join("; ")}${issues.length > 3 ? ` (+${issues.length - 3} more)` : ""}`,
|
|
706
|
-
};
|
|
707
|
-
}
|
|
708
|
-
function buildTerminologyMap(config, profileTerminology) {
|
|
709
|
-
const result = {};
|
|
710
|
-
for (const key of Object.keys(TERMINOLOGY_DEFAULTS)) {
|
|
711
|
-
result[key] = resolveTerminology(config, profileTerminology, key);
|
|
712
|
-
}
|
|
713
|
-
// Also include any custom keys from bindings.terminology
|
|
714
|
-
if (config.bindings?.terminology) {
|
|
715
|
-
for (const key of Object.keys(config.bindings.terminology)) {
|
|
716
|
-
if (!(key in result)) {
|
|
717
|
-
result[key] = resolveTerminology(config, profileTerminology, key);
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
return result;
|
|
722
|
-
}
|
|
723
|
-
function resolveDomainReport(workspaceRoot, forgeRoot) {
|
|
724
|
-
// 1. Try forge.yaml domain field
|
|
725
|
-
try {
|
|
726
|
-
const config = loadForgeConfig(workspaceRoot);
|
|
727
|
-
if (config.project.domain) {
|
|
728
|
-
const terminology = buildTerminologyMap(config);
|
|
729
|
-
const register = readRegisterFromPrefs(workspaceRoot);
|
|
730
|
-
return {
|
|
731
|
-
domain: config.project.domain,
|
|
732
|
-
register,
|
|
733
|
-
terminology,
|
|
734
|
-
invariants: [],
|
|
735
|
-
source: "forge.yaml",
|
|
736
|
-
};
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
catch {
|
|
740
|
-
// forge.yaml not loadable
|
|
741
|
-
}
|
|
742
|
-
// 2. Try to find domain from stack profile matching config.project.stack
|
|
743
|
-
try {
|
|
744
|
-
const config = loadForgeConfig(workspaceRoot);
|
|
745
|
-
const profiles = listStackProfiles(forgeRoot);
|
|
746
|
-
for (const stackId of config.project.stack) {
|
|
747
|
-
const profile = profiles.find((p) => p.id === stackId);
|
|
748
|
-
if (profile?.domain) {
|
|
749
|
-
const terminology = buildTerminologyMap(config, profile.terminology);
|
|
750
|
-
const register = profile.register ?? readRegisterFromPrefs(workspaceRoot);
|
|
751
|
-
return {
|
|
752
|
-
domain: profile.domain,
|
|
753
|
-
register,
|
|
754
|
-
terminology,
|
|
755
|
-
invariants: profile.invariants ?? [],
|
|
756
|
-
source: "profile",
|
|
757
|
-
profileId: profile.id,
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
catch {
|
|
763
|
-
// config or profiles not loadable
|
|
764
|
-
}
|
|
765
|
-
// 3. Default: software domain
|
|
766
|
-
return {
|
|
767
|
-
domain: "software",
|
|
768
|
-
register: null,
|
|
769
|
-
terminology: {},
|
|
770
|
-
invariants: [],
|
|
771
|
-
source: "default",
|
|
772
|
-
};
|
|
773
|
-
}
|
|
774
|
-
function readRegisterFromPrefs(workspaceRoot) {
|
|
775
|
-
try {
|
|
776
|
-
const prefsPath = join(workspaceRoot, "PREFERENCES.md");
|
|
777
|
-
const content = readFileSync(prefsPath, "utf8");
|
|
778
|
-
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
779
|
-
if (fmMatch) {
|
|
780
|
-
const fm = parseYaml(fmMatch[1]);
|
|
781
|
-
if (fm["register"] === "creative")
|
|
782
|
-
return "creative";
|
|
783
|
-
if (fm["register"] === "business")
|
|
784
|
-
return "business";
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
catch {
|
|
788
|
-
// PREFERENCES.md missing or unreadable
|
|
789
|
-
}
|
|
790
|
-
return null;
|
|
791
|
-
}
|
|
792
|
-
function checkDomainInfo(domainReport) {
|
|
793
|
-
const parts = [`domain: ${domainReport.domain}`, `source: ${domainReport.source}`];
|
|
794
|
-
if (domainReport.register) {
|
|
795
|
-
parts.push(`register: ${domainReport.register}`);
|
|
796
|
-
}
|
|
797
|
-
if (Object.keys(domainReport.terminology).length > 0) {
|
|
798
|
-
const terms = Object.entries(domainReport.terminology)
|
|
799
|
-
.map(([k, v]) => `${k}=${v}`)
|
|
800
|
-
.join(", ");
|
|
801
|
-
parts.push(`terminology: ${terms}`);
|
|
802
|
-
}
|
|
803
|
-
if (domainReport.invariants.length > 0) {
|
|
804
|
-
parts.push(`invariants: ${domainReport.invariants.length} declared`);
|
|
805
|
-
}
|
|
806
|
-
return {
|
|
807
|
-
name: "domain-info",
|
|
808
|
-
status: "pass",
|
|
809
|
-
message: parts.join(", "),
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
// RFC-0664: Memory layer health check
|
|
813
|
-
function checkMemoryLayer(workspaceRoot) {
|
|
814
|
-
const health = checkMemoryLayerHealth(workspaceRoot);
|
|
815
|
-
if (!health.memoryMdExists) {
|
|
816
|
-
return {
|
|
817
|
-
name: "memory-layer",
|
|
818
|
-
status: "pass",
|
|
819
|
-
message: "Memory layer not initialized — run 'forge create' or 'forge upgrade' to scaffold .agents/memory/",
|
|
820
|
-
};
|
|
821
|
-
}
|
|
822
|
-
const overBudget = health.memoryMdChars > health.budget;
|
|
823
|
-
const leakRisk = !health.gitignoreCoversDaily && health.dailyFileCount > 0;
|
|
824
|
-
if (overBudget && leakRisk) {
|
|
825
|
-
return {
|
|
826
|
-
name: "memory-layer",
|
|
827
|
-
status: "warn",
|
|
828
|
-
message: `MEMORY.md over budget (${health.memoryMdChars}/${health.budget} chars); ${health.dailyFileCount} daily file(s) untracked by .gitignore — add forge-agent-memory block`,
|
|
829
|
-
};
|
|
830
|
-
}
|
|
831
|
-
if (overBudget) {
|
|
832
|
-
return {
|
|
833
|
-
name: "memory-layer",
|
|
834
|
-
status: "warn",
|
|
835
|
-
message: `MEMORY.md over budget (${health.memoryMdChars}/${health.budget} chars) — compact or promote to skill knowledge`,
|
|
836
|
-
};
|
|
837
|
-
}
|
|
838
|
-
if (leakRisk) {
|
|
839
|
-
return {
|
|
840
|
-
name: "memory-layer",
|
|
841
|
-
status: "warn",
|
|
842
|
-
message: `${health.dailyFileCount} daily file(s) not covered by .gitignore — add forge-agent-memory block to prevent committing ephemeral logs`,
|
|
843
|
-
};
|
|
844
|
-
}
|
|
845
|
-
return {
|
|
846
|
-
name: "memory-layer",
|
|
847
|
-
status: "pass",
|
|
848
|
-
message: `MEMORY.md ${health.memoryMdChars}/${health.budget} chars; ${health.dailyFileCount} daily file(s); gitignore ${health.gitignoreCoversDaily ? "covers" : "absent (no daily files)"}`,
|
|
849
|
-
};
|
|
850
|
-
}
|
|
851
|
-
// ---------------------------------------------------------------------------
|
|
852
|
-
// Prerequisite checks (profile-declared system dependencies)
|
|
853
|
-
// ---------------------------------------------------------------------------
|
|
854
|
-
function checkPrerequisites(prerequisites) {
|
|
855
|
-
if (prerequisites.length === 0) {
|
|
856
|
-
return { name: "prerequisites", status: "pass", message: "No prerequisites declared" };
|
|
857
|
-
}
|
|
858
|
-
const results = [];
|
|
859
|
-
for (const prereq of prerequisites) {
|
|
860
|
-
try {
|
|
861
|
-
execSync(prereq.check, { stdio: "pipe", timeout: 10000 });
|
|
862
|
-
results.push({ id: prereq.id, name: prereq.name, status: "pass", message: `${prereq.name} found` });
|
|
863
|
-
}
|
|
864
|
-
catch {
|
|
865
|
-
const hint = prereq.installHint ? ` — install: ${prereq.installHint}` : "";
|
|
866
|
-
results.push({ id: prereq.id, name: prereq.name, status: "fail", message: `${prereq.name} not found${hint}` });
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
const failed = results.filter((r) => r.status === "fail");
|
|
870
|
-
const hasErrors = failed.some((r) => prerequisites.find((p) => p.id === r.id)?.severity === "error");
|
|
871
|
-
const hasWarnings = failed.some((r) => prerequisites.find((p) => p.id === r.id)?.severity === "warning");
|
|
872
|
-
const status = hasErrors ? "fail" : hasWarnings ? "warn" : "pass";
|
|
873
|
-
const parts = results.map((r) => `${r.name}: ${r.status === "pass" ? "ok" : "missing"}`);
|
|
874
|
-
return {
|
|
875
|
-
name: "prerequisites",
|
|
876
|
-
status,
|
|
877
|
-
message: `${results.length} prerequisite(s): ${parts.join(", ")}`,
|
|
878
|
-
};
|
|
879
|
-
}
|
|
880
|
-
export async function runDoctor(input, context) {
|
|
881
|
-
const { workspaceRoot, logger, outputFormat } = context;
|
|
882
|
-
const strict = input.flags["strict"] === true;
|
|
883
|
-
const checks = [];
|
|
884
|
-
// Check forge.yaml
|
|
885
|
-
const forgeYamlExists = await pathExists(join(workspaceRoot, "forge.yaml"));
|
|
886
|
-
checks.push({
|
|
887
|
-
name: "forge.yaml",
|
|
888
|
-
status: forgeYamlExists ? "pass" : "warn",
|
|
889
|
-
message: forgeYamlExists
|
|
890
|
-
? "forge.yaml found"
|
|
891
|
-
: "forge.yaml not found — run 'forge create' to create project configuration",
|
|
892
|
-
});
|
|
893
|
-
// Check AGENTS.md
|
|
894
|
-
const agentsMdExists = await pathExists(join(workspaceRoot, "AGENTS.md"));
|
|
895
|
-
checks.push({
|
|
896
|
-
name: "AGENTS.md",
|
|
897
|
-
status: agentsMdExists ? "pass" : "warn",
|
|
898
|
-
message: agentsMdExists
|
|
899
|
-
? "AGENTS.md found"
|
|
900
|
-
: "AGENTS.md not found — run 'forge create' to deploy agent instructions",
|
|
901
|
-
});
|
|
902
|
-
// Check PREFERENCES.md
|
|
903
|
-
const preferencesExists = await pathExists(join(workspaceRoot, "PREFERENCES.md"));
|
|
904
|
-
checks.push({
|
|
905
|
-
name: "PREFERENCES.md",
|
|
906
|
-
status: preferencesExists ? "pass" : "warn",
|
|
907
|
-
message: preferencesExists
|
|
908
|
-
? "PREFERENCES.md found"
|
|
909
|
-
: "PREFERENCES.md not found — run 'forge create' to create preferences file",
|
|
910
|
-
});
|
|
911
|
-
// Check .agents/skills/
|
|
912
|
-
const skillsDirExists = await pathExists(join(workspaceRoot, ".agents", "skills"));
|
|
913
|
-
checks.push({
|
|
914
|
-
name: ".agents/skills/",
|
|
915
|
-
status: skillsDirExists ? "pass" : "fail",
|
|
916
|
-
message: skillsDirExists
|
|
917
|
-
? ".agents/skills/ directory found"
|
|
918
|
-
: ".agents/skills/ directory not found — run 'forge create' to deploy skills",
|
|
919
|
-
});
|
|
920
|
-
// Check docs/rfcs/
|
|
921
|
-
const rfcsDirExists = await pathExists(join(workspaceRoot, "docs", "rfcs"));
|
|
922
|
-
checks.push({
|
|
923
|
-
name: "docs/rfcs/",
|
|
924
|
-
status: rfcsDirExists ? "pass" : "warn",
|
|
925
|
-
message: rfcsDirExists
|
|
926
|
-
? "docs/rfcs/ directory found"
|
|
927
|
-
: "docs/rfcs/ directory not found — run 'forge create' to create RFC directory",
|
|
928
|
-
});
|
|
929
|
-
// Check docs/adrs/
|
|
930
|
-
const adrsDirExists = await pathExists(join(workspaceRoot, "docs", "adrs"));
|
|
931
|
-
checks.push({
|
|
932
|
-
name: "docs/adrs/",
|
|
933
|
-
status: adrsDirExists ? "pass" : "warn",
|
|
934
|
-
message: adrsDirExists
|
|
935
|
-
? "docs/adrs/ directory found"
|
|
936
|
-
: "docs/adrs/ directory not found — run 'forge create' to create ADR directory",
|
|
937
|
-
});
|
|
938
|
-
// Check @warpgogol/* forbidden imports (autonomy guard)
|
|
939
|
-
let forgeRoot;
|
|
940
|
-
try {
|
|
941
|
-
forgeRoot = resolveForgeRoot(workspaceRoot);
|
|
942
|
-
}
|
|
943
|
-
catch {
|
|
944
|
-
forgeRoot = join(workspaceRoot, "packages", "forge");
|
|
945
|
-
}
|
|
946
|
-
// RFC-0640: Resolve domain report for domain-aware checks
|
|
947
|
-
const domainReport = resolveDomainReport(workspaceRoot, forgeRoot);
|
|
948
|
-
// RFC-0640: Domain info check
|
|
949
|
-
checks.push(checkDomainInfo(domainReport));
|
|
950
|
-
// RFC-0675: Enforce invariants using the invariant engine
|
|
951
|
-
if (domainReport.invariants.length > 0) {
|
|
952
|
-
const profiles = listStackProfiles(forgeRoot);
|
|
953
|
-
const profile = domainReport.profileId
|
|
954
|
-
? profiles.find((p) => p.id === domainReport.profileId)
|
|
955
|
-
: undefined;
|
|
956
|
-
const invariantResults = profile
|
|
957
|
-
? checkInvariants(profile, workspaceRoot)
|
|
958
|
-
: [];
|
|
959
|
-
const allViolations = invariantResults.flatMap((r) => r.violations);
|
|
960
|
-
const errorViolations = allViolations.filter((v) => v.severity === "error");
|
|
961
|
-
const warningViolations = allViolations.filter((v) => v.severity === "warning");
|
|
962
|
-
const checkedCount = invariantResults.filter((r) => r.checked).length;
|
|
963
|
-
const advisoryCount = invariantResults.filter((r) => !r.checked).length;
|
|
964
|
-
const status = errorViolations.length > 0 ? "fail" :
|
|
965
|
-
warningViolations.length > 0 ? "warn" :
|
|
966
|
-
"pass";
|
|
967
|
-
const parts = [];
|
|
968
|
-
if (allViolations.length > 0) {
|
|
969
|
-
parts.push(`${allViolations.length} violation(s)`);
|
|
970
|
-
for (const v of allViolations.slice(0, 3)) {
|
|
971
|
-
parts.push(`${v.invariantId}: ${v.file} — ${v.message}`);
|
|
972
|
-
}
|
|
973
|
-
if (allViolations.length > 3)
|
|
974
|
-
parts.push(`(+${allViolations.length - 3} more)`);
|
|
975
|
-
}
|
|
976
|
-
else {
|
|
977
|
-
parts.push(`${checkedCount} checked, ${advisoryCount} advisory`);
|
|
978
|
-
}
|
|
979
|
-
checks.push({
|
|
980
|
-
name: "domain-invariants",
|
|
981
|
-
status,
|
|
982
|
-
message: parts.join("; "),
|
|
983
|
-
invariantViolations: allViolations.length > 0 ? allViolations : undefined,
|
|
984
|
-
});
|
|
985
|
-
}
|
|
986
|
-
// Prerequisite checks (profile-declared system dependencies)
|
|
987
|
-
if (domainReport.profileId) {
|
|
988
|
-
const profiles = listStackProfiles(forgeRoot);
|
|
989
|
-
const profile = profiles.find((p) => p.id === domainReport.profileId);
|
|
990
|
-
if (profile?.prerequisites && profile.prerequisites.length > 0) {
|
|
991
|
-
checks.push(checkPrerequisites(profile.prerequisites));
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
// RFC-0640: Run forge.profile.validate as advisory check (warn on failure, not fail)
|
|
995
|
-
const profileValidateResult = await runProfileValidate({ argv: [], flags: {} }, { ...context, forgeRoot });
|
|
996
|
-
const invalidProfiles = profileValidateResult.data?.profiles.filter((p) => !p.valid) ?? [];
|
|
997
|
-
checks.push({
|
|
998
|
-
name: "profile-validate",
|
|
999
|
-
status: invalidProfiles.length === 0 ? "pass" : "warn",
|
|
1000
|
-
message: invalidProfiles.length === 0
|
|
1001
|
-
? `${profileValidateResult.data?.profiles.length ?? 0} profile(s) valid`
|
|
1002
|
-
: `${invalidProfiles.length} profile(s) invalid (advisory): ${invalidProfiles.map((p) => p.id).join(", ")}`,
|
|
1003
|
-
});
|
|
1004
|
-
const forbiddenImports = await scanForForbiddenImports(forgeRoot, workspaceRoot);
|
|
1005
|
-
checks.push({
|
|
1006
|
-
name: "autonomy-guard",
|
|
1007
|
-
status: forbiddenImports.length === 0 ? "pass" : "fail",
|
|
1008
|
-
message: forbiddenImports.length === 0
|
|
1009
|
-
? "No @warpgogol/* imports in forge source"
|
|
1010
|
-
: `${forbiddenImports.length} @warpgogol/* import(s) found in forge source — remove them`,
|
|
1011
|
-
});
|
|
1012
|
-
// Check bindings contract (RFC-0393)
|
|
1013
|
-
const bindingsResult = await validateBindings(workspaceRoot);
|
|
1014
|
-
checks.push({
|
|
1015
|
-
name: "bindings",
|
|
1016
|
-
status: bindingsResult.invalid.length === 0 ? "pass" : "fail",
|
|
1017
|
-
message: bindingsResult.invalid.length === 0
|
|
1018
|
-
? `Bindings: ${bindingsResult.resolved.length} resolved, ${bindingsResult.absent.length} absent`
|
|
1019
|
-
: `Bindings: ${bindingsResult.invalid.length} invalid — ${bindingsResult.invalid.join(", ")}`,
|
|
1020
|
-
});
|
|
1021
|
-
// Check stale knowledge files (RFC-0524, RFC-0539)
|
|
1022
|
-
const staleCheck = await checkStaleKnowledgeFiles(workspaceRoot, forgeRoot);
|
|
1023
|
-
checks.push(staleCheck);
|
|
1024
|
-
// RFC-0660: Check legacy sections in knowledge files
|
|
1025
|
-
const legacyCheck = checkLegacyKnowledgeSections(workspaceRoot, forgeRoot);
|
|
1026
|
-
checks.push(legacyCheck);
|
|
1027
|
-
// RFC-0661: Check knowledge layer token budgets
|
|
1028
|
-
const budgetCheck = checkKnowledgeBudgets(workspaceRoot, forgeRoot);
|
|
1029
|
-
checks.push(budgetCheck);
|
|
1030
|
-
// RFC-0663: Check cross-skill duplicate principles
|
|
1031
|
-
const duplicatesCheck = checkKnowledgeDuplicates(workspaceRoot, forgeRoot);
|
|
1032
|
-
checks.push(duplicatesCheck);
|
|
1033
|
-
// RFC-0663: Validate shared knowledge layer file
|
|
1034
|
-
const sharedKnowledgeCheck = checkSharedKnowledgeFile(workspaceRoot, forgeRoot);
|
|
1035
|
-
checks.push(sharedKnowledgeCheck);
|
|
1036
|
-
// RFC-0664: Check memory layer health (budget, gitignore coverage, leak risk)
|
|
1037
|
-
checks.push(checkMemoryLayer(workspaceRoot));
|
|
1038
|
-
// RFC-0539: Check pack skills — stale/missing copies and config validation
|
|
1039
|
-
const packCheck = await checkPackSkills(workspaceRoot);
|
|
1040
|
-
checks.push(packCheck);
|
|
1041
|
-
// RFC-0704: Check independent version packages — paths must exist and contain package.json
|
|
1042
|
-
const independentCheck = await checkIndependentVersionPackages(workspaceRoot);
|
|
1043
|
-
checks.push(independentCheck);
|
|
1044
|
-
// RFC-0611: Check nested AGENTS.md — missing, stale, hand-written
|
|
1045
|
-
// RFC-0640: Use profile-driven workspace types when available (all domains)
|
|
1046
|
-
// RFC-0640 fix: previously gated by isSoftwareDomain, which skipped the check
|
|
1047
|
-
// entirely for non-software domains. Now runs for all domains — profile-driven
|
|
1048
|
-
// wsTypes replace hardcoded detection when present.
|
|
1049
|
-
{
|
|
1050
|
-
let wsTypes;
|
|
1051
|
-
try {
|
|
1052
|
-
const config = loadForgeConfig(workspaceRoot);
|
|
1053
|
-
// RFC-0643: prefer config.profile (loaded by loadForgeConfig)
|
|
1054
|
-
if (config.profile?.workspaceTypes && config.profile.workspaceTypes.length > 0) {
|
|
1055
|
-
wsTypes = config.profile.workspaceTypes;
|
|
1056
|
-
}
|
|
1057
|
-
else {
|
|
1058
|
-
const profiles = listStackProfiles(forgeRoot);
|
|
1059
|
-
for (const stackId of config.project.stack) {
|
|
1060
|
-
const profile = profiles.find((p) => p.id === stackId);
|
|
1061
|
-
if (profile?.workspaceTypes && profile.workspaceTypes.length > 0) {
|
|
1062
|
-
wsTypes = profile.workspaceTypes;
|
|
1063
|
-
break;
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
catch {
|
|
1069
|
-
// profiles not loadable
|
|
1070
|
-
}
|
|
1071
|
-
const nestedCheck = await checkNestedAgentsMd(workspaceRoot, wsTypes);
|
|
1072
|
-
checks.push(nestedCheck);
|
|
1073
|
-
}
|
|
1074
|
-
// RFC-0640: --strict flag elevates warn to fail for domain-related checks
|
|
1075
|
-
const finalChecks = strict
|
|
1076
|
-
? checks.map((c) => c.status === "warn" &&
|
|
1077
|
-
(c.name === "domain-invariants" || c.name === "profile-validate")
|
|
1078
|
-
? { ...c, status: "fail" }
|
|
1079
|
-
: c)
|
|
1080
|
-
: checks;
|
|
1081
|
-
const allPass = finalChecks.every((c) => c.status === "pass");
|
|
1082
|
-
const hasFails = finalChecks.some((c) => c.status === "fail");
|
|
1083
|
-
if (outputFormat === "pretty") {
|
|
1084
|
-
logger.section(`Forge Doctor — ${workspaceRoot}`);
|
|
1085
|
-
for (const check of finalChecks) {
|
|
1086
|
-
const icon = check.status === "pass" ? "✓" : check.status === "warn" ? "⚠" : "✖";
|
|
1087
|
-
const fn = check.status === "pass" ? logger.success : check.status === "warn" ? logger.warn : logger.error;
|
|
1088
|
-
fn(`${icon} ${check.name}: ${check.message}`);
|
|
1089
|
-
}
|
|
1090
|
-
if (allPass) {
|
|
1091
|
-
logger.success("All checks passed — forge is properly configured.");
|
|
1092
|
-
}
|
|
1093
|
-
else if (hasFails) {
|
|
1094
|
-
logger.error("Some checks failed — run 'forge create' to fix.");
|
|
1095
|
-
}
|
|
1096
|
-
else {
|
|
1097
|
-
logger.warn("Some checks warn — review above.");
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
return {
|
|
1101
|
-
data: { command: "forge.doctor", checks: finalChecks, allPass, forbiddenImports, bindings: bindingsResult, domain: domainReport },
|
|
1102
|
-
exitCode: hasFails ? 1 : 0,
|
|
1103
|
-
summary: allPass
|
|
1104
|
-
? "forge.doctor: all checks passed"
|
|
1105
|
-
: `forge.doctor: ${finalChecks.filter((c) => c.status === "fail").length} fail(s), ${finalChecks.filter((c) => c.status === "warn").length} warn(s)`,
|
|
1106
|
-
};
|
|
1107
|
-
}
|
|
1108
|
-
//# sourceMappingURL=doctor.js.map
|