@organon-methodology/tools 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (287) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +152 -0
  3. package/dist/cli/commands/coverage.d.ts +12 -0
  4. package/dist/cli/commands/coverage.d.ts.map +1 -0
  5. package/dist/cli/commands/coverage.js +80 -0
  6. package/dist/cli/commands/coverage.js.map +1 -0
  7. package/dist/cli/commands/find.d.ts +15 -0
  8. package/dist/cli/commands/find.d.ts.map +1 -0
  9. package/dist/cli/commands/find.js +81 -0
  10. package/dist/cli/commands/find.js.map +1 -0
  11. package/dist/cli/commands/generate-tests.d.ts +14 -0
  12. package/dist/cli/commands/generate-tests.d.ts.map +1 -0
  13. package/dist/cli/commands/generate-tests.js +87 -0
  14. package/dist/cli/commands/generate-tests.js.map +1 -0
  15. package/dist/cli/commands/generate.d.ts +15 -0
  16. package/dist/cli/commands/generate.d.ts.map +1 -0
  17. package/dist/cli/commands/generate.js +77 -0
  18. package/dist/cli/commands/generate.js.map +1 -0
  19. package/dist/cli/commands/health.d.ts +13 -0
  20. package/dist/cli/commands/health.d.ts.map +1 -0
  21. package/dist/cli/commands/health.js +79 -0
  22. package/dist/cli/commands/health.js.map +1 -0
  23. package/dist/cli/commands/init.d.ts +14 -0
  24. package/dist/cli/commands/init.d.ts.map +1 -0
  25. package/dist/cli/commands/init.js +132 -0
  26. package/dist/cli/commands/init.js.map +1 -0
  27. package/dist/cli/commands/mcp.d.ts +11 -0
  28. package/dist/cli/commands/mcp.d.ts.map +1 -0
  29. package/dist/cli/commands/mcp.js +26 -0
  30. package/dist/cli/commands/mcp.js.map +1 -0
  31. package/dist/cli/commands/query.d.ts +19 -0
  32. package/dist/cli/commands/query.d.ts.map +1 -0
  33. package/dist/cli/commands/query.js +103 -0
  34. package/dist/cli/commands/query.js.map +1 -0
  35. package/dist/cli/commands/upgrade.d.ts +13 -0
  36. package/dist/cli/commands/upgrade.d.ts.map +1 -0
  37. package/dist/cli/commands/upgrade.js +162 -0
  38. package/dist/cli/commands/upgrade.js.map +1 -0
  39. package/dist/cli/commands/validate.d.ts +13 -0
  40. package/dist/cli/commands/validate.d.ts.map +1 -0
  41. package/dist/cli/commands/validate.js +89 -0
  42. package/dist/cli/commands/validate.js.map +1 -0
  43. package/dist/cli/commands/verify.d.ts +12 -0
  44. package/dist/cli/commands/verify.d.ts.map +1 -0
  45. package/dist/cli/commands/verify.js +67 -0
  46. package/dist/cli/commands/verify.js.map +1 -0
  47. package/dist/cli/index.d.ts +19 -0
  48. package/dist/cli/index.d.ts.map +1 -0
  49. package/dist/cli/index.js +59 -0
  50. package/dist/cli/index.js.map +1 -0
  51. package/dist/core/add-protocols-array.d.ts +17 -0
  52. package/dist/core/add-protocols-array.d.ts.map +1 -0
  53. package/dist/core/add-protocols-array.js +95 -0
  54. package/dist/core/add-protocols-array.js.map +1 -0
  55. package/dist/core/add-protocols-array.test.d.ts +2 -0
  56. package/dist/core/add-protocols-array.test.d.ts.map +1 -0
  57. package/dist/core/add-protocols-array.test.js +86 -0
  58. package/dist/core/add-protocols-array.test.js.map +1 -0
  59. package/dist/core/config.d.ts +44 -0
  60. package/dist/core/config.d.ts.map +1 -0
  61. package/dist/core/config.js +130 -0
  62. package/dist/core/config.js.map +1 -0
  63. package/dist/core/config.test.d.ts +2 -0
  64. package/dist/core/config.test.d.ts.map +1 -0
  65. package/dist/core/config.test.js +88 -0
  66. package/dist/core/config.test.js.map +1 -0
  67. package/dist/core/find.d.ts +29 -0
  68. package/dist/core/find.d.ts.map +1 -0
  69. package/dist/core/find.js +191 -0
  70. package/dist/core/find.js.map +1 -0
  71. package/dist/core/find.test.d.ts +2 -0
  72. package/dist/core/find.test.d.ts.map +1 -0
  73. package/dist/core/find.test.js +91 -0
  74. package/dist/core/find.test.js.map +1 -0
  75. package/dist/core/frontmatter-parser.d.ts +45 -0
  76. package/dist/core/frontmatter-parser.d.ts.map +1 -0
  77. package/dist/core/frontmatter-parser.js +122 -0
  78. package/dist/core/frontmatter-parser.js.map +1 -0
  79. package/dist/core/frontmatter-parser.test.d.ts +2 -0
  80. package/dist/core/frontmatter-parser.test.d.ts.map +1 -0
  81. package/dist/core/frontmatter-parser.test.js +200 -0
  82. package/dist/core/frontmatter-parser.test.js.map +1 -0
  83. package/dist/core/generate-frontmatter.d.ts +27 -0
  84. package/dist/core/generate-frontmatter.d.ts.map +1 -0
  85. package/dist/core/generate-frontmatter.js +219 -0
  86. package/dist/core/generate-frontmatter.js.map +1 -0
  87. package/dist/core/generate-frontmatter.test.d.ts +2 -0
  88. package/dist/core/generate-frontmatter.test.d.ts.map +1 -0
  89. package/dist/core/generate-frontmatter.test.js +161 -0
  90. package/dist/core/generate-frontmatter.test.js.map +1 -0
  91. package/dist/core/generate-tests.d.ts +41 -0
  92. package/dist/core/generate-tests.d.ts.map +1 -0
  93. package/dist/core/generate-tests.js +191 -0
  94. package/dist/core/generate-tests.js.map +1 -0
  95. package/dist/core/generate-tests.test.d.ts +2 -0
  96. package/dist/core/generate-tests.test.d.ts.map +1 -0
  97. package/dist/core/generate-tests.test.js +205 -0
  98. package/dist/core/generate-tests.test.js.map +1 -0
  99. package/dist/core/health.d.ts +16 -0
  100. package/dist/core/health.d.ts.map +1 -0
  101. package/dist/core/health.js +156 -0
  102. package/dist/core/health.js.map +1 -0
  103. package/dist/core/health.test.d.ts +2 -0
  104. package/dist/core/health.test.d.ts.map +1 -0
  105. package/dist/core/health.test.js +97 -0
  106. package/dist/core/health.test.js.map +1 -0
  107. package/dist/core/init.d.ts +25 -0
  108. package/dist/core/init.d.ts.map +1 -0
  109. package/dist/core/init.js +100 -0
  110. package/dist/core/init.js.map +1 -0
  111. package/dist/core/init.test.d.ts +8 -0
  112. package/dist/core/init.test.d.ts.map +1 -0
  113. package/dist/core/init.test.js +203 -0
  114. package/dist/core/init.test.js.map +1 -0
  115. package/dist/core/invariant-coverage.d.ts +41 -0
  116. package/dist/core/invariant-coverage.d.ts.map +1 -0
  117. package/dist/core/invariant-coverage.js +181 -0
  118. package/dist/core/invariant-coverage.js.map +1 -0
  119. package/dist/core/invariant-coverage.test.d.ts +2 -0
  120. package/dist/core/invariant-coverage.test.d.ts.map +1 -0
  121. package/dist/core/invariant-coverage.test.js +188 -0
  122. package/dist/core/invariant-coverage.test.js.map +1 -0
  123. package/dist/core/meta-invariants.test.d.ts +17 -0
  124. package/dist/core/meta-invariants.test.d.ts.map +1 -0
  125. package/dist/core/meta-invariants.test.js +191 -0
  126. package/dist/core/meta-invariants.test.js.map +1 -0
  127. package/dist/core/node-fs.d.ts +22 -0
  128. package/dist/core/node-fs.d.ts.map +1 -0
  129. package/dist/core/node-fs.js +47 -0
  130. package/dist/core/node-fs.js.map +1 -0
  131. package/dist/core/organon-invariants.test.d.ts +15 -0
  132. package/dist/core/organon-invariants.test.d.ts.map +1 -0
  133. package/dist/core/organon-invariants.test.js +149 -0
  134. package/dist/core/organon-invariants.test.js.map +1 -0
  135. package/dist/core/query.d.ts +35 -0
  136. package/dist/core/query.d.ts.map +1 -0
  137. package/dist/core/query.js +139 -0
  138. package/dist/core/query.js.map +1 -0
  139. package/dist/core/query.test.d.ts +2 -0
  140. package/dist/core/query.test.d.ts.map +1 -0
  141. package/dist/core/query.test.js +97 -0
  142. package/dist/core/query.test.js.map +1 -0
  143. package/dist/core/suggest-tools.d.ts +15 -0
  144. package/dist/core/suggest-tools.d.ts.map +1 -0
  145. package/dist/core/suggest-tools.js +139 -0
  146. package/dist/core/suggest-tools.js.map +1 -0
  147. package/dist/core/suggest-tools.test.d.ts +2 -0
  148. package/dist/core/suggest-tools.test.d.ts.map +1 -0
  149. package/dist/core/suggest-tools.test.js +122 -0
  150. package/dist/core/suggest-tools.test.js.map +1 -0
  151. package/dist/core/test-helpers.d.ts +63 -0
  152. package/dist/core/test-helpers.d.ts.map +1 -0
  153. package/dist/core/test-helpers.js +265 -0
  154. package/dist/core/test-helpers.js.map +1 -0
  155. package/dist/core/types.d.ts +277 -0
  156. package/dist/core/types.d.ts.map +1 -0
  157. package/dist/core/types.js +9 -0
  158. package/dist/core/types.js.map +1 -0
  159. package/dist/core/upgrade.d.ts +46 -0
  160. package/dist/core/upgrade.d.ts.map +1 -0
  161. package/dist/core/upgrade.js +227 -0
  162. package/dist/core/upgrade.js.map +1 -0
  163. package/dist/core/upgrade.test.d.ts +8 -0
  164. package/dist/core/upgrade.test.d.ts.map +1 -0
  165. package/dist/core/upgrade.test.js +370 -0
  166. package/dist/core/upgrade.test.js.map +1 -0
  167. package/dist/core/validate-frontmatter.d.ts +20 -0
  168. package/dist/core/validate-frontmatter.d.ts.map +1 -0
  169. package/dist/core/validate-frontmatter.js +529 -0
  170. package/dist/core/validate-frontmatter.js.map +1 -0
  171. package/dist/core/validate-frontmatter.test.d.ts +2 -0
  172. package/dist/core/validate-frontmatter.test.d.ts.map +1 -0
  173. package/dist/core/validate-frontmatter.test.js +366 -0
  174. package/dist/core/validate-frontmatter.test.js.map +1 -0
  175. package/dist/core/validate-workflow.d.ts +17 -0
  176. package/dist/core/validate-workflow.d.ts.map +1 -0
  177. package/dist/core/validate-workflow.js +233 -0
  178. package/dist/core/validate-workflow.js.map +1 -0
  179. package/dist/core/validate-workflow.test.d.ts +2 -0
  180. package/dist/core/validate-workflow.test.d.ts.map +1 -0
  181. package/dist/core/validate-workflow.test.js +205 -0
  182. package/dist/core/validate-workflow.test.js.map +1 -0
  183. package/dist/core/verify-tier4-tests.d.ts +34 -0
  184. package/dist/core/verify-tier4-tests.d.ts.map +1 -0
  185. package/dist/core/verify-tier4-tests.js +106 -0
  186. package/dist/core/verify-tier4-tests.js.map +1 -0
  187. package/dist/core/verify-tier4-tests.test.d.ts +2 -0
  188. package/dist/core/verify-tier4-tests.test.d.ts.map +1 -0
  189. package/dist/core/verify-tier4-tests.test.js +140 -0
  190. package/dist/core/verify-tier4-tests.test.js.map +1 -0
  191. package/dist/core/verify-triplets.d.ts +17 -0
  192. package/dist/core/verify-triplets.d.ts.map +1 -0
  193. package/dist/core/verify-triplets.js +217 -0
  194. package/dist/core/verify-triplets.js.map +1 -0
  195. package/dist/core/verify-triplets.test.d.ts +2 -0
  196. package/dist/core/verify-triplets.test.d.ts.map +1 -0
  197. package/dist/core/verify-triplets.test.js +147 -0
  198. package/dist/core/verify-triplets.test.js.map +1 -0
  199. package/dist/core/verify.d.ts +19 -0
  200. package/dist/core/verify.d.ts.map +1 -0
  201. package/dist/core/verify.js +162 -0
  202. package/dist/core/verify.js.map +1 -0
  203. package/dist/core/verify.test.d.ts +2 -0
  204. package/dist/core/verify.test.d.ts.map +1 -0
  205. package/dist/core/verify.test.js +147 -0
  206. package/dist/core/verify.test.js.map +1 -0
  207. package/dist/index.d.ts +31 -0
  208. package/dist/index.d.ts.map +1 -0
  209. package/dist/index.js +27 -0
  210. package/dist/index.js.map +1 -0
  211. package/dist/mcp/prompts.d.ts +9 -0
  212. package/dist/mcp/prompts.d.ts.map +1 -0
  213. package/dist/mcp/prompts.js +265 -0
  214. package/dist/mcp/prompts.js.map +1 -0
  215. package/dist/mcp/resources.d.ts +7 -0
  216. package/dist/mcp/resources.d.ts.map +1 -0
  217. package/dist/mcp/resources.js +111 -0
  218. package/dist/mcp/resources.js.map +1 -0
  219. package/dist/mcp/server.d.ts +7 -0
  220. package/dist/mcp/server.d.ts.map +1 -0
  221. package/dist/mcp/server.js +31 -0
  222. package/dist/mcp/server.js.map +1 -0
  223. package/dist/mcp/tools.d.ts +7 -0
  224. package/dist/mcp/tools.d.ts.map +1 -0
  225. package/dist/mcp/tools.js +130 -0
  226. package/dist/mcp/tools.js.map +1 -0
  227. package/dist/templates/config.d.ts +6 -0
  228. package/dist/templates/config.d.ts.map +1 -0
  229. package/dist/templates/config.js +30 -0
  230. package/dist/templates/config.js.map +1 -0
  231. package/dist/templates/index.d.ts +7 -0
  232. package/dist/templates/index.d.ts.map +1 -0
  233. package/dist/templates/index.js +7 -0
  234. package/dist/templates/index.js.map +1 -0
  235. package/dist/templates/organon/claude-md.d.ts +7 -0
  236. package/dist/templates/organon/claude-md.d.ts.map +1 -0
  237. package/dist/templates/organon/claude-md.js +32 -0
  238. package/dist/templates/organon/claude-md.js.map +1 -0
  239. package/dist/templates/organon/ethos.d.ts +5 -0
  240. package/dist/templates/organon/ethos.d.ts.map +1 -0
  241. package/dist/templates/organon/ethos.js +69 -0
  242. package/dist/templates/organon/ethos.js.map +1 -0
  243. package/dist/templates/organon/index.d.ts +10 -0
  244. package/dist/templates/organon/index.d.ts.map +1 -0
  245. package/dist/templates/organon/index.js +10 -0
  246. package/dist/templates/organon/index.js.map +1 -0
  247. package/dist/templates/organon/observations-readme.d.ts +5 -0
  248. package/dist/templates/organon/observations-readme.d.ts.map +1 -0
  249. package/dist/templates/organon/observations-readme.js +25 -0
  250. package/dist/templates/organon/observations-readme.js.map +1 -0
  251. package/dist/templates/organon/philosophy.d.ts +5 -0
  252. package/dist/templates/organon/philosophy.d.ts.map +1 -0
  253. package/dist/templates/organon/philosophy.js +75 -0
  254. package/dist/templates/organon/philosophy.js.map +1 -0
  255. package/dist/templates/organon/protocols.d.ts +7 -0
  256. package/dist/templates/organon/protocols.d.ts.map +1 -0
  257. package/dist/templates/organon/protocols.js +197 -0
  258. package/dist/templates/organon/protocols.js.map +1 -0
  259. package/dist/templates/organon/readme.d.ts +5 -0
  260. package/dist/templates/organon/readme.d.ts.map +1 -0
  261. package/dist/templates/organon/readme.js +40 -0
  262. package/dist/templates/organon/readme.js.map +1 -0
  263. package/dist/templates/skills/domain-feature-design.d.ts +9 -0
  264. package/dist/templates/skills/domain-feature-design.d.ts.map +1 -0
  265. package/dist/templates/skills/domain-feature-design.js +123 -0
  266. package/dist/templates/skills/domain-feature-design.js.map +1 -0
  267. package/dist/templates/skills/index.d.ts +15 -0
  268. package/dist/templates/skills/index.d.ts.map +1 -0
  269. package/dist/templates/skills/index.js +35 -0
  270. package/dist/templates/skills/index.js.map +1 -0
  271. package/dist/templates/skills/organon-file-creation.d.ts +9 -0
  272. package/dist/templates/skills/organon-file-creation.d.ts.map +1 -0
  273. package/dist/templates/skills/organon-file-creation.js +138 -0
  274. package/dist/templates/skills/organon-file-creation.js.map +1 -0
  275. package/dist/templates/skills/quality-review.d.ts +9 -0
  276. package/dist/templates/skills/quality-review.d.ts.map +1 -0
  277. package/dist/templates/skills/quality-review.js +127 -0
  278. package/dist/templates/skills/quality-review.js.map +1 -0
  279. package/dist/templates/skills/session-compounding.d.ts +9 -0
  280. package/dist/templates/skills/session-compounding.d.ts.map +1 -0
  281. package/dist/templates/skills/session-compounding.js +118 -0
  282. package/dist/templates/skills/session-compounding.js.map +1 -0
  283. package/dist/templates/skills/verify-and-health.d.ts +9 -0
  284. package/dist/templates/skills/verify-and-health.d.ts.map +1 -0
  285. package/dist/templates/skills/verify-and-health.js +99 -0
  286. package/dist/templates/skills/verify-and-health.js.map +1 -0
  287. package/package.json +72 -0
@@ -0,0 +1,205 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { validateWorkflow } from './validate-workflow.js';
3
+ import { MemoryFileSystem, makeWorkflow } from './test-helpers.js';
4
+ function makeConfig(projectRoot) {
5
+ return {
6
+ projectRoot,
7
+ organonPaths: ['.'],
8
+ organonGlobs: ['**/ETHOS.md'],
9
+ ignorePatterns: [],
10
+ workflowPaths: { generic: 'workflows' },
11
+ freshnessThresholdHours: 24,
12
+ };
13
+ }
14
+ describe('validateWorkflow', () => {
15
+ it('passes for a well-formed workflow', async () => {
16
+ const fs = new MemoryFileSystem({
17
+ '/project/workflows/test.md': makeWorkflow(),
18
+ '/project/ETHOS.md': '# ethos',
19
+ });
20
+ const config = makeConfig('/project');
21
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
22
+ expect(result.success).toBe(true);
23
+ expect(result.workflowsChecked).toBe(1);
24
+ expect(result.workflowsWithErrors).toBe(0);
25
+ });
26
+ it('succeeds when no workflow files exist', async () => {
27
+ const fs = new MemoryFileSystem({});
28
+ const config = makeConfig('/project');
29
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
30
+ expect(result.success).toBe(true);
31
+ expect(result.workflowsChecked).toBe(0);
32
+ });
33
+ it('reports error when protocol_id is missing', async () => {
34
+ const content = makeWorkflow().replace(/protocol_id: .*\n/, '');
35
+ const fs = new MemoryFileSystem({
36
+ '/project/workflows/test.md': content,
37
+ '/project/ETHOS.md': '# ethos',
38
+ });
39
+ const config = makeConfig('/project');
40
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
41
+ expect(result.errors).toContainEqual(expect.objectContaining({ code: 'WORKFLOW_MISSING_PROTOCOL_ID' }));
42
+ });
43
+ it('reports error when protocol_file is missing', async () => {
44
+ const content = makeWorkflow().replace(/protocol_file: .*\n/, '');
45
+ const fs = new MemoryFileSystem({
46
+ '/project/workflows/test.md': content,
47
+ '/project/ETHOS.md': '# ethos',
48
+ });
49
+ const config = makeConfig('/project');
50
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
51
+ expect(result.errors).toContainEqual(expect.objectContaining({ code: 'WORKFLOW_MISSING_PROTOCOL_FILE' }));
52
+ });
53
+ it('reports error when tools array is missing', async () => {
54
+ const content = makeWorkflow().replace(/tools:\n - tool:verify\n/, '');
55
+ const fs = new MemoryFileSystem({
56
+ '/project/workflows/test.md': content,
57
+ '/project/ETHOS.md': '# ethos',
58
+ });
59
+ const config = makeConfig('/project');
60
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
61
+ expect(result.errors).toContainEqual(expect.objectContaining({ code: 'WORKFLOW_MISSING_TOOLS' }));
62
+ });
63
+ it('reports error when loads array is missing', async () => {
64
+ const content = makeWorkflow().replace(/loads:\n - \/ETHOS\.md\n/, '');
65
+ const fs = new MemoryFileSystem({
66
+ '/project/workflows/test.md': content,
67
+ });
68
+ const config = makeConfig('/project');
69
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
70
+ expect(result.errors).toContainEqual(expect.objectContaining({ code: 'WORKFLOW_MISSING_LOADS' }));
71
+ });
72
+ it('reports error when loads path does not resolve', async () => {
73
+ const fs = new MemoryFileSystem({
74
+ '/project/workflows/test.md': makeWorkflow({ loads: ['/nonexistent.md'] }),
75
+ });
76
+ const config = makeConfig('/project');
77
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
78
+ expect(result.errors).toContainEqual(expect.objectContaining({ code: 'WORKFLOW_BROKEN_LOADS_REF' }));
79
+ });
80
+ it('warns when error recovery section is missing', async () => {
81
+ const fs = new MemoryFileSystem({
82
+ '/project/workflows/test.md': makeWorkflow({ includeRecovery: false }),
83
+ '/project/ETHOS.md': '# ethos',
84
+ });
85
+ const config = makeConfig('/project');
86
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
87
+ expect(result.warnings).toContainEqual(expect.objectContaining({ code: 'WORKFLOW_NO_ERROR_RECOVERY' }));
88
+ });
89
+ it('warns when error recovery section has no table', async () => {
90
+ const content = makeWorkflow({ includeRecovery: false }) + '\n## Error Recovery\n\nJust some text, no table.\n';
91
+ const fs = new MemoryFileSystem({
92
+ '/project/workflows/test.md': content,
93
+ '/project/ETHOS.md': '# ethos',
94
+ });
95
+ const config = makeConfig('/project');
96
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
97
+ expect(result.warnings).toContainEqual(expect.objectContaining({ code: 'WORKFLOW_RECOVERY_NO_TABLE' }));
98
+ });
99
+ it('warns when loads array exceeds threshold', async () => {
100
+ const manyLoadsPaths = Array.from({ length: 12 }, (_, i) => `/file${i}.md`);
101
+ const fs = new MemoryFileSystem({
102
+ '/project/workflows/test.md': makeWorkflow({ loads: manyLoadsPaths }),
103
+ });
104
+ // Create all the loads files so they resolve
105
+ for (const p of manyLoadsPaths) {
106
+ fs.addFile(`/project${p}`, '# content');
107
+ }
108
+ const config = makeConfig('/project');
109
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
110
+ expect(result.warnings).toContainEqual(expect.objectContaining({ code: 'WORKFLOW_LOADS_OVERLOAD' }));
111
+ });
112
+ it('warns when a tool in tools array is not referenced in body', async () => {
113
+ const fs = new MemoryFileSystem({
114
+ '/project/workflows/test.md': makeWorkflow({ tools: ['tool:verify', 'tool:unused'] }),
115
+ '/project/ETHOS.md': '# ethos',
116
+ });
117
+ const config = makeConfig('/project');
118
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
119
+ expect(result.warnings).toContainEqual(expect.objectContaining({
120
+ code: 'WORKFLOW_UNREFERENCED_TOOL',
121
+ message: expect.stringContaining('tool:unused'),
122
+ }));
123
+ });
124
+ it('matches kebab-case tool ids against CLI-command form in body', async () => {
125
+ // Tool listed as "organon-verify" should match body text "organon verify"
126
+ const content = `---
127
+ name: cli-workflow
128
+ protocol_id: PROTO-TEST-1
129
+ protocol_file: PROTOCOLS.md
130
+ tools:
131
+ - organon-verify
132
+ - organon-health
133
+ loads:
134
+ - /ETHOS.md
135
+ ---
136
+
137
+ # Workflow
138
+
139
+ ## Steps
140
+
141
+ 1. Run \`organon verify\` to check gates.
142
+ 2. Run \`organon health\` to check score.
143
+
144
+ ## Error Recovery
145
+
146
+ | Failure | Recovery Action |
147
+ |---------|-----------------|
148
+ | Fails | Fix it |
149
+ `;
150
+ const fs = new MemoryFileSystem({
151
+ '/project/workflows/test.md': content,
152
+ '/project/ETHOS.md': '# ethos',
153
+ });
154
+ const config = makeConfig('/project');
155
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
156
+ const toolWarnings = result.warnings.filter(w => w.code === 'WORKFLOW_UNREFERENCED_TOOL');
157
+ expect(toolWarnings).toHaveLength(0);
158
+ });
159
+ it('warns when workflow step count is less than protocol step count', async () => {
160
+ const protocolContent = `---
161
+ type: procedures
162
+ scope: domain
163
+ name: test-protocol
164
+ version: "1.0"
165
+ summary: Test protocol
166
+ token_estimate: 200
167
+ protocols_count: 1
168
+ protocols:
169
+ - id: PROTO-TEST-1
170
+ name: Test Protocol
171
+ steps: 6
172
+ automation_tier: automated
173
+ workflow: test-workflow
174
+ complexity: medium
175
+ ---
176
+
177
+ ## Steps
178
+ 1. Step one
179
+ 2. Step two
180
+ 3. Step three
181
+ 4. Step four
182
+ 5. Step five
183
+ 6. Step six
184
+ `;
185
+ const fs = new MemoryFileSystem({
186
+ '/project/workflows/test.md': makeWorkflow({ steps: 3, protocolFile: 'PROTOCOLS.md', protocolId: 'PROTO-TEST-1' }),
187
+ '/project/PROTOCOLS.md': protocolContent,
188
+ '/project/ETHOS.md': '# ethos',
189
+ });
190
+ const config = makeConfig('/project');
191
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
192
+ expect(result.warnings).toContainEqual(expect.objectContaining({ code: 'WORKFLOW_STEP_COUNT_LOW' }));
193
+ });
194
+ it('handles workflow files without frontmatter gracefully', async () => {
195
+ const fs = new MemoryFileSystem({
196
+ '/project/workflows/test.md': '# No frontmatter workflow\n\nJust content.',
197
+ });
198
+ const config = makeConfig('/project');
199
+ const result = await validateWorkflow({ projectRoot: '/project', config, fs });
200
+ // Should report errors for missing required fields, not crash
201
+ expect(result.success).toBe(false);
202
+ expect(result.errors.length).toBeGreaterThan(0);
203
+ });
204
+ });
205
+ //# sourceMappingURL=validate-workflow.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-workflow.test.js","sourceRoot":"","sources":["../../src/core/validate-workflow.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * tier4-tests verification gate.
3
+ *
4
+ * Static analysis gate that checks whether test files with @organon-invariant
5
+ * annotations properly import from @organon-methodology/testing and call testInvariant().
6
+ *
7
+ * This gate does NOT run tests — that's CI's job. It only checks structure:
8
+ * 1. Find files with @organon-invariant annotations
9
+ * 2. Verify they import from @organon-methodology/testing
10
+ * 3. Verify they contain testInvariant() calls
11
+ * 4. Report gaps
12
+ */
13
+ import type { DiagnosticMessage, FileSystem, OrganonConfig } from './types.js';
14
+ export interface Tier4TestsResult {
15
+ success: boolean;
16
+ /** Test files that were scanned */
17
+ filesScanned: number;
18
+ /** Files with @organon-invariant annotations */
19
+ annotatedFiles: number;
20
+ /** Files that pass all checks */
21
+ validFiles: number;
22
+ errors: DiagnosticMessage[];
23
+ warnings: DiagnosticMessage[];
24
+ }
25
+ /**
26
+ * Verify that test files with @organon-invariant annotations
27
+ * properly use @organon-methodology/testing infrastructure.
28
+ */
29
+ export declare function verifyTier4Tests(options: {
30
+ projectRoot: string;
31
+ config: OrganonConfig;
32
+ fs: FileSystem;
33
+ }): Promise<Tier4TestsResult>;
34
+ //# sourceMappingURL=verify-tier4-tests.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-tier4-tests.d.ts","sourceRoot":"","sources":["../../src/core/verify-tier4-tests.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EACV,iBAAiB,EACjB,UAAU,EACV,aAAa,EACd,MAAM,YAAY,CAAC;AAMpB,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,cAAc,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAuBD;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;IACtB,EAAE,EAAE,UAAU,CAAC;CAChB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA6E5B"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * tier4-tests verification gate.
3
+ *
4
+ * Static analysis gate that checks whether test files with @organon-invariant
5
+ * annotations properly import from @organon-methodology/testing and call testInvariant().
6
+ *
7
+ * This gate does NOT run tests — that's CI's job. It only checks structure:
8
+ * 1. Find files with @organon-invariant annotations
9
+ * 2. Verify they import from @organon-methodology/testing
10
+ * 3. Verify they contain testInvariant() calls
11
+ * 4. Report gaps
12
+ */
13
+ import { joinPath } from './config.js';
14
+ // ---------------------------------------------------------------------------
15
+ // Constants
16
+ // ---------------------------------------------------------------------------
17
+ const DEFAULT_TEST_GLOBS = [
18
+ '**/*.test.ts',
19
+ '**/*.test.js',
20
+ '**/*.test.tsx',
21
+ '**/*.test.jsx',
22
+ '**/*.spec.ts',
23
+ '**/*.spec.js',
24
+ ];
25
+ const ANNOTATION_RE = /@organon-invariant\s+INV-[\w-]+/;
26
+ const TESTING_IMPORT_RE = /from\s+['"]@organon-methodology\/testing/;
27
+ const TEST_INVARIANT_RE = /testInvariant\s*\(/;
28
+ // ---------------------------------------------------------------------------
29
+ // Public API
30
+ // ---------------------------------------------------------------------------
31
+ /**
32
+ * Verify that test files with @organon-invariant annotations
33
+ * properly use @organon-methodology/testing infrastructure.
34
+ */
35
+ export async function verifyTier4Tests(options) {
36
+ const { projectRoot, config, fs } = options;
37
+ const testGlobs = config.testGlobs ?? DEFAULT_TEST_GLOBS;
38
+ const ignorePatterns = config.testIgnorePatterns ?? config.ignorePatterns;
39
+ const errors = [];
40
+ const warnings = [];
41
+ let filesScanned = 0;
42
+ let annotatedFiles = 0;
43
+ let validFiles = 0;
44
+ for (const pattern of testGlobs) {
45
+ const files = await fs.glob(pattern, { cwd: projectRoot, ignore: ignorePatterns });
46
+ for (const file of files) {
47
+ filesScanned++;
48
+ const absPath = joinPath(projectRoot, file);
49
+ let content;
50
+ try {
51
+ content = await fs.readFile(absPath);
52
+ }
53
+ catch {
54
+ continue;
55
+ }
56
+ // Only check files that have @organon-invariant annotations
57
+ if (!ANNOTATION_RE.test(content))
58
+ continue;
59
+ annotatedFiles++;
60
+ let isValid = true;
61
+ // Check for @organon-methodology/testing import
62
+ if (!TESTING_IMPORT_RE.test(content)) {
63
+ warnings.push({
64
+ severity: 'warning',
65
+ code: 'TIER4_MISSING_IMPORT',
66
+ message: `Test file has @organon-invariant annotation but does not import from @organon-methodology/testing`,
67
+ file,
68
+ suggestion: `Add: import { testInvariant } from '@organon-methodology/testing/vitest';`,
69
+ });
70
+ isValid = false;
71
+ }
72
+ // Check for testInvariant() call
73
+ if (!TEST_INVARIANT_RE.test(content)) {
74
+ warnings.push({
75
+ severity: 'warning',
76
+ code: 'TIER4_MISSING_TEST_INVARIANT',
77
+ message: `Test file has @organon-invariant annotation but does not call testInvariant()`,
78
+ file,
79
+ suggestion: `Wrap assertions with testInvariant('INV-ID', 'description', async () => { ... });`,
80
+ });
81
+ isValid = false;
82
+ }
83
+ if (isValid) {
84
+ validFiles++;
85
+ }
86
+ }
87
+ }
88
+ // Info warning when no annotated files found
89
+ if (annotatedFiles === 0 && filesScanned > 0) {
90
+ warnings.push({
91
+ severity: 'warning',
92
+ code: 'TIER4_NO_ANNOTATED_FILES',
93
+ message: `No test files found with @organon-invariant annotations (scanned ${filesScanned} file(s))`,
94
+ suggestion: `Add // @organon-invariant INV-ID comments to test files that verify invariants`,
95
+ });
96
+ }
97
+ return {
98
+ success: errors.length === 0,
99
+ filesScanned,
100
+ annotatedFiles,
101
+ validFiles,
102
+ errors,
103
+ warnings,
104
+ };
105
+ }
106
+ //# sourceMappingURL=verify-tier4-tests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-tier4-tests.js","sourceRoot":"","sources":["../../src/core/verify-tier4-tests.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=verify-tier4-tests.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-tier4-tests.test.d.ts","sourceRoot":"","sources":["../../src/core/verify-tier4-tests.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,140 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { verifyTier4Tests } from './verify-tier4-tests.js';
3
+ import { MemoryFileSystem } from './test-helpers.js';
4
+ const PROJECT_ROOT = '/project';
5
+ function makeConfig(overrides) {
6
+ return {
7
+ projectRoot: PROJECT_ROOT,
8
+ organonPaths: ['.'],
9
+ organonGlobs: ['**/ETHOS.md'],
10
+ ignorePatterns: ['node_modules/**'],
11
+ workflowPaths: {},
12
+ freshnessThresholdHours: 720,
13
+ testGlobs: ['**/*.test.ts'],
14
+ testIgnorePatterns: ['node_modules/**'],
15
+ ...overrides,
16
+ };
17
+ }
18
+ describe('verifyTier4Tests', () => {
19
+ it('passes when annotated files have proper imports and testInvariant calls', async () => {
20
+ const fs = new MemoryFileSystem({
21
+ '/project/tests/my.test.ts': [
22
+ `// @organon-invariant INV-FOO-1`,
23
+ `import { testInvariant } from '@organon-methodology/testing/vitest';`,
24
+ `testInvariant('INV-FOO-1', 'test', async () => {});`,
25
+ ].join('\n'),
26
+ });
27
+ const result = await verifyTier4Tests({
28
+ projectRoot: PROJECT_ROOT,
29
+ config: makeConfig(),
30
+ fs,
31
+ });
32
+ expect(result.success).toBe(true);
33
+ expect(result.annotatedFiles).toBe(1);
34
+ expect(result.validFiles).toBe(1);
35
+ expect(result.warnings).toHaveLength(0);
36
+ });
37
+ it('warns when annotated file is missing @organon-methodology/testing import', async () => {
38
+ const fs = new MemoryFileSystem({
39
+ '/project/tests/my.test.ts': [
40
+ `// @organon-invariant INV-FOO-1`,
41
+ `import { it } from 'vitest';`,
42
+ `it('test', () => {});`,
43
+ ].join('\n'),
44
+ });
45
+ const result = await verifyTier4Tests({
46
+ projectRoot: PROJECT_ROOT,
47
+ config: makeConfig(),
48
+ fs,
49
+ });
50
+ // Advisory gate — still passes
51
+ expect(result.success).toBe(true);
52
+ expect(result.warnings.some((w) => w.code === 'TIER4_MISSING_IMPORT')).toBe(true);
53
+ expect(result.warnings.some((w) => w.code === 'TIER4_MISSING_TEST_INVARIANT')).toBe(true);
54
+ });
55
+ it('warns when annotated file has import but no testInvariant call', async () => {
56
+ const fs = new MemoryFileSystem({
57
+ '/project/tests/my.test.ts': [
58
+ `// @organon-invariant INV-FOO-1`,
59
+ `import { assertMaxValue } from '@organon-methodology/testing/vitest';`,
60
+ `// no testInvariant call`,
61
+ ].join('\n'),
62
+ });
63
+ const result = await verifyTier4Tests({
64
+ projectRoot: PROJECT_ROOT,
65
+ config: makeConfig(),
66
+ fs,
67
+ });
68
+ expect(result.success).toBe(true);
69
+ expect(result.warnings.some((w) => w.code === 'TIER4_MISSING_TEST_INVARIANT')).toBe(true);
70
+ });
71
+ it('ignores test files without annotations', async () => {
72
+ const fs = new MemoryFileSystem({
73
+ '/project/tests/regular.test.ts': [
74
+ `import { it } from 'vitest';`,
75
+ `it('regular test', () => {});`,
76
+ ].join('\n'),
77
+ });
78
+ const result = await verifyTier4Tests({
79
+ projectRoot: PROJECT_ROOT,
80
+ config: makeConfig(),
81
+ fs,
82
+ });
83
+ expect(result.success).toBe(true);
84
+ expect(result.annotatedFiles).toBe(0);
85
+ expect(result.filesScanned).toBe(1);
86
+ });
87
+ it('warns when no annotated files found', async () => {
88
+ const fs = new MemoryFileSystem({
89
+ '/project/tests/regular.test.ts': `// no annotations\nit('test', () => {});`,
90
+ });
91
+ const result = await verifyTier4Tests({
92
+ projectRoot: PROJECT_ROOT,
93
+ config: makeConfig(),
94
+ fs,
95
+ });
96
+ expect(result.success).toBe(true);
97
+ expect(result.warnings.some((w) => w.code === 'TIER4_NO_ANNOTATED_FILES')).toBe(true);
98
+ });
99
+ it('checks multiple files independently', async () => {
100
+ const fs = new MemoryFileSystem({
101
+ '/project/tests/good.test.ts': [
102
+ `// @organon-invariant INV-FOO-1`,
103
+ `import { testInvariant } from '@organon-methodology/testing/vitest';`,
104
+ `testInvariant('INV-FOO-1', 'test', async () => {});`,
105
+ ].join('\n'),
106
+ '/project/tests/bad.test.ts': [
107
+ `// @organon-invariant INV-BAR-1`,
108
+ `import { it } from 'vitest';`,
109
+ `it('test', () => {});`,
110
+ ].join('\n'),
111
+ });
112
+ const result = await verifyTier4Tests({
113
+ projectRoot: PROJECT_ROOT,
114
+ config: makeConfig(),
115
+ fs,
116
+ });
117
+ expect(result.success).toBe(true); // Advisory
118
+ expect(result.annotatedFiles).toBe(2);
119
+ expect(result.validFiles).toBe(1);
120
+ expect(result.warnings.length).toBeGreaterThan(0);
121
+ });
122
+ it('reports warning suggestions with correct import path', async () => {
123
+ const fs = new MemoryFileSystem({
124
+ '/project/tests/my.test.ts': [
125
+ `// @organon-invariant INV-FOO-1`,
126
+ `console.log('no imports at all');`,
127
+ ].join('\n'),
128
+ });
129
+ const result = await verifyTier4Tests({
130
+ projectRoot: PROJECT_ROOT,
131
+ config: makeConfig(),
132
+ fs,
133
+ });
134
+ const importWarning = result.warnings.find((w) => w.code === 'TIER4_MISSING_IMPORT');
135
+ expect(importWarning).toBeDefined();
136
+ expect(importWarning.suggestion).toContain('@organon-methodology/testing/vitest');
137
+ expect(importWarning.file).toBe('tests/my.test.ts');
138
+ });
139
+ });
140
+ //# sourceMappingURL=verify-tier4-tests.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-tier4-tests.test.js","sourceRoot":"","sources":["../../src/core/verify-tier4-tests.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Protocol ↔ Workflow ↔ Tool binding verification.
3
+ *
4
+ * Checks that the three-layer architecture is properly connected:
5
+ * - Every automated protocol has a workflow binding
6
+ * - Every workflow references back to its protocol
7
+ * - No orphaned workflows (workflow without a protocol)
8
+ * - No phantom automation (protocol claims automated but workflow is missing)
9
+ */
10
+ import type { FileSystem, OrganonConfig, VerifyTripletsResult } from './types.js';
11
+ export interface VerifyTripletsOptions {
12
+ projectRoot: string;
13
+ config: OrganonConfig;
14
+ fs: FileSystem;
15
+ }
16
+ export declare function verifyTriplets(options: VerifyTripletsOptions): Promise<VerifyTripletsResult>;
17
+ //# sourceMappingURL=verify-triplets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-triplets.d.ts","sourceRoot":"","sources":["../../src/core/verify-triplets.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAGV,UAAU,EAEV,aAAa,EAGb,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAMpB,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;IACtB,EAAE,EAAE,UAAU,CAAC;CAChB;AAMD,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CA6J/B"}