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,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* check-env.js — Verifica os pré-requisitos para gerar os relatórios.
|
|
5
|
+
* Uso: node check-env.js
|
|
6
|
+
*/
|
|
7
|
+
const { execSync } = require("child_process");
|
|
8
|
+
|
|
9
|
+
/** Print a green check line (requirement satisfied). @param {string} m */
|
|
10
|
+
function ok(m) { console.log(" \x1b[32m✓\x1b[0m " + m); }
|
|
11
|
+
/** Print a red cross line (required prerequisite missing). @param {string} m */
|
|
12
|
+
function bad(m) { console.log(" \x1b[31m✗\x1b[0m " + m); }
|
|
13
|
+
/** Print a yellow bullet line (optional/informational note). @param {string} m */
|
|
14
|
+
function info(m) { console.log(" \x1b[33m•\x1b[0m " + m); }
|
|
15
|
+
|
|
16
|
+
let fail = 0;
|
|
17
|
+
|
|
18
|
+
console.log("\nVerificando ambiente para o tema Claro:\n");
|
|
19
|
+
|
|
20
|
+
// Node
|
|
21
|
+
try { const v = process.version; ok(`Node.js ${v}`); } catch { bad("Node.js não encontrado"); fail++; }
|
|
22
|
+
|
|
23
|
+
// docx
|
|
24
|
+
try { require.resolve("docx"); ok("pacote 'docx' instalado"); }
|
|
25
|
+
catch { bad("pacote 'docx' ausente → npm i docx"); fail++; }
|
|
26
|
+
|
|
27
|
+
// image-size
|
|
28
|
+
try { require.resolve("image-size"); ok("pacote 'image-size' instalado"); }
|
|
29
|
+
catch { info("pacote 'image-size' ausente (recomendado p/ diagramas) → npm i image-size"); }
|
|
30
|
+
|
|
31
|
+
// mermaid-cli
|
|
32
|
+
try { execSync("mmdc -V", { stdio: "pipe" }); ok("mermaid-cli (mmdc) disponível"); }
|
|
33
|
+
catch { info("mermaid-cli ausente (só necessário se houver diagramas) → npm i -g @mermaid-js/mermaid-cli"); }
|
|
34
|
+
|
|
35
|
+
// chrome para puppeteer
|
|
36
|
+
const fs = require("fs"); const os = require("os"); const path = require("path");
|
|
37
|
+
/** Whether a Chrome/Chromium binary is available (env var, puppeteer cache, or system path). @returns {boolean} */
|
|
38
|
+
function hasChrome() {
|
|
39
|
+
if (process.env.PUPPETEER_EXECUTABLE_PATH && fs.existsSync(process.env.PUPPETEER_EXECUTABLE_PATH)) return true;
|
|
40
|
+
const cache = path.join(os.homedir(), ".cache", "puppeteer");
|
|
41
|
+
let found = false;
|
|
42
|
+
const walk = (d) => { let e = []; try { e = fs.readdirSync(d, { withFileTypes: true }); } catch { return; }
|
|
43
|
+
for (const x of e) { const p = path.join(d, x.name); if (x.isDirectory()) walk(p);
|
|
44
|
+
else if (["chrome-headless-shell", "chrome", "chromium"].includes(x.name)) found = true; } };
|
|
45
|
+
walk(cache);
|
|
46
|
+
for (const p of ["/usr/bin/google-chrome", "/usr/bin/chromium", "/usr/bin/chromium-browser"]) if (fs.existsSync(p)) found = true;
|
|
47
|
+
return found;
|
|
48
|
+
}
|
|
49
|
+
if (hasChrome()) ok("Chrome/Chromium para renderizar Mermaid");
|
|
50
|
+
else info("Chrome ausente (só p/ diagramas) → npx puppeteer browsers install chrome-headless-shell");
|
|
51
|
+
|
|
52
|
+
// validação opcional (soffice)
|
|
53
|
+
try { execSync("soffice --version", { stdio: "pipe" }); ok("LibreOffice (soffice) — validação visual opcional"); }
|
|
54
|
+
catch { info("LibreOffice ausente (opcional, só p/ gerar PDF de conferência)"); }
|
|
55
|
+
|
|
56
|
+
console.log("");
|
|
57
|
+
if (fail) { console.log(`\x1b[31m${fail} pré-requisito(s) obrigatório(s) faltando.\x1b[0m\n`); process.exit(1); }
|
|
58
|
+
console.log("\x1b[32mPronto para gerar relatórios.\x1b[0m\n");
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* docmodel.js — render a .docx (Claro theme) from a content file with FIXED sections.
|
|
4
|
+
*
|
|
5
|
+
* A model (see build-release.js, build-architecture.js) declares the sections, the
|
|
6
|
+
* front-matter fields, the title/cover and the layout; the content file supplies
|
|
7
|
+
* front matter (key: value between `---` lines) plus `## ` sections in that order.
|
|
8
|
+
* Inside a section: paragraphs, `- ` bullets, `1. ` steps, pipe tables (optional
|
|
9
|
+
* `<!-- cols: 30 70 -->` before one), fenced code (```mermaid rendered to PNG via
|
|
10
|
+
* render-mermaid.js), `> ` callouts, ``, `### `/`#### `
|
|
11
|
+
* sub-headings, "Figura N –"/"Tabela N –" caption lines, HTML comments (ignored).
|
|
12
|
+
* Unknown sections, missing mandatory sections and malformed tables fail the build.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require("fs");
|
|
16
|
+
const path = require("path");
|
|
17
|
+
const os = require("os");
|
|
18
|
+
const { execFileSync } = require("child_process");
|
|
19
|
+
const { Packer, Paragraph, PageBreak } = require("docx");
|
|
20
|
+
const T = require("./theme-claro");
|
|
21
|
+
|
|
22
|
+
// ---- parsing helpers -------------------------------------------------------
|
|
23
|
+
const stripLinks = (s) => s.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
|
|
24
|
+
const isTableLine = (s) => /^\s*\|.*\|\s*$/.test(s);
|
|
25
|
+
const isSep = (s) => /^\s*\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)*\|?\s*$/.test(s);
|
|
26
|
+
const splitRow = (line) => line.trim().replace(/^\|/, "").replace(/\|$/, "").split(/(?<!\\)\|/).map((c) => c.trim().replace(/\\\|/g, "|"));
|
|
27
|
+
const isCaption = (s) => /^(Figura|Tabela|Quadro)\s+\d+\s*[–-]/.test(s.trim());
|
|
28
|
+
const isBlockStart = (s) => /^\s*([-*]|\d+[.)])\s+/.test(s) || isTableLine(s) || /^\s*```/.test(s) || /^\s*>/.test(s) || /^#{3,4}\s+/.test(s) || /^\s*!\[/.test(s) || /^\s*<!--/.test(s) || isCaption(s);
|
|
29
|
+
|
|
30
|
+
/** Column widths: the longest unbreakable token sets a floor; the longest cell shares the rest. */
|
|
31
|
+
function colWidths(rows, override) {
|
|
32
|
+
const W = T.contentWidth(), n = rows[0].length;
|
|
33
|
+
let w;
|
|
34
|
+
if (override && override.length === n) {
|
|
35
|
+
const sum = override.reduce((a, b) => a + b, 0);
|
|
36
|
+
w = override.map((x) => Math.floor(W * x / sum));
|
|
37
|
+
} else {
|
|
38
|
+
const clean = (c) => (c || "").replace(/[`*]/g, "");
|
|
39
|
+
const mins = Array.from({ length: n }, (_, c) => 260 + 105 * Math.max(...rows.map((r) => Math.max(...clean(r[c]).split(/\s+/).map((x) => x.length)))));
|
|
40
|
+
const weights = Array.from({ length: n }, (_, c) => Math.max(...rows.map((r) => Math.min(70, clean(r[c]).length))));
|
|
41
|
+
const minSum = mins.reduce((a, b) => a + b, 0);
|
|
42
|
+
const scale = minSum > W ? W / minSum : 1;
|
|
43
|
+
const rest = Math.max(0, W - minSum * scale);
|
|
44
|
+
const wSum = weights.reduce((a, b) => a + b, 0);
|
|
45
|
+
w = mins.map((m, c) => Math.floor(m * scale + rest * weights[c] / wSum));
|
|
46
|
+
}
|
|
47
|
+
w[n - 1] += W - w.reduce((a, b) => a + b, 0);
|
|
48
|
+
return w;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Render every ```mermaid block of the content file to PNGs (document order). */
|
|
52
|
+
function renderDiagrams(inputPath, fail) {
|
|
53
|
+
const src = fs.readFileSync(inputPath, "utf8");
|
|
54
|
+
if (!/^\s*```mermaid/m.test(src)) return [];
|
|
55
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "claro-diagrams-"));
|
|
56
|
+
try {
|
|
57
|
+
const out = execFileSync(process.execPath, [path.join(__dirname, "render-mermaid.js"), inputPath, dir], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
58
|
+
const json = JSON.parse(out.slice(out.indexOf("{")));
|
|
59
|
+
return json.pngs || [];
|
|
60
|
+
} catch (e) {
|
|
61
|
+
fail(`mermaid render failed (needs @mermaid-js/mermaid-cli + Chrome): ${String(e.stderr || e.message).trim().split("\n").pop()}`);
|
|
62
|
+
}
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Parse the blocks of one section into theme elements.
|
|
68
|
+
* @param {string[]} body - section lines.
|
|
69
|
+
* @param {object} ctx - { fail, baseDir, diagrams, nextDiagram, listInstance, subHeadings, categories }.
|
|
70
|
+
* @returns {Array} theme elements.
|
|
71
|
+
*/
|
|
72
|
+
function renderBlocks(body, ctx) {
|
|
73
|
+
const out = [];
|
|
74
|
+
let colsOverride = null;
|
|
75
|
+
let widthOverride = null;
|
|
76
|
+
let j = 0;
|
|
77
|
+
while (j < body.length) {
|
|
78
|
+
const line = body[j];
|
|
79
|
+
if (!line.trim()) { j++; continue; }
|
|
80
|
+
if (/^\s*<!--/.test(line)) { // guidance comments; "<!-- cols: 30 70 -->" sets the next table's widths, "<!-- width: 70 -->" the next image's width (% of text width)
|
|
81
|
+
const c = line.match(/cols:\s*([\d\s]+)-->/);
|
|
82
|
+
if (c) colsOverride = c[1].trim().split(/\s+/).map(Number);
|
|
83
|
+
const wd = line.match(/width:\s*(\d+)\s*-->/);
|
|
84
|
+
if (wd) widthOverride = Math.round(T.contentWidth() * 635 * Number(wd[1]) / 100);
|
|
85
|
+
while (j < body.length && !/-->/.test(body[j])) j++;
|
|
86
|
+
j++; continue;
|
|
87
|
+
}
|
|
88
|
+
const h = line.match(/^(#{3,4})\s+(.+?)\s*$/);
|
|
89
|
+
if (h) {
|
|
90
|
+
let title = h[2];
|
|
91
|
+
if (ctx.categories && h[1] === "###" && !ctx.categories.includes(title)) ctx.fail(`unknown category "### ${title}" — allowed: ${ctx.categories.join(" | ")}`);
|
|
92
|
+
const level = ctx.subHeadings === "h3" ? "h3" : (h[1] === "###" ? "h2" : "h3");
|
|
93
|
+
if (level === "h2" && ctx.sectionNumber !== undefined && ctx.sectionNumber !== null) { ctx.subCount += 1; title = `${ctx.sectionNumber}.${ctx.subCount} ${title}`; }
|
|
94
|
+
out.push(T[level](title));
|
|
95
|
+
j++; continue;
|
|
96
|
+
}
|
|
97
|
+
if (/^\s*```/.test(line)) {
|
|
98
|
+
const lang = line.trim().slice(3).trim().toLowerCase();
|
|
99
|
+
const code = [];
|
|
100
|
+
j++;
|
|
101
|
+
while (j < body.length && !/^\s*```/.test(body[j])) code.push(body[j++]);
|
|
102
|
+
j++;
|
|
103
|
+
if (lang === "mermaid") {
|
|
104
|
+
const png = ctx.diagrams[ctx.nextDiagram++];
|
|
105
|
+
if (!png) ctx.fail("mermaid block without a rendered diagram");
|
|
106
|
+
out.push(T.image(png, widthOverride || ctx.diagramWidth));
|
|
107
|
+
widthOverride = null;
|
|
108
|
+
} else out.push(T.codeBlock(code));
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const img = line.match(/^\s*!\[([^\]]*)\]\(([^)]+)\)\s*$/);
|
|
112
|
+
if (img) {
|
|
113
|
+
const p = path.resolve(ctx.baseDir, img[2]);
|
|
114
|
+
if (!fs.existsSync(p)) ctx.fail(`image not found: ${img[2]}`);
|
|
115
|
+
out.push(T.image(p, widthOverride || ctx.diagramWidth));
|
|
116
|
+
widthOverride = null;
|
|
117
|
+
if (img[1]) out.push(T.caption(img[1], { center: true }));
|
|
118
|
+
j++; continue;
|
|
119
|
+
}
|
|
120
|
+
if (isCaption(line)) { out.push(T.caption(line.trim(), { center: true })); j++; continue; }
|
|
121
|
+
if (/^\s*>/.test(line)) {
|
|
122
|
+
let text = "";
|
|
123
|
+
while (j < body.length && /^\s*>/.test(body[j])) text += (text ? " " : "") + body[j++].replace(/^\s*>\s?/, "").trim();
|
|
124
|
+
const kind = /^\*\*(atenção|aviso|risco|não|nota)/i.test(text) ? "note" : /^\*\*(quebra|incompat|crítico|bloqueio)/i.test(text) ? "danger" : /^\*\*(decisão|ok|aprovado|recomenda)/i.test(text) ? "success" : "info";
|
|
125
|
+
out.push(T.callout(stripLinks(text), kind));
|
|
126
|
+
out.push(T.spacer(80));
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (isTableLine(line)) {
|
|
130
|
+
const rows = [];
|
|
131
|
+
while (j < body.length && isTableLine(body[j])) { if (!isSep(body[j])) rows.push(splitRow(body[j])); j++; }
|
|
132
|
+
if (rows.length < 2) continue;
|
|
133
|
+
const head = rows[0];
|
|
134
|
+
const data = rows.slice(1).map((r) => { if (r.length !== head.length) ctx.fail(`table row has ${r.length} cells, header has ${head.length} (escape a literal pipe as \\|): ${r.join(" | ")}`); return r.map(stripLinks); });
|
|
135
|
+
out.push(T.makeTable(colWidths(rows, colsOverride), head, data, { rich: true }));
|
|
136
|
+
colsOverride = null;
|
|
137
|
+
// a caption line directly after the table keeps its spacing tight
|
|
138
|
+
if (j < body.length && isCaption(body[j])) { out.push(T.caption(body[j].trim())); j++; } else out.push(T.spacer(100));
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (/^\s*([-*]|\d+[.)])\s+/.test(line)) {
|
|
142
|
+
ctx.listInstance += 1;
|
|
143
|
+
while (j < body.length) {
|
|
144
|
+
const m = body[j].match(/^(\s*)([-*]|\d+[.)])\s+(.*)$/);
|
|
145
|
+
if (!m) break;
|
|
146
|
+
const lvl = m[1].replace(/\t/g, " ").length >= 2 ? 1 : 0;
|
|
147
|
+
let text = m[3];
|
|
148
|
+
let k = j + 1;
|
|
149
|
+
while (k < body.length && /^\s{2,}\S/.test(body[k]) && !isBlockStart(body[k])) text += " " + body[k++].trim();
|
|
150
|
+
if (/^\d/.test(m[2])) out.push(T.num(stripLinks(text), { instance: ctx.listInstance, lvl }));
|
|
151
|
+
else out.push(T.li(stripLinks(text), lvl));
|
|
152
|
+
j = k;
|
|
153
|
+
}
|
|
154
|
+
out.push(T.spacer(40));
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
let text = line.trim();
|
|
158
|
+
j++;
|
|
159
|
+
while (j < body.length && body[j].trim() && !isBlockStart(body[j])) text += " " + body[j++].trim();
|
|
160
|
+
out.push(T.p(stripLinks(text)));
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Front matter + sections of the content file, validated against the model. */
|
|
166
|
+
function parse(inputPath, model, fail) {
|
|
167
|
+
const lines = fs.readFileSync(inputPath, "utf8").split(/\r?\n/);
|
|
168
|
+
const meta = {};
|
|
169
|
+
let i = 0;
|
|
170
|
+
if (lines[0] && lines[0].trim() === "---") {
|
|
171
|
+
for (i = 1; i < lines.length && lines[i].trim() !== "---"; i++) {
|
|
172
|
+
const m = lines[i].match(/^([A-Za-z_]+)\s*:\s*(.*)$/);
|
|
173
|
+
if (m) meta[m[1]] = m[2].trim();
|
|
174
|
+
}
|
|
175
|
+
i += 1;
|
|
176
|
+
}
|
|
177
|
+
for (const k of model.requiredMeta) if (!meta[k]) fail(`front matter is missing "${k}"`);
|
|
178
|
+
const sections = new Map();
|
|
179
|
+
let current = null;
|
|
180
|
+
for (; i < lines.length; i++) {
|
|
181
|
+
const h = lines[i].match(/^##\s+(.+?)\s*$/);
|
|
182
|
+
if (h) {
|
|
183
|
+
const def = model.sections.find((s) => s.title === h[1]);
|
|
184
|
+
if (!def) fail(`unknown section "## ${h[1]}" — allowed: ${model.sections.map((s) => s.title).join(" | ")}`);
|
|
185
|
+
if (sections.has(def.key)) fail(`section "${def.title}" appears twice`);
|
|
186
|
+
current = []; sections.set(def.key, current);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (current) current.push(lines[i]);
|
|
190
|
+
}
|
|
191
|
+
for (const s of model.sections) if (s.mandatory && !sections.has(s.key)) fail(`mandatory section "## ${s.title}" is missing`);
|
|
192
|
+
return { meta, sections };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Build the document for a model and write the .docx.
|
|
197
|
+
* @param {object} model - { name, layout, sections, requiredMeta, meta, title(meta), headerText(meta),
|
|
198
|
+
* cover: "compact"|"page", subtitle(meta)?, subHeadings?, categories?, authorHeading?,
|
|
199
|
+
* renderSection?(key, body, ctx, children) -> boolean handled }.
|
|
200
|
+
* @param {string} inputPath - content file (.md).
|
|
201
|
+
* @param {string} outputPath - target .docx.
|
|
202
|
+
*/
|
|
203
|
+
async function build(model, inputPath, outputPath) {
|
|
204
|
+
const fail = (msg) => { console.error(`${model.name} model: ${msg}`); process.exit(1); };
|
|
205
|
+
T.configure({ layout: model.layout || "compact" });
|
|
206
|
+
const { meta, sections } = parse(inputPath, model, fail);
|
|
207
|
+
const diagrams = renderDiagrams(inputPath, fail);
|
|
208
|
+
const ctx = { fail, baseDir: path.dirname(path.resolve(inputPath)), diagrams, nextDiagram: 0, listInstance: 0,
|
|
209
|
+
subHeadings: model.subHeadings, categories: model.categories, diagramWidth: model.diagramWidth, meta };
|
|
210
|
+
|
|
211
|
+
const children = [];
|
|
212
|
+
const metaRows = model.meta.filter(([k]) => meta[k]).map(([k, label]) => [label, (model.monoMeta || []).includes(k) ? meta[k].replace(/^(?!`)(\S+)/, "`$1`") : meta[k]]);
|
|
213
|
+
if (model.cover === "page") {
|
|
214
|
+
children.push(...T.coverBlock({ title: model.coverTitle || model.title(meta), subtitle: model.subtitle ? model.subtitle(meta) : undefined, tagline: model.tagline ? model.tagline(meta) : undefined, org: model.org ? model.org(meta) : undefined, metaLines: model.coverLines ? model.coverLines(meta) : [] }));
|
|
215
|
+
children.push(T.spacer(200));
|
|
216
|
+
if (model.coverTable !== false) children.push(T.metaTable(metaRows));
|
|
217
|
+
children.push(new Paragraph({ children: [new PageBreak()] }));
|
|
218
|
+
if (model.toc !== false) {
|
|
219
|
+
// static table of contents (titles only): deterministic in Word and LibreOffice,
|
|
220
|
+
// no "update fields" prompt; Word's navigation pane still works via outline levels
|
|
221
|
+
children.push(T.h1(model.tocTitle || "Sumário"));
|
|
222
|
+
let n = model.numberFrom === undefined ? null : model.numberFrom - 1;
|
|
223
|
+
for (const s of model.sections) {
|
|
224
|
+
const body = sections.get(s.key);
|
|
225
|
+
if (!body) continue;
|
|
226
|
+
let number = null;
|
|
227
|
+
if (s.numbered && n !== null) { n += 1; number = n; }
|
|
228
|
+
const label = number !== null ? `${number}. ${s.title}` : s.title;
|
|
229
|
+
children.push(new Paragraph({ spacing: { before: 80, after: 20 }, children: [T.t(label, { bold: true, size: T.SZ.body, color: T.C.h2 })] }));
|
|
230
|
+
let k = 0;
|
|
231
|
+
const clean = body.join("\n").replace(/<!--[\s\S]*?-->/g, "").split("\n");
|
|
232
|
+
for (const ln of clean) {
|
|
233
|
+
const m = ln.match(/^###\s+(.+?)\s*$/);
|
|
234
|
+
if (!m) continue;
|
|
235
|
+
k += 1;
|
|
236
|
+
const sub = number !== null ? `${number}.${k} ${m[1]}` : m[1];
|
|
237
|
+
children.push(new Paragraph({ spacing: { after: 10 }, indent: { left: 480 }, children: [T.t(sub, { size: T.SZ.cell, color: T.C.body })] }));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
children.push(new Paragraph({ children: [new PageBreak()] }));
|
|
241
|
+
}
|
|
242
|
+
} else {
|
|
243
|
+
children.push(...T.coverBlock({ title: model.title(meta), rule: false }));
|
|
244
|
+
children.push(T.metaTable(metaRows));
|
|
245
|
+
children.push(T.spacer(200));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
let seq = model.numberFrom === undefined ? null : model.numberFrom - 1; // numbered sections count only those present
|
|
249
|
+
for (const s of model.sections) {
|
|
250
|
+
const body = sections.get(s.key);
|
|
251
|
+
if (!body) continue;
|
|
252
|
+
const content = body.join("\n").replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
253
|
+
if (!content) fail(`section "## ${s.title}" is empty — fill it or remove it${s.mandatory ? ' (mandatory: write "Nenhuma." / "Não se aplica." when it does not apply)' : ""}`);
|
|
254
|
+
let number = null;
|
|
255
|
+
if (s.numbered && seq !== null) { seq += 1; number = seq; }
|
|
256
|
+
ctx.sectionNumber = number; ctx.subCount = 0;
|
|
257
|
+
children.push(T.h1(number !== null ? `${number}. ${s.title}` : s.title, s.pageBreakBefore ? { pageBreakBefore: true } : {}));
|
|
258
|
+
if (model.renderSection && model.renderSection(s.key, body, ctx, children, content)) continue;
|
|
259
|
+
children.push(...renderBlocks(body, ctx));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
children.push(...T.authorBlock({ heading: model.authorHeading || "ELABORAÇÃO", name: meta.author || "André Negrelli", role: meta.role || "Tech Lead AI Data Engineer", area: meta.area, project: meta.project || meta.app }));
|
|
263
|
+
const doc = T.buildDocument({ children, headerText: model.headerText(meta), footerAuthor: `${meta.author || "André Negrelli"} — ${meta.role || "Tech Lead AI Data Engineer"} | ${meta.area || "DADOS & IA"}`, updateFields: false });
|
|
264
|
+
|
|
265
|
+
// never overwrite a document Word holds open (lock "~$<name>"): Word reloads images lazily and would save broken links
|
|
266
|
+
const outAbs = path.resolve(outputPath);
|
|
267
|
+
const lock = path.join(path.dirname(outAbs), "~$" + path.basename(outAbs).slice(2));
|
|
268
|
+
const target = fs.existsSync(lock) ? outAbs.replace(/\.docx$/i, "-new.docx") : outAbs;
|
|
269
|
+
if (target !== outAbs) console.warn(`${model.name} model: ${path.basename(outAbs)} is open in Word; writing ${path.basename(target)} instead — close Word and rename.`);
|
|
270
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
271
|
+
const buf = await Packer.toBuffer(doc);
|
|
272
|
+
fs.writeFileSync(target, buf);
|
|
273
|
+
console.log("Generated:", target, `(${buf.length} bytes)`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** CLI wrapper: `node build-<model>.js <content.md> <out.docx>`. */
|
|
277
|
+
function main(model) {
|
|
278
|
+
const [inputPath, outputPath] = process.argv.slice(2);
|
|
279
|
+
if (!inputPath || !outputPath) { console.error(`usage: build-${model.name}.js <content.md> <output.docx>`); process.exit(2); }
|
|
280
|
+
build(model, inputPath, outputPath).catch((e) => { console.error(e); process.exit(1); });
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
module.exports = { build, main, renderBlocks, parse, colWidths };
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* example-build.js — Template MÍNIMO de geração de um relatório no tema Claro.
|
|
5
|
+
*
|
|
6
|
+
* Copie este arquivo, renomeie (ex.: build-<slug>.js) e preencha `children`
|
|
7
|
+
* com o conteúdo real, usando os helpers de ./theme-claro.js.
|
|
8
|
+
*
|
|
9
|
+
* Uso:
|
|
10
|
+
* node example-build.js # gera ./out/Exemplo_Tema_Claro.docx
|
|
11
|
+
* node example-build.js /caminho/saida.docx # caminho de saída custom
|
|
12
|
+
*
|
|
13
|
+
* Para diagramas Mermaid: rode antes
|
|
14
|
+
* node render-mermaid.js entrada.md ./_diagramas
|
|
15
|
+
* e use T.image("./_diagramas/diagram_01.png") nas posições certas.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require("fs");
|
|
19
|
+
const path = require("path");
|
|
20
|
+
const { Packer, AlignmentType } = require("docx");
|
|
21
|
+
const T = require("./theme-claro");
|
|
22
|
+
|
|
23
|
+
const children = [];
|
|
24
|
+
|
|
25
|
+
// ---- CAPA ----
|
|
26
|
+
children.push(...T.coverBlock({
|
|
27
|
+
title: "Título do Relatório — Subsistema",
|
|
28
|
+
subtitle: "STT — Claro (Projeto Speech-to-Text)",
|
|
29
|
+
tagline: "Linha de descrição curta do que o relatório entrega",
|
|
30
|
+
org: "Projeto STT — Claro | Aquisição DADOS & IA",
|
|
31
|
+
metaLines: [
|
|
32
|
+
"Status: proposta para validação",
|
|
33
|
+
"Data: 19/06/2026",
|
|
34
|
+
"Fonte dos dados: <origem>",
|
|
35
|
+
],
|
|
36
|
+
}));
|
|
37
|
+
children.push(T.spacer(240));
|
|
38
|
+
|
|
39
|
+
// ---- METADADOS (memorando) ----
|
|
40
|
+
children.push(T.metaTable([
|
|
41
|
+
["Para", "Destinatário"],
|
|
42
|
+
["De", "Aquisição DADOS & IA — (Projeto Speech-to-Text)"],
|
|
43
|
+
["Data", "19/06/2026"],
|
|
44
|
+
["Referência", [T.t("Documento relacionado, se houver", { size: 20, color: T.C.body })]],
|
|
45
|
+
]));
|
|
46
|
+
children.push(T.spacer(200));
|
|
47
|
+
|
|
48
|
+
// ---- SUMÁRIO EXECUTIVO ----
|
|
49
|
+
children.push(T.h1("1. Sumário executivo"));
|
|
50
|
+
children.push(T.body([
|
|
51
|
+
T.t("Frase de abertura com o achado central em ", { size: 22, color: T.C.body }),
|
|
52
|
+
T.t("negrito para o que importa", { size: 22, bold: true }),
|
|
53
|
+
T.t(". O transporte é a poeira; o gargalo é a montanha.", { size: 22, color: T.C.body }),
|
|
54
|
+
]));
|
|
55
|
+
|
|
56
|
+
// stat cards (números que importam)
|
|
57
|
+
children.push(T.statCards([
|
|
58
|
+
{ value: "99,99%", label: "métrica crítica", color: T.C.deepRed, fill: "FFEDED" },
|
|
59
|
+
{ value: "306×", label: "outro indicador", color: T.C.deepRed, fill: "FFEDED" },
|
|
60
|
+
{ value: "16,3%", label: "alerta", color: T.C.amber, fill: T.C.noteFill },
|
|
61
|
+
{ value: "OK", label: "saudável", color: T.C.green, fill: T.C.successFill },
|
|
62
|
+
]));
|
|
63
|
+
children.push(T.spacer(160));
|
|
64
|
+
|
|
65
|
+
children.push(T.bullet([T.t("Mensagem-âncora 1. ", { size: 22, bold: true }), T.t("explicação.", { size: 22, color: T.C.body })]));
|
|
66
|
+
children.push(T.bullet([T.t("Mensagem-âncora 2. ", { size: 22, bold: true }), T.t("explicação.", { size: 22, color: T.C.body })]));
|
|
67
|
+
|
|
68
|
+
children.push(T.calloutLine("Recomendação:", "ação principal proposta, em uma frase.", "success"));
|
|
69
|
+
children.push(T.spacer(200));
|
|
70
|
+
|
|
71
|
+
// ---- SEÇÃO COM TABELA ----
|
|
72
|
+
children.push(T.h1("2. Análise"));
|
|
73
|
+
children.push(T.body("Texto introdutório da tabela."));
|
|
74
|
+
children.push(T.makeTable(
|
|
75
|
+
[3200, 1600, 4840],
|
|
76
|
+
["Item", "Valor", "Observação"],
|
|
77
|
+
[
|
|
78
|
+
[{ runs: "Linha A" }, { runs: [T.t("12.775", { size: 20, bold: true, color: T.C.red })], align: AlignmentType.RIGHT }, { runs: "nota" }],
|
|
79
|
+
[{ runs: "Linha B" }, { runs: "7.194", align: AlignmentType.RIGHT }, { runs: [T.t("ok", { size: 20, color: T.C.green })] }],
|
|
80
|
+
]
|
|
81
|
+
));
|
|
82
|
+
children.push(T.caption("Tabela 1 – Legenda da tabela."));
|
|
83
|
+
|
|
84
|
+
children.push(T.calloutLine("Leitura executiva:", "o que esses números significam para a decisão.", "info"));
|
|
85
|
+
children.push(T.spacer(160));
|
|
86
|
+
|
|
87
|
+
// ---- BLOCO DE CÓDIGO / LOG ----
|
|
88
|
+
children.push(T.h2("2.1 Evidência (log)"));
|
|
89
|
+
children.push(T.codeBlock([
|
|
90
|
+
'"event":"processing_error", "stage":"transcribe", "attempt":4,',
|
|
91
|
+
'"error_type":"UnboundLocalError"',
|
|
92
|
+
]));
|
|
93
|
+
|
|
94
|
+
// ---- DIAGRAMA (descomente após render-mermaid.js) ----
|
|
95
|
+
// children.push(T.h1("3. Diagramas"));
|
|
96
|
+
// children.push(T.image(path.join(__dirname, "_diagramas", "diagram_01.png"), 6050000));
|
|
97
|
+
// children.push(T.caption("Figura 1 – Legenda.", { center: true }));
|
|
98
|
+
|
|
99
|
+
// ---- AUTORIA ----
|
|
100
|
+
children.push(...T.authorBlock({
|
|
101
|
+
name: "André Negrelli",
|
|
102
|
+
role: "Tech Lead — AI Data Engineer",
|
|
103
|
+
area: "DADOS & IA | Tech Dados & IA — Aquisição e Transformação de Dados & IA",
|
|
104
|
+
project: "Projeto STT — Claro · 19/06/2026",
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
// ---- MONTAGEM ----
|
|
108
|
+
const doc = T.buildDocument({
|
|
109
|
+
children,
|
|
110
|
+
headerText: "Título do Relatório | STT Claro",
|
|
111
|
+
footerAuthor: "André Negrelli — DADOS & IA",
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const outPath = process.argv[2] || path.join(process.cwd(), "out", "Exemplo_Tema_Claro.docx");
|
|
115
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
116
|
+
Packer.toBuffer(doc).then((buf) => {
|
|
117
|
+
fs.writeFileSync(outPath, buf);
|
|
118
|
+
console.log("Gerado:", outPath, `(${buf.length} bytes)`);
|
|
119
|
+
});
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Template: Architecture review report (.docx, Claro theme).
|
|
5
|
+
*
|
|
6
|
+
* For a review of an existing system or agentic design: what was reviewed, how the
|
|
7
|
+
* architecture stands today, what was found (ranked by severity), which decisions
|
|
8
|
+
* the team already took, what still puts the system at risk, and the roadmap that
|
|
9
|
+
* closes the findings. The verdict is the first thing the reader sees. Copy this
|
|
10
|
+
* file, rename (build-<slug>.js), and fill `children` with the real content using
|
|
11
|
+
* the ./theme-claro.js helpers. Content placeholders are PT-BR (client-facing);
|
|
12
|
+
* comments are English.
|
|
13
|
+
*
|
|
14
|
+
* Differs from the Architecture & System Design model (build-architecture.js): that
|
|
15
|
+
* one DESCRIBES a system (arc42/C4); this one JUDGES it against criteria and ends
|
|
16
|
+
* with a PASS / FAIL / CONDITIONAL verdict and a remediation plan.
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* node example_build_ArchitectureReview_docx.js # ./out/Revisao_Arquitetural.docx
|
|
20
|
+
* node example_build_ArchitectureReview_docx.js /path/out.docx
|
|
21
|
+
*/
|
|
22
|
+
const fs = require("fs");
|
|
23
|
+
const path = require("path");
|
|
24
|
+
const { Packer, AlignmentType } = require("docx");
|
|
25
|
+
const T = require("./theme-claro");
|
|
26
|
+
|
|
27
|
+
const children = [];
|
|
28
|
+
|
|
29
|
+
/** Severity scale shared by the findings table and the summary cards. */
|
|
30
|
+
const SEV = {
|
|
31
|
+
critica: { label: "Crítica", color: T.C.deepRed, fill: T.C.dangerFill },
|
|
32
|
+
alta: { label: "Alta", color: T.C.red, fill: "FFEDED" },
|
|
33
|
+
media: { label: "Média", color: T.C.amber, fill: T.C.noteFill },
|
|
34
|
+
baixa: { label: "Baixa", color: T.C.green, fill: T.C.successFill },
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Builds one findings-table row with a severity chip in the first cell.
|
|
39
|
+
* @param {string} id Finding id (e.g. "F-01").
|
|
40
|
+
* @param {keyof SEV} sev Severity key.
|
|
41
|
+
* @param {string} area Architectural area (e.g. "Fronteira core/infra").
|
|
42
|
+
* @param {string} finding One-sentence finding.
|
|
43
|
+
* @param {string} evidence Where it was observed (file, module, trace).
|
|
44
|
+
* @returns {object[]} Row cells for T.makeTable.
|
|
45
|
+
*/
|
|
46
|
+
function findingRow(id, sev, area, finding, evidence) {
|
|
47
|
+
const s = SEV[sev];
|
|
48
|
+
return [
|
|
49
|
+
{ runs: [T.t(id, { size: 20, bold: true })] },
|
|
50
|
+
{ runs: [T.t(s.label, { size: 20, bold: true, color: s.color })], fill: s.fill, align: AlignmentType.CENTER },
|
|
51
|
+
{ runs: area },
|
|
52
|
+
{ runs: finding },
|
|
53
|
+
{ runs: [T.mono(evidence, 18)] },
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ---- COVER ----
|
|
58
|
+
children.push(...T.coverBlock({
|
|
59
|
+
title: "Revisão Arquitetural — <Sistema / Componente>",
|
|
60
|
+
subtitle: "<Projeto> — Claro",
|
|
61
|
+
tagline: "Achados, decisões e roadmap de remediação",
|
|
62
|
+
org: "<Projeto> — Claro | DADOS & IA",
|
|
63
|
+
metaLines: ["Escopo: <versão / branch / PR revisados>", "Data: DD/MM/AAAA"],
|
|
64
|
+
}));
|
|
65
|
+
children.push(T.spacer(240));
|
|
66
|
+
|
|
67
|
+
// ---- VERDICT FIRST ----
|
|
68
|
+
children.push(T.h1("Resumo executivo e veredito"));
|
|
69
|
+
children.push(T.body([
|
|
70
|
+
T.t("Veredito: ", { size: 22, bold: true }),
|
|
71
|
+
T.t("APROVADO COM CONDIÇÕES", { size: 22, bold: true, color: T.C.amber }),
|
|
72
|
+
T.t(" — uma frase com o motivo dominante e o que precisa mudar antes do próximo marco.", { size: 22, color: T.C.body }),
|
|
73
|
+
]));
|
|
74
|
+
children.push(T.statCards([
|
|
75
|
+
{ value: "1", label: "achado crítico", color: SEV.critica.color, fill: SEV.critica.fill },
|
|
76
|
+
{ value: "2", label: "achados altos", color: SEV.alta.color, fill: SEV.alta.fill },
|
|
77
|
+
{ value: "3", label: "médios / baixos", color: SEV.media.color, fill: SEV.media.fill },
|
|
78
|
+
{ value: "4 sem", label: "prazo de remediação", color: T.C.accent, fill: T.C.infoFill },
|
|
79
|
+
]));
|
|
80
|
+
children.push(T.spacer(140));
|
|
81
|
+
children.push(T.calloutLine("Condição de aprovação:", "os achados críticos e altos fechados e re-verificados antes do go-live.", "note"));
|
|
82
|
+
children.push(T.spacer(200));
|
|
83
|
+
|
|
84
|
+
// ---- 1. CONTEXT ----
|
|
85
|
+
children.push(T.h1("1. Contexto da revisão"));
|
|
86
|
+
children.push(T.metaTable([
|
|
87
|
+
["Objeto revisado", "<sistema / serviço / subgrafo> — versão <x.y> (commit <sha>)"],
|
|
88
|
+
["Motivação", "<gate de fase, incidente, mudança de escopo, auditoria>"],
|
|
89
|
+
["Critérios", "aderência ao blueprint, regra de dependência, contratos externos, segurança de entrada, observabilidade, testabilidade"],
|
|
90
|
+
["Método", "leitura de código e specs, execução da suíte, rastreamento de uma requisição ponta a ponta"],
|
|
91
|
+
["Fora de escopo", "<o que não foi avaliado e por quê>"],
|
|
92
|
+
]));
|
|
93
|
+
children.push(T.caption("Tabela 1 – Escopo e critérios da revisão."));
|
|
94
|
+
|
|
95
|
+
// ---- 2. CURRENT ARCHITECTURE ----
|
|
96
|
+
children.push(T.h1("2. Arquitetura atual"));
|
|
97
|
+
children.push(T.p("Descrição curta de como o sistema está hoje: camadas, fronteiras, fluxo principal. Um diagrama pré-renderizado (render-mermaid.js) ajuda aqui."));
|
|
98
|
+
// children.push(T.image("./_diagrams/contexto.png", T.CONTENT_W));
|
|
99
|
+
children.push(T.makeTable(
|
|
100
|
+
[2400, 3600, 3440],
|
|
101
|
+
["Camada", "Responsabilidade observada", "Desvio em relação ao blueprint"],
|
|
102
|
+
[
|
|
103
|
+
[{ runs: "core" }, { runs: "regra de negócio e contratos" }, { runs: [T.t("nenhum", { size: 20, color: T.C.green })] }],
|
|
104
|
+
[{ runs: "infra" }, { runs: "adaptadores LLM, persistência, observabilidade" }, { runs: [T.t("importa core corretamente; um adaptador acopla framework ao domínio", { size: 20, color: T.C.amber })] }],
|
|
105
|
+
[{ runs: "entry" }, { runs: "API HTTP, composição" }, { runs: [T.t("composição duplicada em dois pontos", { size: 20, color: T.C.deepRed })] }],
|
|
106
|
+
]
|
|
107
|
+
));
|
|
108
|
+
children.push(T.caption("Tabela 2 – Camadas e desvios observados."));
|
|
109
|
+
|
|
110
|
+
// ---- 3. FINDINGS BY SEVERITY ----
|
|
111
|
+
children.push(T.h1("3. Achados por severidade"));
|
|
112
|
+
children.push(T.p("Ordem: Crítica > Alta > Média > Baixa. Cada achado aponta a evidência (arquivo, módulo ou trace) e recebe uma ação no roadmap da seção 6."));
|
|
113
|
+
children.push(T.makeTable(
|
|
114
|
+
[800, 1100, 1900, 3640, 2000],
|
|
115
|
+
["ID", "Severidade", "Área", "Achado", "Evidência"],
|
|
116
|
+
[
|
|
117
|
+
findingRow("F-01", "critica", "Fronteira de decisão", "A decisão de negócio depende da saída do LLM em vez do motor determinístico.", "infra/llm/router.py:88"),
|
|
118
|
+
findingRow("F-02", "alta", "Contrato externo", "Campo renomeado no payload de resposta sem versionamento.", "core/contract.py"),
|
|
119
|
+
findingRow("F-03", "alta", "Segurança de entrada", "Texto livre do operador entra no prompt sem delimitação.", "infra/llm/prompts.py"),
|
|
120
|
+
findingRow("F-04", "media", "Observabilidade", "Trace não correlaciona a chamada LLM com a requisição HTTP.", "entry/api.py"),
|
|
121
|
+
findingRow("F-05", "baixa", "Toolchain", "Lint de dependência configurado mas não executado no CI.", ".github/workflows"),
|
|
122
|
+
]
|
|
123
|
+
));
|
|
124
|
+
children.push(T.caption("Tabela 3 – Achados ordenados por severidade."));
|
|
125
|
+
children.push(T.h2("Detalhe dos achados críticos e altos"));
|
|
126
|
+
children.push(T.callout([
|
|
127
|
+
T.body([T.t("F-01 — ", { size: 22, bold: true }), T.t("o que acontece, por que viola o critério, qual o impacto se ficar como está.", { size: 22, color: T.C.body })]),
|
|
128
|
+
T.bullet([T.t("Evidência: ", { size: 22, bold: true }), T.t("trecho, log ou trace.", { size: 22, color: T.C.body })]),
|
|
129
|
+
T.bullet([T.t("Correção esperada: ", { size: 22, bold: true }), T.t("a mudança mínima que fecha o achado.", { size: 22, color: T.C.body })]),
|
|
130
|
+
], "danger"));
|
|
131
|
+
children.push(T.spacer(160));
|
|
132
|
+
|
|
133
|
+
// ---- 4. DECISION RECORDS ----
|
|
134
|
+
children.push(T.h1("4. Registro de decisões (ADR resumido)"));
|
|
135
|
+
children.push(T.p("Decisões tomadas durante ou em consequência da revisão. Uma linha por decisão; o ADR completo fica na documentação de arquitetura."));
|
|
136
|
+
children.push(T.makeTable(
|
|
137
|
+
[900, 3000, 2800, 2740],
|
|
138
|
+
["ADR", "Decisão", "Alternativas descartadas", "Consequências"],
|
|
139
|
+
[
|
|
140
|
+
[{ runs: [T.t("ADR-01", { size: 20, bold: true })] }, { runs: "Motor determinístico decide; LLM só classifica e redige." }, { runs: "LLM decide com guardrails" }, { runs: "decisão auditável; menor latência; eval mais simples" }],
|
|
141
|
+
[{ runs: [T.t("ADR-02", { size: 20, bold: true })] }, { runs: "Contrato externo versionado por cabeçalho." }, { runs: "campo novo sem versão" }, { runs: "compatibilidade com o consumidor; custo de manter duas versões" }],
|
|
142
|
+
]
|
|
143
|
+
));
|
|
144
|
+
children.push(T.caption("Tabela 4 – Decisões registradas."));
|
|
145
|
+
|
|
146
|
+
// ---- 5. RISKS ----
|
|
147
|
+
children.push(T.h1("5. Riscos residuais"));
|
|
148
|
+
children.push(T.makeTable(
|
|
149
|
+
[900, 3400, 1400, 1400, 2340],
|
|
150
|
+
["ID", "Risco", "Probabilidade", "Impacto", "Mitigação / dono"],
|
|
151
|
+
[
|
|
152
|
+
[{ runs: [T.t("R-01", { size: 20, bold: true })] }, { runs: "Regressão silenciosa no contrato após a migração." }, { runs: [T.t("Média", { size: 20, color: T.C.amber })], align: AlignmentType.CENTER }, { runs: [T.t("Alto", { size: 20, color: T.C.deepRed })], align: AlignmentType.CENTER }, { runs: "teste de contrato no CI — <dono>" }],
|
|
153
|
+
[{ runs: [T.t("R-02", { size: 20, bold: true })] }, { runs: "Provedor LLM indisponível durante o pico." }, { runs: [T.t("Baixa", { size: 20, color: T.C.green })], align: AlignmentType.CENTER }, { runs: [T.t("Médio", { size: 20, color: T.C.amber })], align: AlignmentType.CENTER }, { runs: "nó de erro de negócio + retry — <dono>" }],
|
|
154
|
+
]
|
|
155
|
+
));
|
|
156
|
+
children.push(T.caption("Tabela 5 – Riscos que permanecem após a remediação planejada."));
|
|
157
|
+
|
|
158
|
+
// ---- 6. RECOMMENDATION ROADMAP ----
|
|
159
|
+
children.push(T.h1("6. Roadmap de recomendações"));
|
|
160
|
+
children.push(T.p("Ondas curtas, cada uma fechando achados nomeados. A onda 1 é condição do veredito."));
|
|
161
|
+
children.push(T.makeTable(
|
|
162
|
+
[1400, 3600, 1800, 2640],
|
|
163
|
+
["Onda", "Ação", "Fecha", "Prazo / dono"],
|
|
164
|
+
[
|
|
165
|
+
[{ runs: [T.t("Onda 1", { size: 20, bold: true, color: T.C.deepRed })], fill: T.C.dangerFill }, { runs: "Mover a decisão para o motor determinístico; delimitar o texto do operador." }, { runs: [T.mono("F-01, F-03", 18)] }, { runs: "2 semanas — <dono>" }],
|
|
166
|
+
[{ runs: [T.t("Onda 2", { size: 20, bold: true, color: T.C.amber })], fill: T.C.noteFill }, { runs: "Versionar o contrato; correlacionar traces." }, { runs: [T.mono("F-02, F-04", 18)] }, { runs: "4 semanas — <dono>" }],
|
|
167
|
+
[{ runs: [T.t("Onda 3", { size: 20, bold: true, color: T.C.green })], fill: T.C.successFill }, { runs: "Lint de dependência no CI; higiene." }, { runs: [T.mono("F-05", 18)] }, { runs: "contínuo — <dono>" }],
|
|
168
|
+
]
|
|
169
|
+
));
|
|
170
|
+
children.push(T.caption("Tabela 6 – Roadmap de remediação."));
|
|
171
|
+
children.push(T.spacer(160));
|
|
172
|
+
children.push(T.callout([
|
|
173
|
+
T.body([T.t("Re-verificação: ", { size: 22, bold: true }), T.t("a revisão é reaberta ao fim da onda 1 com os mesmos critérios; o veredito muda para APROVADO apenas com evidência (testes, traces) anexada.", { size: 22, color: T.C.body })]),
|
|
174
|
+
], "info"));
|
|
175
|
+
|
|
176
|
+
// ---- AUTHORSHIP ----
|
|
177
|
+
children.push(...T.authorBlock({
|
|
178
|
+
name: "André Negrelli",
|
|
179
|
+
role: "Tech Lead — AI Data Engineer",
|
|
180
|
+
area: "DADOS & IA | Tech Dados & IA — Aquisição e Transformação de Dados & IA",
|
|
181
|
+
project: "<Projeto> — Claro · DD/MM/AAAA",
|
|
182
|
+
}));
|
|
183
|
+
|
|
184
|
+
const doc = T.buildDocument({
|
|
185
|
+
children,
|
|
186
|
+
headerText: "Revisão Arquitetural | <Projeto> Claro",
|
|
187
|
+
footerAuthor: "André Negrelli — DADOS & IA",
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const outPath = process.argv[2] || path.join(process.cwd(), "out", "Revisao_Arquitetural.docx");
|
|
191
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
192
|
+
Packer.toBuffer(doc).then((buf) => {
|
|
193
|
+
fs.writeFileSync(outPath, buf);
|
|
194
|
+
console.log("Gerado:", outPath, `(${buf.length} bytes)`);
|
|
195
|
+
});
|