@warpgogol/forge 2.8.0 → 2.8.2

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.
Files changed (271) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.md +23 -13
  3. package/README.uk.md +19 -12
  4. package/dist/os/session/handlers/validate.d.ts.map +1 -1
  5. package/dist/os/session/handlers/validate.js +23 -1
  6. package/dist/os/session/handlers/validate.js.map +1 -1
  7. package/dist/os/session/types.d.ts +31 -1
  8. package/dist/os/session/types.d.ts.map +1 -1
  9. package/dist/os/session/types.js +7 -0
  10. package/dist/os/session/types.js.map +1 -1
  11. package/os/adr/adr.module.ts +158 -0
  12. package/os/adr/frontmatter-io.ts +80 -0
  13. package/os/adr/handlers/archive.ts +244 -0
  14. package/os/adr/handlers/implement-stamp.ts +331 -0
  15. package/os/adr/handlers/list-create.ts +207 -0
  16. package/os/adr/handlers/validate.test.ts +232 -0
  17. package/os/adr/handlers/validate.ts +429 -0
  18. package/os/adr/index.ts +33 -0
  19. package/os/adr/types.ts +141 -0
  20. package/os/audit/audit.module.ts +48 -0
  21. package/os/audit/frontmatter-io.ts +84 -0
  22. package/os/audit/handlers/archive.ts +239 -0
  23. package/os/audit/index.ts +23 -0
  24. package/os/audit/types.ts +29 -0
  25. package/os/compass/compass.module.ts +186 -0
  26. package/os/compass/handlers/compass-audit-handler.ts +382 -0
  27. package/os/compass/handlers/compass-change-summary-handler.ts +272 -0
  28. package/os/compass/handlers/compass-inventory-handler.ts +294 -0
  29. package/os/compass/handlers/compass-inventory.ts +521 -0
  30. package/os/compass/handlers/git-revision.ts +137 -0
  31. package/os/compass/handlers/resolve-scan-root-workpiece.test.ts +65 -0
  32. package/os/compass/handlers/resolve-scan-root.ts +79 -0
  33. package/os/compass/index.ts +33 -0
  34. package/os/core/core.module.ts +948 -0
  35. package/os/core/handlers/assets-check.ts +122 -0
  36. package/os/core/handlers/assets-helpers.ts +174 -0
  37. package/os/core/handlers/assets-list.ts +99 -0
  38. package/os/core/handlers/build.ts +155 -0
  39. package/os/core/handlers/determinism-check.ts +354 -0
  40. package/os/core/handlers/dev.ts +127 -0
  41. package/os/core/handlers/invariant-engine.test.ts +681 -0
  42. package/os/core/handlers/knowledge-compact.ts +248 -0
  43. package/os/core/handlers/lifecycle-handlers.test.ts +524 -0
  44. package/os/core/handlers/note-frontmatter-validate.test.ts +93 -0
  45. package/os/core/handlers/note-link-validate.test.ts +117 -0
  46. package/os/core/handlers/note-orphan-detect.test.ts +94 -0
  47. package/os/core/handlers/package-health.test.ts +226 -0
  48. package/os/core/handlers/package-health.ts +231 -0
  49. package/os/core/handlers/pinned-check.ts +200 -0
  50. package/os/core/handlers/pinned-init.ts +333 -0
  51. package/os/core/handlers/pinned-types.ts +50 -0
  52. package/os/core/handlers/pinned-validate.ts +301 -0
  53. package/os/core/handlers/profile-resolve.ts +92 -0
  54. package/os/core/handlers/release-prepare.ts +294 -0
  55. package/os/core/handlers/release-publish.ts +211 -0
  56. package/os/core/handlers/validate.ts +262 -0
  57. package/os/core/handlers/workspace-deps.ts +55 -0
  58. package/os/core/index.ts +13 -0
  59. package/os/exploration/exploration.module.ts +90 -0
  60. package/os/exploration/frontmatter-io.ts +77 -0
  61. package/os/exploration/handlers/archive.ts +159 -0
  62. package/os/exploration/handlers/list.ts +77 -0
  63. package/os/exploration/handlers/show.ts +107 -0
  64. package/os/exploration/index.ts +25 -0
  65. package/os/exploration/types.ts +65 -0
  66. package/os/mission/handlers/archive.test.ts +391 -0
  67. package/os/mission/handlers/archive.ts +453 -0
  68. package/os/mission/index.ts +1 -0
  69. package/os/mission/mission.module.ts +48 -0
  70. package/os/mission/types.ts +41 -0
  71. package/os/naming/index.ts +14 -0
  72. package/os/naming/naming-convention.test.ts +163 -0
  73. package/os/naming/naming-convention.ts +378 -0
  74. package/os/naming/naming.module.ts +36 -0
  75. package/os/notes/index.ts +10 -0
  76. package/os/notes/notes.module.ts +109 -0
  77. package/os/plan/frontmatter-io.ts +82 -0
  78. package/os/plan/handlers/archive.ts +238 -0
  79. package/os/plan/index.ts +23 -0
  80. package/os/plan/plan.module.ts +48 -0
  81. package/os/plan/types.ts +29 -0
  82. package/os/program/discovery.ts +294 -0
  83. package/os/program/handlers/complete.ts +419 -0
  84. package/os/program/handlers/lease.ts +433 -0
  85. package/os/program/handlers/seal.ts +332 -0
  86. package/os/program/handlers/validate.ts +213 -0
  87. package/os/program/lease.ts +156 -0
  88. package/os/program/program.module.ts +212 -0
  89. package/os/program/schemas.ts +218 -0
  90. package/os/program/state.ts +264 -0
  91. package/os/rfc/acceptance.ts +344 -0
  92. package/os/rfc/decision-log.ts +310 -0
  93. package/os/rfc/dna-trace.ts +280 -0
  94. package/os/rfc/frontmatter-io.test.ts +132 -0
  95. package/os/rfc/frontmatter-io.ts +130 -0
  96. package/os/rfc/handlers/archive.ts +300 -0
  97. package/os/rfc/handlers/check.ts +238 -0
  98. package/os/rfc/handlers/implement-stamp.ts +515 -0
  99. package/os/rfc/handlers/index-graph.ts +237 -0
  100. package/os/rfc/handlers/lifecycle.test.ts +127 -0
  101. package/os/rfc/handlers/lifecycle.ts +249 -0
  102. package/os/rfc/handlers/list-create.ts +296 -0
  103. package/os/rfc/handlers/pipeline-status.ts +173 -0
  104. package/os/rfc/handlers/shared.ts +121 -0
  105. package/os/rfc/handlers/supersede-propose.ts +241 -0
  106. package/os/rfc/handlers/validate-rules.test.ts +891 -0
  107. package/os/rfc/handlers/validate-rules.ts +984 -0
  108. package/os/rfc/handlers/validate.ts +166 -0
  109. package/os/rfc/handlers.ts +19 -0
  110. package/os/rfc/index.ts +97 -0
  111. package/os/rfc/rfc.module.ts +416 -0
  112. package/os/rfc/types.ts +596 -0
  113. package/os/rfc/verification-evidence.ts +244 -0
  114. package/os/session/atif-parser.ts +166 -0
  115. package/os/session/frontmatter-io.ts +163 -0
  116. package/os/session/handlers/archive.ts +288 -0
  117. package/os/session/handlers/list.ts +174 -0
  118. package/os/session/handlers/save.ts +348 -0
  119. package/os/session/handlers/validate.ts +250 -0
  120. package/os/session/index.ts +50 -0
  121. package/os/session/session.module.ts +126 -0
  122. package/os/session/types.ts +203 -0
  123. package/os/spec/live-spec-list-show-validate.test.ts +257 -0
  124. package/os/spec/live-spec-list.ts +78 -0
  125. package/os/spec/live-spec-merge.test.ts +261 -0
  126. package/os/spec/live-spec-merge.ts +413 -0
  127. package/os/spec/live-spec-show.ts +117 -0
  128. package/os/spec/live-spec-types.ts +93 -0
  129. package/os/spec/live-spec-validate.ts +170 -0
  130. package/os/spec/spec-materialize.ts +390 -0
  131. package/os/spec/spec-schema.ts +174 -0
  132. package/os/spec/spec-status.ts +284 -0
  133. package/os/spec/spec-validate.ts +513 -0
  134. package/os/spec/spec.module.ts +135 -0
  135. package/os/werkstatt/handlers/lock.ts +168 -0
  136. package/os/werkstatt/handlers/schema.ts +47 -0
  137. package/os/werkstatt/handlers/werkstatt-lock-recover.ts +175 -0
  138. package/os/werkstatt/handlers/werkstatt-lock-status.ts +73 -0
  139. package/os/werkstatt/handlers/werkstatt-operation-validate.ts +104 -0
  140. package/os/werkstatt/index.ts +39 -0
  141. package/os/werkstatt/werkstatt.module.ts +62 -0
  142. package/os/workflow/handlers.ts +304 -0
  143. package/os/workflow/index.ts +28 -0
  144. package/os/workflow/types.ts +99 -0
  145. package/os/workflow/workflow.module.ts +54 -0
  146. package/package.json +3 -3
  147. package/profiles/godot-csharp.yaml +4 -4
  148. package/profiles/knowledge-typescript-turborepo.yaml +110 -0
  149. package/profiles/phaser-turborepo.yaml +5 -5
  150. package/skills/_shared/fo-session-summary.md +132 -16
  151. package/skills/fo/fo-add-tests/pbt-guide.md +13 -13
  152. package/skills/fo/fo-doc-audit/SKILL.md +6 -6
  153. package/skills/fo/fo-handoff/SKILL.md +5 -0
  154. package/skills/fo/fo-idea/SKILL.md +1 -1
  155. package/skills/fo/fo-review/SKILL.md +1 -1
  156. package/skills/fo/fo-session-retro/SKILL.md +8 -0
  157. package/skills/fo/fo-session-save/SKILL.md +8 -0
  158. package/src/cli-output.ts +59 -0
  159. package/src/config/__tests__/resolve-terminology.test.ts +45 -0
  160. package/src/config/forge-config.ts +524 -0
  161. package/src/forge-module.ts +39 -0
  162. package/src/index.ts +172 -0
  163. package/src/knowledge/__tests__/promote.test.ts +219 -0
  164. package/src/knowledge/__tests__/serialize.test.ts +192 -0
  165. package/src/knowledge/budgets.ts +202 -0
  166. package/src/knowledge/compact.ts +405 -0
  167. package/src/knowledge/index.ts +53 -0
  168. package/src/knowledge/parse.ts +227 -0
  169. package/src/knowledge/promote.ts +156 -0
  170. package/src/knowledge/schema.ts +112 -0
  171. package/src/knowledge/serialize.ts +72 -0
  172. package/src/migration-adapters/__tests__/ignored-files.test.ts +51 -0
  173. package/src/migration-adapters/__tests__/registry.test.ts +131 -0
  174. package/src/migration-adapters/__tests__/types.test.ts +86 -0
  175. package/src/migration-adapters/git-utils.ts +71 -0
  176. package/src/migration-adapters/ignored-files.ts +221 -0
  177. package/src/migration-adapters/index.ts +21 -0
  178. package/src/migration-adapters/node-typescript-pnpm/index.ts +189 -0
  179. package/src/migration-adapters/phaser-pnpm/index.ts +189 -0
  180. package/src/migration-adapters/registry.ts +61 -0
  181. package/src/migration-adapters/types.ts +68 -0
  182. package/src/onboarding/__tests__/workspace-discovery.test.ts +134 -0
  183. package/src/onboarding/agents-generate.ts +443 -0
  184. package/src/onboarding/create.ts +427 -0
  185. package/src/onboarding/doctor.ts +1297 -0
  186. package/src/onboarding/init.ts +337 -0
  187. package/src/onboarding/invariant-engine.ts +448 -0
  188. package/src/onboarding/memory-scaffold.ts +189 -0
  189. package/src/onboarding/nested-agents-generate.ts +93 -0
  190. package/src/onboarding/nested-agents-templates.ts +233 -0
  191. package/src/onboarding/profile-validate.ts +139 -0
  192. package/src/onboarding/scaffold-project.ts +299 -0
  193. package/src/onboarding/scaffold.ts +143 -0
  194. package/src/onboarding/upgrade.ts +558 -0
  195. package/src/onboarding/workspace-discovery.ts +167 -0
  196. package/src/profiles/__tests__/profile-schema.test.ts +228 -0
  197. package/src/profiles/__tests__/stack-profile.test.ts +190 -0
  198. package/src/profiles/__tests__/terminology-utils.test.ts +71 -0
  199. package/src/profiles/profile-schema.ts +350 -0
  200. package/src/profiles/stack-profile.ts +188 -0
  201. package/src/profiles/terminology-utils.ts +36 -0
  202. package/src/registry.ts +185 -0
  203. package/src/skill-schema.ts +37 -0
  204. package/src/tests/acceptance-criteria.test.ts +99 -0
  205. package/src/tests/adr-implement-stamp.test.ts +368 -0
  206. package/src/tests/agents-generate-domain.test.ts +317 -0
  207. package/src/tests/agents-generate.test.ts +458 -0
  208. package/src/tests/bindings-schema.test.ts +314 -0
  209. package/src/tests/budgets.test.ts +213 -0
  210. package/src/tests/cli-output.test.ts +196 -0
  211. package/src/tests/compact.test.ts +796 -0
  212. package/src/tests/create.test.ts +289 -0
  213. package/src/tests/doctor-autonomy.test.ts +98 -0
  214. package/src/tests/doctor-bindings.test.ts +286 -0
  215. package/src/tests/doctor-domain.test.ts +113 -0
  216. package/src/tests/exploration-handlers.test.ts +256 -0
  217. package/src/tests/fixtures/agents-generate-business-before.txt +288 -0
  218. package/src/tests/forge-config.test.ts +420 -0
  219. package/src/tests/fs-atomic.test.ts +96 -0
  220. package/src/tests/fs.test.ts +103 -0
  221. package/src/tests/generated-marker.test.ts +161 -0
  222. package/src/tests/hash.test.ts +37 -0
  223. package/src/tests/implement-stamp.test.ts +505 -0
  224. package/src/tests/init-bindings.test.ts +183 -0
  225. package/src/tests/knowledge-parse.test.ts +307 -0
  226. package/src/tests/knowledge-pbt.test.ts +164 -0
  227. package/src/tests/memory-scaffold.test.ts +192 -0
  228. package/src/tests/migration-adapters.test.ts +480 -0
  229. package/src/tests/package-files.test.ts +54 -0
  230. package/src/tests/pinned-check.test.ts +194 -0
  231. package/src/tests/pinned-init.test.ts +126 -0
  232. package/src/tests/profile-schema.test.ts +194 -0
  233. package/src/tests/profile-validate.test.ts +120 -0
  234. package/src/tests/program-lease.test.ts +245 -0
  235. package/src/tests/program-paths-extended.test.ts +117 -0
  236. package/src/tests/program-paths.test.ts +98 -0
  237. package/src/tests/program-property.test.ts +139 -0
  238. package/src/tests/program-schemas.test.ts +445 -0
  239. package/src/tests/program-spec-node.test.ts +250 -0
  240. package/src/tests/promote.test.ts +481 -0
  241. package/src/tests/registry.test.ts +73 -0
  242. package/src/tests/scaffold-project.test.ts +150 -0
  243. package/src/tests/session-handlers.test.ts +503 -0
  244. package/src/tests/session-pbt.test.ts +190 -0
  245. package/src/tests/skill-schema.test.ts +146 -0
  246. package/src/tests/skill-validate-knowledge.test.ts +26 -0
  247. package/src/tests/skill-validate.test.ts +254 -0
  248. package/src/tests/stack-profile.test.ts +221 -0
  249. package/src/tests/string-utils.test.ts +42 -0
  250. package/src/tests/upgrade.test.ts +428 -0
  251. package/src/tests/werkstatt-lock.test.ts +343 -0
  252. package/src/tests/workspace-discovery-domain.test.ts +112 -0
  253. package/src/tests/workspace-discovery.test.ts +135 -0
  254. package/src/types.ts +221 -0
  255. package/src/utils/__tests__/fs-idempotent.test.ts +73 -0
  256. package/src/utils/__tests__/fs-trash.test.ts +45 -0
  257. package/src/utils/fs-atomic.ts +93 -0
  258. package/src/utils/fs-idempotent.ts +41 -0
  259. package/src/utils/fs-trash-sync.ts +37 -0
  260. package/src/utils/fs-trash.ts +24 -0
  261. package/src/utils/fs.ts +74 -0
  262. package/src/utils/generated-marker.ts +166 -0
  263. package/src/utils/hash.ts +19 -0
  264. package/src/utils/index.ts +29 -0
  265. package/src/utils/string-utils.ts +19 -0
  266. package/src/validators/__tests__/note-orphan-detect.test.ts +94 -0
  267. package/src/validators/note-frontmatter-validate.ts +142 -0
  268. package/src/validators/note-link-validate.ts +145 -0
  269. package/src/validators/note-orphan-detect.ts +146 -0
  270. package/src/validators/port-validate.ts +97 -0
  271. package/src/validators/skill-validate.ts +831 -0
