freeharness 0.4.1

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 (375) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +108 -0
  3. package/README.md +134 -0
  4. package/canonical/HARVEST.yaml +858 -0
  5. package/canonical/PROVENANCE.yaml +740 -0
  6. package/canonical/agents/README.md +95 -0
  7. package/canonical/agents/agentic-architect.md +18 -0
  8. package/canonical/agents/database-reviewer.md +41 -0
  9. package/canonical/agents/explorer-ai-engineer-analyst.md +65 -0
  10. package/canonical/agents/pr-reviewer.md +96 -0
  11. package/canonical/agents/python-reviewer.md +55 -0
  12. package/canonical/agents/report-formatter.md +19 -0
  13. package/canonical/agents/security-reviewer.md +53 -0
  14. package/canonical/agents/test-writer.md +34 -0
  15. package/canonical/commands/fh-context.md +37 -0
  16. package/canonical/evals/promptfoo.redteam.yaml +108 -0
  17. package/canonical/hooks/cost-prices.json +14 -0
  18. package/canonical/hooks/freeharness-auto-memory.mjs +158 -0
  19. package/canonical/hooks/freeharness-config-guard.mjs +162 -0
  20. package/canonical/hooks/freeharness-context-monitor.mjs +198 -0
  21. package/canonical/hooks/freeharness-converge.mjs +227 -0
  22. package/canonical/hooks/freeharness-cost-tracker.mjs +1027 -0
  23. package/canonical/hooks/freeharness-memory-guard.mjs +57 -0
  24. package/canonical/hooks/freeharness-output-pruner.mjs +333 -0
  25. package/canonical/hooks/freeharness-precompact.mjs +323 -0
  26. package/canonical/hooks/freeharness-repeat-tool.mjs +208 -0
  27. package/canonical/hooks/freeharness-security-guidance.mjs +164 -0
  28. package/canonical/hooks/freeharness-session-start +583 -0
  29. package/canonical/hooks/hooks.auto-memory.claude-code.json +16 -0
  30. package/canonical/hooks/hooks.claude-code.json +17 -0
  31. package/canonical/hooks/hooks.config-guard.claude-code.json +16 -0
  32. package/canonical/hooks/hooks.context-monitor.claude-code.json +15 -0
  33. package/canonical/hooks/hooks.converge.claude-code.json +15 -0
  34. package/canonical/hooks/hooks.cost-tracker.claude-code.json +37 -0
  35. package/canonical/hooks/hooks.memory-guard.claude-code.json +16 -0
  36. package/canonical/hooks/hooks.output-pruner.claude-code.json +16 -0
  37. package/canonical/hooks/hooks.precompact.claude-code.json +15 -0
  38. package/canonical/hooks/hooks.repeat-tool.claude-code.json +25 -0
  39. package/canonical/hooks/hooks.security-guidance.claude-code.json +16 -0
  40. package/canonical/mcp/servers.json +20 -0
  41. package/canonical/openspec/config.base.yaml +89 -0
  42. package/canonical/openspec/schema.spec-driven.yaml +277 -0
  43. package/canonical/openspec/templates/data-contract.md +36 -0
  44. package/canonical/openspec/templates/design.md +84 -0
  45. package/canonical/openspec/templates/eval-plan.md +33 -0
  46. package/canonical/openspec/templates/follow-ups.md +2 -0
  47. package/canonical/openspec/templates/proposal.md +45 -0
  48. package/canonical/openspec/templates/spec.md +42 -0
  49. package/canonical/openspec/templates/tasks.md +38 -0
  50. package/canonical/profiles/local-llamacpp.LOCAL-MODELS.md +47 -0
  51. package/canonical/profiles/local-llamacpp.json +27 -0
  52. package/canonical/profiles/local-ollama.json +20 -0
  53. package/canonical/profiles/mcp.json +91 -0
  54. package/canonical/rules/CLAUDE.md +78 -0
  55. package/canonical/rules/project-CLAUDE.template.md +62 -0
  56. package/canonical/rules/routing.md +20 -0
  57. package/canonical/rules/safety.md +41 -0
  58. package/canonical/settings/settings.cache-hygiene.claude-code.json +5 -0
  59. package/canonical/skills/agent-evaluation/SKILL.md +102 -0
  60. package/canonical/skills/agent-evaluation/assets/evaluation_report_template.md +206 -0
  61. package/canonical/skills/agent-evaluation/evals/cases.yaml +106 -0
  62. package/canonical/skills/agent-evaluation/references/dataset-preparation.md +351 -0
  63. package/canonical/skills/agent-evaluation/references/scorers-constraints.md +165 -0
  64. package/canonical/skills/agent-evaluation/references/scorers.md +431 -0
  65. package/canonical/skills/agent-evaluation/references/setup-guide.md +252 -0
  66. package/canonical/skills/agent-evaluation/references/tracing-integration.md +164 -0
  67. package/canonical/skills/agent-evaluation/references/troubleshooting.md +514 -0
  68. package/canonical/skills/agent-evaluation/scripts/analyze_results.py +462 -0
  69. package/canonical/skills/agent-evaluation/scripts/create_dataset_template.py +382 -0
  70. package/canonical/skills/agent-evaluation/scripts/list_datasets.py +273 -0
  71. package/canonical/skills/agent-evaluation/scripts/run_evaluation_template.py +309 -0
  72. package/canonical/skills/agent-evaluation/scripts/setup_mlflow.py +353 -0
  73. package/canonical/skills/agent-evaluation/scripts/utils/__init__.py +27 -0
  74. package/canonical/skills/agent-evaluation/scripts/utils/env_validation.py +123 -0
  75. package/canonical/skills/agent-evaluation/scripts/utils/tracing_utils.py +108 -0
  76. package/canonical/skills/agent-evaluation/scripts/validate_agent_tracing.py +148 -0
  77. package/canonical/skills/agent-evaluation/scripts/validate_auth.py +240 -0
  78. package/canonical/skills/agent-evaluation/scripts/validate_environment.py +185 -0
  79. package/canonical/skills/agent-evaluation/scripts/validate_tracing_runtime.py +318 -0
  80. package/canonical/skills/agentic-architecture/SKILL.md +41 -0
  81. package/canonical/skills/agentic-architecture/evals/cases.yaml +94 -0
  82. package/canonical/skills/agentic-architecture/reference/context-engineering.md +75 -0
  83. package/canonical/skills/agentic-architecture/reference/patterns.md +76 -0
  84. package/canonical/skills/agentic-architecture/reference/reliability-observability.md +94 -0
  85. package/canonical/skills/agentic-architecture/reference/review-framework.md +59 -0
  86. package/canonical/skills/code-review/SKILL.md +52 -0
  87. package/canonical/skills/code-review/evals/cases.yaml +197 -0
  88. package/canonical/skills/git-workflow/SKILL.md +41 -0
  89. package/canonical/skills/git-workflow/evals/cases.yaml +92 -0
  90. package/canonical/skills/local-code/SKILL.md +24 -0
  91. package/canonical/skills/local-code/evals/cases.yaml +85 -0
  92. package/canonical/skills/local-code/scripts/query_llama.py +68 -0
  93. package/canonical/skills/report-formatting/SKILL.md +62 -0
  94. package/canonical/skills/report-formatting/evals/cases.yaml +83 -0
  95. package/canonical/skills/report-formatting/reference/ARCHITECTURE.md +135 -0
  96. package/canonical/skills/report-formatting/reference/HELPERS.md +120 -0
  97. package/canonical/skills/report-formatting/reference/PPTX.md +136 -0
  98. package/canonical/skills/report-formatting/reference/RELEASE.md +99 -0
  99. package/canonical/skills/report-formatting/reference/TEMPLATES.md +48 -0
  100. package/canonical/skills/report-formatting/reference/authoring.md +66 -0
  101. package/canonical/skills/report-formatting/scripts/architecture-template.md +271 -0
  102. package/canonical/skills/report-formatting/scripts/assets/claro-logo.png +0 -0
  103. package/canonical/skills/report-formatting/scripts/assets/claro-wordmark.svg +1 -0
  104. package/canonical/skills/report-formatting/scripts/build-architecture.js +57 -0
  105. package/canonical/skills/report-formatting/scripts/build-md-claro.js +224 -0
  106. package/canonical/skills/report-formatting/scripts/build-release.js +51 -0
  107. package/canonical/skills/report-formatting/scripts/check-env.js +58 -0
  108. package/canonical/skills/report-formatting/scripts/docmodel.js +283 -0
  109. package/canonical/skills/report-formatting/scripts/example-build.js +119 -0
  110. package/canonical/skills/report-formatting/scripts/example_build_ArchitectureReview_docx.js +195 -0
  111. package/canonical/skills/report-formatting/scripts/example_build_ExecutiveReport_docx.js +114 -0
  112. package/canonical/skills/report-formatting/scripts/package.json +17 -0
  113. package/canonical/skills/report-formatting/scripts/pptx/example_build_StatusReport_pptx.py +223 -0
  114. package/canonical/skills/report-formatting/scripts/pptx/example_build_WeeklyStatus_pptx.py +245 -0
  115. package/canonical/skills/report-formatting/scripts/pptx/pptx_office.py +144 -0
  116. package/canonical/skills/report-formatting/scripts/pptx/requirements.txt +7 -0
  117. package/canonical/skills/report-formatting/scripts/pptx/status_report_blocks.py +193 -0
  118. package/canonical/skills/report-formatting/scripts/pptx/theme_claro_pptx.py +473 -0
  119. package/canonical/skills/report-formatting/scripts/release-template.md +80 -0
  120. package/canonical/skills/report-formatting/scripts/render-mermaid.js +105 -0
  121. package/canonical/skills/report-formatting/scripts/theme-claro.js +403 -0
  122. package/canonical/skills/subagent-driven-development/SKILL.md +60 -0
  123. package/canonical/skills/subagent-driven-development/evals/cases.yaml +208 -0
  124. package/canonical/skills/subagent-driven-development/reference/brief.md +91 -0
  125. package/canonical/skills/subagent-driven-development/reference/handoff.md +118 -0
  126. package/canonical/skills/subagent-driven-development/scripts/validate-handoff.mjs +850 -0
  127. package/canonical/skills/systematic-debugging/SKILL.md +44 -0
  128. package/canonical/skills/systematic-debugging/evals/cases.yaml +90 -0
  129. package/canonical/skills/test-driven-development/SKILL.md +42 -0
  130. package/canonical/skills/test-driven-development/evals/cases.yaml +86 -0
  131. package/canonical/skills/test-driven-development/reference/writing-good-tests.md +52 -0
  132. package/canonical/skills/verification-before-completion/SKILL.md +53 -0
  133. package/canonical/skills/verification-before-completion/evals/cases.yaml +107 -0
  134. package/dist/adapters/content/language-lint.d.ts +46 -0
  135. package/dist/adapters/content/language-lint.js +191 -0
  136. package/dist/adapters/harness/claude-code.d.ts +57 -0
  137. package/dist/adapters/harness/claude-code.js +385 -0
  138. package/dist/adapters/harness/index.d.ts +3 -0
  139. package/dist/adapters/harness/index.js +17 -0
  140. package/dist/adapters/harness/opencode.d.ts +7 -0
  141. package/dist/adapters/harness/opencode.js +166 -0
  142. package/dist/adapters/harness/plugin.d.ts +22 -0
  143. package/dist/adapters/harness/plugin.js +257 -0
  144. package/dist/adapters/memory/doctor.d.ts +480 -0
  145. package/dist/adapters/memory/doctor.js +1217 -0
  146. package/dist/adapters/memory/vendored.d.ts +150 -0
  147. package/dist/adapters/memory/vendored.js +487 -0
  148. package/dist/adapters/package/node.d.ts +9 -0
  149. package/dist/adapters/package/node.js +20 -0
  150. package/dist/adapters/prompt/readline.d.ts +19 -0
  151. package/dist/adapters/prompt/readline.js +53 -0
  152. package/dist/adapters/sync/diff.d.ts +43 -0
  153. package/dist/adapters/sync/diff.js +380 -0
  154. package/dist/cli/cleanup.d.ts +86 -0
  155. package/dist/cli/cleanup.js +382 -0
  156. package/dist/cli/cost.d.ts +304 -0
  157. package/dist/cli/cost.js +501 -0
  158. package/dist/cli/doctor.d.ts +205 -0
  159. package/dist/cli/doctor.js +654 -0
  160. package/dist/cli/executor.d.ts +5 -0
  161. package/dist/cli/executor.js +48 -0
  162. package/dist/cli/plugin-validate.d.ts +37 -0
  163. package/dist/cli/plugin-validate.js +256 -0
  164. package/dist/cli/prefix.d.ts +68 -0
  165. package/dist/cli/prefix.js +218 -0
  166. package/dist/cli/profile.d.ts +170 -0
  167. package/dist/cli/profile.js +285 -0
  168. package/dist/cli/runner.d.ts +10 -0
  169. package/dist/cli/runner.js +27 -0
  170. package/dist/cli/uninstall.d.ts +65 -0
  171. package/dist/cli/uninstall.js +147 -0
  172. package/dist/index.d.ts +8 -0
  173. package/dist/index.js +989 -0
  174. package/dist/infra/dogfood.d.ts +31 -0
  175. package/dist/infra/dogfood.js +51 -0
  176. package/dist/infra/fsutil.d.ts +40 -0
  177. package/dist/infra/fsutil.js +143 -0
  178. package/dist/infra/manifest.d.ts +76 -0
  179. package/dist/infra/manifest.js +92 -0
  180. package/dist/infra/paths.d.ts +19 -0
  181. package/dist/infra/paths.js +74 -0
  182. package/dist/infra/routing.d.ts +4 -0
  183. package/dist/infra/routing.js +7 -0
  184. package/node_modules/@freeharness/core/dist/context.d.ts +30 -0
  185. package/node_modules/@freeharness/core/dist/context.js +1 -0
  186. package/node_modules/@freeharness/core/dist/index.d.ts +5 -0
  187. package/node_modules/@freeharness/core/dist/index.js +6 -0
  188. package/node_modules/@freeharness/core/dist/planner.d.ts +13 -0
  189. package/node_modules/@freeharness/core/dist/planner.js +18 -0
  190. package/node_modules/@freeharness/core/dist/ports.d.ts +90 -0
  191. package/node_modules/@freeharness/core/dist/ports.js +1 -0
  192. package/node_modules/@freeharness/core/dist/registry.d.ts +41 -0
  193. package/node_modules/@freeharness/core/dist/registry.js +124 -0
  194. package/node_modules/@freeharness/core/dist/tiers.d.ts +30 -0
  195. package/node_modules/@freeharness/core/dist/tiers.js +99 -0
  196. package/node_modules/@freeharness/core/package.json +34 -0
  197. package/node_modules/@freeharness/sdd/PROVENANCE.yaml +175 -0
  198. package/node_modules/@freeharness/sdd/dist/src/bin/openspec.d.ts +2 -0
  199. package/node_modules/@freeharness/sdd/dist/src/bin/openspec.js +166 -0
  200. package/node_modules/@freeharness/sdd/dist/src/index.d.ts +14 -0
  201. package/node_modules/@freeharness/sdd/dist/src/index.js +11 -0
  202. package/node_modules/@freeharness/sdd/dist/src/init.d.ts +39 -0
  203. package/node_modules/@freeharness/sdd/dist/src/init.js +190 -0
  204. package/node_modules/@freeharness/sdd/dist/src/root-resolver.d.ts +8 -0
  205. package/node_modules/@freeharness/sdd/dist/src/root-resolver.js +32 -0
  206. package/node_modules/@freeharness/sdd/dist/src/shim/archive.d.ts +81 -0
  207. package/node_modules/@freeharness/sdd/dist/src/shim/archive.js +483 -0
  208. package/node_modules/@freeharness/sdd/dist/src/shim/context.d.ts +4 -0
  209. package/node_modules/@freeharness/sdd/dist/src/shim/context.js +48 -0
  210. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.d.ts +57 -0
  211. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.js +279 -0
  212. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.d.ts +67 -0
  213. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.js +460 -0
  214. package/node_modules/@freeharness/sdd/dist/src/shim/list.d.ts +5 -0
  215. package/node_modules/@freeharness/sdd/dist/src/shim/list.js +95 -0
  216. package/node_modules/@freeharness/sdd/dist/src/shim/new-change.d.ts +6 -0
  217. package/node_modules/@freeharness/sdd/dist/src/shim/new-change.js +150 -0
  218. package/node_modules/@freeharness/sdd/dist/src/shim/schemas.d.ts +4 -0
  219. package/node_modules/@freeharness/sdd/dist/src/shim/schemas.js +23 -0
  220. package/node_modules/@freeharness/sdd/dist/src/shim/shared.d.ts +56 -0
  221. package/node_modules/@freeharness/sdd/dist/src/shim/shared.js +140 -0
  222. package/node_modules/@freeharness/sdd/dist/src/shim/status.d.ts +8 -0
  223. package/node_modules/@freeharness/sdd/dist/src/shim/status.js +85 -0
  224. package/node_modules/@freeharness/sdd/dist/src/shim/validate.d.ts +6 -0
  225. package/node_modules/@freeharness/sdd/dist/src/shim/validate.js +229 -0
  226. package/node_modules/@freeharness/sdd/dist/src/validate-change.d.ts +40 -0
  227. package/node_modules/@freeharness/sdd/dist/src/validate-change.js +114 -0
  228. package/node_modules/@freeharness/sdd/dist/src/validate.d.ts +24 -0
  229. package/node_modules/@freeharness/sdd/dist/src/validate.js +72 -0
  230. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.d.ts +130 -0
  231. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.js +981 -0
  232. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.d.ts +46 -0
  233. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.js +128 -0
  234. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.d.ts +26 -0
  235. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.js +32 -0
  236. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.d.ts +50 -0
  237. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.js +394 -0
  238. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.d.ts +15 -0
  239. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.js +49 -0
  240. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.d.ts +71 -0
  241. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.js +164 -0
  242. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.d.ts +11 -0
  243. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.js +21 -0
  244. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.d.ts +102 -0
  245. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.js +230 -0
  246. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.d.ts +18 -0
  247. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.js +138 -0
  248. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.d.ts +82 -0
  249. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.js +333 -0
  250. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.d.ts +12 -0
  251. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.js +110 -0
  252. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.d.ts +11 -0
  253. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.js +32 -0
  254. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.d.ts +33 -0
  255. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.js +149 -0
  256. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.d.ts +39 -0
  257. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.js +49 -0
  258. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.d.ts +12 -0
  259. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.js +31 -0
  260. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.d.ts +10 -0
  261. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.js +10 -0
  262. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.d.ts +12 -0
  263. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.js +26 -0
  264. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.d.ts +28 -0
  265. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.js +41 -0
  266. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.d.ts +23 -0
  267. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.js +25 -0
  268. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.d.ts +72 -0
  269. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.js +76 -0
  270. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.d.ts +39 -0
  271. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.js +53 -0
  272. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.d.ts +62 -0
  273. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.js +7 -0
  274. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.d.ts +35 -0
  275. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.js +47 -0
  276. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.d.ts +33 -0
  277. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.js +55 -0
  278. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.d.ts +11 -0
  279. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.js +11 -0
  280. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.d.ts +48 -0
  281. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.js +99 -0
  282. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.d.ts +19 -0
  283. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.js +18 -0
  284. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.d.ts +18 -0
  285. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.js +4 -0
  286. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.d.ts +19 -0
  287. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.js +207 -0
  288. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.d.ts +12 -0
  289. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.js +409 -0
  290. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.d.ts +9 -0
  291. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.js +673 -0
  292. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.d.ts +9 -0
  293. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.js +230 -0
  294. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.d.ts +12 -0
  295. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.js +550 -0
  296. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.d.ts +8 -0
  297. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.js +107 -0
  298. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.d.ts +12 -0
  299. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.js +228 -0
  300. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.d.ts +9 -0
  301. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.js +147 -0
  302. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.d.ts +9 -0
  303. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.js +571 -0
  304. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.d.ts +12 -0
  305. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.js +322 -0
  306. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.d.ts +7 -0
  307. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.js +7 -0
  308. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.d.ts +9 -0
  309. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.js +518 -0
  310. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.d.ts +9 -0
  311. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.js +176 -0
  312. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.d.ts +9 -0
  313. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.js +344 -0
  314. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.d.ts +39 -0
  315. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.js +54 -0
  316. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.d.ts +35 -0
  317. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.js +171 -0
  318. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.d.ts +27 -0
  319. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.js +210 -0
  320. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.d.ts +14 -0
  321. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.js +48 -0
  322. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.d.ts +22 -0
  323. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.js +186 -0
  324. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.d.ts +65 -0
  325. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.js +409 -0
  326. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.d.ts +55 -0
  327. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.js +98 -0
  328. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.d.ts +8 -0
  329. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.js +77 -0
  330. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.d.ts +44 -0
  331. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.js +116 -0
  332. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.d.ts +12 -0
  333. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.js +17 -0
  334. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.d.ts +72 -0
  335. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.js +30 -0
  336. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.d.ts +3 -0
  337. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.js +3 -0
  338. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.d.ts +17 -0
  339. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.js +14 -0
  340. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.d.ts +39 -0
  341. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.js +114 -0
  342. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.d.ts +45 -0
  343. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.js +105 -0
  344. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.d.ts +15 -0
  345. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.js +56 -0
  346. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.d.ts +17 -0
  347. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.js +1 -0
  348. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.d.ts +94 -0
  349. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.js +756 -0
  350. package/node_modules/@freeharness/sdd/package.json +57 -0
  351. package/node_modules/@freeharness/sdd/vendor/openspec/LICENSE.upstream +22 -0
  352. package/node_modules/@freeharness/sdd/vendor/openspec/assets/schema.upstream.yaml +232 -0
  353. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/README.md +19 -0
  354. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-apply-change/SKILL.md +187 -0
  355. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-archive-change/SKILL.md +181 -0
  356. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-bulk-archive-change/SKILL.md +338 -0
  357. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-continue-change/SKILL.md +117 -0
  358. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-explore/SKILL.md +342 -0
  359. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-ff-change/SKILL.md +116 -0
  360. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-new-change/SKILL.md +76 -0
  361. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-onboard/SKILL.md +560 -0
  362. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-propose/SKILL.md +162 -0
  363. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-sync-specs/SKILL.md +261 -0
  364. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-update-change/SKILL.md +90 -0
  365. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-verify-change/SKILL.md +174 -0
  366. package/package.json +70 -0
  367. package/provenance/canonical.PROVENANCE.yaml +740 -0
  368. package/provenance/claude-mem.LICENSE.upstream +202 -0
  369. package/provenance/memory.PROVENANCE.yaml +399 -0
  370. package/provenance/sdd.PROVENANCE.yaml +175 -0
  371. package/vendor-licenses/caveman.LICENSE +27 -0
  372. package/vendor-licenses/deepseek-harness.LICENSE +21 -0
  373. package/vendor-licenses/ecc.LICENSE +21 -0
  374. package/vendor-licenses/pi.LICENSE +21 -0
  375. package/vendor-licenses/superpowers.LICENSE +21 -0
