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.
- package/LICENSE +21 -0
- package/NOTICE +108 -0
- package/README.md +134 -0
- package/canonical/HARVEST.yaml +858 -0
- package/canonical/PROVENANCE.yaml +740 -0
- package/canonical/agents/README.md +95 -0
- package/canonical/agents/agentic-architect.md +18 -0
- package/canonical/agents/database-reviewer.md +41 -0
- package/canonical/agents/explorer-ai-engineer-analyst.md +65 -0
- package/canonical/agents/pr-reviewer.md +96 -0
- package/canonical/agents/python-reviewer.md +55 -0
- package/canonical/agents/report-formatter.md +19 -0
- package/canonical/agents/security-reviewer.md +53 -0
- package/canonical/agents/test-writer.md +34 -0
- package/canonical/commands/fh-context.md +37 -0
- package/canonical/evals/promptfoo.redteam.yaml +108 -0
- package/canonical/hooks/cost-prices.json +14 -0
- package/canonical/hooks/freeharness-auto-memory.mjs +158 -0
- package/canonical/hooks/freeharness-config-guard.mjs +162 -0
- package/canonical/hooks/freeharness-context-monitor.mjs +198 -0
- package/canonical/hooks/freeharness-converge.mjs +227 -0
- package/canonical/hooks/freeharness-cost-tracker.mjs +1027 -0
- package/canonical/hooks/freeharness-memory-guard.mjs +57 -0
- package/canonical/hooks/freeharness-output-pruner.mjs +333 -0
- package/canonical/hooks/freeharness-precompact.mjs +323 -0
- package/canonical/hooks/freeharness-repeat-tool.mjs +208 -0
- package/canonical/hooks/freeharness-security-guidance.mjs +164 -0
- package/canonical/hooks/freeharness-session-start +583 -0
- package/canonical/hooks/hooks.auto-memory.claude-code.json +16 -0
- package/canonical/hooks/hooks.claude-code.json +17 -0
- package/canonical/hooks/hooks.config-guard.claude-code.json +16 -0
- package/canonical/hooks/hooks.context-monitor.claude-code.json +15 -0
- package/canonical/hooks/hooks.converge.claude-code.json +15 -0
- package/canonical/hooks/hooks.cost-tracker.claude-code.json +37 -0
- package/canonical/hooks/hooks.memory-guard.claude-code.json +16 -0
- package/canonical/hooks/hooks.output-pruner.claude-code.json +16 -0
- package/canonical/hooks/hooks.precompact.claude-code.json +15 -0
- package/canonical/hooks/hooks.repeat-tool.claude-code.json +25 -0
- package/canonical/hooks/hooks.security-guidance.claude-code.json +16 -0
- package/canonical/mcp/servers.json +20 -0
- package/canonical/openspec/config.base.yaml +89 -0
- package/canonical/openspec/schema.spec-driven.yaml +277 -0
- package/canonical/openspec/templates/data-contract.md +36 -0
- package/canonical/openspec/templates/design.md +84 -0
- package/canonical/openspec/templates/eval-plan.md +33 -0
- package/canonical/openspec/templates/follow-ups.md +2 -0
- package/canonical/openspec/templates/proposal.md +45 -0
- package/canonical/openspec/templates/spec.md +42 -0
- package/canonical/openspec/templates/tasks.md +38 -0
- package/canonical/profiles/local-llamacpp.LOCAL-MODELS.md +47 -0
- package/canonical/profiles/local-llamacpp.json +27 -0
- package/canonical/profiles/local-ollama.json +20 -0
- package/canonical/profiles/mcp.json +91 -0
- package/canonical/rules/CLAUDE.md +78 -0
- package/canonical/rules/project-CLAUDE.template.md +62 -0
- package/canonical/rules/routing.md +20 -0
- package/canonical/rules/safety.md +41 -0
- package/canonical/settings/settings.cache-hygiene.claude-code.json +5 -0
- package/canonical/skills/agent-evaluation/SKILL.md +102 -0
- package/canonical/skills/agent-evaluation/assets/evaluation_report_template.md +206 -0
- package/canonical/skills/agent-evaluation/evals/cases.yaml +106 -0
- package/canonical/skills/agent-evaluation/references/dataset-preparation.md +351 -0
- package/canonical/skills/agent-evaluation/references/scorers-constraints.md +165 -0
- package/canonical/skills/agent-evaluation/references/scorers.md +431 -0
- package/canonical/skills/agent-evaluation/references/setup-guide.md +252 -0
- package/canonical/skills/agent-evaluation/references/tracing-integration.md +164 -0
- package/canonical/skills/agent-evaluation/references/troubleshooting.md +514 -0
- package/canonical/skills/agent-evaluation/scripts/analyze_results.py +462 -0
- package/canonical/skills/agent-evaluation/scripts/create_dataset_template.py +382 -0
- package/canonical/skills/agent-evaluation/scripts/list_datasets.py +273 -0
- package/canonical/skills/agent-evaluation/scripts/run_evaluation_template.py +309 -0
- package/canonical/skills/agent-evaluation/scripts/setup_mlflow.py +353 -0
- package/canonical/skills/agent-evaluation/scripts/utils/__init__.py +27 -0
- package/canonical/skills/agent-evaluation/scripts/utils/env_validation.py +123 -0
- package/canonical/skills/agent-evaluation/scripts/utils/tracing_utils.py +108 -0
- package/canonical/skills/agent-evaluation/scripts/validate_agent_tracing.py +148 -0
- package/canonical/skills/agent-evaluation/scripts/validate_auth.py +240 -0
- package/canonical/skills/agent-evaluation/scripts/validate_environment.py +185 -0
- package/canonical/skills/agent-evaluation/scripts/validate_tracing_runtime.py +318 -0
- package/canonical/skills/agentic-architecture/SKILL.md +41 -0
- package/canonical/skills/agentic-architecture/evals/cases.yaml +94 -0
- package/canonical/skills/agentic-architecture/reference/context-engineering.md +75 -0
- package/canonical/skills/agentic-architecture/reference/patterns.md +76 -0
- package/canonical/skills/agentic-architecture/reference/reliability-observability.md +94 -0
- package/canonical/skills/agentic-architecture/reference/review-framework.md +59 -0
- package/canonical/skills/code-review/SKILL.md +52 -0
- package/canonical/skills/code-review/evals/cases.yaml +197 -0
- package/canonical/skills/git-workflow/SKILL.md +41 -0
- package/canonical/skills/git-workflow/evals/cases.yaml +92 -0
- package/canonical/skills/local-code/SKILL.md +24 -0
- package/canonical/skills/local-code/evals/cases.yaml +85 -0
- package/canonical/skills/local-code/scripts/query_llama.py +68 -0
- package/canonical/skills/report-formatting/SKILL.md +62 -0
- package/canonical/skills/report-formatting/evals/cases.yaml +83 -0
- package/canonical/skills/report-formatting/reference/ARCHITECTURE.md +135 -0
- package/canonical/skills/report-formatting/reference/HELPERS.md +120 -0
- package/canonical/skills/report-formatting/reference/PPTX.md +136 -0
- package/canonical/skills/report-formatting/reference/RELEASE.md +99 -0
- package/canonical/skills/report-formatting/reference/TEMPLATES.md +48 -0
- package/canonical/skills/report-formatting/reference/authoring.md +66 -0
- package/canonical/skills/report-formatting/scripts/architecture-template.md +271 -0
- package/canonical/skills/report-formatting/scripts/assets/claro-logo.png +0 -0
- package/canonical/skills/report-formatting/scripts/assets/claro-wordmark.svg +1 -0
- package/canonical/skills/report-formatting/scripts/build-architecture.js +57 -0
- package/canonical/skills/report-formatting/scripts/build-md-claro.js +224 -0
- package/canonical/skills/report-formatting/scripts/build-release.js +51 -0
- package/canonical/skills/report-formatting/scripts/check-env.js +58 -0
- package/canonical/skills/report-formatting/scripts/docmodel.js +283 -0
- package/canonical/skills/report-formatting/scripts/example-build.js +119 -0
- package/canonical/skills/report-formatting/scripts/example_build_ArchitectureReview_docx.js +195 -0
- package/canonical/skills/report-formatting/scripts/example_build_ExecutiveReport_docx.js +114 -0
- package/canonical/skills/report-formatting/scripts/package.json +17 -0
- package/canonical/skills/report-formatting/scripts/pptx/example_build_StatusReport_pptx.py +223 -0
- package/canonical/skills/report-formatting/scripts/pptx/example_build_WeeklyStatus_pptx.py +245 -0
- package/canonical/skills/report-formatting/scripts/pptx/pptx_office.py +144 -0
- package/canonical/skills/report-formatting/scripts/pptx/requirements.txt +7 -0
- package/canonical/skills/report-formatting/scripts/pptx/status_report_blocks.py +193 -0
- package/canonical/skills/report-formatting/scripts/pptx/theme_claro_pptx.py +473 -0
- package/canonical/skills/report-formatting/scripts/release-template.md +80 -0
- package/canonical/skills/report-formatting/scripts/render-mermaid.js +105 -0
- package/canonical/skills/report-formatting/scripts/theme-claro.js +403 -0
- package/canonical/skills/subagent-driven-development/SKILL.md +60 -0
- package/canonical/skills/subagent-driven-development/evals/cases.yaml +208 -0
- package/canonical/skills/subagent-driven-development/reference/brief.md +91 -0
- package/canonical/skills/subagent-driven-development/reference/handoff.md +118 -0
- package/canonical/skills/subagent-driven-development/scripts/validate-handoff.mjs +850 -0
- package/canonical/skills/systematic-debugging/SKILL.md +44 -0
- package/canonical/skills/systematic-debugging/evals/cases.yaml +90 -0
- package/canonical/skills/test-driven-development/SKILL.md +42 -0
- package/canonical/skills/test-driven-development/evals/cases.yaml +86 -0
- package/canonical/skills/test-driven-development/reference/writing-good-tests.md +52 -0
- package/canonical/skills/verification-before-completion/SKILL.md +53 -0
- package/canonical/skills/verification-before-completion/evals/cases.yaml +107 -0
- package/dist/adapters/content/language-lint.d.ts +46 -0
- package/dist/adapters/content/language-lint.js +191 -0
- package/dist/adapters/harness/claude-code.d.ts +57 -0
- package/dist/adapters/harness/claude-code.js +385 -0
- package/dist/adapters/harness/index.d.ts +3 -0
- package/dist/adapters/harness/index.js +17 -0
- package/dist/adapters/harness/opencode.d.ts +7 -0
- package/dist/adapters/harness/opencode.js +166 -0
- package/dist/adapters/harness/plugin.d.ts +22 -0
- package/dist/adapters/harness/plugin.js +257 -0
- package/dist/adapters/memory/doctor.d.ts +480 -0
- package/dist/adapters/memory/doctor.js +1217 -0
- package/dist/adapters/memory/vendored.d.ts +150 -0
- package/dist/adapters/memory/vendored.js +487 -0
- package/dist/adapters/package/node.d.ts +9 -0
- package/dist/adapters/package/node.js +20 -0
- package/dist/adapters/prompt/readline.d.ts +19 -0
- package/dist/adapters/prompt/readline.js +53 -0
- package/dist/adapters/sync/diff.d.ts +43 -0
- package/dist/adapters/sync/diff.js +380 -0
- package/dist/cli/cleanup.d.ts +86 -0
- package/dist/cli/cleanup.js +382 -0
- package/dist/cli/cost.d.ts +304 -0
- package/dist/cli/cost.js +501 -0
- package/dist/cli/doctor.d.ts +205 -0
- package/dist/cli/doctor.js +654 -0
- package/dist/cli/executor.d.ts +5 -0
- package/dist/cli/executor.js +48 -0
- package/dist/cli/plugin-validate.d.ts +37 -0
- package/dist/cli/plugin-validate.js +256 -0
- package/dist/cli/prefix.d.ts +68 -0
- package/dist/cli/prefix.js +218 -0
- package/dist/cli/profile.d.ts +170 -0
- package/dist/cli/profile.js +285 -0
- package/dist/cli/runner.d.ts +10 -0
- package/dist/cli/runner.js +27 -0
- package/dist/cli/uninstall.d.ts +65 -0
- package/dist/cli/uninstall.js +147 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +989 -0
- package/dist/infra/dogfood.d.ts +31 -0
- package/dist/infra/dogfood.js +51 -0
- package/dist/infra/fsutil.d.ts +40 -0
- package/dist/infra/fsutil.js +143 -0
- package/dist/infra/manifest.d.ts +76 -0
- package/dist/infra/manifest.js +92 -0
- package/dist/infra/paths.d.ts +19 -0
- package/dist/infra/paths.js +74 -0
- package/dist/infra/routing.d.ts +4 -0
- package/dist/infra/routing.js +7 -0
- package/node_modules/@freeharness/core/dist/context.d.ts +30 -0
- package/node_modules/@freeharness/core/dist/context.js +1 -0
- package/node_modules/@freeharness/core/dist/index.d.ts +5 -0
- package/node_modules/@freeharness/core/dist/index.js +6 -0
- package/node_modules/@freeharness/core/dist/planner.d.ts +13 -0
- package/node_modules/@freeharness/core/dist/planner.js +18 -0
- package/node_modules/@freeharness/core/dist/ports.d.ts +90 -0
- package/node_modules/@freeharness/core/dist/ports.js +1 -0
- package/node_modules/@freeharness/core/dist/registry.d.ts +41 -0
- package/node_modules/@freeharness/core/dist/registry.js +124 -0
- package/node_modules/@freeharness/core/dist/tiers.d.ts +30 -0
- package/node_modules/@freeharness/core/dist/tiers.js +99 -0
- package/node_modules/@freeharness/core/package.json +34 -0
- package/node_modules/@freeharness/sdd/PROVENANCE.yaml +175 -0
- package/node_modules/@freeharness/sdd/dist/src/bin/openspec.d.ts +2 -0
- package/node_modules/@freeharness/sdd/dist/src/bin/openspec.js +166 -0
- package/node_modules/@freeharness/sdd/dist/src/index.d.ts +14 -0
- package/node_modules/@freeharness/sdd/dist/src/index.js +11 -0
- package/node_modules/@freeharness/sdd/dist/src/init.d.ts +39 -0
- package/node_modules/@freeharness/sdd/dist/src/init.js +190 -0
- package/node_modules/@freeharness/sdd/dist/src/root-resolver.d.ts +8 -0
- package/node_modules/@freeharness/sdd/dist/src/root-resolver.js +32 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/archive.d.ts +81 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/archive.js +483 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/context.d.ts +4 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/context.js +48 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.d.ts +57 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.js +279 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/instructions.d.ts +67 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/instructions.js +460 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/list.d.ts +5 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/list.js +95 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/new-change.d.ts +6 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/new-change.js +150 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/schemas.d.ts +4 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/schemas.js +23 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/shared.d.ts +56 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/shared.js +140 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/status.d.ts +8 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/status.js +85 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/validate.d.ts +6 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/validate.js +229 -0
- package/node_modules/@freeharness/sdd/dist/src/validate-change.d.ts +40 -0
- package/node_modules/@freeharness/sdd/dist/src/validate-change.js +114 -0
- package/node_modules/@freeharness/sdd/dist/src/validate.d.ts +24 -0
- package/node_modules/@freeharness/sdd/dist/src/validate.js +72 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.d.ts +130 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.js +981 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.d.ts +46 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.js +128 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.d.ts +26 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.js +32 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.d.ts +50 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.js +394 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.d.ts +15 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.js +49 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.d.ts +71 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.js +164 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.d.ts +11 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.js +21 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.d.ts +102 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.js +230 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.d.ts +18 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.js +138 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.d.ts +82 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.js +333 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.js +110 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.d.ts +11 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.js +32 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.d.ts +33 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.js +149 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.d.ts +39 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.js +49 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.js +31 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.d.ts +10 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.js +10 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.js +26 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.d.ts +28 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.js +41 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.d.ts +23 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.js +25 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.d.ts +72 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.js +76 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.d.ts +39 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.js +53 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.d.ts +62 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.js +7 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.d.ts +35 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.js +47 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.d.ts +33 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.js +55 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.d.ts +11 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.js +11 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.d.ts +48 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.js +99 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.d.ts +19 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.js +18 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.d.ts +18 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.js +4 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.d.ts +19 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.js +207 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.js +409 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.js +673 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.js +230 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.js +550 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.d.ts +8 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.js +107 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.js +228 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.js +147 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.js +571 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.js +322 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.d.ts +7 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.js +7 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.js +518 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.js +176 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.js +344 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.d.ts +39 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.js +54 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.d.ts +35 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.js +171 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.d.ts +27 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.js +210 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.d.ts +14 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.js +48 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.d.ts +22 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.js +186 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.d.ts +65 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.js +409 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.d.ts +55 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.js +98 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.d.ts +8 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.js +77 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.d.ts +44 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.js +116 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.js +17 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.d.ts +72 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.js +30 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.d.ts +3 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.js +3 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.d.ts +17 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.js +14 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.d.ts +39 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.js +114 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.d.ts +45 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.js +105 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.d.ts +15 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.js +56 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.d.ts +17 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.js +1 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.d.ts +94 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.js +756 -0
- package/node_modules/@freeharness/sdd/package.json +57 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/LICENSE.upstream +22 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/schema.upstream.yaml +232 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/README.md +19 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-apply-change/SKILL.md +187 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-archive-change/SKILL.md +181 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-bulk-archive-change/SKILL.md +338 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-continue-change/SKILL.md +117 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-explore/SKILL.md +342 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-ff-change/SKILL.md +116 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-new-change/SKILL.md +76 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-onboard/SKILL.md +560 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-propose/SKILL.md +162 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-sync-specs/SKILL.md +261 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-update-change/SKILL.md +90 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-verify-change/SKILL.md +174 -0
- package/package.json +70 -0
- package/provenance/canonical.PROVENANCE.yaml +740 -0
- package/provenance/claude-mem.LICENSE.upstream +202 -0
- package/provenance/memory.PROVENANCE.yaml +399 -0
- package/provenance/sdd.PROVENANCE.yaml +175 -0
- package/vendor-licenses/caveman.LICENSE +27 -0
- package/vendor-licenses/deepseek-harness.LICENSE +21 -0
- package/vendor-licenses/ecc.LICENSE +21 -0
- package/vendor-licenses/pi.LICENSE +21 -0
- 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();
|