@thebackstoryis/engineering-with-ai 0.2.9

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 (334) hide show
  1. package/Docs/README.md +50 -0
  2. package/Docs/adoption/consultancy-and-multi-project-rollout.md +135 -0
  3. package/Docs/adoption/non-technical-team-guide.md +126 -0
  4. package/Docs/archaeology-technology-and-hosting-discovery.md +212 -0
  5. package/Docs/blast-radius-and-impact-routing-guide.md +325 -0
  6. package/Docs/blueprints/internal-blueprint-catalogue.md +146 -0
  7. package/Docs/blueprints/maintaining-organisation-blueprints.md +154 -0
  8. package/Docs/blueprints/validation-and-troubleshooting.md +168 -0
  9. package/Docs/cli-reference.md +113 -0
  10. package/Docs/completed-phase-evidence-amendments.md +74 -0
  11. package/Docs/consultancy-network-rollout-control-plane-guide.md +202 -0
  12. package/Docs/context-aware-delivery-companion-guide.md +198 -0
  13. package/Docs/context-aware-delivery-companion-user-guide.md +184 -0
  14. package/Docs/context-management-and-token-efficiency.md +113 -0
  15. package/Docs/design-systems/design-system-implementation-guide.md +85 -0
  16. package/Docs/design-systems/design-system-pack-authoring-guide.md +95 -0
  17. package/Docs/design-systems/design-system-review-guide.md +51 -0
  18. package/Docs/design-systems/design-system-user-guide.md +96 -0
  19. package/Docs/design-systems/product-owner-guide.md +49 -0
  20. package/Docs/designing-organisation-blueprint-packs.md +384 -0
  21. package/Docs/developer-delivery-guide.md +224 -0
  22. package/Docs/error-reporting-guide.md +110 -0
  23. package/Docs/error-reporting-provider-guide.md +49 -0
  24. package/Docs/examples/error-report-adapter.md +70 -0
  25. package/Docs/examples/meeting-review.md +76 -0
  26. package/Docs/examples/minimal-design-system.md +67 -0
  27. package/Docs/examples/prototype-review-inputs.md +175 -0
  28. package/Docs/examples/reproducible-archaeology-depth-example.md +144 -0
  29. package/Docs/examples/test-scenario-input.md +68 -0
  30. package/Docs/examples/worked-examples.md +147 -0
  31. package/Docs/existing-project-onboarding-guide.md +214 -0
  32. package/Docs/explanation/core-concepts.md +26 -0
  33. package/Docs/explanation/delivery-workflow.md +48 -0
  34. package/Docs/governance/governance-team-guide.md +139 -0
  35. package/Docs/governed-starter-project-materialisation-guide.md +284 -0
  36. package/Docs/guide-catalogue.md +117 -0
  37. package/Docs/guided-discovery-facilitator-guide.md +172 -0
  38. package/Docs/guided-intent-workspace-guide.md +109 -0
  39. package/Docs/guided-phase-evidence-drafting-guide.md +119 -0
  40. package/Docs/human-approval-and-assurance-guide.md +146 -0
  41. package/Docs/knowledge-proposals-implementer-guide.md +106 -0
  42. package/Docs/knowledge-proposals-user-guide.md +247 -0
  43. package/Docs/maintainers/context-benchmarks.md +29 -0
  44. package/Docs/maintainers/contributing.md +58 -0
  45. package/Docs/maintainers/evidence-depth-acceptance.md +72 -0
  46. package/Docs/maintainers/verification-walkthroughs.md +104 -0
  47. package/Docs/meeting-evidence-implementer-guide.md +132 -0
  48. package/Docs/meeting-evidence-user-guide.md +200 -0
  49. package/Docs/operations/dashboard-and-delivery-state.md +153 -0
  50. package/Docs/operations/dashboard-configuration.md +87 -0
  51. package/Docs/operations/installation-updating-and-entitlements.md +135 -0
  52. package/Docs/operations/premium-personas-setup.md +76 -0
  53. package/Docs/operations/troubleshooting-and-recovery.md +205 -0
  54. package/Docs/organisation-rollout-guide.md +142 -0
  55. package/Docs/persona-entitlement-provider-guide.md +199 -0
  56. package/Docs/persona-guided-prototype-iteration.md +129 -0
  57. package/Docs/personas/organisation-specific-personas.md +103 -0
  58. package/Docs/personas/persona-authoring-cookbook.md +176 -0
  59. package/Docs/personas/persona-engagement-ui.md +133 -0
  60. package/Docs/personas/persona-governance.md +118 -0
  61. package/Docs/platform-export-analysis-guide.md +336 -0
  62. package/Docs/policies/governance-owner-guide.md +36 -0
  63. package/Docs/policies/implementation-guide.md +42 -0
  64. package/Docs/policies/organisation-policy-design-gates.md +58 -0
  65. package/Docs/policies/policy-pack-authoring-guide.md +108 -0
  66. package/Docs/policies/product-owner-guide.md +43 -0
  67. package/Docs/policies/technical-owner-guide.md +37 -0
  68. package/Docs/product-owner-guide.md +327 -0
  69. package/Docs/project-portfolio-orchestration-guide.md +199 -0
  70. package/Docs/quality/manual-qa-and-acceptance.md +162 -0
  71. package/Docs/quality/persona-driven-test-scenarios.md +172 -0
  72. package/Docs/quality/reproducible-archaeology-depth-review-checklist.md +89 -0
  73. package/Docs/reference/capabilities-and-project-layout.md +678 -0
  74. package/Docs/reference/cli-and-configuration.md +398 -0
  75. package/Docs/reference/contributions-api.md +23 -0
  76. package/Docs/reference/security-adapter-authoring.md +81 -0
  77. package/Docs/reference/starter-adapter-authoring.md +74 -0
  78. package/Docs/repository-source-map-guide.md +381 -0
  79. package/Docs/reproducible-archaeology-and-discovery-depth.md +292 -0
  80. package/Docs/screen-prototype-creation-guide.md +324 -0
  81. package/Docs/security-validation-guide.md +353 -0
  82. package/Docs/solution-readiness-review-guide.md +123 -0
  83. package/Docs/standards/project-standards-authoring.md +157 -0
  84. package/Docs/team-hub-guide.md +162 -0
  85. package/Docs/team-hub-resource-registry-guide.md +167 -0
  86. package/Docs/tutorials/first-delivery.md +83 -0
  87. package/Docs/tutorials/first-session.md +62 -0
  88. package/Docs/using-lifecycle-hooks.md +381 -0
  89. package/Docs/working-with-personas.md +274 -0
  90. package/LICENSE +165 -0
  91. package/README.md +96 -0
  92. package/agents-src/claude/ewai-security-reviewer.md +15 -0
  93. package/bin/ewai +5 -0
  94. package/config/archaeology-record-families.yaml +59 -0
  95. package/config/delivery-artifacts.yaml +121 -0
  96. package/config/delivery-stages.yaml +77 -0
  97. package/config/design-system.schema.json +46 -0
  98. package/config/error-reporting.schema.json +79 -0
  99. package/config/evidence-depth.schema.json +53 -0
  100. package/config/intent.schema.json +90 -0
  101. package/config/knowledge-proposals-proposal.schema.json +34 -0
  102. package/config/lifecycle-event.schema.json +68 -0
  103. package/config/lifecycle-handler.schema.json +45 -0
  104. package/config/lifecycle-hook-ack.schema.json +19 -0
  105. package/config/meeting-evidence-candidate.schema.json +102 -0
  106. package/config/organisation-policy.schema.json +137 -0
  107. package/config/pack.schema.json +250 -0
  108. package/config/persona-pack.schema.json +21 -0
  109. package/config/persona.schema.json +17 -0
  110. package/config/policy-evaluation.schema.json +77 -0
  111. package/config/policy-facts.schema.json +140 -0
  112. package/config/portfolio.schema.json +68 -0
  113. package/config/project.schema.json +313 -0
  114. package/config/prototype-iteration.schema.json +128 -0
  115. package/config/rollout.schema.json +87 -0
  116. package/config/security-adapter.schema.json +31 -0
  117. package/config/security-scan-request.schema.json +64 -0
  118. package/config/security-scan-response.schema.json +52 -0
  119. package/config/security-validation-policy.schema.json +74 -0
  120. package/config/starter-source-acknowledgement.schema.json +13 -0
  121. package/config/starter-source-adapter.schema.json +38 -0
  122. package/config/starter-source-request.schema.json +61 -0
  123. package/package.json +77 -0
  124. package/packs/core/pack.yaml +7 -0
  125. package/packs/design-systems/default/experience-promise.md +9 -0
  126. package/packs/design-systems/default/intentional-review.md +10 -0
  127. package/packs/design-systems/default/interaction-and-entry.md +9 -0
  128. package/packs/design-systems/default/meaningful-content-and-states.md +9 -0
  129. package/packs/design-systems/default/pack.yaml +44 -0
  130. package/packs/design-systems/default/principles.md +10 -0
  131. package/packs/personas/core/pack.yaml +7 -0
  132. package/packs/personas/core/personas/archaeologist.md +37 -0
  133. package/packs/personas/core/personas/end-user.md +17 -0
  134. package/packs/personas/core/personas/maintainer.md +17 -0
  135. package/packs/personas/core/personas/operator.md +17 -0
  136. package/packs/personas/core/personas/specs-knowledge-curator.md +35 -0
  137. package/packs/technologies/laravel/pack.yaml +30 -0
  138. package/packs/technologies/laravel-nuxt/pack.yaml +30 -0
  139. package/packs/technologies/nuxt/pack.yaml +30 -0
  140. package/packs/technologies/power-platform/pack.yaml +31 -0
  141. package/packs/technologies/salesforce/pack.yaml +25 -0
  142. package/public/app.js +4896 -0
  143. package/public/apple-touch-icon.png +0 -0
  144. package/public/assets/backstory-icon.png +0 -0
  145. package/public/dashboard-navigation.js +98 -0
  146. package/public/favicon-16.png +0 -0
  147. package/public/favicon-32.png +0 -0
  148. package/public/favicon.ico +0 -0
  149. package/public/index.html +789 -0
  150. package/public/styles.css +2693 -0
  151. package/public/team-hub/app.js +202 -0
  152. package/public/team-hub/index.html +79 -0
  153. package/public/team-hub/styles.css +90 -0
  154. package/scripts/publication-check.mjs +140 -0
  155. package/scripts/setup.mjs +21 -0
  156. package/skills-src/ewai-archaeology/SKILL.md +334 -0
  157. package/skills-src/ewai-archaeology/agents/openai.yaml +4 -0
  158. package/skills-src/ewai-archaeology/references/archaeology-contract.md +201 -0
  159. package/skills-src/ewai-archaeology/references/lifecycle-reconstruction.md +177 -0
  160. package/skills-src/ewai-archaeology/references/maximum-detail-reconstruction.md +97 -0
  161. package/skills-src/ewai-archaeology/references/model-routing.md +26 -0
  162. package/skills-src/ewai-architecture/SKILL.md +108 -0
  163. package/skills-src/ewai-architecture/agents/openai.yaml +4 -0
  164. package/skills-src/ewai-architecture/references/architecture-contract.md +176 -0
  165. package/skills-src/ewai-context/SKILL.md +68 -0
  166. package/skills-src/ewai-context/agents/openai.yaml +4 -0
  167. package/skills-src/ewai-context-import/SKILL.md +118 -0
  168. package/skills-src/ewai-context-import/agents/openai.yaml +4 -0
  169. package/skills-src/ewai-context-import/references/context-import-contract.md +106 -0
  170. package/skills-src/ewai-dashboard-configuration/SKILL.md +20 -0
  171. package/skills-src/ewai-deliver/SKILL.md +122 -0
  172. package/skills-src/ewai-deliver/references/delivery-evidence.md +92 -0
  173. package/skills-src/ewai-deliver/references/phase-routing.md +31 -0
  174. package/skills-src/ewai-design-system-apply/SKILL.md +27 -0
  175. package/skills-src/ewai-design-system-apply/agents/openai.yaml +4 -0
  176. package/skills-src/ewai-design-system-apply/references/application-contract.md +36 -0
  177. package/skills-src/ewai-design-system-author/SKILL.md +28 -0
  178. package/skills-src/ewai-design-system-author/agents/openai.yaml +4 -0
  179. package/skills-src/ewai-design-system-author/references/authoring-contract.md +38 -0
  180. package/skills-src/ewai-design-system-review/SKILL.md +26 -0
  181. package/skills-src/ewai-design-system-review/agents/openai.yaml +4 -0
  182. package/skills-src/ewai-design-system-review/references/review-contract.md +40 -0
  183. package/skills-src/ewai-error-reporting/SKILL.md +46 -0
  184. package/skills-src/ewai-error-reporting/agents/openai.yaml +4 -0
  185. package/skills-src/ewai-error-reporting/references/provider-contract.md +74 -0
  186. package/skills-src/ewai-evidence-depth/SKILL.md +72 -0
  187. package/skills-src/ewai-evidence-depth/agents/openai.yaml +4 -0
  188. package/skills-src/ewai-evidence-depth/references/evidence-depth-contract.md +127 -0
  189. package/skills-src/ewai-intent/SKILL.md +68 -0
  190. package/skills-src/ewai-intent/agents/openai.yaml +4 -0
  191. package/skills-src/ewai-intent/references/intent-contract.md +42 -0
  192. package/skills-src/ewai-knowledge-proposals/SKILL.md +105 -0
  193. package/skills-src/ewai-knowledge-proposals/agents/openai.yaml +4 -0
  194. package/skills-src/ewai-knowledge-proposals/references/proposal-contract.md +59 -0
  195. package/skills-src/ewai-meeting-evidence/SKILL.md +106 -0
  196. package/skills-src/ewai-meeting-evidence/agents/openai.yaml +4 -0
  197. package/skills-src/ewai-meeting-evidence/references/candidate-contract.md +64 -0
  198. package/skills-src/ewai-organisation-policy/SKILL.md +62 -0
  199. package/skills-src/ewai-organisation-policy/agents/openai.yaml +4 -0
  200. package/skills-src/ewai-organisation-policy/references/policy-contract.md +94 -0
  201. package/skills-src/ewai-palace-housekeeping/SKILL.md +55 -0
  202. package/skills-src/ewai-palace-housekeeping/agents/openai.yaml +4 -0
  203. package/skills-src/ewai-persona-entitlement/SKILL.md +60 -0
  204. package/skills-src/ewai-persona-entitlement/agents/openai.yaml +4 -0
  205. package/skills-src/ewai-phase-evidence/SKILL.md +79 -0
  206. package/skills-src/ewai-phase-evidence/agents/openai.yaml +4 -0
  207. package/skills-src/ewai-pipeline/SKILL.md +130 -0
  208. package/skills-src/ewai-pipeline/agents/openai.yaml +4 -0
  209. package/skills-src/ewai-pipeline/references/cli.md +86 -0
  210. package/skills-src/ewai-pipeline/references/specs-contract.md +16 -0
  211. package/skills-src/ewai-portfolio/SKILL.md +70 -0
  212. package/skills-src/ewai-portfolio/agents/openai.yaml +4 -0
  213. package/skills-src/ewai-portfolio/references/portfolio-contract.md +67 -0
  214. package/skills-src/ewai-project-discovery/SKILL.md +95 -0
  215. package/skills-src/ewai-project-discovery/agents/openai.yaml +4 -0
  216. package/skills-src/ewai-project-discovery/references/discovery-contract.md +34 -0
  217. package/skills-src/ewai-prototype-iteration/SKILL.md +30 -0
  218. package/skills-src/ewai-prototype-iteration/agents/openai.yaml +4 -0
  219. package/skills-src/ewai-prototype-iteration/references/review-contract.md +49 -0
  220. package/skills-src/ewai-retro/SKILL.md +48 -0
  221. package/skills-src/ewai-retro/agents/openai.yaml +4 -0
  222. package/skills-src/ewai-retro/references/asset-routing.md +14 -0
  223. package/skills-src/ewai-rollout/SKILL.md +74 -0
  224. package/skills-src/ewai-rollout/agents/openai.yaml +4 -0
  225. package/skills-src/ewai-rollout/references/rollout-contract.md +74 -0
  226. package/skills-src/ewai-shape-intents/SKILL.md +84 -0
  227. package/skills-src/ewai-shape-intents/agents/openai.yaml +4 -0
  228. package/skills-src/ewai-shape-intents/references/intent-mapping-contract.md +109 -0
  229. package/skills-src/ewai-solution-readiness/SKILL.md +55 -0
  230. package/skills-src/ewai-solution-readiness/agents/openai.yaml +4 -0
  231. package/skills-src/ewai-standards-check/SKILL.md +93 -0
  232. package/skills-src/ewai-standards-check/agents/openai.yaml +4 -0
  233. package/skills-src/ewai-standards-check/references/report-contract.md +116 -0
  234. package/skills-src/ewai-test-scenarios/SKILL.md +94 -0
  235. package/skills-src/ewai-test-scenarios/agents/openai.yaml +4 -0
  236. package/skills-src/ewai-test-scenarios/references/scenario-contract.md +88 -0
  237. package/src/afk-worker.mjs +16 -0
  238. package/src/archaeology.mjs +1333 -0
  239. package/src/checkin.mjs +261 -0
  240. package/src/cli.mjs +2427 -0
  241. package/src/companion-guidance.mjs +257 -0
  242. package/src/companion-opening.mjs +62 -0
  243. package/src/companion.mjs +256 -0
  244. package/src/context.mjs +210 -0
  245. package/src/dashboard-preferences.mjs +80 -0
  246. package/src/delivery-artifacts.mjs +204 -0
  247. package/src/delivery-documents.mjs +248 -0
  248. package/src/delivery-gates.mjs +317 -0
  249. package/src/delivery.mjs +1433 -0
  250. package/src/design-system-application.mjs +291 -0
  251. package/src/design-system-authoring.mjs +101 -0
  252. package/src/design-systems.mjs +466 -0
  253. package/src/discovery.mjs +1314 -0
  254. package/src/error-reporting.mjs +323 -0
  255. package/src/evidence-depth.mjs +543 -0
  256. package/src/execution-state.mjs +243 -0
  257. package/src/install.mjs +166 -0
  258. package/src/intent-dependencies.mjs +117 -0
  259. package/src/intent-maps.mjs +402 -0
  260. package/src/intents.mjs +747 -0
  261. package/src/knowledge-proposals.mjs +717 -0
  262. package/src/launcher.mjs +51 -0
  263. package/src/meeting-evidence.mjs +703 -0
  264. package/src/network-rollout.mjs +386 -0
  265. package/src/organisation-blueprints.mjs +438 -0
  266. package/src/organisation-policies.mjs +448 -0
  267. package/src/packs.mjs +44 -0
  268. package/src/paths.mjs +62 -0
  269. package/src/persona-entitlements.mjs +438 -0
  270. package/src/persona-licence-config.mjs +98 -0
  271. package/src/persona-website-provider.mjs +134 -0
  272. package/src/persona-zip.mjs +87 -0
  273. package/src/personas.mjs +159 -0
  274. package/src/platform-metadata-analysis.mjs +314 -0
  275. package/src/policy-design-gates.mjs +623 -0
  276. package/src/policy-gate-integration.mjs +318 -0
  277. package/src/portfolio.mjs +509 -0
  278. package/src/power-platform-source-map.mjs +190 -0
  279. package/src/project.mjs +449 -0
  280. package/src/prototype-iterations.mjs +730 -0
  281. package/src/repository-source-map.mjs +603 -0
  282. package/src/runtime/afk-conductor.mjs +973 -0
  283. package/src/runtime/context-assembly.mjs +457 -0
  284. package/src/runtime/context-benchmarks.mjs +115 -0
  285. package/src/runtime/dashboard-actions.mjs +109 -0
  286. package/src/runtime/dashboard-handoffs.mjs +149 -0
  287. package/src/runtime/dashboard-server.mjs +1272 -0
  288. package/src/runtime/dashboard.mjs +197 -0
  289. package/src/runtime/database.mjs +789 -0
  290. package/src/runtime/error-reporting.mjs +581 -0
  291. package/src/runtime/evidence-depth-workspace.mjs +412 -0
  292. package/src/runtime/execution-leases.mjs +299 -0
  293. package/src/runtime/guided-discovery.mjs +350 -0
  294. package/src/runtime/guided-intents.mjs +517 -0
  295. package/src/runtime/impact-analysis.mjs +535 -0
  296. package/src/runtime/intents.mjs +222 -0
  297. package/src/runtime/knowledge.mjs +86 -0
  298. package/src/runtime/lifecycle-hooks.mjs +1239 -0
  299. package/src/runtime/mcp-config.mjs +110 -0
  300. package/src/runtime/mcp-server.mjs +1885 -0
  301. package/src/runtime/palace.mjs +362 -0
  302. package/src/runtime/paths.mjs +58 -0
  303. package/src/runtime/persona-engagement.mjs +255 -0
  304. package/src/runtime/phase-contributions.mjs +594 -0
  305. package/src/runtime/policy-workspace.mjs +170 -0
  306. package/src/runtime/prototype-iterations.mjs +235 -0
  307. package/src/runtime/provider-adapters.mjs +163 -0
  308. package/src/runtime/repository-index.mjs +838 -0
  309. package/src/runtime/runs.mjs +185 -0
  310. package/src/runtime/security-validation.mjs +1230 -0
  311. package/src/runtime/starter-materialisation.mjs +1155 -0
  312. package/src/runtime/team-hub-client.mjs +479 -0
  313. package/src/runtime/team-hub-database.mjs +288 -0
  314. package/src/runtime/team-hub-server.mjs +191 -0
  315. package/src/runtime/team-hub.mjs +110 -0
  316. package/src/runtime/tree-sitter-index.mjs +390 -0
  317. package/src/runtime/version.mjs +1 -0
  318. package/src/runtime/work.mjs +633 -0
  319. package/src/salesforce-source-map.mjs +212 -0
  320. package/src/security-validation-config.mjs +224 -0
  321. package/src/solution-readiness.mjs +620 -0
  322. package/src/starter-materialisation-contract.mjs +407 -0
  323. package/src/task-graph.mjs +544 -0
  324. package/src/team-hub-resources.mjs +239 -0
  325. package/src/team-hub.mjs +242 -0
  326. package/src/test-scenarios.mjs +622 -0
  327. package/src/validation-config.mjs +289 -0
  328. package/templates/SPECS/1.Scope/personas/registry.yaml +12 -0
  329. package/templates/SPECS/5.Strategy/patterns/context-packet.md +119 -0
  330. package/templates/SPECS/6.Build/_tracker-template.md +16 -0
  331. package/templates/SPECS/pipeline.yaml +62 -0
  332. package/templates/discovery-answers.yaml +86 -0
  333. package/templates/intent-body.md +21 -0
  334. package/tests/fixtures/context-benchmarks.json +9 -0