@@ -0,0 +1,473 @@
1
+ """Claro pptx theme: palette, typography, layout helpers (python-pptx) and
2
+ template-edit helpers (lxml). Default theme for report-formatting .pptx output.
3
+ Import: `import theme_claro_pptx as T`. Reusable across status reports.
4
+ """
5
+ import os
6
+ from pptx.util import Inches, Pt, Emu
7
+ from pptx.dml.color import RGBColor
8
+ from pptx.enum.shapes import MSO_SHAPE
9
+ from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
10
+ from lxml import etree
11
+ import copy as _copy
12
+
13
+ FONT = "Calibri"
14
+
15
+ # Claro logo asset (red orb wordmark, transparent PNG). Resolved relative to this
16
+ # file so it works wherever the skill is emitted.
17
+ LOGO_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "assets", "claro-logo.png")
18
+
19
+ # Claro institutional palette
20
+ CLARO_RED = RGBColor(0xE2, 0x00, 0x0F)
21
+ CLARO_RED_DARK = RGBColor(0xB8, 0x00, 0x0D)
22
+ DARK_GRAY = RGBColor(0x33, 0x33, 0x33)
23
+ MID_GRAY = RGBColor(0x66, 0x66, 0x66)
24
+ LIGHT_GRAY = RGBColor(0xE8, 0xE8, 0xE8)
25
+ VERY_LIGHT_GRAY = RGBColor(0xF5, 0xF5, 0xF5)
26
+ WHITE = RGBColor(0xFF, 0xFF, 0xFF)
27
+
28
+ # Status colors (heatmap, ROAM, badges)
29
+ STATUS_DONE = RGBColor(0x2E, 0x7D, 0x32)
30
+ STATUS_INPROGRESS = RGBColor(0xF9, 0xA8, 0x25)
31
+ STATUS_PENDING = RGBColor(0xE6, 0x7E, 0x22)
32
+ STATUS_BACKLOG = RGBColor(0x95, 0xA5, 0xA6)
33
+ STATUS_RISK = RGBColor(0xC0, 0x39, 0x2B)
34
+
35
+ # Timeline track / category colors
36
+ CAT_COLOR = {
37
+ "Backlog": RGBColor(0xE6, 0x7E, 0x22),
38
+ "WhisperX": RGBColor(0x8E, 0x24, 0xAA),
39
+ "Pipeline": RGBColor(0x1E, 0x88, 0xE5),
40
+ "Data Core": RGBColor(0x00, 0x89, 0x7B),
41
+ "Infraestrutura": RGBColor(0x5D, 0x6D, 0x7E),
42
+ "Documentação": RGBColor(0xB8, 0x00, 0x0D),
43
+ "Análises": RGBColor(0x5E, 0x35, 0xB1),
44
+ }
45
+
46
+ # Heatmap status config: key -> (label, fill, text_color, icon)
47
+ STATUS_CFG = {
48
+ "done": ("Concluído", STATUS_DONE, WHITE, "✓"),
49
+ "inprogress": ("Em Andamento", STATUS_INPROGRESS, WHITE, "▶"),
50
+ "pending": ("Pendente", STATUS_PENDING, WHITE, "○"),
51
+ "backlog": ("Backlog", STATUS_BACKLOG, WHITE, "–"),
52
+ }
53
+
54
+
55
+ def clear_slide_shapes(slide):
56
+ """Remove all editable shapes from the slide, keeping layout and master.
57
+
58
+ Mutates the slide in place, leaving it blank for a rebuild.
59
+
60
+ Args:
61
+ slide: The python-pptx slide to strip.
62
+ """
63
+ spTree = slide.shapes._spTree
64
+ for sp in list(spTree):
65
+ tag = etree.QName(sp).localname
66
+ if tag in ("sp", "pic", "graphicFrame", "cxnSp", "grpSp"):
67
+ spTree.remove(sp)
68
+
69
+
70
+ def add_text(slide, x, y, w, h, text, *, size=11, bold=False, color=DARK_GRAY,
71
+ align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP, italic=False,
72
+ font=FONT, fill=None, line=None):
73
+ """Add a formatted text box to the slide; supports fill, border, alignment.
74
+
75
+ Args:
76
+ slide: Target slide.
77
+ x, y, w, h: Text-box position and size in EMU.
78
+ text: The text content.
79
+ size: Font size in points.
80
+ bold: Whether the text is bold.
81
+ color: Font color.
82
+ align: Horizontal paragraph alignment.
83
+ anchor: Vertical anchor of the text frame.
84
+ italic: Whether the text is italic.
85
+ font: Font name.
86
+ fill: Background fill color, or None for no fill.
87
+ line: Border color, or None for no border.
88
+
89
+ Returns:
90
+ The created textbox shape.
91
+ """
92
+ tb = slide.shapes.add_textbox(x, y, w, h)
93
+ tf = tb.text_frame
94
+ tf.margin_left = Emu(45720)
95
+ tf.margin_right = Emu(45720)
96
+ tf.margin_top = Emu(22860)
97
+ tf.margin_bottom = Emu(22860)
98
+ tf.word_wrap = True
99
+ tf.vertical_anchor = anchor
100
+ p = tf.paragraphs[0]
101
+ p.alignment = align
102
+ run = p.add_run()
103
+ run.text = text
104
+ run.font.name = font
105
+ run.font.size = Pt(size)
106
+ run.font.bold = bold
107
+ run.font.italic = italic
108
+ run.font.color.rgb = color
109
+ if fill is not None:
110
+ tb.fill.solid()
111
+ tb.fill.fore_color.rgb = fill
112
+ else:
113
+ tb.fill.background()
114
+ if line is not None:
115
+ tb.line.color.rgb = line
116
+ tb.line.width = Pt(0.5)
117
+ else:
118
+ tb.line.fill.background()
119
+ return tb
120
+
121
+
122
+ def add_rect(slide, x, y, w, h, fill, *, line=None, line_w=None, corner=False):
123
+ """Add a filled rectangle to the slide.
124
+
125
+ Args:
126
+ slide: Target slide.
127
+ x, y, w, h: Position and size in EMU.
128
+ fill: Fill color.
129
+ line: Border color, or None for no border.
130
+ line_w: Border width; defaults to 0.25pt when a border is set.
131
+ corner: If True, use a rounded rectangle.
132
+
133
+ Returns:
134
+ The created shape.
135
+ """
136
+ st = MSO_SHAPE.ROUNDED_RECTANGLE if corner else MSO_SHAPE.RECTANGLE
137
+ shape = slide.shapes.add_shape(st, x, y, w, h)
138
+ shape.fill.solid()
139
+ shape.fill.fore_color.rgb = fill
140
+ if line is None:
141
+ shape.line.fill.background()
142
+ else:
143
+ shape.line.color.rgb = line
144
+ shape.line.width = line_w or Pt(0.25)
145
+ shape.shadow.inherit = False
146
+ if shape.has_text_frame:
147
+ shape.text_frame.text = ""
148
+ if corner:
149
+ try:
150
+ shape.adjustments[0] = 0.15
151
+ except Exception:
152
+ pass
153
+ return shape
154
+
155
+
156
+ def add_filled_text(slide, x, y, w, h, text, *, fill, tcolor=WHITE, size=10,
157
+ bold=True, align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE,
158
+ corner=False):
159
+ """Add a filled rectangle with centered text (chips, badges, headers).
160
+
161
+ Args:
162
+ slide: Target slide.
163
+ x, y, w, h: Position and size in EMU.
164
+ text: The text content.
165
+ fill: Fill color.
166
+ tcolor: Text color.
167
+ size: Font size in points.
168
+ bold: Whether the text is bold.
169
+ align: Horizontal alignment.
170
+ anchor: Vertical anchor.
171
+ corner: If True, use a rounded rectangle.
172
+
173
+ Returns:
174
+ The created shape.
175
+ """
176
+ st = MSO_SHAPE.ROUNDED_RECTANGLE if corner else MSO_SHAPE.RECTANGLE
177
+ shape = slide.shapes.add_shape(st, x, y, w, h)
178
+ shape.fill.solid()
179
+ shape.fill.fore_color.rgb = fill
180
+ shape.line.fill.background()
181
+ shape.shadow.inherit = False
182
+ if corner:
183
+ try:
184
+ shape.adjustments[0] = 0.18
185
+ except Exception:
186
+ pass
187
+ tf = shape.text_frame
188
+ tf.margin_left = Emu(36000)
189
+ tf.margin_right = Emu(36000)
190
+ tf.margin_top = Emu(9000)
191
+ tf.margin_bottom = Emu(9000)
192
+ tf.word_wrap = True
193
+ tf.vertical_anchor = anchor
194
+ p = tf.paragraphs[0]
195
+ p.alignment = align
196
+ run = p.add_run()
197
+ run.text = text
198
+ run.font.name = FONT
199
+ run.font.size = Pt(size)
200
+ run.font.bold = bold
201
+ run.font.color.rgb = tcolor
202
+ return shape
203
+
204
+
205
+ def add_logo(slide, *, x=None, y=Inches(0.28), height=Inches(0.5)):
206
+ """Place the Claro logo on the slide, preserving aspect ratio.
207
+
208
+ Default position is the top-right header corner (right-aligned to the
209
+ 0.45in margin).
210
+
211
+ Args:
212
+ slide: Target slide.
213
+ x: Left offset in EMU, or None to right-align to the margin.
214
+ y: Top offset in EMU.
215
+ height: Logo height in EMU (width scales to keep aspect ratio).
216
+
217
+ Returns:
218
+ The picture shape, or None if the logo asset is missing (so callers
219
+ degrade cleanly).
220
+ """
221
+ if not os.path.exists(LOGO_PATH):
222
+ return None
223
+ pic = slide.shapes.add_picture(LOGO_PATH, Inches(0), y, height=height)
224
+ pic.left = x if x is not None else int(Inches(13.333) - Inches(0.45) - pic.width)
225
+ return pic
226
+
227
+
228
+ def add_page_header(slide, title, subtitle=None, logo=True):
229
+ """Add the Claro header: red accent flag, title, optional subtitle, logo.
230
+
231
+ Args:
232
+ slide: Target slide.
233
+ title: Header title text.
234
+ subtitle: Optional italic subtitle.
235
+ logo: If True, place the logo in the top-right corner.
236
+ """
237
+ add_rect(slide, Inches(0.5), Inches(0.35), Inches(0.6), Inches(0.08), CLARO_RED)
238
+ add_text(slide, Inches(0.45), Inches(0.48), Inches(11.2), Inches(0.55),
239
+ title, size=23, bold=True, color=DARK_GRAY)
240
+ if subtitle:
241
+ add_text(slide, Inches(0.45), Inches(1.0), Inches(11.2), Inches(0.3),
242
+ subtitle, size=11, color=MID_GRAY, italic=True)
243
+ if logo:
244
+ add_logo(slide)
245
+
246
+
247
+ def add_page_footer(slide, page, total=10,
248
+ left="Status Report | Pipeline STT - Dados & IA"):
249
+ """Add the Claro footer: left label and right page number.
250
+
251
+ Args:
252
+ slide: Target slide.
253
+ page: Current page number.
254
+ total: Total page count.
255
+ left: Left-aligned footer label.
256
+ """
257
+ add_text(slide, Inches(0.45), Inches(7.15), Inches(7), Inches(0.25),
258
+ left, size=9, color=MID_GRAY)
259
+ add_text(slide, Inches(12.2), Inches(7.15), Inches(0.9), Inches(0.25),
260
+ f"{page} / {total}", size=9, color=MID_GRAY, align=PP_ALIGN.RIGHT)
261
+
262
+
263
+ def build_bullet_list(slide, x, y, w, h, items, size=10, color=DARK_GRAY,
264
+ bullet_color=CLARO_RED):
265
+ """Add a bullet list with a red marker on the left.
266
+
267
+ Args:
268
+ slide: Target slide.
269
+ x, y, w, h: Position and size in EMU.
270
+ items: Bullet strings, one per line.
271
+ size: Font size in points.
272
+ color: Text color.
273
+ bullet_color: Marker color.
274
+ """
275
+ tb = slide.shapes.add_textbox(x, y, w, h)
276
+ tf = tb.text_frame
277
+ tf.margin_left = Emu(36000)
278
+ tf.word_wrap = True
279
+ for i, item in enumerate(items):
280
+ p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
281
+ r1 = p.add_run()
282
+ r1.text = "▪ "
283
+ r1.font.name = FONT
284
+ r1.font.size = Pt(size)
285
+ r1.font.bold = True
286
+ r1.font.color.rgb = bullet_color
287
+ r2 = p.add_run()
288
+ r2.text = item
289
+ r2.font.name = FONT
290
+ r2.font.size = Pt(size)
291
+ r2.font.color.rgb = color
292
+
293
+
294
+ # ---------------------------------------------------------------------------
295
+ # lxml helpers — edit template slides in place (preserve complex Claro layouts)
296
+ # ---------------------------------------------------------------------------
297
+ NS = {
298
+ "a": "http://schemas.openxmlformats.org/drawingml/2006/main",
299
+ "p": "http://schemas.openxmlformats.org/presentationml/2006/main",
300
+ "r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
301
+ }
302
+ A_NS = NS["a"]
303
+
304
+
305
+ def get_shape(root, sid):
306
+ """Find a shape by its cNvPr id.
307
+
308
+ Returns:
309
+ The matching <p:sp> element, or None if not found.
310
+ """
311
+ r = root.xpath(f".//p:sp[.//p:cNvPr[@id='{sid}']]", namespaces=NS)
312
+ return r[0] if r else None
313
+
314
+
315
+ def set_pos(shape, x, y):
316
+ """Set the shape's (x, y) offset in EMU, mutating the xfrm in place.
317
+
318
+ A None x leaves the x offset unchanged.
319
+ """
320
+ off = shape.find(".//p:spPr/a:xfrm/a:off", NS)
321
+ if off is not None:
322
+ if x is not None:
323
+ off.set("x", str(int(x)))
324
+ off.set("y", str(int(y)))
325
+
326
+
327
+ def get_dims(shape):
328
+ """Return the shape's (cx, cy) extent in EMU, or (None, None) if absent."""
329
+ ext = shape.find(".//p:spPr/a:xfrm/a:ext", NS)
330
+ if ext is None:
331
+ return None, None
332
+ return int(ext.get("cx")), int(ext.get("cy"))
333
+
334
+
335
+ def set_fill(shape, hex_color):
336
+ """Set the shape's fill color in place (hex without '#', e.g. '2E7D32')."""
337
+ fill = shape.find(".//p:spPr/a:solidFill/a:srgbClr", NS)
338
+ if fill is not None:
339
+ fill.set("val", hex_color)
340
+
341
+
342
+ def set_text(shape, new_text):
343
+ """Replace all text in a shape, preserving formatting; mutates in place.
344
+
345
+ Preserves the first run's rPr and the first paragraph's pPr, so font, size,
346
+ color, and alignment carry over. Most-used template helper.
347
+
348
+ Args:
349
+ shape: The <p:sp> element to edit.
350
+ new_text: Replacement text; newlines become separate paragraphs.
351
+
352
+ Returns:
353
+ True if the text was replaced, False if the shape has no txBody.
354
+ """
355
+ txBody = shape.find("p:txBody", NS)
356
+ if txBody is None:
357
+ return False
358
+ first_run = txBody.find(".//a:r", NS)
359
+ tmpl_rPr = None
360
+ if first_run is not None:
361
+ rPr = first_run.find("a:rPr", NS)
362
+ if rPr is not None:
363
+ tmpl_rPr = etree.tostring(rPr)
364
+ first_p = txBody.find("a:p", NS)
365
+ tmpl_pPr = None
366
+ if first_p is not None:
367
+ pPr = first_p.find("a:pPr", NS)
368
+ if pPr is not None:
369
+ tmpl_pPr = etree.tostring(pPr)
370
+ for p in txBody.findall("a:p", NS):
371
+ txBody.remove(p)
372
+ for line in new_text.split("\n"):
373
+ p = etree.SubElement(txBody, f"{{{A_NS}}}p")
374
+ if tmpl_pPr is not None:
375
+ p.append(etree.fromstring(tmpl_pPr))
376
+ r = etree.SubElement(p, f"{{{A_NS}}}r")
377
+ if tmpl_rPr is not None:
378
+ r.append(etree.fromstring(tmpl_rPr))
379
+ else:
380
+ etree.SubElement(r, f"{{{A_NS}}}rPr").set("lang", "pt-BR")
381
+ t = etree.SubElement(r, f"{{{A_NS}}}t")
382
+ t.text = line
383
+ return True
384
+
385
+
386
+ def del_shape(root, sid):
387
+ """Remove a shape by id from the tree (e.g. discard unused markers)."""
388
+ sh = get_shape(root, sid)
389
+ if sh is not None:
390
+ sh.getparent().remove(sh)
391
+
392
+
393
+ def clone_shape(root, src_shape, new_id):
394
+ """Clone a shape and append it to its parent, returning the copy.
395
+
396
+ Assigns a new cNvPr id and drops extLst to avoid duplicate GUIDs. Used to
397
+ add markers to a timeline track.
398
+
399
+ Args:
400
+ root: Document root (unused; kept for API symmetry).
401
+ src_shape: The shape to clone.
402
+ new_id: cNvPr id to assign to the clone.
403
+
404
+ Returns:
405
+ The newly appended clone element.
406
+ """
407
+ new = _copy.deepcopy(src_shape)
408
+ cNvPr = new.find(".//p:cNvPr", NS)
409
+ cNvPr.set("id", str(new_id))
410
+ cNvPr.set("name", f'{cNvPr.get("name")}_clone{new_id}')
411
+ for ext in new.findall(".//a:extLst", NS):
412
+ ext.getparent().remove(ext)
413
+ src_shape.getparent().append(new)
414
+ return new
415
+
416
+
417
+ def max_shape_id(root):
418
+ """Return the largest cNvPr id in use, or 1000 if none (for unique ids)."""
419
+ ids = []
420
+ for c in root.xpath(".//p:cNvPr", namespaces=NS):
421
+ try:
422
+ ids.append(int(c.get("id")))
423
+ except (TypeError, ValueError):
424
+ pass
425
+ return max(ids) if ids else 1000
426
+
427
+
428
+ # ---------------------------------------------------------------------------
429
+ # Timeline math (EMU axis) — from the Claro template
430
+ # ---------------------------------------------------------------------------
431
+ AXIS_START = 1_692_580
432
+ AXIS_END = 11_970_955
433
+ AXIS_WIDTH = AXIS_END - AXIS_START
434
+ OFF_SLIDE_Y = -2_000_000 # park unused markers off-slide
435
+
436
+ # Track Y centers (diamond_y, label_y)
437
+ TRACK_Y = {
438
+ 1: (3_004_739, 3_148_143),
439
+ 2: (4_137_219, 4_280_623),
440
+ 3: (5_449_646, 5_597_150),
441
+ }
442
+
443
+
444
+ def day_to_x(day, total_days):
445
+ """Map a day index to an X coordinate on the timeline axis."""
446
+ return AXIS_START + int(AXIS_WIDTH * (day / total_days))
447
+
448
+
449
+ def place_event(root, diamond_id, label_id, day, total_days, text, dy, ly):
450
+ """Place a diamond+label pair at the given day, editing the tree in place.
451
+
452
+ Args:
453
+ root: Document root to search.
454
+ diamond_id: cNvPr id of the diamond marker shape.
455
+ label_id: cNvPr id of the label shape.
456
+ day: Day index of the event.
457
+ total_days: Total span of the axis in days.
458
+ text: Label text to set.
459
+ dy: Diamond Y offset in EMU.
460
+ ly: Label Y offset in EMU.
461
+ """
462
+ cx = day_to_x(day, total_days)
463
+ d = get_shape(root, diamond_id)
464
+ if d is not None:
465
+ dw, _ = get_dims(d)
466
+ set_pos(d, cx - (dw // 2 if dw else 94518), dy)
467
+ lb = get_shape(root, label_id)
468
+ if lb is not None:
469
+ lw, _ = get_dims(lb)
470
+ if lw is None:
471
+ lw = 859133
472
+ set_pos(lb, cx - lw // 2, ly)
473
+ set_text(lb, text)
@@ -0,0 +1,80 @@
1
+ ---
2
+ lang: pt-BR
3
+ app: <app>
4
+ version: <x.y.z>
5
+ type: <patch | minor | major> — <uma linha: por que esta release existe>
6
+ artifact: <registry>/<repo>/<app>:<x.y.z>-<commit>
7
+ digest: sha256:<12 primeiros caracteres>…
8
+ date: <DD/MM/AAAA>
9
+ status: <Publicada | Para execução | Executada em DD/MM>
10
+ previous: <x.y.(z-1)>-<commit>
11
+ audience: <CCoE / operação / time X>
12
+ risk: <baixo | médio | alto> — <por quê>; <janela, ticket/aprovação se houver>
13
+ author: André Negrelli
14
+ role: Tech Lead AI Data Engineer
15
+ area: DADOS & IA
16
+ project: <Projeto> — Claro / <app>
17
+ ---
18
+ <!--
19
+ Release document model (reference/RELEASE.md). Fixed sections, in this order; the
20
+ build fails on an unknown or missing mandatory section. Only what changed in THIS
21
+ version: no history of earlier releases, no deploy/installation guide (those are
22
+ other documents — link them in "Referências"). Target: two pages. Every claim comes
23
+ from a commit, a test run, a manifest or a measurement. Inline `code` for commands,
24
+ keys, values and log events; **bold** for the one thing the reader must not miss.
25
+ Comments like this one are never rendered.
26
+ -->
27
+
28
+ ## Resumo
29
+ <!-- mandatory · 2-3 sentences: what this release delivers and why now. -->
30
+ <O que esta release entrega e por quê, em duas ou três frases.>
31
+
32
+ ## Mudanças incompatíveis
33
+ <!-- mandatory · "Nenhuma." or one bullet per break with the action the operator must take. -->
34
+ Nenhuma.
35
+
36
+ ## Mudanças
37
+ <!-- mandatory · Keep a Changelog categories (### Adicionado | Alterado | Corrigido | Removido | Obsoleto | Segurança);
38
+ use only the ones that apply; one bullet per change: what + why + operational impact, with commit/PR id. -->
39
+ ### Corrigido
40
+ - <mudança em uma frase — causa, efeito, impacto para a operação> (`<commit>`).
41
+
42
+ ### Alterado
43
+ - <valor ou comportamento que mudou: antes -> depois> (`<commit>`).
44
+
45
+ ## Modelos, prompts e avaliação
46
+ <!-- agentic/LLM/ASR systems · pinned model/prompt/tool/guardrail versions and the eval gate that released the build;
47
+ "Sem mudança." when nothing moved, plus the evidence line. -->
48
+ | Componente | Nesta release | Evidência / gate |
49
+ |---|---|---|
50
+ | Modelo | `<id/snapshot, quantização>` — <inalterado \| novo> | <suite@versão, métrica, limiar, resultado vs anterior> |
51
+ | Prompt / ferramentas / guardrails | `<id@versão>` | <eval de regressão; n casos> |
52
+ | Telemetria | <spans/métricas novos ou renomeados; conteúdo nunca capturado> | <dashboard / alerta> |
53
+ | Imagem / build | `<tag>` — <como foi validada> | <testes da imagem; gates> |
54
+
55
+ ## Configuração
56
+ <!-- optional · delta only, key by key; Secret keys by name, never values. "Sem mudança." when nothing moved. -->
57
+ | Variável / chave | Antes | Depois | Onde / efeito |
58
+ |---|---|---|---|
59
+ | `<CHAVE>` | `<antes>` | `<depois>` | <ConfigMap/Secret; efeito observável> |
60
+
61
+ ## Rollout e rollback
62
+ <!-- mandatory · how the release enters (one line), who executes, what happens to in-flight work, and the rollback target. -->
63
+ - **Entrada:** <ação única e quem executa — ex.: Restart do Deployment; `latest` já promovida>.
64
+ - **Em andamento:** <o que acontece com mensagens/jobs em voo>.
65
+ - **Rollback:** <alvo imutável `<tag anterior>` e o passo — ou por que não há alvo e qual é o caminho>.
66
+
67
+ ## Verificação
68
+ <!-- mandatory · 2-4 objective signals that prove the release is live and healthy. -->
69
+ - <sinal 1: estado do pod / probe / digest do container>.
70
+ - <sinal 2: evento de log esperado; o que NÃO deve aparecer>.
71
+ - <sinal 3: métrica ou resultado funcional>.
72
+
73
+ ## Problemas conhecidos e pendências
74
+ <!-- optional · open items with owner and closing condition. -->
75
+ - <item, dono, condição para fechar>.
76
+
77
+ ## Referências
78
+ <!-- optional · commits, PRs, the deploy guide, previous release doc, changelog. -->
79
+ - Commits: `<sha>` <título>; `<sha>` <título>.
80
+ - Guia de deploy: <documento/caminho>; release anterior: <documento>.
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * render-mermaid.js — Extrai blocos ```mermaid de um arquivo .md e renderiza
5
+ * cada um como PNG de alta resolução (fundo branco), prontos para embutir no docx.
6
+ *
7
+ * Uso:
8
+ * node render-mermaid.js <arquivo.md> <diretorio-saida>
9
+ *
10
+ * Saída: <saida>/diagram_01.png, diagram_02.png, ...
11
+ * imprime um JSON no stdout com a lista de PNGs gerados (na ordem do .md).
12
+ *
13
+ * Requer: @mermaid-js/mermaid-cli (mmdc) + Chrome/Chromium.
14
+ * npm i -g @mermaid-js/mermaid-cli
15
+ * npx puppeteer browsers install chrome-headless-shell # se faltar o Chrome
16
+ *
17
+ * Tema do Mermaid: "neutral" + fonte Arial, para casar com o tema Claro do docx.
18
+ * As cores definidas via classDef no próprio diagrama (azul/verde/vermelho/amarelo)
19
+ * são preservadas e combinam com a paleta Claro.
20
+ */
21
+
22
+ const fs = require("fs");
23
+ const path = require("path");
24
+ const os = require("os");
25
+ const { execFileSync } = require("child_process");
26
+
27
+ /**
28
+ * Locate a Chrome/Chromium executable for mmdc (Puppeteer).
29
+ * Checks, in order: the PUPPETEER_EXECUTABLE_PATH env var, the puppeteer cache,
30
+ * then common system paths.
31
+ * @returns {string|null} path to the browser, or null if none is found.
32
+ */
33
+ function findChrome() {
34
+ // 1) variável de ambiente explícita
35
+ if (process.env.PUPPETEER_EXECUTABLE_PATH && fs.existsSync(process.env.PUPPETEER_EXECUTABLE_PATH)) {
36
+ return process.env.PUPPETEER_EXECUTABLE_PATH;
37
+ }
38
+ // 2) cache do puppeteer (~/.cache/puppeteer/**/chrome-headless-shell|chrome)
39
+ const cache = path.join(os.homedir(), ".cache", "puppeteer");
40
+ const hits = [];
41
+ const walk = (dir) => {
42
+ let ents = [];
43
+ try { ents = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
44
+ for (const e of ents) {
45
+ const p = path.join(dir, e.name);
46
+ if (e.isDirectory()) walk(p);
47
+ else if (e.isFile() && (e.name === "chrome-headless-shell" || e.name === "chrome" || e.name === "chromium")) hits.push(p);
48
+ }
49
+ };
50
+ walk(cache);
51
+ if (hits.length) return hits.sort().reverse()[0]; // versão mais recente
52
+ // 3) Chrome do sistema
53
+ for (const p of ["/usr/bin/google-chrome", "/usr/bin/chromium", "/usr/bin/chromium-browser"]) {
54
+ if (fs.existsSync(p)) return p;
55
+ }
56
+ return null;
57
+ }
58
+
59
+ /**
60
+ * CLI entry point. Reads the .md at argv[2], renders each ```mermaid block to a
61
+ * high-res PNG under argv[3], and prints a JSON `{ pngs: [...] }` list to stdout.
62
+ * Exits with code 2 on missing arguments. Side effects: creates the output
63
+ * directory and writes .mmd/.png plus temporary config files into it.
64
+ * @returns {void}
65
+ */
66
+ function main() {
67
+ const [, , mdPath, outDir] = process.argv;
68
+ if (!mdPath || !outDir) {
69
+ console.error("Uso: node render-mermaid.js <arquivo.md> <diretorio-saida>");
70
+ process.exit(2);
71
+ }
72
+ fs.mkdirSync(outDir, { recursive: true });
73
+
74
+ const md = fs.readFileSync(mdPath, "utf8");
75
+ const blocks = [...md.matchAll(/```mermaid\s*\n([\s\S]*?)```/g)].map((m) => m[1]);
76
+ if (!blocks.length) { console.log(JSON.stringify({ pngs: [] })); return; }
77
+
78
+ // configs para o mmdc
79
+ const chrome = findChrome();
80
+ const pptr = path.join(outDir, "_puppeteer.json");
81
+ fs.writeFileSync(pptr, JSON.stringify({
82
+ ...(chrome ? { executablePath: chrome } : {}),
83
+ args: ["--no-sandbox", "--disable-setuid-sandbox"],
84
+ }));
85
+ const mconf = path.join(outDir, "_mermaid.json");
86
+ fs.writeFileSync(mconf, JSON.stringify({ theme: "neutral", themeVariables: { fontFamily: "Arial" } }));
87
+
88
+ const pngs = [];
89
+ blocks.forEach((src, i) => {
90
+ const n = String(i + 1).padStart(2, "0");
91
+ const mmd = path.join(outDir, `diagram_${n}.mmd`);
92
+ const png = path.join(outDir, `diagram_${n}.png`);
93
+ fs.writeFileSync(mmd, src);
94
+ try {
95
+ execFileSync("mmdc", ["-i", mmd, "-o", png, "-b", "white", "-s", "3", "-p", pptr, "-c", mconf], { stdio: "pipe" });
96
+ pngs.push(png);
97
+ } catch (e) {
98
+ console.error(`Falha ao renderizar diagrama ${n}:`, (e.stderr || e.message || "").toString().slice(0, 500));
99
+ }
100
+ });
101
+
102
+ console.log(JSON.stringify({ pngs }, null, 2));
103
+ }
104
+
105
+ main();