@@ -0,0 +1,304 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Workflow lint/list/amend handlers for forge — validates .agents/workflows frontmatter, command references, and per-chain phase links.</purpose>
4
+ <non-goals>
5
+ <item>Do not execute workflow steps.</item>
6
+ <item>Do not edit workflow files to repair violations.</item>
7
+ </non-goals>
8
+ </MODULE_CONTRACT>
9
+ <CHANGE_SUMMARY>
10
+ <item>RFC-0075: Add agent workflow lint/list handlers.</item>
11
+ <item>RFC-0374: Migrated from packages/os/site-kernel/src/workflow/ to packages/forge/os/workflow/.</item>
12
+ </CHANGE_SUMMARY>
13
+ */
14
+
15
+ import fs from "node:fs/promises";
16
+ import path from "node:path";
17
+ import YAML from "yaml";
18
+ import type {
19
+ ForgeCommandInput,
20
+ ForgeCommandResult,
21
+ ForgeRuntimeContext,
22
+ } from "../../src/types.ts";
23
+ import {
24
+ WORKFLOW_PHASES,
25
+ WORKFLOW_CHAINS,
26
+ type WorkflowChain,
27
+ type WorkflowFrontmatter,
28
+ type WorkflowLintResult,
29
+ type WorkflowLintViolation,
30
+ type WorkflowListEntry,
31
+ } from "./types.ts";
32
+
33
+ const WORKFLOW_DIR = ".agents/workflows";
34
+ const WORKFLOW_AMEND_DIR = ".agents/workflows-amend";
35
+
36
+ // RFC-0135/RFC-0136 commands (registered in site-kernel-onboarding / site-kernel-checks).
37
+ const _PENDING_AMEND_RFC_COMMANDS = new Set([
38
+ "amend.input.validate",
39
+ "amend.atoms.merge",
40
+ "amend.provenance.append",
41
+ "amend.provenance.validate",
42
+ "amend.phase.validate",
43
+ "content.coverage.delta",
44
+ "audit.delta.run",
45
+ "amend-check.author",
46
+ "amend-check.postbuild",
47
+ "amend-check.run",
48
+ "workflow-amend.list",
49
+ ]);
50
+ const PENDING_ACCEPTED_RFC_COMMANDS = new Set([
51
+ "brief.validate",
52
+ "biome.tokens.derive",
53
+ "family.contract.validate",
54
+ "family.list",
55
+ "archetype.registry.validate",
56
+ "cosmic.name.pick",
57
+ "section.scaffold",
58
+ "section.contract.validate",
59
+ "section.similarity.report",
60
+ "system-md.compile",
61
+ "constellation.contract.validate",
62
+ "content.coverage.validate",
63
+ "content.voice.lint",
64
+ "pbp.content.validate",
65
+ "content.references.validate",
66
+ "audit.agent.readiness.validate",
67
+ "seo.technical.validate",
68
+ "seo.structured-data.validate",
69
+ "seo.internal-linking.validate",
70
+ "analytics.config.validate",
71
+ "first-party-data.validate",
72
+ "infra.brief.validate",
73
+ "audit.llm.run",
74
+ "app.qa.validate",
75
+ "kernel.wire",
76
+ "onboarding.scaffold",
77
+ "onboarding.input.validate",
78
+ "onboarding.phase.validate",
79
+ "biome.contract.validate",
80
+ "biome.css.generate",
81
+ ]);
82
+
83
+ async function pathExists(target: string): Promise<boolean> {
84
+ try {
85
+ await fs.access(target);
86
+ return true;
87
+ } catch {
88
+ return false;
89
+ }
90
+ }
91
+
92
+ async function readWorkflowFiles(workspaceRoot: string, dir: string) {
93
+ const directory = path.join(workspaceRoot, dir);
94
+ const entries = await fs.readdir(directory, { withFileTypes: true }).catch(() => []);
95
+ return entries
96
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".md") && entry.name !== "README.md")
97
+ .map((entry) => path.join(directory, entry.name))
98
+ .sort();
99
+ }
100
+
101
+ function parseMarkdownFrontmatter(source: string): unknown {
102
+ if (!source.startsWith("---\n")) return undefined;
103
+ const end = source.indexOf("\n---", 4);
104
+ if (end === -1) return undefined;
105
+ return YAML.parse(source.slice(4, end));
106
+ }
107
+
108
+ function isStringArray(value: unknown): value is string[] {
109
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
110
+ }
111
+
112
+ function isPlannedWorkflowArtifact(root: string, writes: string[]): boolean {
113
+ return root.startsWith("onboarding/.output/") || writes.includes(root);
114
+ }
115
+
116
+ function validateFrontmatter(file: string, value: unknown): WorkflowFrontmatter {
117
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
118
+ throw new Error(`${file}: missing or invalid workflow frontmatter`);
119
+ }
120
+ const candidate = value as WorkflowFrontmatter;
121
+ const valid =
122
+ typeof candidate.id === "string" &&
123
+ typeof candidate.title === "string" &&
124
+ WORKFLOW_PHASES.includes(candidate.phase) &&
125
+ (candidate.chain === undefined || WORKFLOW_CHAINS.includes(candidate.chain)) &&
126
+ isStringArray(candidate.reads) &&
127
+ isStringArray(candidate.writes) &&
128
+ Boolean(candidate.scope) &&
129
+ isStringArray(candidate.scope.allowedWriteRoots) &&
130
+ isStringArray(candidate.scope.forbiddenWriteRoots) &&
131
+ isStringArray(candidate.runs) &&
132
+ Array.isArray(candidate.recoveryRules) &&
133
+ candidate.recoveryRules.every(
134
+ (rule) => typeof rule?.on === "string" && typeof rule?.do === "string",
135
+ ) &&
136
+ isStringArray(candidate.agentInvariants) &&
137
+ Boolean(candidate.selfOrchestration) &&
138
+ typeof candidate.selfOrchestration.autoRun === "boolean" &&
139
+ isStringArray(candidate.selfOrchestration.pauseFor) &&
140
+ isStringArray(candidate.checkpoints) &&
141
+ (candidate.nextWorkflow === undefined || typeof candidate.nextWorkflow === "string") &&
142
+ (candidate.branch === undefined ||
143
+ (typeof candidate.branch.on === "string" && isStringArray(candidate.branch.cases)));
144
+
145
+ if (!valid) throw new Error(`${file}: invalid workflow frontmatter shape`);
146
+ return candidate;
147
+ }
148
+
149
+ /** Load one chain's workflow files. The chain a file belongs to is fixed by its directory. */
150
+ async function loadWorkflows(workspaceRoot: string, chain: WorkflowChain = "greenfield") {
151
+ const dir = chain === "amend" ? WORKFLOW_AMEND_DIR : WORKFLOW_DIR;
152
+ const files = await readWorkflowFiles(workspaceRoot, dir);
153
+ const workflows: Array<{
154
+ relativeFile: string;
155
+ chain: WorkflowChain;
156
+ data: WorkflowFrontmatter;
157
+ }> = [];
158
+ const violations: WorkflowLintViolation[] = [];
159
+
160
+ for (const file of files) {
161
+ const relativeFile = path.relative(workspaceRoot, file).replace(/\\/g, "/");
162
+ try {
163
+ const source = await fs.readFile(file, "utf8");
164
+ workflows.push({
165
+ relativeFile,
166
+ chain,
167
+ data: validateFrontmatter(relativeFile, parseMarkdownFrontmatter(source)),
168
+ });
169
+ } catch (error) {
170
+ violations.push({
171
+ file: relativeFile,
172
+ code: "WF002",
173
+ message: error instanceof Error ? error.message : String(error),
174
+ });
175
+ }
176
+ }
177
+
178
+ return { workflows, violations };
179
+ }
180
+
181
+ function toListEntries(
182
+ workflows: Array<{ relativeFile: string; data: WorkflowFrontmatter }>,
183
+ ): WorkflowListEntry[] {
184
+ return workflows.map(({ relativeFile, data }) => ({
185
+ id: data.id,
186
+ title: data.title,
187
+ phase: data.phase,
188
+ file: relativeFile,
189
+ reads: data.reads,
190
+ writes: data.writes,
191
+ runs: data.runs,
192
+ nextWorkflow: data.nextWorkflow,
193
+ }));
194
+ }
195
+
196
+ export async function runWorkflowList(
197
+ _input: ForgeCommandInput,
198
+ context: ForgeRuntimeContext,
199
+ ): Promise<ForgeCommandResult<{ command: "workflow.list"; workflows: WorkflowListEntry[] }>> {
200
+ const { workflows } = await loadWorkflows(context.workspaceRoot, "greenfield");
201
+ const entries = toListEntries(workflows);
202
+ return {
203
+ data: { command: "workflow.list", workflows: entries },
204
+ exitCode: 0,
205
+ summary: `workflow.list: ${entries.length} workflow file(s) found`,
206
+ };
207
+ }
208
+
209
+ export async function runWorkflowAmendList(
210
+ _input: ForgeCommandInput,
211
+ context: ForgeRuntimeContext,
212
+ ): Promise<ForgeCommandResult<{ command: "workflow-amend.list"; workflows: WorkflowListEntry[] }>> {
213
+ const { workflows } = await loadWorkflows(context.workspaceRoot, "amend");
214
+ const entries = toListEntries(workflows);
215
+ return {
216
+ data: { command: "workflow-amend.list", workflows: entries },
217
+ exitCode: 0,
218
+ summary: `workflow-amend.list: ${entries.length} amend workflow file(s) found`,
219
+ };
220
+ }
221
+
222
+ export async function runWorkflowLint(
223
+ _input: ForgeCommandInput,
224
+ context: ForgeRuntimeContext,
225
+ ): Promise<ForgeCommandResult<WorkflowLintResult>> {
226
+ const workflowDirectory = path.join(context.workspaceRoot, WORKFLOW_DIR);
227
+ const { workflows, violations } = await loadWorkflows(context.workspaceRoot);
228
+ const commandNames = new Set(context.commandRegistry?.listCommandNames() ?? []);
229
+ for (const commandName of [
230
+ "sites-check.run",
231
+ "sites-check.author",
232
+ "sites-check.postbuild",
233
+ "packages-check.run",
234
+ "app.contract.full",
235
+ "workflow.lint",
236
+ "workflow.list",
237
+ ]) {
238
+ commandNames.add(commandName);
239
+ }
240
+ for (const commandName of PENDING_ACCEPTED_RFC_COMMANDS) commandNames.add(commandName);
241
+
242
+ const workflowIds = new Set(workflows.map(({ data }) => data.id));
243
+
244
+ for (const { relativeFile, data } of workflows) {
245
+ for (const runEntry of data.runs) {
246
+ // RFC-0075: runs entries may carry inline flags (e.g. "onboarding.phase.validate --phase=03-compose").
247
+ // The kernel registry stores bare command names; strip flag tokens before lookup.
248
+ const commandName = runEntry.split(/\s+/, 1)[0] ?? runEntry;
249
+ if (!commandNames.has(commandName)) {
250
+ violations.push({
251
+ file: relativeFile,
252
+ code: "WF003",
253
+ message: `Unknown kernel command in runs: ${commandName}`,
254
+ });
255
+ }
256
+ }
257
+
258
+ if (!data.scope.forbiddenWriteRoots.includes("onboarding/.input/")) {
259
+ violations.push({
260
+ file: relativeFile,
261
+ code: "WF004",
262
+ message: "scope.forbiddenWriteRoots must include onboarding/.input/.",
263
+ });
264
+ }
265
+
266
+ if (data.nextWorkflow && !workflowIds.has(data.nextWorkflow)) {
267
+ violations.push({
268
+ file: relativeFile,
269
+ code: "WF005",
270
+ message: `nextWorkflow references missing workflow id: ${data.nextWorkflow}`,
271
+ });
272
+ }
273
+
274
+ for (const root of [...data.reads, ...data.writes, ...data.scope.allowedWriteRoots]) {
275
+ if (
276
+ !root.includes("<") &&
277
+ !root.includes("*") &&
278
+ !root.endsWith("/") &&
279
+ !isPlannedWorkflowArtifact(root, data.writes) &&
280
+ !(await pathExists(path.join(context.workspaceRoot, root)))
281
+ ) {
282
+ violations.push({
283
+ file: relativeFile,
284
+ code: "WF007",
285
+ message: `Path does not exist and is not a pattern: ${root}`,
286
+ });
287
+ }
288
+ }
289
+ }
290
+
291
+ return {
292
+ data: {
293
+ command: "workflow.lint",
294
+ workflowDirectory,
295
+ filesChecked: workflows.length,
296
+ violations,
297
+ },
298
+ exitCode: violations.length > 0 ? 1 : 0,
299
+ summary:
300
+ violations.length > 0
301
+ ? `workflow.lint: ${violations.length} violation(s)`
302
+ : `workflow.lint: ${workflows.length} workflow file(s) valid`,
303
+ };
304
+ }
@@ -0,0 +1,28 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Facilitates the export of workflow-related modules and types for use in the application.</purpose>
4
+
5
+
6
+ <non-goals>
7
+ <item>Do not implement workflow execution logic.</item>
8
+ <item>Do not handle raw content parsing or transformation.</item>
9
+ </non-goals>
10
+ </MODULE_CONTRACT>
11
+
12
+ <CHANGE_SUMMARY>
13
+ <item>Tidied by compass.changesummary.tidy; see git history for prior entries.</item>
14
+ </CHANGE_SUMMARY>
15
+ */
16
+
17
+ export { forgeWorkflowModule } from "./workflow.module.ts";
18
+ export { runWorkflowLint, runWorkflowList, runWorkflowAmendList } from "./handlers.ts";
19
+ export type {
20
+ WorkflowPhase,
21
+ WorkflowChain,
22
+ WorkflowPreconditions,
23
+ WorkflowBranch,
24
+ WorkflowFrontmatter,
25
+ WorkflowListEntry,
26
+ WorkflowLintViolation,
27
+ WorkflowLintResult,
28
+ } from "./types.ts";
@@ -0,0 +1,99 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Defines the RFC-0075 workflow frontmatter contract and command result types.</purpose>
4
+ <non-goals>
5
+ <item>Do not execute workflows or mutate onboarding artifacts.</item>
6
+ </non-goals>
7
+ </MODULE_CONTRACT>
8
+ <CHANGE_SUMMARY>
9
+ <item>RFC-0075: Add workflow command type contracts.</item>
10
+ </CHANGE_SUMMARY>
11
+ */
12
+
13
+ export const WORKFLOW_PHASES = [
14
+ "prepare",
15
+ "synthesize",
16
+ "scaffold",
17
+ "compose",
18
+ "author",
19
+ "audit",
20
+ "handoff",
21
+ ] as const;
22
+
23
+ export type WorkflowPhase = (typeof WORKFLOW_PHASES)[number];
24
+
25
+ /** RFC-0136: which onboarding chain a workflow file belongs to. */
26
+ export const WORKFLOW_CHAINS = ["greenfield", "amend"] as const;
27
+ export type WorkflowChain = (typeof WORKFLOW_CHAINS)[number];
28
+
29
+ /** RFC-0136: declarative, lint-checked preconditions for amend workflows. */
30
+ export interface WorkflowPreconditions {
31
+ appPresent?: boolean;
32
+ systemManifestValid?: boolean;
33
+ }
34
+
35
+ /** RFC-0136: strengthen vs new-route branch, allowed only on the compose phase. */
36
+ export interface WorkflowBranch {
37
+ on: string;
38
+ cases: string[];
39
+ }
40
+
41
+ export interface WorkflowScope {
42
+ allowedWriteRoots: string[];
43
+ forbiddenWriteRoots: string[];
44
+ }
45
+
46
+ export interface WorkflowRecoveryRule {
47
+ on: string;
48
+ do: string;
49
+ }
50
+
51
+ export interface WorkflowSelfOrchestration {
52
+ autoRun: boolean;
53
+ pauseFor: string[];
54
+ }
55
+
56
+ export interface WorkflowFrontmatter {
57
+ id: string;
58
+ title: string;
59
+ phase: WorkflowPhase;
60
+ /** RFC-0136: defaults to "greenfield" when absent. */
61
+ chain?: WorkflowChain;
62
+ /** RFC-0136: amend-only declarative preconditions (e.g. appPresent). */
63
+ preconditions?: WorkflowPreconditions;
64
+ /** RFC-0136: branch declaration, allowed only on the compose phase. */
65
+ branch?: WorkflowBranch;
66
+ reads: string[];
67
+ writes: string[];
68
+ scope: WorkflowScope;
69
+ runs: string[];
70
+ recoveryRules: WorkflowRecoveryRule[];
71
+ agentInvariants: string[];
72
+ selfOrchestration: WorkflowSelfOrchestration;
73
+ checkpoints: string[];
74
+ nextWorkflow?: string;
75
+ }
76
+
77
+ export interface WorkflowListEntry {
78
+ id: string;
79
+ title: string;
80
+ phase: WorkflowPhase;
81
+ file: string;
82
+ reads: string[];
83
+ writes: string[];
84
+ runs: string[];
85
+ nextWorkflow?: string;
86
+ }
87
+
88
+ export interface WorkflowLintViolation {
89
+ file: string;
90
+ code: string;
91
+ message: string;
92
+ }
93
+
94
+ export interface WorkflowLintResult {
95
+ command: "workflow.lint";
96
+ workflowDirectory: string;
97
+ filesChecked: number;
98
+ violations: WorkflowLintViolation[];
99
+ }
@@ -0,0 +1,54 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>forgeWorkflowModule — registers workflow.lint, workflow.list, and workflow-amend.list commands from forge.</purpose>
4
+ <non-goals>
5
+ <item>Do not register app-specific workflow commands.</item>
6
+ </non-goals>
7
+ </MODULE_CONTRACT>
8
+ <CHANGE_SUMMARY>
9
+ <item>RFC-0075: Add workflow command module.</item>
10
+ <item>RFC-0374: Migrated from packages/os/site-kernel/src/workflow/ to packages/forge/os/workflow/.</item>
11
+ </CHANGE_SUMMARY>
12
+ */
13
+
14
+ import type { ForgeModule } from "../../src/forge-module.ts";
15
+
16
+ export const forgeWorkflowModule: ForgeModule = {
17
+ name: "workflow",
18
+ version: "0.1.0",
19
+ async register(registry) {
20
+ const { runWorkflowLint, runWorkflowList, runWorkflowAmendList } =
21
+ await import("./handlers.ts");
22
+ registry.registerCommand({
23
+ name: "workflow.lint",
24
+ description:
25
+ "Validate .agents/workflows AND .agents/workflows-amend markdown frontmatter, command references, " +
26
+ "and per-chain phase links (RFC-0075 + RFC-0136).",
27
+ scope: "workspace",
28
+ flags: {},
29
+ supportsAllSites: true,
30
+ reads: [".agents/workflows/**/*.md", ".windsurf/workflows/**/*.md"],
31
+ execute: runWorkflowLint,
32
+ });
33
+ registry.registerCommand({
34
+ name: "workflow.list",
35
+ description:
36
+ "List .agents/workflows entries with phase, IO summary, and next workflow (RFC-0075).",
37
+ scope: "workspace",
38
+ flags: {},
39
+ supportsAllSites: true,
40
+ reads: [".agents/workflows/**/*.md", ".windsurf/workflows/**/*.md"],
41
+ execute: runWorkflowList,
42
+ });
43
+ registry.registerCommand({
44
+ name: "workflow-amend.list",
45
+ description:
46
+ "List .agents/workflows-amend entries with phase, IO summary, and next workflow (RFC-0136).",
47
+ scope: "workspace",
48
+ flags: {},
49
+ supportsAllSites: true,
50
+ reads: [".agents/workflows-amend/**/*.md"],
51
+ execute: runWorkflowAmendList,
52
+ });
53
+ },
54
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warpgogol/forge",
3
- "version": "2.8.0",
3
+ "version": "2.8.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -147,8 +147,8 @@
147
147
  "bin/cli.js",
148
148
  "skills/",
149
149
  "profiles/",
150
- "src/onboarding/templates/",
151
- "os/rfc/rfc-0000-template.md",
150
+ "src/",
151
+ "os/",
152
152
  "AGENTS.md",
153
153
  "README.md",
154
154
  "LICENSE"
@@ -362,7 +362,7 @@ workspace:
362
362
  "prettier": "^3.4.0",
363
363
  "@warpgogol/forge": "^2.2.0",
364
364
  "@warpgogol/werkstatt": "^1.2.0",
365
- "@warpgogol/werkstatt-godot": "^0.6.0"
365
+ "@warpgogol/werkstatt-godot-game": "^0.6.0"
366
366
  }