@@ -0,0 +1,323 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+
3
+ const inputFields = new Set([
4
+ 'capability', 'errorCode', 'command', 'ewaiVersion', 'nodeVersion', 'osClass',
5
+ 'installationSource', 'title', 'expected', 'actual', 'reproductionSteps',
6
+ ]);
7
+ const revisionFields = new Set(['title', 'expected', 'actual', 'reproductionSteps']);
8
+ const osClasses = new Set(['darwin', 'linux', 'win32', 'other']);
9
+ const installationSources = new Set(['npm', 'git', 'local', 'unknown']);
10
+ const maxAttachmentBytes = 5 * 1024 * 1024;
11
+ const maxPackageBytes = 25 * 1024 * 1024;
12
+ const safeAttachmentPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$/;
13
+ const absolutePathPattern = /(?:^|\s)(?:\/(?:Users|home|private|var|etc|opt|srv|mnt|Volumes)\/|[A-Za-z]:\\)/;
14
+ const credentialPattern = /(?:Bearer\s+[A-Za-z0-9._~+\/-]{8,}|sk-[A-Za-z0-9_-]{8,}|(?:token|password|secret|api[_-]?key)\s*[:=])/i;
15
+
16
+ export const ERROR_REPORT_EXCLUDED_CLASSES = Object.freeze([
17
+ 'absolute-paths',
18
+ 'credentials',
19
+ 'environment-values',
20
+ 'persona-bodies',
21
+ 'prompts-and-responses',
22
+ 'raw-logs',
23
+ 'repository-names',
24
+ 'source-and-specs',
25
+ ]);
26
+
27
+ const excludedClassByKey = Object.freeze({
28
+ absolutePath: 'absolute-paths',
29
+ paths: 'absolute-paths',
30
+ credential: 'credentials',
31
+ credentials: 'credentials',
32
+ environment: 'environment-values',
33
+ environmentValues: 'environment-values',
34
+ persona: 'persona-bodies',
35
+ personaBody: 'persona-bodies',
36
+ prompt: 'prompts-and-responses',
37
+ response: 'prompts-and-responses',
38
+ rawLog: 'raw-logs',
39
+ logs: 'raw-logs',
40
+ repositoryName: 'repository-names',
41
+ repositoryNames: 'repository-names',
42
+ source: 'source-and-specs',
43
+ specs: 'source-and-specs',
44
+ });
45
+
46
+ function digest(bytes) {
47
+ return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
48
+ }
49
+
50
+ function stableValue(value) {
51
+ if (Array.isArray(value)) return value.map(stableValue);
52
+ if (!value || typeof value !== 'object') return value;
53
+ return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stableValue(value[key])]));
54
+ }
55
+
56
+ export function canonicalJson(value) {
57
+ return `${JSON.stringify(stableValue(value), null, 2)}\n`;
58
+ }
59
+
60
+ function strictFields(value, fields, label) {
61
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${label} must be an object.`);
62
+ for (const key of Object.keys(value)) {
63
+ if (!fields.has(key)) throw new Error(`${label} contains unknown field: ${key}`);
64
+ }
65
+ }
66
+
67
+ function boundedText(value, label, max, options = {}) {
68
+ const text = String(value ?? '').trim();
69
+ if ((!text && options.required !== false) || text.length > max) throw new Error(`${label} is missing or exceeds ${max} characters.`);
70
+ if (text.includes('\0') || credentialPattern.test(text)) throw new Error(`${label} contains unsafe credential-shaped content.`);
71
+ if (absolutePathPattern.test(text)) throw new Error(`${label} contains an absolute path.`);
72
+ return text;
73
+ }
74
+
75
+ function normaliseDescription(input) {
76
+ if (!Array.isArray(input.reproductionSteps) || input.reproductionSteps.length > 50) {
77
+ throw new Error('Reproduction steps must be a bounded array of at most 50 entries.');
78
+ }
79
+ return {
80
+ title: boundedText(input.title, 'Report title', 500),
81
+ expected: boundedText(input.expected, 'Expected behaviour', 4000, { required: false }),
82
+ actual: boundedText(input.actual, 'Actual behaviour', 4000, { required: false }),
83
+ reproductionSteps: input.reproductionSteps.map((step) => boundedText(step, 'Reproduction step', 1000)),
84
+ };
85
+ }
86
+
87
+ function normaliseDiagnostics(input) {
88
+ const capability = String(input.capability ?? '').trim();
89
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(capability)) throw new Error('Capability must be lower kebab-case.');
90
+ const errorCode = String(input.errorCode ?? '').trim();
91
+ if (!/^[A-Z][A-Z0-9-]{2,79}$/.test(errorCode)) throw new Error('Public error code is invalid.');
92
+ const command = String(input.command ?? '').trim();
93
+ if (!/^ewai(?: [a-z0-9][a-z0-9:-]*){0,4}$/.test(command) || command.length > 160) throw new Error('Command identity is invalid or unsafe.');
94
+ const ewaiVersion = String(input.ewaiVersion ?? '').trim();
95
+ const nodeVersion = String(input.nodeVersion ?? '').trim().replace(/^v/, '');
96
+ if (!/^[0-9]+(?:\.[0-9]+){0,2}(?:[-+][0-9A-Za-z.-]+)?$/.test(ewaiVersion)) throw new Error('EWAI version is invalid.');
97
+ if (!/^[0-9]+(?:\.[0-9]+){0,2}$/.test(nodeVersion)) throw new Error('Node version is invalid.');
98
+ const osClass = String(input.osClass ?? '').trim();
99
+ if (!osClasses.has(osClass)) throw new Error('OS class is invalid.');
100
+ const installationSource = String(input.installationSource ?? '').trim();
101
+ if (!installationSources.has(installationSource)) throw new Error('Installation source is invalid.');
102
+ return { capability, errorCode, command, ewaiVersion, nodeVersion, osClass, installationSource };
103
+ }
104
+
105
+ function redactionSummary(excluded = {}) {
106
+ if (!excluded || typeof excluded !== 'object' || Array.isArray(excluded)) throw new Error('Excluded diagnostics must be an object.');
107
+ const counts = {};
108
+ for (const [key, value] of Object.entries(excluded)) {
109
+ const className = excludedClassByKey[key];
110
+ if (!className) throw new Error(`Excluded diagnostics contain unknown class: ${key}`);
111
+ const count = Array.isArray(value) ? value.length : value && typeof value === 'object' ? Object.keys(value).length : value === undefined || value === null || value === '' ? 0 : 1;
112
+ counts[className] = (counts[className] ?? 0) + count;
113
+ }
114
+ const classes = Object.keys(counts).filter((key) => counts[key] > 0).sort();
115
+ return {
116
+ schema: 'ewai.error-report-redactions/v1',
117
+ classes,
118
+ counts: Object.fromEntries(classes.map((name) => [name, counts[name]])),
119
+ };
120
+ }
121
+
122
+ function reportId(value) {
123
+ const id = String(value ?? `report_${randomUUID().replaceAll('-', '')}`).trim();
124
+ if (!/^report_[a-z0-9_]{3,80}$/.test(id)) throw new Error('Report id is invalid.');
125
+ return id;
126
+ }
127
+
128
+ function isoTimestamp(value) {
129
+ const text = String(value ?? new Date().toISOString());
130
+ if (!/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(text) || Number.isNaN(Date.parse(text))) throw new Error('Report timestamp is invalid.');
131
+ return text;
132
+ }
133
+
134
+ export function createErrorReportDraft(input, options = {}) {
135
+ strictFields(input, inputFields, 'Error report input');
136
+ const at = isoTimestamp(options.at);
137
+ return {
138
+ schema: 'ewai.error-report/v1',
139
+ id: reportId(options.id),
140
+ status: 'draft',
141
+ revision: 1,
142
+ createdAt: at,
143
+ updatedAt: at,
144
+ diagnostics: normaliseDiagnostics(input),
145
+ description: normaliseDescription(input),
146
+ redactions: redactionSummary(options.excluded),
147
+ attachments: [],
148
+ };
149
+ }
150
+
151
+ export function errorReportIdentity(report) {
152
+ const identity = {
153
+ schema: report.schema,
154
+ id: report.id,
155
+ revision: report.revision,
156
+ diagnostics: report.diagnostics,
157
+ description: report.description,
158
+ redactions: report.redactions,
159
+ attachments: report.attachments,
160
+ };
161
+ return digest(Buffer.from(canonicalJson(identity)));
162
+ }
163
+
164
+ export function reviseErrorReport(report, changes, options = {}) {
165
+ if (report.status !== 'draft') throw new Error('A finalised error report is immutable; create a new revision instead.');
166
+ strictFields(changes, revisionFields, 'Error report revision');
167
+ const description = normaliseDescription({ ...report.description, ...changes });
168
+ return {
169
+ ...report,
170
+ revision: report.revision + 1,
171
+ updatedAt: isoTimestamp(options.at),
172
+ description,
173
+ package: undefined,
174
+ };
175
+ }
176
+
177
+ function attachmentMembers(attachments = []) {
178
+ if (!Array.isArray(attachments) || attachments.length > 20) throw new Error('Attachments must be a bounded array of at most 20 entries.');
179
+ let total = 0;
180
+ const seen = new Set();
181
+ return attachments.map((attachment) => {
182
+ if (!attachment || typeof attachment !== 'object' || Array.isArray(attachment)) throw new Error('Attachment must be an object.');
183
+ for (const key of Object.keys(attachment)) if (!['name', 'bytes'].includes(key)) throw new Error(`Attachment contains unknown field: ${key}`);
184
+ const name = String(attachment.name ?? '').trim();
185
+ if (!safeAttachmentPattern.test(name) || name === '.' || name === '..' || seen.has(name.toLowerCase())) throw new Error('Attachment name is unsafe or duplicated.');
186
+ seen.add(name.toLowerCase());
187
+ const bytes = Buffer.isBuffer(attachment.bytes) ? attachment.bytes : Buffer.from(attachment.bytes ?? '');
188
+ if (bytes.length > maxAttachmentBytes) throw new Error('Attachment is too large.');
189
+ total += bytes.length;
190
+ if (total > maxPackageBytes) throw new Error('Attachment package is too large.');
191
+ return { name: `attachments/${name}`, bytes };
192
+ }).sort((left, right) => left.name.localeCompare(right.name));
193
+ }
194
+
195
+ function summaryMarkdown(report) {
196
+ const steps = report.description.reproductionSteps.length
197
+ ? report.description.reproductionSteps.map((step, index) => `${index + 1}. ${step}`).join('\n')
198
+ : 'No reproduction steps supplied.';
199
+ return `# ${report.description.title}\n\n## Expected behaviour\n\n${report.description.expected || 'Not supplied.'}\n\n## Actual behaviour\n\n${report.description.actual || 'Not supplied.'}\n\n## Reproduction steps\n\n${steps}\n`;
200
+ }
201
+
202
+ let crcTable;
203
+ function crc32(bytes) {
204
+ if (!crcTable) {
205
+ crcTable = Array.from({ length: 256 }, (_, value) => {
206
+ let crc = value;
207
+ for (let bit = 0; bit < 8; bit += 1) crc = (crc & 1) ? (0xedb88320 ^ (crc >>> 1)) : (crc >>> 1);
208
+ return crc >>> 0;
209
+ });
210
+ }
211
+ let crc = 0xffffffff;
212
+ for (const byte of bytes) crc = crcTable[(crc ^ byte) & 0xff] ^ (crc >>> 8);
213
+ return (crc ^ 0xffffffff) >>> 0;
214
+ }
215
+
216
+ function storedZip(members) {
217
+ const localParts = [];
218
+ const centralParts = [];
219
+ let offset = 0;
220
+ for (const member of members) {
221
+ const name = Buffer.from(member.name, 'utf8');
222
+ const bytes = member.bytes;
223
+ const crc = crc32(bytes);
224
+ const local = Buffer.alloc(30);
225
+ local.writeUInt32LE(0x04034b50, 0);
226
+ local.writeUInt16LE(20, 4);
227
+ local.writeUInt16LE(0x0800, 6);
228
+ local.writeUInt16LE(0, 8);
229
+ local.writeUInt16LE(0, 10);
230
+ local.writeUInt16LE(33, 12);
231
+ local.writeUInt32LE(crc, 14);
232
+ local.writeUInt32LE(bytes.length, 18);
233
+ local.writeUInt32LE(bytes.length, 22);
234
+ local.writeUInt16LE(name.length, 26);
235
+ local.writeUInt16LE(0, 28);
236
+ localParts.push(local, name, bytes);
237
+
238
+ const central = Buffer.alloc(46);
239
+ central.writeUInt32LE(0x02014b50, 0);
240
+ central.writeUInt16LE(20, 4);
241
+ central.writeUInt16LE(20, 6);
242
+ central.writeUInt16LE(0x0800, 8);
243
+ central.writeUInt16LE(0, 10);
244
+ central.writeUInt16LE(0, 12);
245
+ central.writeUInt16LE(33, 14);
246
+ central.writeUInt32LE(crc, 16);
247
+ central.writeUInt32LE(bytes.length, 20);
248
+ central.writeUInt32LE(bytes.length, 24);
249
+ central.writeUInt16LE(name.length, 28);
250
+ central.writeUInt16LE(0, 30);
251
+ central.writeUInt16LE(0, 32);
252
+ central.writeUInt16LE(0, 34);
253
+ central.writeUInt16LE(0, 36);
254
+ central.writeUInt32LE(0, 38);
255
+ central.writeUInt32LE(offset, 42);
256
+ centralParts.push(central, name);
257
+ offset += local.length + name.length + bytes.length;
258
+ }
259
+ const centralBytes = Buffer.concat(centralParts);
260
+ const end = Buffer.alloc(22);
261
+ end.writeUInt32LE(0x06054b50, 0);
262
+ end.writeUInt16LE(0, 4);
263
+ end.writeUInt16LE(0, 6);
264
+ end.writeUInt16LE(members.length, 8);
265
+ end.writeUInt16LE(members.length, 10);
266
+ end.writeUInt32LE(centralBytes.length, 12);
267
+ end.writeUInt32LE(offset, 16);
268
+ end.writeUInt16LE(0, 20);
269
+ return Buffer.concat([...localParts, centralBytes, end]);
270
+ }
271
+
272
+ export function buildErrorReportPackage(report, options = {}) {
273
+ if (!report || report.schema !== 'ewai.error-report/v1') throw new Error('A valid EWAI error report is required.');
274
+ const diagnostics = Buffer.from(canonicalJson({
275
+ schema: 'ewai.error-report-diagnostics/v1',
276
+ reportId: report.id,
277
+ revision: report.revision,
278
+ diagnostics: report.diagnostics,
279
+ }));
280
+ const redactions = Buffer.from(canonicalJson(report.redactions));
281
+ const summary = Buffer.from(summaryMarkdown(report));
282
+ const members = [
283
+ { name: 'diagnostics.json', bytes: diagnostics },
284
+ { name: 'redaction-report.json', bytes: redactions },
285
+ { name: 'summary.md', bytes: summary },
286
+ ...attachmentMembers(options.attachments),
287
+ ];
288
+ const memberRecords = members.map((member) => ({ name: member.name, size: member.bytes.length, digest: digest(member.bytes) }));
289
+ const packageDigest = digest(Buffer.from(canonicalJson(memberRecords)));
290
+ const manifest = {
291
+ schema: 'ewai.error-report-package/v1',
292
+ reportId: report.id,
293
+ revision: report.revision,
294
+ packageDigest,
295
+ members: memberRecords,
296
+ };
297
+ const archiveMembers = [...members, { name: 'manifest.json', bytes: Buffer.from(canonicalJson(manifest)) }];
298
+ const bytes = storedZip(archiveMembers);
299
+ if (bytes.length > maxPackageBytes) throw new Error('Final error-report package is too large.');
300
+ return { schema: 'ewai.error-report-package-result/v1', bytes, manifest, packageDigest, archiveDigest: digest(bytes), size: bytes.length, memberCount: archiveMembers.length };
301
+ }
302
+
303
+ export function finaliseErrorReport(report, options = {}) {
304
+ if (report.status === 'finalised') throw new Error('Error report is already finalised.');
305
+ if (report.status !== 'draft') throw new Error('Only a draft error report can be finalised.');
306
+ const packaged = buildErrorReportPackage(report, options);
307
+ const attachmentRecords = packaged.manifest.members.filter(({ name }) => name.startsWith('attachments/')).map(({ name, size, digest: memberDigest }) => ({
308
+ name: name.slice('attachments/'.length), size, digest: memberDigest,
309
+ }));
310
+ const finalised = {
311
+ ...report,
312
+ status: 'finalised',
313
+ updatedAt: isoTimestamp(options.at),
314
+ attachments: attachmentRecords,
315
+ package: {
316
+ packageDigest: packaged.packageDigest,
317
+ archiveDigest: packaged.archiveDigest,
318
+ size: packaged.size,
319
+ memberCount: packaged.memberCount,
320
+ },
321
+ };
322
+ return { report: finalised, package: packaged };
323
+ }