@tiic-tech/openworkflow 0.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.
Files changed (145) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/adapters/codex/src/doctorCodexAdapter.d.ts +6 -0
  4. package/dist/adapters/codex/src/doctorCodexAdapter.js +124 -0
  5. package/dist/adapters/codex/src/doctorCodexAdapter.js.map +1 -0
  6. package/dist/adapters/codex/src/generateAgents.d.ts +2 -0
  7. package/dist/adapters/codex/src/generateAgents.js +40 -0
  8. package/dist/adapters/codex/src/generateAgents.js.map +1 -0
  9. package/dist/adapters/codex/src/generateCodexAdapter.d.ts +9 -0
  10. package/dist/adapters/codex/src/generateCodexAdapter.js +59 -0
  11. package/dist/adapters/codex/src/generateCodexAdapter.js.map +1 -0
  12. package/dist/adapters/codex/src/generateCommands.d.ts +6 -0
  13. package/dist/adapters/codex/src/generateCommands.js +205 -0
  14. package/dist/adapters/codex/src/generateCommands.js.map +1 -0
  15. package/dist/adapters/codex/src/generateSkills.d.ts +7 -0
  16. package/dist/adapters/codex/src/generateSkills.js +60 -0
  17. package/dist/adapters/codex/src/generateSkills.js.map +1 -0
  18. package/dist/adapters/codex/src/generatedFiles.d.ts +4 -0
  19. package/dist/adapters/codex/src/generatedFiles.js +67 -0
  20. package/dist/adapters/codex/src/generatedFiles.js.map +1 -0
  21. package/dist/adapters/codex/src/manifest.d.ts +4 -0
  22. package/dist/adapters/codex/src/manifest.js +40 -0
  23. package/dist/adapters/codex/src/manifest.js.map +1 -0
  24. package/dist/adapters/codex/src/templates.d.ts +7 -0
  25. package/dist/adapters/codex/src/templates.js +6 -0
  26. package/dist/adapters/codex/src/templates.js.map +1 -0
  27. package/dist/cli/src/args.d.ts +8 -0
  28. package/dist/cli/src/args.js +34 -0
  29. package/dist/cli/src/args.js.map +1 -0
  30. package/dist/cli/src/commands/doctor.d.ts +1 -0
  31. package/dist/cli/src/commands/doctor.js +26 -0
  32. package/dist/cli/src/commands/doctor.js.map +1 -0
  33. package/dist/cli/src/commands/init.d.ts +1 -0
  34. package/dist/cli/src/commands/init.js +52 -0
  35. package/dist/cli/src/commands/init.js.map +1 -0
  36. package/dist/cli/src/commands/shared.d.ts +4 -0
  37. package/dist/cli/src/commands/shared.js +19 -0
  38. package/dist/cli/src/commands/shared.js.map +1 -0
  39. package/dist/cli/src/commands/sync.d.ts +1 -0
  40. package/dist/cli/src/commands/sync.js +27 -0
  41. package/dist/cli/src/commands/sync.js.map +1 -0
  42. package/dist/cli/src/commands/validate.d.ts +1 -0
  43. package/dist/cli/src/commands/validate.js +17 -0
  44. package/dist/cli/src/commands/validate.js.map +1 -0
  45. package/dist/cli/src/dev/validateRepositoryContractsCli.d.ts +2 -0
  46. package/dist/cli/src/dev/validateRepositoryContractsCli.js +37 -0
  47. package/dist/cli/src/dev/validateRepositoryContractsCli.js.map +1 -0
  48. package/dist/cli/src/dev/verifyRuntimeSurface.d.ts +2 -0
  49. package/dist/cli/src/dev/verifyRuntimeSurface.js +344 -0
  50. package/dist/cli/src/dev/verifyRuntimeSurface.js.map +1 -0
  51. package/dist/cli/src/dev/verifyWorkflowE2E.d.ts +2 -0
  52. package/dist/cli/src/dev/verifyWorkflowE2E.js +366 -0
  53. package/dist/cli/src/dev/verifyWorkflowE2E.js.map +1 -0
  54. package/dist/cli/src/index.d.ts +2 -0
  55. package/dist/cli/src/index.js +51 -0
  56. package/dist/cli/src/index.js.map +1 -0
  57. package/dist/core/src/artifacts/registry.d.ts +53 -0
  58. package/dist/core/src/artifacts/registry.js +483 -0
  59. package/dist/core/src/artifacts/registry.js.map +1 -0
  60. package/dist/core/src/commands/registry.d.ts +36 -0
  61. package/dist/core/src/commands/registry.js +539 -0
  62. package/dist/core/src/commands/registry.js.map +1 -0
  63. package/dist/core/src/contracts/index.d.ts +23 -0
  64. package/dist/core/src/contracts/index.js +16 -0
  65. package/dist/core/src/contracts/index.js.map +1 -0
  66. package/dist/core/src/contracts/yaml.d.ts +2 -0
  67. package/dist/core/src/contracts/yaml.js +12 -0
  68. package/dist/core/src/contracts/yaml.js.map +1 -0
  69. package/dist/core/src/contracts.d.ts +23 -0
  70. package/dist/core/src/contracts.js +15 -0
  71. package/dist/core/src/contracts.js.map +1 -0
  72. package/dist/core/src/fs/index.d.ts +4 -0
  73. package/dist/core/src/fs/index.js +28 -0
  74. package/dist/core/src/fs/index.js.map +1 -0
  75. package/dist/core/src/fs.d.ts +4 -0
  76. package/dist/core/src/fs.js +28 -0
  77. package/dist/core/src/fs.js.map +1 -0
  78. package/dist/core/src/initOpenWorkflow.d.ts +7 -0
  79. package/dist/core/src/initOpenWorkflow.js +220 -0
  80. package/dist/core/src/initOpenWorkflow.js.map +1 -0
  81. package/dist/core/src/validateOpenWorkflow.d.ts +5 -0
  82. package/dist/core/src/validateOpenWorkflow.js +145 -0
  83. package/dist/core/src/validateOpenWorkflow.js.map +1 -0
  84. package/dist/core/src/validators/validateOpenWorkflow.d.ts +5 -0
  85. package/dist/core/src/validators/validateOpenWorkflow.js +551 -0
  86. package/dist/core/src/validators/validateOpenWorkflow.js.map +1 -0
  87. package/dist/core/src/validators/validateRepositoryContracts.d.ts +2 -0
  88. package/dist/core/src/validators/validateRepositoryContracts.js +827 -0
  89. package/dist/core/src/validators/validateRepositoryContracts.js.map +1 -0
  90. package/dist/core/src/workflow/initOpenWorkflow.d.ts +7 -0
  91. package/dist/core/src/workflow/initOpenWorkflow.js +182 -0
  92. package/dist/core/src/workflow/initOpenWorkflow.js.map +1 -0
  93. package/dist/core/src/yaml.d.ts +2 -0
  94. package/dist/core/src/yaml.js +12 -0
  95. package/dist/core/src/yaml.js.map +1 -0
  96. package/package.json +55 -0
  97. package/references/artifact-authoring-templates.md +78 -0
  98. package/references/audit-first-discovery-loop.md +85 -0
  99. package/references/contract-graph.md +129 -0
  100. package/references/discovery-artifact-contracts.md +155 -0
  101. package/references/engineering-skill-reference-research.md +204 -0
  102. package/references/npm-cli-architecture.md +63 -0
  103. package/references/runtime-command-surface.md +169 -0
  104. package/schemas/artifact-contracts.schema.json +130 -0
  105. package/schemas/change.schema.json +71 -0
  106. package/schemas/contract-graph.schema.json +80 -0
  107. package/schemas/decision-record.schema.json +92 -0
  108. package/schemas/disclosure-levels.schema.json +66 -0
  109. package/schemas/openworkflow-contract.schema.json +88 -0
  110. package/schemas/product-design.schema.json +356 -0
  111. package/schemas/prototype-evidence.schema.json +325 -0
  112. package/schemas/prototype.schema.json +149 -0
  113. package/schemas/validation-target.schema.json +127 -0
  114. package/schemas/validation.schema.json +123 -0
  115. package/schemas/vision-session.schema.json +78 -0
  116. package/schemas/work-items.schema.json +87 -0
  117. package/schemas/workflow-index.schema.json +70 -0
  118. package/skills/build-prototype/SKILL.md +87 -0
  119. package/skills/build-prototype/agents/openai.yaml +4 -0
  120. package/skills/build-prototype/references/prototype-protocol.md +56 -0
  121. package/skills/build-prototype/scripts/init_prototype.py +260 -0
  122. package/skills/build-team/SKILL.md +292 -0
  123. package/skills/build-team/agents/openai.yaml +4 -0
  124. package/skills/build-team/references/runtime-schema.md +275 -0
  125. package/skills/build-team/references/team-protocol.md +244 -0
  126. package/skills/build-team/scripts/init_team_runtime.py +431 -0
  127. package/skills/build-validation/SKILL.md +81 -0
  128. package/skills/build-validation/agents/openai.yaml +4 -0
  129. package/skills/build-validation/references/validation-protocol.md +51 -0
  130. package/skills/build-validation/scripts/init_validation.py +194 -0
  131. package/skills/build-workflow/SKILL.md +65 -0
  132. package/skills/build-workflow/agents/openai.yaml +4 -0
  133. package/skills/build-workflow/references/workflow-layout.md +57 -0
  134. package/skills/build-workflow/scripts/init_workflow.py +423 -0
  135. package/skills/run-team/SKILL.md +93 -0
  136. package/skills/run-team/agents/openai.yaml +4 -0
  137. package/skills/run-team/references/delegation-and-agent-lifecycle.md +78 -0
  138. package/skills/run-team/references/run-loop.md +73 -0
  139. package/skills/run-team/references/runtime-audit.md +56 -0
  140. package/skills/run-team/references/scope-selection.md +64 -0
  141. package/skills/run-team/scripts/audit_team_runtime.py +173 -0
  142. package/skills/run-team/scripts/init_next_scope.py +304 -0
  143. package/templates/README.md +5 -0
  144. package/templates/codex/README.md +4 -0
  145. package/templates/openworkflow/README.md +4 -0
@@ -0,0 +1,827 @@
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
+ import { statSync } from "node:fs";
3
+ import { basename, join, relative, resolve } from "node:path";
4
+ import { SCHEMA_VERSION } from "../contracts/index.js";
5
+ import { parseYaml } from "../contracts/yaml.js";
6
+ import { isNotFound } from "../fs/index.js";
7
+ const REQUIRED_FILES = [
8
+ "AGENT.md",
9
+ "README.md",
10
+ "LICENSE",
11
+ "build_system_vision.md",
12
+ "references/contract-graph.md",
13
+ "references/npm-cli-architecture.md",
14
+ "references/engineering-skill-reference-research.md",
15
+ "references/audit-first-discovery-loop.md",
16
+ "references/discovery-artifact-contracts.md",
17
+ "references/artifact-authoring-templates.md",
18
+ "references/runtime-command-surface.md",
19
+ "schemas/openworkflow-contract.schema.json",
20
+ "schemas/workflow-index.schema.json",
21
+ "schemas/contract-graph.schema.json",
22
+ "schemas/artifact-contracts.schema.json",
23
+ "schemas/disclosure-levels.schema.json",
24
+ "schemas/vision-session.schema.json",
25
+ "schemas/validation-target.schema.json",
26
+ "schemas/prototype-evidence.schema.json",
27
+ "schemas/decision-record.schema.json",
28
+ "schemas/product-design.schema.json",
29
+ "schemas/change.schema.json",
30
+ "schemas/validation.schema.json",
31
+ "schemas/prototype.schema.json",
32
+ "schemas/work-items.schema.json",
33
+ "package.json",
34
+ "tsconfig.json",
35
+ "packages/cli/src/index.ts",
36
+ "packages/cli/src/commands/init.ts",
37
+ "packages/cli/src/commands/validate.ts",
38
+ "packages/cli/src/commands/sync.ts",
39
+ "packages/cli/src/commands/doctor.ts",
40
+ "packages/cli/src/dev/validateRepositoryContractsCli.ts",
41
+ "packages/cli/src/dev/verifyRuntimeSurface.ts",
42
+ "packages/cli/src/dev/verifyWorkflowE2E.ts",
43
+ "packages/core/src/artifacts/registry.ts",
44
+ "packages/core/src/contracts/index.ts",
45
+ "packages/core/src/contracts/yaml.ts",
46
+ "packages/core/src/commands/registry.ts",
47
+ "packages/core/src/fs/index.ts",
48
+ "packages/core/src/workflow/initOpenWorkflow.ts",
49
+ "packages/core/src/validators/validateOpenWorkflow.ts",
50
+ "packages/core/src/validators/validateRepositoryContracts.ts",
51
+ "packages/core/src/graph/README.md",
52
+ "packages/adapters/codex/src/generateCodexAdapter.ts",
53
+ "packages/adapters/codex/src/generateCommands.ts",
54
+ "packages/adapters/codex/src/generateSkills.ts",
55
+ "packages/adapters/codex/src/doctorCodexAdapter.ts",
56
+ "packages/adapters/codex/src/templates.ts",
57
+ "templates/openworkflow/README.md",
58
+ "templates/codex/README.md",
59
+ "skills/build-validation/SKILL.md",
60
+ "skills/build-validation/scripts/init_validation.py",
61
+ "skills/build-prototype/SKILL.md",
62
+ "skills/build-prototype/scripts/init_prototype.py",
63
+ "skills/build-workflow/SKILL.md",
64
+ "skills/build-workflow/scripts/init_workflow.py",
65
+ "skills/build-team/SKILL.md",
66
+ "skills/run-team/SKILL.md",
67
+ "changes/M01-contract-foundation/CHANGE.yaml",
68
+ "changes/M01-contract-foundation/WORK_ITEMS.yaml",
69
+ "changes/M02-validation-first-prioritization/CHANGE.yaml",
70
+ "changes/M02-validation-first-prioritization/WORK_ITEMS.yaml",
71
+ "changes/M03-prototype-discovery-loop/CHANGE.yaml",
72
+ "changes/M03-prototype-discovery-loop/WORK_ITEMS.yaml",
73
+ "changes/M04-npm-first-cli-architecture/CHANGE.yaml",
74
+ "changes/M04-npm-first-cli-architecture/WORK_ITEMS.yaml",
75
+ "changes/M05-codex-adapter-sync/CHANGE.yaml",
76
+ "changes/M05-codex-adapter-sync/WORK_ITEMS.yaml",
77
+ "changes/M06-repository-architecture-scaffold/CHANGE.yaml",
78
+ "changes/M06-repository-architecture-scaffold/WORK_ITEMS.yaml",
79
+ "changes/M07-command-namespace-contract/CHANGE.yaml",
80
+ "changes/M07-command-namespace-contract/WORK_ITEMS.yaml",
81
+ "changes/M08-engineering-skill-reference-research/CHANGE.yaml",
82
+ "changes/M08-engineering-skill-reference-research/WORK_ITEMS.yaml",
83
+ "changes/M09-audit-first-discovery-loop/CHANGE.yaml",
84
+ "changes/M09-audit-first-discovery-loop/WORK_ITEMS.yaml",
85
+ "changes/M10-discovery-artifact-contracts/CHANGE.yaml",
86
+ "changes/M10-discovery-artifact-contracts/WORK_ITEMS.yaml",
87
+ "changes/M11-artifact-authoring-templates/CHANGE.yaml",
88
+ "changes/M11-artifact-authoring-templates/WORK_ITEMS.yaml",
89
+ "changes/M12-runtime-command-surface/CHANGE.yaml",
90
+ "changes/M12-runtime-command-surface/WORK_ITEMS.yaml",
91
+ "changes/M13-codex-skill-adapter-alignment/CHANGE.yaml",
92
+ "changes/M13-codex-skill-adapter-alignment/WORK_ITEMS.yaml",
93
+ "changes/M14-python-to-typescript-script-migration/CHANGE.yaml",
94
+ "changes/M14-python-to-typescript-script-migration/WORK_ITEMS.yaml",
95
+ "changes/M14-python-to-typescript-script-migration/LEGACY_SKILL_SCRIPTS.md",
96
+ "changes/M15-interactive-vision-design-flow/CHANGE.yaml",
97
+ "changes/M15-interactive-vision-design-flow/WORK_ITEMS.yaml",
98
+ "changes/M16-prototype-creation-skill-upgrade/CHANGE.yaml",
99
+ "changes/M16-prototype-creation-skill-upgrade/WORK_ITEMS.yaml",
100
+ "changes/M17-tune-orchestration-internal-decision/CHANGE.yaml",
101
+ "changes/M17-tune-orchestration-internal-decision/WORK_ITEMS.yaml",
102
+ "changes/M18-e2e-friction-fixes/CHANGE.yaml",
103
+ "changes/M18-e2e-friction-fixes/WORK_ITEMS.yaml",
104
+ "changes/M19-command-display-label-cleanup/CHANGE.yaml",
105
+ "changes/M19-command-display-label-cleanup/WORK_ITEMS.yaml",
106
+ "changes/M20-workflow-e2e-regression/CHANGE.yaml",
107
+ "changes/M20-workflow-e2e-regression/WORK_ITEMS.yaml",
108
+ "changes/M21-npm-package-release-readiness/CHANGE.yaml",
109
+ "changes/M21-npm-package-release-readiness/WORK_ITEMS.yaml",
110
+ ];
111
+ const IGNORED_DIRS = new Set([".git", "node_modules", "dist", "build", "coverage"]);
112
+ const COMMON_REQUIRED = ["schema_version", "contract_id", "contract_type", "title", "status"];
113
+ export async function validateRepositoryContracts(rootInput) {
114
+ const root = resolve(rootInput);
115
+ const errors = [];
116
+ await validateRequiredFiles(root, errors);
117
+ await validateJsonSchemas(root, errors);
118
+ await validateYamlContracts(root, errors);
119
+ return { ok: errors.length === 0, errors };
120
+ }
121
+ async function validateRequiredFiles(root, errors) {
122
+ for (const item of REQUIRED_FILES) {
123
+ if (!(await exists(join(root, item)))) {
124
+ errors.push(`missing required file: ${item}`);
125
+ }
126
+ }
127
+ }
128
+ async function validateJsonSchemas(root, errors) {
129
+ const schemasRoot = join(root, "schemas");
130
+ for (const path of await findFiles(schemasRoot, (entry) => entry.endsWith(".json"))) {
131
+ let data;
132
+ try {
133
+ data = JSON.parse(await readFile(path, "utf8"));
134
+ }
135
+ catch (error) {
136
+ errors.push(`${relative(root, path)} is not valid JSON: ${messageFor(error)}`);
137
+ continue;
138
+ }
139
+ if (!isRecord(data)) {
140
+ errors.push(`${relative(root, path)} must be a JSON object`);
141
+ continue;
142
+ }
143
+ for (const key of ["$schema", "title", "type"]) {
144
+ if (!(key in data)) {
145
+ errors.push(`${relative(root, path)} missing JSON schema key ${key}`);
146
+ }
147
+ }
148
+ }
149
+ }
150
+ async function validateYamlContracts(root, errors) {
151
+ for (const path of await findFiles(root, (entry) => entry.endsWith(".yaml") || entry.endsWith(".yml"))) {
152
+ let data;
153
+ try {
154
+ data = parseYaml(await readFile(path, "utf8"));
155
+ }
156
+ catch (error) {
157
+ errors.push(`${relative(root, path)} is not valid YAML: ${messageFor(error)}`);
158
+ continue;
159
+ }
160
+ validateCommonContract(root, path, data, errors);
161
+ if (isRecord(data)) {
162
+ validateChange(root, path, data, errors);
163
+ validateWorkItems(root, path, data, errors);
164
+ validateValidation(root, path, data, errors);
165
+ validatePrototype(root, path, data, errors);
166
+ validateArtifactContracts(root, path, data, errors);
167
+ validateDisclosureLevels(root, path, data, errors);
168
+ validateActivePointer(root, path, data, errors);
169
+ validateDiscoveryArtifact(root, path, data, errors);
170
+ validateWorkflowIndex(root, path, data, errors);
171
+ validateContractGraph(root, path, data, errors);
172
+ }
173
+ }
174
+ }
175
+ function validateCommonContract(root, path, data, errors) {
176
+ if (!isRecord(data)) {
177
+ return;
178
+ }
179
+ if (!("contract_type" in data) && !("schema_version" in data)) {
180
+ return;
181
+ }
182
+ const label = relative(root, path);
183
+ for (const key of COMMON_REQUIRED) {
184
+ if (!(key in data)) {
185
+ errors.push(`${label} missing contract key ${key}`);
186
+ }
187
+ }
188
+ if (data.schema_version !== SCHEMA_VERSION) {
189
+ errors.push(`${label} must use schema_version ${SCHEMA_VERSION}`);
190
+ }
191
+ for (const listKey of ["depends_on", "produces"]) {
192
+ const value = data[listKey];
193
+ if (Array.isArray(value)) {
194
+ for (const item of value) {
195
+ if (typeof item !== "string") {
196
+ errors.push(`${label} has non-string ${listKey} value`);
197
+ }
198
+ }
199
+ }
200
+ }
201
+ }
202
+ function validateChange(root, path, data, errors) {
203
+ if (basename(path) !== "CHANGE.yaml") {
204
+ return;
205
+ }
206
+ for (const key of ["problem", "goals", "non_goals", "affected_paths", "acceptance", "validation"]) {
207
+ if (!(key in data)) {
208
+ errors.push(`${relative(root, path)} missing change key ${key}`);
209
+ }
210
+ }
211
+ if (data.contract_type !== "change") {
212
+ errors.push(`${relative(root, path)} contract_type must be change`);
213
+ }
214
+ }
215
+ function validateWorkItems(root, path, data, errors) {
216
+ if (basename(path) !== "WORK_ITEMS.yaml") {
217
+ return;
218
+ }
219
+ const label = relative(root, path);
220
+ if (data.contract_type !== "work_items") {
221
+ errors.push(`${label} contract_type must be work_items`);
222
+ }
223
+ const changeContract = data.change_contract;
224
+ if (typeof changeContract !== "string") {
225
+ errors.push(`${label} missing change_contract`);
226
+ }
227
+ else if (!(existsSyncSafe(join(contractRootFor(root, path), changeContract)) || existsSyncSafe(join(root, changeContract)))) {
228
+ errors.push(`${label} references missing change_contract ${changeContract}`);
229
+ }
230
+ const items = data.items;
231
+ if (!Array.isArray(items) || items.length === 0) {
232
+ errors.push(`${label} must contain non-empty items`);
233
+ return;
234
+ }
235
+ const seen = new Set();
236
+ items.forEach((item, index) => {
237
+ if (!isRecord(item)) {
238
+ errors.push(`${label} item ${index} is not a mapping`);
239
+ return;
240
+ }
241
+ const taskId = item.task_id;
242
+ if (typeof taskId !== "string" || taskId.length === 0) {
243
+ errors.push(`${label} item ${index} missing task_id`);
244
+ return;
245
+ }
246
+ if (seen.has(taskId)) {
247
+ errors.push(`${label} duplicate task_id ${taskId}`);
248
+ }
249
+ seen.add(taskId);
250
+ for (const key of ["title", "status", "owned_paths", "acceptance"]) {
251
+ if (!(key in item)) {
252
+ errors.push(`${label} ${taskId} missing ${key}`);
253
+ }
254
+ }
255
+ });
256
+ }
257
+ function validateValidation(root, path, data, errors) {
258
+ if (basename(path) !== "VALIDATION.yaml") {
259
+ return;
260
+ }
261
+ const label = relative(root, path);
262
+ if (data.contract_type !== "validation") {
263
+ errors.push(`${label} contract_type must be validation`);
264
+ }
265
+ validateValidationTarget(label, data, errors);
266
+ for (const key of [
267
+ "core_question",
268
+ "feature_classification",
269
+ "critical_assumptions",
270
+ "prototype_scope",
271
+ "acceptance",
272
+ "decision_options",
273
+ ]) {
274
+ if (!(key in data)) {
275
+ errors.push(`${label} missing validation key ${key}`);
276
+ }
277
+ }
278
+ const decisionOptions = data.decision_options;
279
+ if (Array.isArray(decisionOptions)) {
280
+ const allowed = new Set(["continue", "revise", "pivot", "stop", "needs_more_evidence"]);
281
+ for (const option of decisionOptions) {
282
+ if (typeof option !== "string" || !allowed.has(option)) {
283
+ errors.push(`${label} has invalid decision option ${String(option)}`);
284
+ }
285
+ }
286
+ }
287
+ }
288
+ function validatePrototype(root, path, data, errors) {
289
+ if (basename(path) !== "TODO.yaml" || data.contract_type !== "prototype") {
290
+ return;
291
+ }
292
+ const label = relative(root, path);
293
+ for (const key of [
294
+ "validation_contract",
295
+ "core_question",
296
+ "prototype_scope",
297
+ "todo",
298
+ "acceptance",
299
+ "artifact",
300
+ "decision_handoff",
301
+ ]) {
302
+ if (!(key in data)) {
303
+ errors.push(`${label} missing prototype key ${key}`);
304
+ }
305
+ }
306
+ validatePrototypeScope(label, data.prototype_scope, errors);
307
+ validatePrototypeTodo(label, data.todo, errors);
308
+ const artifact = data.artifact;
309
+ if (isRecord(artifact) && typeof artifact.path === "string" && !existsSyncSafe(join(contractRootFor(root, path), artifact.path))) {
310
+ errors.push(`${label} references missing artifact path ${artifact.path}`);
311
+ }
312
+ const decisionHandoff = data.decision_handoff;
313
+ if (isRecord(decisionHandoff) && decisionHandoff.requires_user_review !== true) {
314
+ errors.push(`${label} decision_handoff.requires_user_review must be true`);
315
+ }
316
+ }
317
+ function validateArtifactContracts(root, path, data, errors) {
318
+ if (basename(path) !== "ARTIFACT_CONTRACTS.yaml") {
319
+ return;
320
+ }
321
+ const label = relative(root, path);
322
+ const artifacts = data.artifacts;
323
+ if (!Array.isArray(artifacts) || artifacts.length === 0) {
324
+ errors.push(`${label} must contain artifacts`);
325
+ return;
326
+ }
327
+ const missing = new Set(["vision_session", "validation_target", "prototype_evidence", "decision_record", "product_design"]);
328
+ artifacts.forEach((artifact, index) => {
329
+ if (!isRecord(artifact)) {
330
+ errors.push(`${label} artifact ${index} is not a mapping`);
331
+ return;
332
+ }
333
+ if (typeof artifact.artifact_type === "string") {
334
+ missing.delete(artifact.artifact_type);
335
+ }
336
+ for (const key of [
337
+ "artifact_type",
338
+ "contract_type",
339
+ "command",
340
+ "source_of_truth_path",
341
+ "template_path",
342
+ "read_policy",
343
+ "active_pointer",
344
+ "required_keys",
345
+ ]) {
346
+ if (!(key in artifact)) {
347
+ errors.push(`${label} artifact ${index} missing ${key}`);
348
+ }
349
+ }
350
+ validateArtifactContractMetadata(label, index, artifact, errors);
351
+ });
352
+ for (const artifactType of [...missing].sort()) {
353
+ errors.push(`${label} missing artifact_type ${artifactType}`);
354
+ }
355
+ }
356
+ function validateArtifactContractMetadata(label, index, artifact, errors) {
357
+ const readPolicy = artifact.read_policy;
358
+ if (isRecord(readPolicy)) {
359
+ for (const key of ["load_by_default", "agent_read_order", "max_yaml_lines", "max_note_lines", "raw_evidence"]) {
360
+ if (!(key in readPolicy)) {
361
+ errors.push(`${label} artifact ${index} read_policy missing ${key}`);
362
+ }
363
+ }
364
+ }
365
+ else {
366
+ errors.push(`${label} artifact ${index} read_policy must be a mapping`);
367
+ }
368
+ const activePointer = artifact.active_pointer;
369
+ if (isRecord(activePointer)) {
370
+ for (const key of ["index_path", "pointer_key", "collection_key", "id_key", "path_key"]) {
371
+ if (!(key in activePointer)) {
372
+ errors.push(`${label} artifact ${index} active_pointer missing ${key}`);
373
+ }
374
+ }
375
+ }
376
+ else {
377
+ errors.push(`${label} artifact ${index} active_pointer must be a mapping`);
378
+ }
379
+ }
380
+ function validateDisclosureLevels(root, path, data, errors) {
381
+ if (basename(path) !== "DISCLOSURE_LEVELS.yaml") {
382
+ return;
383
+ }
384
+ const label = relative(root, path);
385
+ const levels = data.levels;
386
+ if (!Array.isArray(levels) || levels.length < 5) {
387
+ errors.push(`${label} must contain disclosure levels 0 through 4`);
388
+ return;
389
+ }
390
+ const seen = new Set();
391
+ levels.forEach((level, index) => {
392
+ if (!isRecord(level)) {
393
+ errors.push(`${label} level ${index} is not a mapping`);
394
+ return;
395
+ }
396
+ if (typeof level.level === "number") {
397
+ seen.add(level.level);
398
+ }
399
+ for (const key of ["name", "default_for_agents", "purpose", "examples"]) {
400
+ if (!(key in level)) {
401
+ errors.push(`${label} level ${index} missing ${key}`);
402
+ }
403
+ }
404
+ });
405
+ for (let level = 0; level <= 4; level += 1) {
406
+ if (!seen.has(level)) {
407
+ errors.push(`${label} missing disclosure level ${level}`);
408
+ }
409
+ }
410
+ }
411
+ function validateDiscoveryArtifact(root, path, data, errors) {
412
+ if (typeof data.artifact_type !== "string") {
413
+ return;
414
+ }
415
+ const label = relative(root, path);
416
+ const required = artifactRequiredKeys(data.artifact_type);
417
+ if (!required) {
418
+ errors.push(`${label} has unknown artifact_type ${data.artifact_type}`);
419
+ return;
420
+ }
421
+ for (const key of required) {
422
+ if (!(key in data)) {
423
+ errors.push(`${label} missing artifact key ${key}`);
424
+ }
425
+ }
426
+ if (data.artifact_type === "validation_target") {
427
+ validateValidationTarget(label, data, errors);
428
+ }
429
+ else if (data.artifact_type === "prototype_evidence") {
430
+ validatePrototypeEvidence(root, label, data, errors);
431
+ }
432
+ else if (data.artifact_type === "decision_record") {
433
+ validateDecisionRecord(label, data, errors);
434
+ }
435
+ else if (data.artifact_type === "product_design") {
436
+ validateProductDesign(label, data, errors);
437
+ }
438
+ }
439
+ function artifactRequiredKeys(artifactType) {
440
+ const requiredByType = {
441
+ vision_session: ["current_question", "stable_answers", "unresolved_questions", "vision_delta", "handoff"],
442
+ validation_target: [
443
+ "core_question",
444
+ "feature_classification",
445
+ "critical_assumptions",
446
+ "prototype_scope",
447
+ "acceptance",
448
+ "decision_options",
449
+ ],
450
+ prototype_evidence: [
451
+ "validation_target",
452
+ "core_question",
453
+ "prototype_mode",
454
+ "reference_analysis",
455
+ "visual_direction",
456
+ "visual_concept_policy",
457
+ "concept_evidence",
458
+ "prototype_artifact",
459
+ "run",
460
+ "implementation_evidence",
461
+ "observations",
462
+ "evidence",
463
+ "verification",
464
+ "self_critique",
465
+ "known_limits",
466
+ "result",
467
+ "handoff",
468
+ ],
469
+ decision_record: [
470
+ "reviewed_evidence",
471
+ "outcome",
472
+ "rationale",
473
+ "accepted_scope",
474
+ "rejected_scope",
475
+ "revision_scope",
476
+ "next_command",
477
+ "follow_up_questions",
478
+ ],
479
+ product_design: [
480
+ "accepted_prototype_evidence",
481
+ "personas",
482
+ "journey_map",
483
+ "user_stories",
484
+ "feature_matrix",
485
+ "kano_classification",
486
+ "behavior_model",
487
+ "ux_states",
488
+ "scope",
489
+ "open_questions",
490
+ "conditional_packets",
491
+ "spec_readiness",
492
+ ],
493
+ };
494
+ return requiredByType[artifactType] ?? null;
495
+ }
496
+ function validateValidationTarget(label, data, errors) {
497
+ const featureClassification = data.feature_classification;
498
+ if (isRecord(featureClassification)) {
499
+ for (const key of ["existential", "supporting", "later", "out_of_scope"]) {
500
+ if (!(key in featureClassification)) {
501
+ errors.push(`${label} feature_classification missing ${key}`);
502
+ }
503
+ }
504
+ }
505
+ validatePrototypeScope(label, data.prototype_scope, errors);
506
+ }
507
+ function validatePrototypeScope(label, value, errors) {
508
+ if (!isRecord(value)) {
509
+ return;
510
+ }
511
+ for (const key of ["include", "exclude"]) {
512
+ if (!(key in value)) {
513
+ errors.push(`${label} prototype_scope missing ${key}`);
514
+ }
515
+ }
516
+ }
517
+ function validatePrototypeTodo(label, value, errors) {
518
+ if (!Array.isArray(value) || value.length === 0) {
519
+ errors.push(`${label} must contain non-empty todo list`);
520
+ return;
521
+ }
522
+ const seen = new Set();
523
+ value.forEach((item, index) => {
524
+ if (!isRecord(item)) {
525
+ errors.push(`${label} todo item ${index} is not a mapping`);
526
+ return;
527
+ }
528
+ const taskId = item.task_id;
529
+ if (typeof taskId !== "string" || taskId.length === 0) {
530
+ errors.push(`${label} todo item ${index} missing task_id`);
531
+ return;
532
+ }
533
+ if (seen.has(taskId)) {
534
+ errors.push(`${label} duplicate prototype task_id ${taskId}`);
535
+ }
536
+ seen.add(taskId);
537
+ for (const key of ["title", "status", "acceptance"]) {
538
+ if (!(key in item)) {
539
+ errors.push(`${label} ${taskId} missing ${key}`);
540
+ }
541
+ }
542
+ });
543
+ }
544
+ function validatePrototypeEvidence(root, label, data, errors) {
545
+ if (!["visual", "interaction", "technical_feasibility", "3d_material", "workflow", "data_logic"].includes(String(data.prototype_mode))) {
546
+ errors.push(`${label} has invalid prototype_mode ${String(data.prototype_mode)}`);
547
+ }
548
+ for (const key of ["reference_analysis", "concept_evidence", "implementation_evidence", "known_limits"]) {
549
+ if (key in data && !Array.isArray(data[key])) {
550
+ errors.push(`${label} ${key} must be an array`);
551
+ }
552
+ }
553
+ if ("visual_direction" in data && !isRecord(data.visual_direction)) {
554
+ errors.push(`${label} visual_direction must be a mapping`);
555
+ }
556
+ validateVisualConceptPolicy(label, data, errors);
557
+ if ("verification" in data && !isRecord(data.verification)) {
558
+ errors.push(`${label} verification must be a mapping`);
559
+ }
560
+ if ("self_critique" in data && !isRecord(data.self_critique)) {
561
+ errors.push(`${label} self_critique must be a mapping`);
562
+ }
563
+ else {
564
+ validateSelfCritique(label, data.self_critique, errors);
565
+ }
566
+ const prototypeArtifact = data.prototype_artifact;
567
+ if (isRecord(prototypeArtifact)) {
568
+ for (const key of ["path", "type"]) {
569
+ if (!(key in prototypeArtifact)) {
570
+ errors.push(`${label} prototype_artifact missing ${key}`);
571
+ }
572
+ }
573
+ validateLocalRef(root, label, "prototype_artifact.path", prototypeArtifact.path, errors);
574
+ }
575
+ validateEvidenceRefs(root, label, data, errors);
576
+ if (!["pass", "fail", "unclear", "not_reviewed"].includes(String(data.result))) {
577
+ errors.push(`${label} has invalid result ${String(data.result)}`);
578
+ }
579
+ }
580
+ function validateVisualConceptPolicy(label, data, errors) {
581
+ const policy = data.visual_concept_policy;
582
+ if (!isRecord(policy)) {
583
+ errors.push(`${label} visual_concept_policy must be a mapping`);
584
+ return;
585
+ }
586
+ const imageGeneration = policy.image_generation;
587
+ if (!["generated", "skipped_by_user", "not_applicable"].includes(String(imageGeneration))) {
588
+ errors.push(`${label} visual_concept_policy.image_generation has invalid value ${String(imageGeneration)}`);
589
+ return;
590
+ }
591
+ if (imageGeneration === "skipped_by_user" && !nonEmptyString(policy.skip_reason)) {
592
+ errors.push(`${label} visual_concept_policy.skip_reason is required when image generation is skipped`);
593
+ }
594
+ if (["visual", "interaction", "3d_material"].includes(String(data.prototype_mode))) {
595
+ if (imageGeneration === "not_applicable") {
596
+ errors.push(`${label} visual_concept_policy.image_generation cannot be not_applicable for ${String(data.prototype_mode)} prototypes`);
597
+ }
598
+ if (imageGeneration === "generated" && (!Array.isArray(data.concept_evidence) || data.concept_evidence.length === 0)) {
599
+ errors.push(`${label} concept_evidence is required when image generation is generated`);
600
+ }
601
+ }
602
+ }
603
+ function validateSelfCritique(label, value, errors) {
604
+ if (!isRecord(value)) {
605
+ return;
606
+ }
607
+ for (const key of ["philosophy", "hierarchy", "execution", "specificity", "restraint", "accessibility", "responsive_behavior"]) {
608
+ if (!nonEmptyString(value[key])) {
609
+ errors.push(`${label} self_critique.${key} must be a non-empty string`);
610
+ }
611
+ }
612
+ if (!Array.isArray(value.repairs)) {
613
+ errors.push(`${label} self_critique.repairs must be an array`);
614
+ }
615
+ }
616
+ function validateEvidenceRefs(root, label, data, errors) {
617
+ for (const key of ["reference_analysis", "concept_evidence", "implementation_evidence", "evidence"]) {
618
+ const items = data[key];
619
+ if (!Array.isArray(items)) {
620
+ continue;
621
+ }
622
+ items.forEach((item, index) => {
623
+ if (isRecord(item)) {
624
+ validateLocalRef(root, label, `${key}[${index}].ref`, item.ref, errors);
625
+ }
626
+ });
627
+ }
628
+ const verification = data.verification;
629
+ if (!isRecord(verification)) {
630
+ return;
631
+ }
632
+ for (const key of ["screenshots", "logs"]) {
633
+ const refs = verification[key];
634
+ if (!Array.isArray(refs)) {
635
+ continue;
636
+ }
637
+ refs.forEach((ref, index) => validateLocalRef(root, label, `verification.${key}[${index}]`, ref, errors));
638
+ }
639
+ }
640
+ function validateLocalRef(root, label, field, value, errors) {
641
+ if (typeof value !== "string" || value.length === 0 || isExternalRef(value)) {
642
+ return;
643
+ }
644
+ const resolved = resolve(root, value);
645
+ if (resolved !== root && !resolved.startsWith(`${root}/`)) {
646
+ errors.push(`${label} ${field} references path outside root: ${value}`);
647
+ return;
648
+ }
649
+ if (!existsSyncSafe(resolved)) {
650
+ errors.push(`${label} ${field} references missing path ${value}`);
651
+ }
652
+ }
653
+ function isExternalRef(value) {
654
+ return /^[a-z][a-z0-9+.-]*:/i.test(value);
655
+ }
656
+ function nonEmptyString(value) {
657
+ return typeof value === "string" && value.trim().length > 0;
658
+ }
659
+ function validateDecisionRecord(label, data, errors) {
660
+ if (!["continue", "revise", "pivot", "stop", "needs_more_evidence"].includes(String(data.outcome))) {
661
+ errors.push(`${label} has invalid outcome ${String(data.outcome)}`);
662
+ }
663
+ }
664
+ function validateProductDesign(label, data, errors) {
665
+ const specReadiness = data.spec_readiness;
666
+ if (isRecord(specReadiness)) {
667
+ for (const key of ["ready", "next_command"]) {
668
+ if (!(key in specReadiness)) {
669
+ errors.push(`${label} spec_readiness missing ${key}`);
670
+ }
671
+ }
672
+ }
673
+ }
674
+ function validateActivePointer(root, path, data, errors) {
675
+ const rule = [
676
+ pointerRule("VISION_CONTRACT.yaml", "current_session", "sessions", "session_id", "path"),
677
+ pointerRule("VALIDATION_INDEX.yaml", "current_validation", "validations", "validation_id", "path"),
678
+ pointerRule("PROTOTYPE_INDEX.yaml", "current_prototype", "prototypes", "prototype_id", "path"),
679
+ pointerRule("DECISION_INDEX.yaml", "current_decision", "decisions", "decision_id", "path"),
680
+ pointerRule("DESIGN_INDEX.yaml", "current_design", "designs", "design_id", "path"),
681
+ ].find((item) => basename(path) === item.fileName);
682
+ if (!rule) {
683
+ return;
684
+ }
685
+ const label = relative(root, path);
686
+ const pointer = data[rule.pointerKey];
687
+ if (pointer === null || pointer === undefined) {
688
+ return;
689
+ }
690
+ if (typeof pointer !== "string" || pointer.length === 0) {
691
+ errors.push(`${label} ${rule.pointerKey} must be null or a non-empty string`);
692
+ return;
693
+ }
694
+ const collection = data[rule.collectionKey];
695
+ if (!Array.isArray(collection)) {
696
+ errors.push(`${label} ${rule.collectionKey} must be a list when ${rule.pointerKey} is set`);
697
+ return;
698
+ }
699
+ const entry = collection.find((item) => isRecord(item) && item[rule.idKey] === pointer);
700
+ if (!isRecord(entry)) {
701
+ errors.push(`${label} ${rule.pointerKey} references missing ${rule.collectionKey} entry ${pointer}`);
702
+ return;
703
+ }
704
+ const artifactPath = entry[rule.pathKey];
705
+ if (typeof artifactPath !== "string" || artifactPath.length === 0) {
706
+ errors.push(`${label} ${pointer} missing ${rule.pathKey}`);
707
+ return;
708
+ }
709
+ if (!existsSyncSafe(join(contractRootFor(root, path), artifactPath))) {
710
+ errors.push(`${label} ${rule.pointerKey} references missing artifact path ${artifactPath}`);
711
+ }
712
+ }
713
+ function validateWorkflowIndex(root, path, data, errors) {
714
+ if (basename(path) !== "WORKFLOW_INDEX.yaml") {
715
+ return;
716
+ }
717
+ const label = relative(root, path);
718
+ const contracts = data.contracts;
719
+ if (!Array.isArray(contracts) || contracts.length === 0) {
720
+ errors.push(`${label} must contain contracts`);
721
+ return;
722
+ }
723
+ const projectRoot = workflowRootFor(path);
724
+ for (const entry of contracts) {
725
+ if (!isRecord(entry)) {
726
+ errors.push(`${label} has non-mapping contract entry`);
727
+ continue;
728
+ }
729
+ const entryPath = entry.path;
730
+ if (typeof entryPath === "string" && !existsSyncSafe(join(projectRoot, entryPath))) {
731
+ errors.push(`${label} references missing contract path ${entryPath}`);
732
+ }
733
+ }
734
+ }
735
+ function validateContractGraph(root, path, data, errors) {
736
+ if (basename(path) !== "CONTRACT_GRAPH.yaml") {
737
+ return;
738
+ }
739
+ const label = relative(root, path);
740
+ const nodes = data.nodes;
741
+ const edges = data.edges;
742
+ if (!Array.isArray(nodes) || !Array.isArray(edges)) {
743
+ errors.push(`${label} must contain nodes and edges lists`);
744
+ return;
745
+ }
746
+ const nodeIds = new Set(nodes.flatMap((node) => (isRecord(node) && typeof node.contract_id === "string" ? [node.contract_id] : [])));
747
+ for (const edge of edges) {
748
+ if (!isRecord(edge)) {
749
+ errors.push(`${label} has non-mapping edge`);
750
+ continue;
751
+ }
752
+ for (const key of ["from", "to"]) {
753
+ const value = edge[key];
754
+ if (typeof value !== "string" || !nodeIds.has(value)) {
755
+ errors.push(`${label} edge ${key} references missing node ${String(value)}`);
756
+ }
757
+ }
758
+ }
759
+ }
760
+ function pointerRule(fileName, pointerKey, collectionKey, idKey, pathKey) {
761
+ return { fileName, pointerKey, collectionKey, idKey, pathKey };
762
+ }
763
+ function contractRootFor(root, path) {
764
+ const parts = path.split("/");
765
+ const codexIndex = parts.indexOf(".codex");
766
+ if (codexIndex <= 0) {
767
+ return root;
768
+ }
769
+ return parts.slice(0, codexIndex).join("/");
770
+ }
771
+ function workflowRootFor(path) {
772
+ return resolve(path, "..", "..", "..");
773
+ }
774
+ async function findFiles(root, predicate) {
775
+ if (!(await exists(root))) {
776
+ return [];
777
+ }
778
+ const found = [];
779
+ async function walk(dir) {
780
+ const entries = await readdir(dir, { withFileTypes: true });
781
+ for (const entry of entries) {
782
+ if (entry.isDirectory() && IGNORED_DIRS.has(entry.name)) {
783
+ continue;
784
+ }
785
+ const path = join(dir, entry.name);
786
+ if (entry.isDirectory()) {
787
+ await walk(path);
788
+ }
789
+ else if (entry.isFile() && predicate(entry.name)) {
790
+ found.push(path);
791
+ }
792
+ }
793
+ }
794
+ await walk(root);
795
+ return found.sort();
796
+ }
797
+ async function exists(path) {
798
+ try {
799
+ await stat(path);
800
+ return true;
801
+ }
802
+ catch (error) {
803
+ if (isNotFound(error)) {
804
+ return false;
805
+ }
806
+ throw error;
807
+ }
808
+ }
809
+ function existsSyncSafe(path) {
810
+ try {
811
+ statSync(path);
812
+ return true;
813
+ }
814
+ catch (error) {
815
+ if (isNotFound(error)) {
816
+ return false;
817
+ }
818
+ throw error;
819
+ }
820
+ }
821
+ function isRecord(value) {
822
+ return typeof value === "object" && value !== null && !Array.isArray(value);
823
+ }
824
+ function messageFor(error) {
825
+ return error instanceof Error ? error.message : String(error);
826
+ }
827
+ //# sourceMappingURL=validateRepositoryContracts.js.map