367
367
  }
368
368
  - path: godot.version
@@ -613,7 +613,7 @@ workspace:
613
613
  - path: tools/kernel.config.ts
614
614
  content: |
615
615
  import { defineKernelConfig } from "@warpgogol/werkstatt/kernel/types";
616
- import { werkstattGodotPlugin } from "@warpgogol/werkstatt-godot";
616
+ import { werkstattGodotPlugin } from "@warpgogol/werkstatt-godot-game";
617
617
 
618
618
  export default defineKernelConfig({
619
619
  name: "__PROJECT_NAME__",
@@ -709,7 +709,7 @@ workspace:
709
709
  content: |
710
710
  # __PROJECT_NAME__
711
711
 
712
- A Warpgogol workshop powered by the Werkstatt engine and the @warpgogol/werkstatt-godot plugin.
712
+ A Warpgogol workshop powered by the Werkstatt engine and the @warpgogol/werkstatt-godot-game plugin.
713
713
 
714
714
  ## Prerequisites
715
715
 
@@ -776,7 +776,7 @@ workspace:
776
776
  ## Stack
777
777
 
778
778
  - Engine: @warpgogol/werkstatt
779
- - Plugin: @warpgogol/werkstatt-godot
779
+ - Plugin: @warpgogol/werkstatt-godot-game
780
780
  - Stack profile: godot-csharp
781
781
  install:
782
782
  - pnpm install
@@ -0,0 +1,110 @@
1
+ schema: forge/stack-profile@1
2
+ id: knowledge-typescript-turborepo
3
+ displayName: Knowledge Base + Turborepo
4
+ detect:
5
+ anyOf:
6
+ - knowledge/manifest.yaml
7
+ - knowledge.config.yaml
8
+ workspace:
9
+ dirs:
10
+ - apps
11
+ - packages
12
+ - knowledge
13
+ - staging
14
+ - laboratory
15
+ - projections
16
+ - docs
17
+ - tools
18
+ - missions
19
+ - systems-cache
20
+ files:
21
+ - path: .vscode/extensions.json
22
+ content: |
23
+ {
24
+ "recommendations": [
25
+ "dbaeumer.vscode-eslint",
26
+ "esbenp.prettier-vscode",
27
+ "github.vscode-github-actions",
28
+ "mechatroner.rainbow-csv",
29
+ "redhat.vscode-yaml"
30
+ ]
31
+ }
32
+ - path: pnpm-workspace.yaml
33
+ content: |
34
+ packages:
35
+ - "apps/*"
36
+ - "packages/*"
37
+ - path: turbo.json
38
+ content: |
39
+ {
40
+ "$schema": "https://turbo.build/schema.json",
41
+ "tasks": {
42
+ "build": {
43
+ "dependsOn": ["^build"],
44
+ "outputs": ["dist/**", ".generated/**"]
45
+ },
46
+ "build:check": {
47
+ "dependsOn": ["^build:check"]
48
+ },
49
+ "test": {
50
+ "dependsOn": ["^build:check"]
51
+ }
52
+ }
53
+ }
54
+ - path: tsconfig.base.json
55
+ content: |
56
+ {
57
+ "compilerOptions": {
58
+ "target": "ESNext",
59
+ "module": "ESNext",
60
+ "moduleResolution": "bundler",
61
+ "strict": true,
62
+ "esModuleInterop": true,
63
+ "skipLibCheck": true,
64
+ "forceConsistentCasingInFileNames": true,
65
+ "resolveJsonModule": true,
66
+ "declaration": true,
67
+ "declarationMap": true,
68
+ "sourceMap": true
69
+ }
70
+ }
71
+ - path: .gitignore
72
+ content: |
73
+ node_modules/
74
+ dist/
75
+ .generated/
76
+ .turbo/
77
+ .cache/
78
+ - path: knowledge/manifest.yaml
79
+ content: |
80
+ # Knowledge manifest — canonical dataset identity
81
+ id: ""
82
+ name: ""
83
+ modelVersion: "1.0.0"
84
+ description: ""
85
+ license: ""
86
+ - path: knowledge/ontology/schema-registry.yaml
87
+ content: |
88
+ # Ontology schema registry
89
+ # Register canonical record schemas here
90
+ schemas: []
91
+ - path: knowledge.config.yaml
92
+ content: |
93
+ # Knowledge operational configuration
94
+ source:
95
+ rootPattern: "../<kb-id>-source"
96
+ extractors: []
97
+ projections:
98
+ - name: web
99
+ path: apps/web
100
+ - name: mcp
101
+ path: apps/mcp
102
+ plugin:
103
+ id: werkstatt-knowledge
104
+ package: "@warpgogol/werkstatt-knowledge"
105
+ agents:
106
+ root: |
107
+ # Knowledge Base Workshop
108
+
109
+ This workshop uses the **werkstatt-knowledge** plugin (`werkstatt/plugin@1`).
110
+ See `packages/werkstatt-knowledge/AGENTS.md` for plugin-specific rules.
@@ -219,7 +219,7 @@ workspace:
219
219
  - path: tools/kernel.config.ts
220
220
  content: |
221
221
  import { defineKernelConfig } from "@warpgogol/werkstatt/kernel/types";
222
- import { werkstattGamePlugin } from "@warpgogol/werkstatt-game";
222
+ import { werkstattPhaserPlugin } from "@warpgogol/werkstatt-phaser-game";
223
223
 
224
224
  export default defineKernelConfig({
225
225
  name: "__PROJECT_NAME__",
@@ -249,7 +249,7 @@ workspace:
249
249
  evidence: async () => (await import("@warpgogol/werkstatt/evidence-module")).createEvidenceModule(),
250
250
  "werkstatt-plugin": async () => (await import("@warpgogol/werkstatt/os/werkstatt-plugin-module")).forgeWerkstattPluginModule,
251
251
  "werkstatt-autonomy": async () => (await import("@warpgogol/werkstatt/os/werkstatt-autonomy-module")).werkstattAutonomyModule,
252
- "__PROJECT_NAME__-plugin": async () => werkstattGamePlugin,
252
+ "__PROJECT_NAME__-plugin": async () => werkstattPhaserPlugin,
253
253
  },
254
254
  });
255
255
  - path: .npmrc
@@ -313,7 +313,7 @@ workspace:
313
313
  content: |
314
314
  # __PROJECT_NAME__
315
315
 
316
- A Warpgogol workshop powered by the Werkstatt engine and the @warpgogol/werkstatt-game plugin.
316
+ A Warpgogol workshop powered by the Werkstatt engine and the @warpgogol/werkstatt-phaser-game plugin.
317
317
 
318
318
  ## Prerequisites
319
319
 
@@ -347,10 +347,10 @@ workspace:
347
347
  ## Stack
348
348
 
349
349
  - Engine: @warpgogol/werkstatt
350
- - Plugin: @warpgogol/werkstatt-game
350
+ - Plugin: @warpgogol/werkstatt-phaser-game
351
351
  - Stack profile: phaser-turborepo
352
352
  install:
353
- - pnpm add -wD typescript turbo @warpgogol/forge @warpgogol/werkstatt @warpgogol/werkstatt-shared @warpgogol/werkstatt-game prettier
353
+ - pnpm add -wD typescript turbo @warpgogol/forge @warpgogol/werkstatt @warpgogol/werkstatt-shared @warpgogol/werkstatt-phaser-game prettier
354
354
  firstWorkspace:
355
355
  path: apps/my-game
356
356
  files: