grimoire-framework 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CLAUDE.md +318 -0
- package/.claude/hooks/README.md +170 -0
- package/.claude/hooks/enforce-architecture-first.py +198 -0
- package/.claude/hooks/install-hooks.sh +43 -0
- package/.claude/hooks/mind-clone-governance.py +192 -0
- package/.claude/hooks/pre-commit-version-check.sh +157 -0
- package/.claude/hooks/precompact-session-digest.js +47 -0
- package/.claude/hooks/read-protection.py +153 -0
- package/.claude/hooks/slug-validation.py +176 -0
- package/.claude/hooks/sql-governance.py +182 -0
- package/.claude/hooks/synapse-engine.js +77 -0
- package/.claude/hooks/write-path-validation.py +196 -0
- package/.claude/rules/mcp-usage.md +177 -0
- package/.grimoire/cli/commands/config/index.js +609 -0
- package/.grimoire/cli/commands/generate/index.js +222 -0
- package/.grimoire/cli/commands/manifest/index.js +47 -0
- package/.grimoire/cli/commands/manifest/regenerate.js +97 -0
- package/.grimoire/cli/commands/manifest/validate.js +66 -0
- package/.grimoire/cli/commands/mcp/add.js +235 -0
- package/.grimoire/cli/commands/mcp/index.js +77 -0
- package/.grimoire/cli/commands/mcp/link.js +218 -0
- package/.grimoire/cli/commands/mcp/setup.js +165 -0
- package/.grimoire/cli/commands/mcp/status.js +184 -0
- package/.grimoire/cli/commands/metrics/cleanup.js +91 -0
- package/.grimoire/cli/commands/metrics/index.js +66 -0
- package/.grimoire/cli/commands/metrics/record.js +154 -0
- package/.grimoire/cli/commands/metrics/seed.js +127 -0
- package/.grimoire/cli/commands/metrics/show.js +209 -0
- package/.grimoire/cli/commands/migrate/analyze.js +355 -0
- package/.grimoire/cli/commands/migrate/backup.js +354 -0
- package/.grimoire/cli/commands/migrate/execute.js +294 -0
- package/.grimoire/cli/commands/migrate/index.js +443 -0
- package/.grimoire/cli/commands/migrate/rollback.js +325 -0
- package/.grimoire/cli/commands/migrate/update-imports.js +398 -0
- package/.grimoire/cli/commands/migrate/validate.js +454 -0
- package/.grimoire/cli/commands/pro/index.js +705 -0
- package/.grimoire/cli/commands/qa/index.js +57 -0
- package/.grimoire/cli/commands/qa/run.js +163 -0
- package/.grimoire/cli/commands/qa/status.js +195 -0
- package/.grimoire/cli/commands/validate/index.js +431 -0
- package/.grimoire/cli/commands/workers/formatters/info-formatter.js +275 -0
- package/.grimoire/cli/commands/workers/formatters/list-table.js +265 -0
- package/.grimoire/cli/commands/workers/formatters/list-tree.js +160 -0
- package/.grimoire/cli/commands/workers/index.js +57 -0
- package/.grimoire/cli/commands/workers/info.js +195 -0
- package/.grimoire/cli/commands/workers/list.js +215 -0
- package/.grimoire/cli/commands/workers/search-filters.js +185 -0
- package/.grimoire/cli/commands/workers/search-keyword.js +310 -0
- package/.grimoire/cli/commands/workers/search-semantic.js +294 -0
- package/.grimoire/cli/commands/workers/search.js +155 -0
- package/.grimoire/cli/commands/workers/utils/pagination.js +102 -0
- package/.grimoire/cli/index.js +150 -0
- package/.grimoire/cli/utils/output-formatter-cli.js +233 -0
- package/.grimoire/cli/utils/score-calculator.js +221 -0
- package/.grimoire/constitution.md +172 -0
- package/.grimoire/core/README.md +231 -0
- package/.grimoire/core/code-intel/code-intel-client.js +280 -0
- package/.grimoire/core/code-intel/code-intel-enricher.js +160 -0
- package/.grimoire/core/code-intel/index.js +137 -0
- package/.grimoire/core/code-intel/providers/code-graph-provider.js +201 -0
- package/.grimoire/core/code-intel/providers/provider-interface.js +108 -0
- package/.grimoire/core/config/config-cache.js +233 -0
- package/.grimoire/core/config/config-loader.js +281 -0
- package/.grimoire/core/config/config-resolver.js +609 -0
- package/.grimoire/core/config/env-interpolator.js +122 -0
- package/.grimoire/core/config/merge-utils.js +101 -0
- package/.grimoire/core/config/migrate-config.js +293 -0
- package/.grimoire/core/config/schemas/framework-config.schema.json +19 -0
- package/.grimoire/core/config/schemas/local-config.schema.json +20 -0
- package/.grimoire/core/config/schemas/project-config.schema.json +32 -0
- package/.grimoire/core/config/schemas/user-config.schema.json +33 -0
- package/.grimoire/core/config/templates/user-config.yaml +24 -0
- package/.grimoire/core/docs/SHARD-TRANSLATION-GUIDE.md +337 -0
- package/.grimoire/core/docs/component-creation-guide.md +459 -0
- package/.grimoire/core/docs/session-update-pattern.md +316 -0
- package/.grimoire/core/docs/template-syntax.md +267 -0
- package/.grimoire/core/docs/troubleshooting-guide.md +626 -0
- package/.grimoire/core/elicitation/agent-elicitation.js +272 -0
- package/.grimoire/core/elicitation/elicitation-engine.js +486 -0
- package/.grimoire/core/elicitation/session-manager.js +322 -0
- package/.grimoire/core/elicitation/task-elicitation.js +281 -0
- package/.grimoire/core/elicitation/workflow-elicitation.js +349 -0
- package/.grimoire/core/events/dashboard-emitter.js +369 -0
- package/.grimoire/core/events/index.js +17 -0
- package/.grimoire/core/events/types.js +52 -0
- package/.grimoire/core/execution/autonomous-build-loop.js +1068 -0
- package/.grimoire/core/execution/build-orchestrator.js +1055 -0
- package/.grimoire/core/execution/build-state-manager.js +1530 -0
- package/.grimoire/core/execution/context-injector.js +537 -0
- package/.grimoire/core/execution/parallel-executor.js +292 -0
- package/.grimoire/core/execution/parallel-monitor.js +429 -0
- package/.grimoire/core/execution/rate-limit-manager.js +314 -0
- package/.grimoire/core/execution/result-aggregator.js +486 -0
- package/.grimoire/core/execution/semantic-merge-engine.js +1736 -0
- package/.grimoire/core/execution/subagent-dispatcher.js +848 -0
- package/.grimoire/core/execution/wave-executor.js +397 -0
- package/.grimoire/core/health-check/base-check.js +224 -0
- package/.grimoire/core/health-check/check-registry.js +253 -0
- package/.grimoire/core/health-check/checks/deployment/build-config.js +111 -0
- package/.grimoire/core/health-check/checks/deployment/ci-config.js +125 -0
- package/.grimoire/core/health-check/checks/deployment/deployment-readiness.js +152 -0
- package/.grimoire/core/health-check/checks/deployment/docker-config.js +122 -0
- package/.grimoire/core/health-check/checks/deployment/env-file.js +111 -0
- package/.grimoire/core/health-check/checks/deployment/index.js +29 -0
- package/.grimoire/core/health-check/checks/index.js +56 -0
- package/.grimoire/core/health-check/checks/local/disk-space.js +214 -0
- package/.grimoire/core/health-check/checks/local/environment-vars.js +136 -0
- package/.grimoire/core/health-check/checks/local/git-install.js +158 -0
- package/.grimoire/core/health-check/checks/local/ide-detection.js +148 -0
- package/.grimoire/core/health-check/checks/local/index.js +35 -0
- package/.grimoire/core/health-check/checks/local/memory.js +138 -0
- package/.grimoire/core/health-check/checks/local/network.js +170 -0
- package/.grimoire/core/health-check/checks/local/npm-install.js +149 -0
- package/.grimoire/core/health-check/checks/local/shell-environment.js +120 -0
- package/.grimoire/core/health-check/checks/project/agent-config.js +167 -0
- package/.grimoire/core/health-check/checks/project/dependencies.js +150 -0
- package/.grimoire/core/health-check/checks/project/framework-config.js +133 -0
- package/.grimoire/core/health-check/checks/project/grimoire-directory.js +143 -0
- package/.grimoire/core/health-check/checks/project/index.js +35 -0
- package/.grimoire/core/health-check/checks/project/node-version.js +163 -0
- package/.grimoire/core/health-check/checks/project/package-json.js +107 -0
- package/.grimoire/core/health-check/checks/project/task-definitions.js +192 -0
- package/.grimoire/core/health-check/checks/project/workflow-dependencies.js +214 -0
- package/.grimoire/core/health-check/checks/repository/branch-protection.js +107 -0
- package/.grimoire/core/health-check/checks/repository/commit-history.js +144 -0
- package/.grimoire/core/health-check/checks/repository/conflicts.js +152 -0
- package/.grimoire/core/health-check/checks/repository/git-repo.js +159 -0
- package/.grimoire/core/health-check/checks/repository/git-status.js +149 -0
- package/.grimoire/core/health-check/checks/repository/gitignore.js +194 -0
- package/.grimoire/core/health-check/checks/repository/index.js +35 -0
- package/.grimoire/core/health-check/checks/repository/large-files.js +183 -0
- package/.grimoire/core/health-check/checks/repository/lockfile-integrity.js +144 -0
- package/.grimoire/core/health-check/checks/services/api-endpoints.js +168 -0
- package/.grimoire/core/health-check/checks/services/claude-code.js +139 -0
- package/.grimoire/core/health-check/checks/services/gemini-cli.js +241 -0
- package/.grimoire/core/health-check/checks/services/github-cli.js +117 -0
- package/.grimoire/core/health-check/checks/services/index.js +29 -0
- package/.grimoire/core/health-check/checks/services/mcp-integration.js +125 -0
- package/.grimoire/core/health-check/engine.js +407 -0
- package/.grimoire/core/health-check/healers/backup-manager.js +340 -0
- package/.grimoire/core/health-check/healers/index.js +330 -0
- package/.grimoire/core/health-check/index.js +370 -0
- package/.grimoire/core/health-check/reporters/console.js +331 -0
- package/.grimoire/core/health-check/reporters/index.js +117 -0
- package/.grimoire/core/health-check/reporters/json.js +301 -0
- package/.grimoire/core/health-check/reporters/markdown.js +323 -0
- package/.grimoire/core/ideation/ideation-engine.js +834 -0
- package/.grimoire/core/ids/README.md +123 -0
- package/.grimoire/core/ids/circuit-breaker.js +156 -0
- package/.grimoire/core/ids/framework-governor.js +567 -0
- package/.grimoire/core/ids/gates/g1-epic-creation.js +101 -0
- package/.grimoire/core/ids/gates/g2-story-creation.js +133 -0
- package/.grimoire/core/ids/gates/g3-story-validation.js +166 -0
- package/.grimoire/core/ids/gates/g4-dev-context.js +155 -0
- package/.grimoire/core/ids/incremental-decision-engine.js +651 -0
- package/.grimoire/core/ids/index.js +157 -0
- package/.grimoire/core/ids/registry-healer.js +868 -0
- package/.grimoire/core/ids/registry-loader.js +281 -0
- package/.grimoire/core/ids/registry-updater.js +703 -0
- package/.grimoire/core/ids/verification-gate.js +306 -0
- package/.grimoire/core/index.esm.js +44 -0
- package/.grimoire/core/index.js +90 -0
- package/.grimoire/core/manifest/manifest-generator.js +388 -0
- package/.grimoire/core/manifest/manifest-validator.js +431 -0
- package/.grimoire/core/mcp/config-migrator.js +341 -0
- package/.grimoire/core/mcp/global-config-manager.js +370 -0
- package/.grimoire/core/mcp/index.js +34 -0
- package/.grimoire/core/mcp/os-detector.js +189 -0
- package/.grimoire/core/mcp/symlink-manager.js +415 -0
- package/.grimoire/core/memory/__tests__/active-modules.verify.js +254 -0
- package/.grimoire/core/memory/gotchas-memory.js +1154 -0
- package/.grimoire/core/migration/migration-config.yaml +85 -0
- package/.grimoire/core/migration/module-mapping.yaml +91 -0
- package/.grimoire/core/orchestration/agent-invoker.js +612 -0
- package/.grimoire/core/orchestration/bob-orchestrator.js +1032 -0
- package/.grimoire/core/orchestration/bob-status-writer.js +482 -0
- package/.grimoire/core/orchestration/bob-surface-criteria.yaml +272 -0
- package/.grimoire/core/orchestration/brownfield-handler.js +741 -0
- package/.grimoire/core/orchestration/checklist-runner.js +328 -0
- package/.grimoire/core/orchestration/cli-commands.js +581 -0
- package/.grimoire/core/orchestration/condition-evaluator.js +379 -0
- package/.grimoire/core/orchestration/context-manager.js +616 -0
- package/.grimoire/core/orchestration/dashboard-integration.js +520 -0
- package/.grimoire/core/orchestration/data-lifecycle-manager.js +357 -0
- package/.grimoire/core/orchestration/epic-context-accumulator.js +396 -0
- package/.grimoire/core/orchestration/execution-profile-resolver.js +107 -0
- package/.grimoire/core/orchestration/executor-assignment.js +413 -0
- package/.grimoire/core/orchestration/executors/epic-3-executor.js +223 -0
- package/.grimoire/core/orchestration/executors/epic-4-executor.js +269 -0
- package/.grimoire/core/orchestration/executors/epic-5-executor.js +329 -0
- package/.grimoire/core/orchestration/executors/epic-6-executor.js +265 -0
- package/.grimoire/core/orchestration/executors/epic-executor.js +237 -0
- package/.grimoire/core/orchestration/executors/index.js +86 -0
- package/.grimoire/core/orchestration/gate-evaluator.js +495 -0
- package/.grimoire/core/orchestration/gemini-model-selector.js +161 -0
- package/.grimoire/core/orchestration/greenfield-handler.js +890 -0
- package/.grimoire/core/orchestration/index.js +323 -0
- package/.grimoire/core/orchestration/lock-manager.js +327 -0
- package/.grimoire/core/orchestration/master-orchestrator.js +1544 -0
- package/.grimoire/core/orchestration/message-formatter.js +279 -0
- package/.grimoire/core/orchestration/parallel-executor.js +225 -0
- package/.grimoire/core/orchestration/recovery-handler.js +721 -0
- package/.grimoire/core/orchestration/session-state.js +876 -0
- package/.grimoire/core/orchestration/skill-dispatcher.js +364 -0
- package/.grimoire/core/orchestration/subagent-prompt-builder.js +370 -0
- package/.grimoire/core/orchestration/surface-checker.js +403 -0
- package/.grimoire/core/orchestration/task-complexity-classifier.js +123 -0
- package/.grimoire/core/orchestration/tech-stack-detector.js +599 -0
- package/.grimoire/core/orchestration/terminal-spawner.js +1044 -0
- package/.grimoire/core/orchestration/workflow-executor.js +1182 -0
- package/.grimoire/core/orchestration/workflow-orchestrator.js +907 -0
- package/.grimoire/core/permissions/__tests__/permission-mode.test.js +293 -0
- package/.grimoire/core/permissions/index.js +140 -0
- package/.grimoire/core/permissions/operation-guard.js +395 -0
- package/.grimoire/core/permissions/permission-mode.js +271 -0
- package/.grimoire/core/quality-gates/base-layer.js +134 -0
- package/.grimoire/core/quality-gates/checklist-generator.js +329 -0
- package/.grimoire/core/quality-gates/focus-area-recommender.js +361 -0
- package/.grimoire/core/quality-gates/human-review-orchestrator.js +530 -0
- package/.grimoire/core/quality-gates/layer1-precommit.js +336 -0
- package/.grimoire/core/quality-gates/layer2-pr-automation.js +331 -0
- package/.grimoire/core/quality-gates/layer3-human-review.js +350 -0
- package/.grimoire/core/quality-gates/notification-manager.js +551 -0
- package/.grimoire/core/quality-gates/quality-gate-config.yaml +87 -0
- package/.grimoire/core/quality-gates/quality-gate-manager.js +603 -0
- package/.grimoire/core/registry/README.md +181 -0
- package/.grimoire/core/registry/build-registry.js +454 -0
- package/.grimoire/core/registry/registry-loader.js +331 -0
- package/.grimoire/core/registry/registry-schema.json +168 -0
- package/.grimoire/core/registry/service-registry.json +6468 -0
- package/.grimoire/core/registry/validate-registry.js +341 -0
- package/.grimoire/core/session/context-detector.js +233 -0
- package/.grimoire/core/session/context-loader.js +443 -0
- package/.grimoire/core/synapse/context/context-builder.js +34 -0
- package/.grimoire/core/synapse/context/context-tracker.js +190 -0
- package/.grimoire/core/synapse/diagnostics/collectors/consistency-collector.js +168 -0
- package/.grimoire/core/synapse/diagnostics/collectors/hook-collector.js +129 -0
- package/.grimoire/core/synapse/diagnostics/collectors/manifest-collector.js +82 -0
- package/.grimoire/core/synapse/diagnostics/collectors/output-analyzer.js +134 -0
- package/.grimoire/core/synapse/diagnostics/collectors/pipeline-collector.js +75 -0
- package/.grimoire/core/synapse/diagnostics/collectors/quality-collector.js +252 -0
- package/.grimoire/core/synapse/diagnostics/collectors/relevance-matrix.js +174 -0
- package/.grimoire/core/synapse/diagnostics/collectors/safe-read-json.js +31 -0
- package/.grimoire/core/synapse/diagnostics/collectors/session-collector.js +102 -0
- package/.grimoire/core/synapse/diagnostics/collectors/timing-collector.js +126 -0
- package/.grimoire/core/synapse/diagnostics/collectors/uap-collector.js +83 -0
- package/.grimoire/core/synapse/diagnostics/report-formatter.js +485 -0
- package/.grimoire/core/synapse/diagnostics/synapse-diagnostics.js +95 -0
- package/.grimoire/core/synapse/domain/domain-loader.js +322 -0
- package/.grimoire/core/synapse/engine.js +380 -0
- package/.grimoire/core/synapse/layers/l0-constitution.js +80 -0
- package/.grimoire/core/synapse/layers/l1-global.js +102 -0
- package/.grimoire/core/synapse/layers/l2-agent.js +94 -0
- package/.grimoire/core/synapse/layers/l3-workflow.js +94 -0
- package/.grimoire/core/synapse/layers/l4-task.js +83 -0
- package/.grimoire/core/synapse/layers/l5-squad.js +244 -0
- package/.grimoire/core/synapse/layers/l6-keyword.js +154 -0
- package/.grimoire/core/synapse/layers/l7-star-command.js +169 -0
- package/.grimoire/core/synapse/layers/layer-processor.js +82 -0
- package/.grimoire/core/synapse/memory/memory-bridge.js +246 -0
- package/.grimoire/core/synapse/output/formatter.js +561 -0
- package/.grimoire/core/synapse/runtime/hook-runtime.js +61 -0
- package/.grimoire/core/synapse/scripts/generate-constitution.js +205 -0
- package/.grimoire/core/synapse/session/session-manager.js +403 -0
- package/.grimoire/core/synapse/utils/paths.js +57 -0
- package/.grimoire/core/synapse/utils/tokens.js +25 -0
- package/.grimoire/core/ui/index.js +43 -0
- package/.grimoire/core/ui/observability-panel.js +394 -0
- package/.grimoire/core/ui/panel-renderer.js +337 -0
- package/.grimoire/core/utils/output-formatter.js +299 -0
- package/.grimoire/core/utils/security-utils.js +336 -0
- package/.grimoire/core/utils/yaml-validator.js +416 -0
- package/.grimoire/core-config.yaml +357 -0
- package/.grimoire/data/agent-config-requirements.yaml +409 -0
- package/.grimoire/data/entity-registry.yaml +9219 -0
- package/.grimoire/data/grimoire-kb.md +918 -0
- package/.grimoire/data/learned-patterns.yaml +3 -0
- package/.grimoire/data/tech-presets/_template.md +259 -0
- package/.grimoire/data/tech-presets/nextjs-react.md +933 -0
- package/.grimoire/data/technical-preferences.md +85 -0
- package/.grimoire/data/workflow-patterns.yaml +836 -0
- package/.grimoire/data/workflow-state-schema.yaml +203 -0
- package/.grimoire/development/README.md +143 -0
- package/.grimoire/development/agent-teams/team-all.yaml +16 -0
- package/.grimoire/development/agent-teams/team-fullstack.yaml +19 -0
- package/.grimoire/development/agent-teams/team-ide-minimal.yaml +10 -0
- package/.grimoire/development/agent-teams/team-no-ui.yaml +14 -0
- package/.grimoire/development/agent-teams/team-qa-focused.yaml +155 -0
- package/.grimoire/development/agents/analyst.md +261 -0
- package/.grimoire/development/agents/architect.md +461 -0
- package/.grimoire/development/agents/caravaggio.md +31 -0
- package/.grimoire/development/agents/data-engineer.md +482 -0
- package/.grimoire/development/agents/dev.md +548 -0
- package/.grimoire/development/agents/devops.md +500 -0
- package/.grimoire/development/agents/frida.md +31 -0
- package/.grimoire/development/agents/grimoire-master.md +447 -0
- package/.grimoire/development/agents/picasso.md +31 -0
- package/.grimoire/development/agents/pm.md +365 -0
- package/.grimoire/development/agents/po.md +323 -0
- package/.grimoire/development/agents/qa.md +437 -0
- package/.grimoire/development/agents/salvador.md +31 -0
- package/.grimoire/development/agents/sm.md +275 -0
- package/.grimoire/development/agents/squad-creator.md +330 -0
- package/.grimoire/development/agents/tarsila.md +31 -0
- package/.grimoire/development/agents/ux-design-expert.md +482 -0
- package/.grimoire/development/agents/van-gogh.md +31 -0
- package/.grimoire/development/agents/warhol.md +31 -0
- package/.grimoire/development/checklists/agent-quality-gate.md +560 -0
- package/.grimoire/development/checklists/brownfield-compatibility-checklist.md +116 -0
- package/.grimoire/development/checklists/self-critique-checklist.md +274 -0
- package/.grimoire/development/data/decision-heuristics-framework.md +622 -0
- package/.grimoire/development/data/quality-dimensions-framework.md +427 -0
- package/.grimoire/development/data/tier-system-framework.md +476 -0
- package/.grimoire/development/scripts/activation-runtime.js +64 -0
- package/.grimoire/development/scripts/agent-assignment-resolver.js +231 -0
- package/.grimoire/development/scripts/agent-config-loader.js +628 -0
- package/.grimoire/development/scripts/agent-exit-hooks.js +97 -0
- package/.grimoire/development/scripts/apply-inline-greeting-all-agents.js +147 -0
- package/.grimoire/development/scripts/approval-workflow.js +643 -0
- package/.grimoire/development/scripts/audit-agent-config.js +382 -0
- package/.grimoire/development/scripts/backlog-manager.js +409 -0
- package/.grimoire/development/scripts/backup-manager.js +607 -0
- package/.grimoire/development/scripts/batch-update-agents-session-context.js +97 -0
- package/.grimoire/development/scripts/branch-manager.js +390 -0
- package/.grimoire/development/scripts/code-quality-improver.js +1312 -0
- package/.grimoire/development/scripts/commit-message-generator.js +850 -0
- package/.grimoire/development/scripts/conflict-resolver.js +675 -0
- package/.grimoire/development/scripts/decision-context.js +229 -0
- package/.grimoire/development/scripts/decision-log-generator.js +294 -0
- package/.grimoire/development/scripts/decision-log-indexer.js +285 -0
- package/.grimoire/development/scripts/decision-recorder.js +169 -0
- package/.grimoire/development/scripts/dependency-analyzer.js +639 -0
- package/.grimoire/development/scripts/dev-context-loader.js +298 -0
- package/.grimoire/development/scripts/diff-generator.js +352 -0
- package/.grimoire/development/scripts/elicitation-engine.js +385 -0
- package/.grimoire/development/scripts/elicitation-session-manager.js +300 -0
- package/.grimoire/development/scripts/generate-greeting.js +109 -0
- package/.grimoire/development/scripts/git-wrapper.js +462 -0
- package/.grimoire/development/scripts/greeting-builder.js +1406 -0
- package/.grimoire/development/scripts/greeting-config-cli.js +86 -0
- package/.grimoire/development/scripts/greeting-preference-manager.js +170 -0
- package/.grimoire/development/scripts/manifest-preview.js +245 -0
- package/.grimoire/development/scripts/metrics-tracker.js +776 -0
- package/.grimoire/development/scripts/migrate-task-to-v2.js +379 -0
- package/.grimoire/development/scripts/modification-validator.js +555 -0
- package/.grimoire/development/scripts/pattern-learner.js +1225 -0
- package/.grimoire/development/scripts/performance-analyzer.js +758 -0
- package/.grimoire/development/scripts/populate-entity-registry.js +281 -0
- package/.grimoire/development/scripts/refactoring-suggester.js +1139 -0
- package/.grimoire/development/scripts/rollback-handler.js +532 -0
- package/.grimoire/development/scripts/security-checker.js +359 -0
- package/.grimoire/development/scripts/skill-validator.js +343 -0
- package/.grimoire/development/scripts/squad/README.md +114 -0
- package/.grimoire/development/scripts/squad/index.js +124 -0
- package/.grimoire/development/scripts/squad/squad-analyzer.js +638 -0
- package/.grimoire/development/scripts/squad/squad-designer.js +1010 -0
- package/.grimoire/development/scripts/squad/squad-downloader.js +511 -0
- package/.grimoire/development/scripts/squad/squad-extender.js +872 -0
- package/.grimoire/development/scripts/squad/squad-generator.js +1406 -0
- package/.grimoire/development/scripts/squad/squad-loader.js +359 -0
- package/.grimoire/development/scripts/squad/squad-migrator.js +628 -0
- package/.grimoire/development/scripts/squad/squad-publisher.js +630 -0
- package/.grimoire/development/scripts/squad/squad-validator.js +857 -0
- package/.grimoire/development/scripts/story-index-generator.js +339 -0
- package/.grimoire/development/scripts/story-manager.js +375 -0
- package/.grimoire/development/scripts/story-update-hook.js +259 -0
- package/.grimoire/development/scripts/task-identifier-resolver.js +145 -0
- package/.grimoire/development/scripts/template-engine.js +240 -0
- package/.grimoire/development/scripts/template-validator.js +279 -0
- package/.grimoire/development/scripts/test-generator.js +844 -0
- package/.grimoire/development/scripts/test-greeting-system.js +143 -0
- package/.grimoire/development/scripts/transaction-manager.js +591 -0
- package/.grimoire/development/scripts/unified-activation-pipeline.js +796 -0
- package/.grimoire/development/scripts/usage-tracker.js +675 -0
- package/.grimoire/development/scripts/validate-filenames.js +228 -0
- package/.grimoire/development/scripts/validate-task-v2.js +320 -0
- package/.grimoire/development/scripts/verify-workflow-gaps.js +1034 -0
- package/.grimoire/development/scripts/version-tracker.js +527 -0
- package/.grimoire/development/scripts/workflow-navigator.js +328 -0
- package/.grimoire/development/scripts/workflow-state-manager.js +652 -0
- package/.grimoire/development/scripts/workflow-validator.js +697 -0
- package/.grimoire/development/scripts/yaml-validator.js +397 -0
- package/.grimoire/development/tasks/add-mcp.md +437 -0
- package/.grimoire/development/tasks/advanced-elicitation.md +320 -0
- package/.grimoire/development/tasks/analyst-facilitate-brainstorming.md +343 -0
- package/.grimoire/development/tasks/analyze-brownfield.md +458 -0
- package/.grimoire/development/tasks/analyze-cross-artifact.md +358 -0
- package/.grimoire/development/tasks/analyze-framework.md +698 -0
- package/.grimoire/development/tasks/analyze-performance.md +639 -0
- package/.grimoire/development/tasks/analyze-project-structure.md +623 -0
- package/.grimoire/development/tasks/apply-qa-fixes.md +342 -0
- package/.grimoire/development/tasks/architect-analyze-impact.md +828 -0
- package/.grimoire/development/tasks/audit-codebase.md +431 -0
- package/.grimoire/development/tasks/audit-tailwind-config.md +272 -0
- package/.grimoire/development/tasks/audit-utilities.md +360 -0
- package/.grimoire/development/tasks/blocks/README.md +180 -0
- package/.grimoire/development/tasks/blocks/agent-prompt-template.md +117 -0
- package/.grimoire/development/tasks/blocks/context-loading.md +110 -0
- package/.grimoire/development/tasks/blocks/execution-pattern.md +122 -0
- package/.grimoire/development/tasks/blocks/finalization.md +123 -0
- package/.grimoire/development/tasks/bootstrap-shadcn-library.md +288 -0
- package/.grimoire/development/tasks/brownfield-create-epic.md +533 -0
- package/.grimoire/development/tasks/brownfield-create-story.md +358 -0
- package/.grimoire/development/tasks/build-autonomous.md +186 -0
- package/.grimoire/development/tasks/build-component.md +480 -0
- package/.grimoire/development/tasks/build-resume.md +125 -0
- package/.grimoire/development/tasks/build-status.md +155 -0
- package/.grimoire/development/tasks/build.md +142 -0
- package/.grimoire/development/tasks/calculate-roi.md +457 -0
- package/.grimoire/development/tasks/check-docs-links.md +114 -0
- package/.grimoire/development/tasks/ci-cd-configuration.md +766 -0
- package/.grimoire/development/tasks/cleanup-utilities.md +672 -0
- package/.grimoire/development/tasks/cleanup-worktrees.md +39 -0
- package/.grimoire/development/tasks/collaborative-edit.md +1110 -0
- package/.grimoire/development/tasks/compose-molecule.md +286 -0
- package/.grimoire/development/tasks/consolidate-patterns.md +416 -0
- package/.grimoire/development/tasks/correct-course.md +281 -0
- package/.grimoire/development/tasks/create-agent.md +1199 -0
- package/.grimoire/development/tasks/create-brownfield-story.md +728 -0
- package/.grimoire/development/tasks/create-deep-research-prompt.md +500 -0
- package/.grimoire/development/tasks/create-doc.md +318 -0
- package/.grimoire/development/tasks/create-next-story.md +776 -0
- package/.grimoire/development/tasks/create-service.md +393 -0
- package/.grimoire/development/tasks/create-suite.md +285 -0
- package/.grimoire/development/tasks/create-task.md +391 -0
- package/.grimoire/development/tasks/create-workflow.md +429 -0
- package/.grimoire/development/tasks/create-worktree.md +439 -0
- package/.grimoire/development/tasks/db-analyze-hotpaths.md +574 -0
- package/.grimoire/development/tasks/db-apply-migration.md +383 -0
- package/.grimoire/development/tasks/db-bootstrap.md +644 -0
- package/.grimoire/development/tasks/db-domain-modeling.md +695 -0
- package/.grimoire/development/tasks/db-dry-run.md +295 -0
- package/.grimoire/development/tasks/db-env-check.md +262 -0
- package/.grimoire/development/tasks/db-explain.md +633 -0
- package/.grimoire/development/tasks/db-impersonate.md +497 -0
- package/.grimoire/development/tasks/db-load-csv.md +595 -0
- package/.grimoire/development/tasks/db-policy-apply.md +655 -0
- package/.grimoire/development/tasks/db-rls-audit.md +413 -0
- package/.grimoire/development/tasks/db-rollback.md +741 -0
- package/.grimoire/development/tasks/db-run-sql.md +615 -0
- package/.grimoire/development/tasks/db-schema-audit.md +1013 -0
- package/.grimoire/development/tasks/db-seed.md +392 -0
- package/.grimoire/development/tasks/db-smoke-test.md +353 -0
- package/.grimoire/development/tasks/db-snapshot.md +571 -0
- package/.grimoire/development/tasks/db-squad-integration.md +665 -0
- package/.grimoire/development/tasks/db-supabase-setup.md +714 -0
- package/.grimoire/development/tasks/db-verify-order.md +517 -0
- package/.grimoire/development/tasks/deprecate-component.md +958 -0
- package/.grimoire/development/tasks/dev-apply-qa-fixes.md +320 -0
- package/.grimoire/development/tasks/dev-backlog-debt.md +471 -0
- package/.grimoire/development/tasks/dev-develop-story.md +912 -0
- package/.grimoire/development/tasks/dev-improve-code-quality.md +874 -0
- package/.grimoire/development/tasks/dev-optimize-performance.md +1035 -0
- package/.grimoire/development/tasks/dev-suggest-refactoring.md +872 -0
- package/.grimoire/development/tasks/dev-validate-next-story.md +350 -0
- package/.grimoire/development/tasks/document-gotchas.md +479 -0
- package/.grimoire/development/tasks/document-project.md +554 -0
- package/.grimoire/development/tasks/environment-bootstrap.md +1391 -0
- package/.grimoire/development/tasks/execute-checklist.md +303 -0
- package/.grimoire/development/tasks/execute-epic-plan.md +887 -0
- package/.grimoire/development/tasks/export-design-tokens-dtcg.md +276 -0
- package/.grimoire/development/tasks/extend-pattern.md +271 -0
- package/.grimoire/development/tasks/extract-patterns.md +399 -0
- package/.grimoire/development/tasks/extract-tokens.md +469 -0
- package/.grimoire/development/tasks/facilitate-brainstorming-session.md +520 -0
- package/.grimoire/development/tasks/generate-ai-frontend-prompt.md +262 -0
- package/.grimoire/development/tasks/generate-documentation.md +286 -0
- package/.grimoire/development/tasks/generate-migration-strategy.md +524 -0
- package/.grimoire/development/tasks/generate-shock-report.md +503 -0
- package/.grimoire/development/tasks/github-devops-github-pr-automation.md +666 -0
- package/.grimoire/development/tasks/github-devops-pre-push-quality-gate.md +791 -0
- package/.grimoire/development/tasks/github-devops-repository-cleanup.md +376 -0
- package/.grimoire/development/tasks/github-devops-version-management.md +485 -0
- package/.grimoire/development/tasks/gotcha.md +138 -0
- package/.grimoire/development/tasks/gotchas.md +155 -0
- package/.grimoire/development/tasks/health-check.yaml +227 -0
- package/.grimoire/development/tasks/ids-governor.md +96 -0
- package/.grimoire/development/tasks/ids-health.md +91 -0
- package/.grimoire/development/tasks/ids-query.md +156 -0
- package/.grimoire/development/tasks/improve-self.md +824 -0
- package/.grimoire/development/tasks/index-docs.md +389 -0
- package/.grimoire/development/tasks/init-project-status.md +508 -0
- package/.grimoire/development/tasks/integrate-squad.md +316 -0
- package/.grimoire/development/tasks/kb-mode-interaction.md +285 -0
- package/.grimoire/development/tasks/learn-patterns.md +902 -0
- package/.grimoire/development/tasks/list-mcps.md +33 -0
- package/.grimoire/development/tasks/list-worktrees.md +344 -0
- package/.grimoire/development/tasks/mcp-workflow.md +438 -0
- package/.grimoire/development/tasks/merge-worktree.md +42 -0
- package/.grimoire/development/tasks/modify-agent.md +399 -0
- package/.grimoire/development/tasks/modify-task.md +442 -0
- package/.grimoire/development/tasks/modify-workflow.md +511 -0
- package/.grimoire/development/tasks/next.md +327 -0
- package/.grimoire/development/tasks/orchestrate-resume.md +60 -0
- package/.grimoire/development/tasks/orchestrate-status.md +64 -0
- package/.grimoire/development/tasks/orchestrate-stop.md +55 -0
- package/.grimoire/development/tasks/orchestrate.md +66 -0
- package/.grimoire/development/tasks/patterns.md +336 -0
- package/.grimoire/development/tasks/plan-create-context.md +812 -0
- package/.grimoire/development/tasks/plan-create-implementation.md +797 -0
- package/.grimoire/development/tasks/plan-execute-subtask.md +962 -0
- package/.grimoire/development/tasks/po-backlog-add.md +372 -0
- package/.grimoire/development/tasks/po-close-story.md +428 -0
- package/.grimoire/development/tasks/po-manage-story-backlog.md +525 -0
- package/.grimoire/development/tasks/po-pull-story-from-clickup.md +542 -0
- package/.grimoire/development/tasks/po-pull-story.md +318 -0
- package/.grimoire/development/tasks/po-stories-index.md +353 -0
- package/.grimoire/development/tasks/po-sync-story-to-clickup.md +459 -0
- package/.grimoire/development/tasks/po-sync-story.md +305 -0
- package/.grimoire/development/tasks/pr-automation.md +703 -0
- package/.grimoire/development/tasks/propose-modification.md +844 -0
- package/.grimoire/development/tasks/publish-npm.md +259 -0
- package/.grimoire/development/tasks/qa-after-creation.md +519 -0
- package/.grimoire/development/tasks/qa-backlog-add-followup.md +427 -0
- package/.grimoire/development/tasks/qa-browser-console-check.md +343 -0
- package/.grimoire/development/tasks/qa-create-fix-request.md +625 -0
- package/.grimoire/development/tasks/qa-evidence-requirements.md +314 -0
- package/.grimoire/development/tasks/qa-false-positive-detection.md +374 -0
- package/.grimoire/development/tasks/qa-fix-issues.md +686 -0
- package/.grimoire/development/tasks/qa-gate.md +375 -0
- package/.grimoire/development/tasks/qa-generate-tests.md +1176 -0
- package/.grimoire/development/tasks/qa-library-validation.md +497 -0
- package/.grimoire/development/tasks/qa-migration-validation.md +584 -0
- package/.grimoire/development/tasks/qa-nfr-assess.md +559 -0
- package/.grimoire/development/tasks/qa-review-build.md +1225 -0
- package/.grimoire/development/tasks/qa-review-proposal.md +1159 -0
- package/.grimoire/development/tasks/qa-review-story.md +684 -0
- package/.grimoire/development/tasks/qa-risk-profile.md +568 -0
- package/.grimoire/development/tasks/qa-run-tests.md +279 -0
- package/.grimoire/development/tasks/qa-security-checklist.md +552 -0
- package/.grimoire/development/tasks/qa-test-design.md +389 -0
- package/.grimoire/development/tasks/qa-trace-requirements.md +478 -0
- package/.grimoire/development/tasks/release-management.md +754 -0
- package/.grimoire/development/tasks/remove-mcp.md +35 -0
- package/.grimoire/development/tasks/remove-worktree.md +435 -0
- package/.grimoire/development/tasks/run-design-system-pipeline.md +642 -0
- package/.grimoire/development/tasks/run-workflow-engine.md +861 -0
- package/.grimoire/development/tasks/run-workflow.md +389 -0
- package/.grimoire/development/tasks/search-mcp.md +309 -0
- package/.grimoire/development/tasks/security-audit.md +556 -0
- package/.grimoire/development/tasks/security-scan.md +792 -0
- package/.grimoire/development/tasks/session-resume.md +193 -0
- package/.grimoire/development/tasks/setup-database.md +743 -0
- package/.grimoire/development/tasks/setup-design-system.md +464 -0
- package/.grimoire/development/tasks/setup-github.md +876 -0
- package/.grimoire/development/tasks/setup-llm-routing.md +231 -0
- package/.grimoire/development/tasks/setup-mcp-docker.md +628 -0
- package/.grimoire/development/tasks/setup-project-docs.md +442 -0
- package/.grimoire/development/tasks/shard-doc.md +539 -0
- package/.grimoire/development/tasks/sm-create-next-story.md +482 -0
- package/.grimoire/development/tasks/spec-assess-complexity.md +461 -0
- package/.grimoire/development/tasks/spec-critique.md +595 -0
- package/.grimoire/development/tasks/spec-gather-requirements.md +545 -0
- package/.grimoire/development/tasks/spec-research-dependencies.md +446 -0
- package/.grimoire/development/tasks/spec-write-spec.md +531 -0
- package/.grimoire/development/tasks/squad-creator-analyze.md +318 -0
- package/.grimoire/development/tasks/squad-creator-create.md +314 -0
- package/.grimoire/development/tasks/squad-creator-design.md +335 -0
- package/.grimoire/development/tasks/squad-creator-download.md +169 -0
- package/.grimoire/development/tasks/squad-creator-extend.md +413 -0
- package/.grimoire/development/tasks/squad-creator-list.md +226 -0
- package/.grimoire/development/tasks/squad-creator-migrate.md +245 -0
- package/.grimoire/development/tasks/squad-creator-publish.md +231 -0
- package/.grimoire/development/tasks/squad-creator-sync-grimoire.md +317 -0
- package/.grimoire/development/tasks/squad-creator-sync-ide-command.md +403 -0
- package/.grimoire/development/tasks/squad-creator-validate.md +160 -0
- package/.grimoire/development/tasks/story-checkpoint.md +361 -0
- package/.grimoire/development/tasks/sync-documentation.md +866 -0
- package/.grimoire/development/tasks/tailwind-upgrade.md +296 -0
- package/.grimoire/development/tasks/test-as-user.md +623 -0
- package/.grimoire/development/tasks/test-validation-task.md +172 -0
- package/.grimoire/development/tasks/undo-last.md +348 -0
- package/.grimoire/development/tasks/update-grimoire.md +153 -0
- package/.grimoire/development/tasks/update-manifest.md +411 -0
- package/.grimoire/development/tasks/update-source-tree.md +138 -0
- package/.grimoire/development/tasks/ux-create-wireframe.md +619 -0
- package/.grimoire/development/tasks/ux-ds-scan-artifact.md +674 -0
- package/.grimoire/development/tasks/ux-user-research.md +561 -0
- package/.grimoire/development/tasks/validate-agents.md +117 -0
- package/.grimoire/development/tasks/validate-next-story.md +456 -0
- package/.grimoire/development/tasks/validate-tech-preset.md +187 -0
- package/.grimoire/development/tasks/validate-workflow.md +323 -0
- package/.grimoire/development/tasks/verify-subtask.md +237 -0
- package/.grimoire/development/tasks/waves.md +206 -0
- package/.grimoire/development/tasks/yolo-toggle.md +115 -0
- package/.grimoire/development/templates/grimoire-doc-template.md +496 -0
- package/.grimoire/development/templates/research-prompt-tmpl.md +486 -0
- package/.grimoire/development/templates/service-template/README.md.hbs +159 -0
- package/.grimoire/development/templates/service-template/__tests__/index.test.ts.hbs +238 -0
- package/.grimoire/development/templates/service-template/client.ts.hbs +404 -0
- package/.grimoire/development/templates/service-template/errors.ts.hbs +183 -0
- package/.grimoire/development/templates/service-template/index.ts.hbs +121 -0
- package/.grimoire/development/templates/service-template/jest.config.js +89 -0
- package/.grimoire/development/templates/service-template/package.json.hbs +88 -0
- package/.grimoire/development/templates/service-template/tsconfig.json +45 -0
- package/.grimoire/development/templates/service-template/types.ts.hbs +146 -0
- package/.grimoire/development/templates/squad/agent-template.md +69 -0
- package/.grimoire/development/templates/squad/checklist-template.md +82 -0
- package/.grimoire/development/templates/squad/data-template.yaml +105 -0
- package/.grimoire/development/templates/squad/script-template.js +179 -0
- package/.grimoire/development/templates/squad/task-template.md +125 -0
- package/.grimoire/development/templates/squad/template-template.md +98 -0
- package/.grimoire/development/templates/squad/tool-template.js +103 -0
- package/.grimoire/development/templates/squad/workflow-template.yaml +108 -0
- package/.grimoire/development/templates/squad-template/LICENSE +21 -0
- package/.grimoire/development/templates/squad-template/README.md +37 -0
- package/.grimoire/development/templates/squad-template/agents/example-agent.yaml +36 -0
- package/.grimoire/development/templates/squad-template/package.json +20 -0
- package/.grimoire/development/templates/squad-template/squad.yaml +26 -0
- package/.grimoire/development/templates/squad-template/tasks/example-task.yaml +46 -0
- package/.grimoire/development/templates/squad-template/templates/example-template.md +24 -0
- package/.grimoire/development/templates/squad-template/tests/example-agent.test.js +54 -0
- package/.grimoire/development/templates/squad-template/workflows/example-workflow.yaml +54 -0
- package/.grimoire/development/templates/subagent-step-prompt.md +122 -0
- package/.grimoire/development/workflows/README.md +82 -0
- package/.grimoire/development/workflows/auto-worktree.yaml +423 -0
- package/.grimoire/development/workflows/brownfield-discovery.yaml +933 -0
- package/.grimoire/development/workflows/brownfield-fullstack.yaml +369 -0
- package/.grimoire/development/workflows/brownfield-service.yaml +246 -0
- package/.grimoire/development/workflows/brownfield-ui.yaml +260 -0
- package/.grimoire/development/workflows/design-system-build-quality.yaml +228 -0
- package/.grimoire/development/workflows/development-cycle.yaml +427 -0
- package/.grimoire/development/workflows/epic-orchestration.yaml +328 -0
- package/.grimoire/development/workflows/greenfield-fullstack.yaml +386 -0
- package/.grimoire/development/workflows/greenfield-service.yaml +278 -0
- package/.grimoire/development/workflows/greenfield-ui.yaml +284 -0
- package/.grimoire/development/workflows/qa-loop.yaml +444 -0
- package/.grimoire/development/workflows/spec-pipeline.yaml +577 -0
- package/.grimoire/development/workflows/story-development-cycle.yaml +285 -0
- package/.grimoire/docs/standards/AGENT-PERSONALIZATION-STANDARD-V1.md +574 -0
- package/.grimoire/docs/standards/EXECUTOR-DECISION-TREE.md +698 -0
- package/.grimoire/docs/standards/OPEN-SOURCE-VS-SERVICE-DIFFERENCES.md +513 -0
- package/.grimoire/docs/standards/QUALITY-GATES-SPECIFICATION.md +558 -0
- package/.grimoire/docs/standards/STANDARDS-INDEX.md +212 -0
- package/.grimoire/docs/standards/STORY-TEMPLATE-V2-SPECIFICATION.md +551 -0
- package/.grimoire/docs/standards/TASK-FORMAT-SPECIFICATION-V1.md +1415 -0
- package/.grimoire/docs/standards/grimoire-COLOR-PALETTE-QUICK-REFERENCE.md +186 -0
- package/.grimoire/docs/standards/grimoire-COLOR-PALETTE-V2.1.md +354 -0
- package/.grimoire/docs/standards/grimoire-LIVRO-DE-OURO-V2.1-COMPLETE.md +839 -0
- package/.grimoire/docs/standards/grimoire-LIVRO-DE-OURO-V2.2-SUMMARY.md +1341 -0
- package/.grimoire/elicitation/agent-elicitation.js +272 -0
- package/.grimoire/elicitation/task-elicitation.js +281 -0
- package/.grimoire/elicitation/workflow-elicitation.js +315 -0
- package/.grimoire/framework-config.yaml +152 -0
- package/.grimoire/hooks/gemini/after-tool.js +78 -0
- package/.grimoire/hooks/gemini/before-agent.js +80 -0
- package/.grimoire/hooks/gemini/before-tool.js +115 -0
- package/.grimoire/hooks/gemini/rewind-handler.js +69 -0
- package/.grimoire/hooks/gemini/session-end.js +91 -0
- package/.grimoire/hooks/gemini/session-start.js +91 -0
- package/.grimoire/hooks/ids-post-commit.js +118 -0
- package/.grimoire/hooks/ids-pre-push.js +125 -0
- package/.grimoire/hooks/unified/README.md +309 -0
- package/.grimoire/hooks/unified/hook-interface.js +161 -0
- package/.grimoire/hooks/unified/hook-registry.js +143 -0
- package/.grimoire/hooks/unified/index.js +36 -0
- package/.grimoire/hooks/unified/runners/precompact-runner.js +98 -0
- package/.grimoire/index.esm.js +17 -0
- package/.grimoire/index.js +17 -0
- package/.grimoire/infrastructure/README.md +128 -0
- package/.grimoire/infrastructure/contracts/compatibility/grimoire-4.0.4.yaml +46 -0
- package/.grimoire/infrastructure/index.js +200 -0
- package/.grimoire/infrastructure/integrations/ai-providers/README.md +103 -0
- package/.grimoire/infrastructure/integrations/ai-providers/ai-provider-factory.js +286 -0
- package/.grimoire/infrastructure/integrations/ai-providers/ai-provider.js +145 -0
- package/.grimoire/infrastructure/integrations/ai-providers/claude-provider.js +170 -0
- package/.grimoire/infrastructure/integrations/ai-providers/gemini-provider.js +365 -0
- package/.grimoire/infrastructure/integrations/ai-providers/index.js +45 -0
- package/.grimoire/infrastructure/integrations/gemini-extensions/cloudrun-adapter.js +129 -0
- package/.grimoire/infrastructure/integrations/gemini-extensions/index.js +41 -0
- package/.grimoire/infrastructure/integrations/gemini-extensions/policy-sync.js +74 -0
- package/.grimoire/infrastructure/integrations/gemini-extensions/security-adapter.js +159 -0
- package/.grimoire/infrastructure/integrations/gemini-extensions/supabase-adapter.js +88 -0
- package/.grimoire/infrastructure/integrations/gemini-extensions/workspace-adapter.js +100 -0
- package/.grimoire/infrastructure/integrations/pm-adapters/README.md +60 -0
- package/.grimoire/infrastructure/integrations/pm-adapters/clickup-adapter.js +345 -0
- package/.grimoire/infrastructure/integrations/pm-adapters/github-adapter.js +393 -0
- package/.grimoire/infrastructure/integrations/pm-adapters/jira-adapter.js +449 -0
- package/.grimoire/infrastructure/integrations/pm-adapters/local-adapter.js +176 -0
- package/.grimoire/infrastructure/schemas/agent-v3-schema.json +160 -0
- package/.grimoire/infrastructure/schemas/build-state.schema.json +158 -0
- package/.grimoire/infrastructure/schemas/task-v3-schema.json +152 -0
- package/.grimoire/infrastructure/scripts/approach-manager.js +1005 -0
- package/.grimoire/infrastructure/scripts/approval-workflow.js +644 -0
- package/.grimoire/infrastructure/scripts/asset-inventory.js +622 -0
- package/.grimoire/infrastructure/scripts/atomic-layer-classifier.js +309 -0
- package/.grimoire/infrastructure/scripts/backup-manager.js +607 -0
- package/.grimoire/infrastructure/scripts/batch-creator.js +609 -0
- package/.grimoire/infrastructure/scripts/branch-manager.js +391 -0
- package/.grimoire/infrastructure/scripts/capability-analyzer.js +535 -0
- package/.grimoire/infrastructure/scripts/changelog-generator.js +554 -0
- package/.grimoire/infrastructure/scripts/cicd-discovery.js +1269 -0
- package/.grimoire/infrastructure/scripts/clickup-helpers.js +227 -0
- package/.grimoire/infrastructure/scripts/code-quality-improver.js +1312 -0
- package/.grimoire/infrastructure/scripts/codebase-mapper.js +1288 -0
- package/.grimoire/infrastructure/scripts/codex-skills-sync/index.js +184 -0
- package/.grimoire/infrastructure/scripts/codex-skills-sync/validate.js +174 -0
- package/.grimoire/infrastructure/scripts/commit-message-generator.js +850 -0
- package/.grimoire/infrastructure/scripts/component-generator.js +738 -0
- package/.grimoire/infrastructure/scripts/component-metadata.js +628 -0
- package/.grimoire/infrastructure/scripts/component-search.js +278 -0
- package/.grimoire/infrastructure/scripts/config-cache.js +322 -0
- package/.grimoire/infrastructure/scripts/config-loader.js +351 -0
- package/.grimoire/infrastructure/scripts/conflict-resolver.js +675 -0
- package/.grimoire/infrastructure/scripts/coverage-analyzer.js +882 -0
- package/.grimoire/infrastructure/scripts/dashboard-status-writer.js +310 -0
- package/.grimoire/infrastructure/scripts/dependency-analyzer.js +639 -0
- package/.grimoire/infrastructure/scripts/dependency-impact-analyzer.js +704 -0
- package/.grimoire/infrastructure/scripts/diff-generator.js +129 -0
- package/.grimoire/infrastructure/scripts/documentation-integrity/brownfield-analyzer.js +502 -0
- package/.grimoire/infrastructure/scripts/documentation-integrity/config-generator.js +369 -0
- package/.grimoire/infrastructure/scripts/documentation-integrity/deployment-config-loader.js +309 -0
- package/.grimoire/infrastructure/scripts/documentation-integrity/doc-generator.js +331 -0
- package/.grimoire/infrastructure/scripts/documentation-integrity/gitignore-generator.js +314 -0
- package/.grimoire/infrastructure/scripts/documentation-integrity/index.js +75 -0
- package/.grimoire/infrastructure/scripts/documentation-integrity/mode-detector.js +391 -0
- package/.grimoire/infrastructure/scripts/documentation-synchronizer.js +1432 -0
- package/.grimoire/infrastructure/scripts/framework-analyzer.js +763 -0
- package/.grimoire/infrastructure/scripts/git-config-detector.js +293 -0
- package/.grimoire/infrastructure/scripts/git-hooks/post-commit.js +75 -0
- package/.grimoire/infrastructure/scripts/git-wrapper.js +444 -0
- package/.grimoire/infrastructure/scripts/gotchas-documenter.js +1296 -0
- package/.grimoire/infrastructure/scripts/grimoire-validator.js +295 -0
- package/.grimoire/infrastructure/scripts/ide-sync/README.md +220 -0
- package/.grimoire/infrastructure/scripts/ide-sync/agent-parser.js +295 -0
- package/.grimoire/infrastructure/scripts/ide-sync/gemini-commands.js +207 -0
- package/.grimoire/infrastructure/scripts/ide-sync/index.js +540 -0
- package/.grimoire/infrastructure/scripts/ide-sync/redirect-generator.js +179 -0
- package/.grimoire/infrastructure/scripts/ide-sync/transformers/antigravity.js +107 -0
- package/.grimoire/infrastructure/scripts/ide-sync/transformers/claude-code.js +86 -0
- package/.grimoire/infrastructure/scripts/ide-sync/transformers/cursor.js +96 -0
- package/.grimoire/infrastructure/scripts/ide-sync/validator.js +273 -0
- package/.grimoire/infrastructure/scripts/improvement-engine.js +758 -0
- package/.grimoire/infrastructure/scripts/improvement-validator.js +710 -0
- package/.grimoire/infrastructure/scripts/llm-routing/install-llm-routing.js +282 -0
- package/.grimoire/infrastructure/scripts/llm-routing/templates/claude-free-tracked.cmd +129 -0
- package/.grimoire/infrastructure/scripts/llm-routing/templates/claude-free-tracked.sh +108 -0
- package/.grimoire/infrastructure/scripts/llm-routing/templates/claude-free.cmd +80 -0
- package/.grimoire/infrastructure/scripts/llm-routing/templates/claude-free.sh +62 -0
- package/.grimoire/infrastructure/scripts/llm-routing/templates/claude-max.cmd +26 -0
- package/.grimoire/infrastructure/scripts/llm-routing/templates/claude-max.sh +18 -0
- package/.grimoire/infrastructure/scripts/llm-routing/templates/deepseek-proxy.cmd +73 -0
- package/.grimoire/infrastructure/scripts/llm-routing/templates/deepseek-proxy.sh +65 -0
- package/.grimoire/infrastructure/scripts/llm-routing/templates/deepseek-usage.cmd +53 -0
- package/.grimoire/infrastructure/scripts/llm-routing/templates/deepseek-usage.sh +16 -0
- package/.grimoire/infrastructure/scripts/llm-routing/usage-tracker/index.js +551 -0
- package/.grimoire/infrastructure/scripts/migrate-agent.js +528 -0
- package/.grimoire/infrastructure/scripts/modification-risk-assessment.js +970 -0
- package/.grimoire/infrastructure/scripts/modification-validator.js +555 -0
- package/.grimoire/infrastructure/scripts/output-formatter.js +298 -0
- package/.grimoire/infrastructure/scripts/path-analyzer.js +476 -0
- package/.grimoire/infrastructure/scripts/pattern-extractor.js +1563 -0
- package/.grimoire/infrastructure/scripts/performance-analyzer.js +758 -0
- package/.grimoire/infrastructure/scripts/performance-and-error-resolver.js +258 -0
- package/.grimoire/infrastructure/scripts/performance-optimizer.js +1902 -0
- package/.grimoire/infrastructure/scripts/performance-tracker.js +454 -0
- package/.grimoire/infrastructure/scripts/plan-tracker.js +922 -0
- package/.grimoire/infrastructure/scripts/pm-adapter-factory.js +182 -0
- package/.grimoire/infrastructure/scripts/pm-adapter.js +134 -0
- package/.grimoire/infrastructure/scripts/pr-review-ai.js +1062 -0
- package/.grimoire/infrastructure/scripts/project-status-loader.js +850 -0
- package/.grimoire/infrastructure/scripts/qa-loop-orchestrator.js +1264 -0
- package/.grimoire/infrastructure/scripts/qa-report-generator.js +1154 -0
- package/.grimoire/infrastructure/scripts/recovery-tracker.js +965 -0
- package/.grimoire/infrastructure/scripts/refactoring-suggester.js +1139 -0
- package/.grimoire/infrastructure/scripts/repository-detector.js +66 -0
- package/.grimoire/infrastructure/scripts/rollback-manager.js +734 -0
- package/.grimoire/infrastructure/scripts/sandbox-tester.js +618 -0
- package/.grimoire/infrastructure/scripts/security-checker.js +359 -0
- package/.grimoire/infrastructure/scripts/spot-check-validator.js +149 -0
- package/.grimoire/infrastructure/scripts/status-mapper.js +116 -0
- package/.grimoire/infrastructure/scripts/story-worktree-hooks.js +426 -0
- package/.grimoire/infrastructure/scripts/stuck-detector.js +1251 -0
- package/.grimoire/infrastructure/scripts/subtask-verifier.js +793 -0
- package/.grimoire/infrastructure/scripts/template-engine.js +240 -0
- package/.grimoire/infrastructure/scripts/template-validator.js +279 -0
- package/.grimoire/infrastructure/scripts/test-discovery.js +1259 -0
- package/.grimoire/infrastructure/scripts/test-generator.js +845 -0
- package/.grimoire/infrastructure/scripts/test-quality-assessment.js +1082 -0
- package/.grimoire/infrastructure/scripts/test-utilities-fast.js +126 -0
- package/.grimoire/infrastructure/scripts/test-utilities.js +201 -0
- package/.grimoire/infrastructure/scripts/tool-resolver.js +362 -0
- package/.grimoire/infrastructure/scripts/transaction-manager.js +590 -0
- package/.grimoire/infrastructure/scripts/usage-analytics.js +636 -0
- package/.grimoire/infrastructure/scripts/validate-agents.js +527 -0
- package/.grimoire/infrastructure/scripts/validate-claude-integration.js +103 -0
- package/.grimoire/infrastructure/scripts/validate-codex-integration.js +143 -0
- package/.grimoire/infrastructure/scripts/validate-gemini-integration.js +153 -0
- package/.grimoire/infrastructure/scripts/validate-output-pattern.js +213 -0
- package/.grimoire/infrastructure/scripts/validate-parity.js +357 -0
- package/.grimoire/infrastructure/scripts/validate-paths.js +144 -0
- package/.grimoire/infrastructure/scripts/validate-user-profile.js +251 -0
- package/.grimoire/infrastructure/scripts/visual-impact-generator.js +1056 -0
- package/.grimoire/infrastructure/scripts/worktree-manager.js +704 -0
- package/.grimoire/infrastructure/scripts/yaml-validator.js +397 -0
- package/.grimoire/infrastructure/templates/coderabbit.yaml.template +280 -0
- package/.grimoire/infrastructure/templates/core-config/core-config-brownfield.tmpl.yaml +177 -0
- package/.grimoire/infrastructure/templates/core-config/core-config-greenfield.tmpl.yaml +169 -0
- package/.grimoire/infrastructure/templates/github-workflows/README.md +110 -0
- package/.grimoire/infrastructure/templates/github-workflows/ci.yml.template +170 -0
- package/.grimoire/infrastructure/templates/github-workflows/pr-automation.yml.template +331 -0
- package/.grimoire/infrastructure/templates/github-workflows/release.yml.template +197 -0
- package/.grimoire/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +20 -0
- package/.grimoire/infrastructure/templates/gitignore/gitignore-grimoire-base.tmpl +65 -0
- package/.grimoire/infrastructure/templates/gitignore/gitignore-node.tmpl +86 -0
- package/.grimoire/infrastructure/templates/gitignore/gitignore-python.tmpl +146 -0
- package/.grimoire/infrastructure/templates/grimoire-sync.yaml.template +183 -0
- package/.grimoire/infrastructure/templates/project-docs/coding-standards-tmpl.md +347 -0
- package/.grimoire/infrastructure/templates/project-docs/source-tree-tmpl.md +179 -0
- package/.grimoire/infrastructure/templates/project-docs/tech-stack-tmpl.md +269 -0
- package/.grimoire/infrastructure/tests/project-status-loader.test.js +569 -0
- package/.grimoire/infrastructure/tests/regression-suite-v2.md +622 -0
- package/.grimoire/infrastructure/tests/validate-module.js +98 -0
- package/.grimoire/infrastructure/tests/worktree-manager.test.js +620 -0
- package/.grimoire/infrastructure/tools/README.md +224 -0
- package/.grimoire/infrastructure/tools/cli/github-cli.yaml +200 -0
- package/.grimoire/infrastructure/tools/cli/llm-routing.yaml +128 -0
- package/.grimoire/infrastructure/tools/cli/railway-cli.yaml +260 -0
- package/.grimoire/infrastructure/tools/cli/supabase-cli.yaml +224 -0
- package/.grimoire/infrastructure/tools/local/ffmpeg.yaml +261 -0
- package/.grimoire/infrastructure/tools/mcp/21st-dev-magic.yaml +127 -0
- package/.grimoire/infrastructure/tools/mcp/browser.yaml +103 -0
- package/.grimoire/infrastructure/tools/mcp/clickup.yaml +535 -0
- package/.grimoire/infrastructure/tools/mcp/context7.yaml +78 -0
- package/.grimoire/infrastructure/tools/mcp/desktop-commander.yaml +180 -0
- package/.grimoire/infrastructure/tools/mcp/exa.yaml +103 -0
- package/.grimoire/infrastructure/tools/mcp/google-workspace.yaml +930 -0
- package/.grimoire/infrastructure/tools/mcp/n8n.yaml +551 -0
- package/.grimoire/infrastructure/tools/mcp/supabase.yaml +808 -0
- package/.grimoire/install-manifest.yaml +4058 -0
- package/.grimoire/local-config.yaml.template +73 -0
- package/.grimoire/manifests/schema/manifest-schema.json +191 -0
- package/.grimoire/monitor/hooks/lib/__init__.py +2 -0
- package/.grimoire/monitor/hooks/lib/enrich.py +59 -0
- package/.grimoire/monitor/hooks/lib/send_event.py +48 -0
- package/.grimoire/monitor/hooks/notification.py +30 -0
- package/.grimoire/monitor/hooks/post_tool_use.py +46 -0
- package/.grimoire/monitor/hooks/pre_compact.py +30 -0
- package/.grimoire/monitor/hooks/pre_tool_use.py +41 -0
- package/.grimoire/monitor/hooks/stop.py +30 -0
- package/.grimoire/monitor/hooks/subagent_stop.py +30 -0
- package/.grimoire/monitor/hooks/user_prompt_submit.py +39 -0
- package/.grimoire/package.json +104 -0
- package/.grimoire/presets/README.md +359 -0
- package/.grimoire/product/README.md +57 -0
- package/.grimoire/product/checklists/accessibility-wcag-checklist.md +80 -0
- package/.grimoire/product/checklists/architect-checklist.md +444 -0
- package/.grimoire/product/checklists/change-checklist.md +183 -0
- package/.grimoire/product/checklists/component-quality-checklist.md +74 -0
- package/.grimoire/product/checklists/database-design-checklist.md +119 -0
- package/.grimoire/product/checklists/dba-predeploy-checklist.md +97 -0
- package/.grimoire/product/checklists/dba-rollback-checklist.md +99 -0
- package/.grimoire/product/checklists/migration-readiness-checklist.md +75 -0
- package/.grimoire/product/checklists/pattern-audit-checklist.md +88 -0
- package/.grimoire/product/checklists/pm-checklist.md +376 -0
- package/.grimoire/product/checklists/po-master-checklist.md +442 -0
- package/.grimoire/product/checklists/pre-push-checklist.md +108 -0
- package/.grimoire/product/checklists/release-checklist.md +122 -0
- package/.grimoire/product/checklists/self-critique-checklist.md +387 -0
- package/.grimoire/product/checklists/story-dod-checklist.md +102 -0
- package/.grimoire/product/checklists/story-draft-checklist.md +216 -0
- package/.grimoire/product/data/atomic-design-principles.md +108 -0
- package/.grimoire/product/data/brainstorming-techniques.md +37 -0
- package/.grimoire/product/data/consolidation-algorithms.md +142 -0
- package/.grimoire/product/data/database-best-practices.md +182 -0
- package/.grimoire/product/data/design-token-best-practices.md +107 -0
- package/.grimoire/product/data/elicitation-methods.md +135 -0
- package/.grimoire/product/data/integration-patterns.md +207 -0
- package/.grimoire/product/data/migration-safety-guide.md +329 -0
- package/.grimoire/product/data/mode-selection-best-practices.md +471 -0
- package/.grimoire/product/data/postgres-tuning-guide.md +300 -0
- package/.grimoire/product/data/rls-security-patterns.md +333 -0
- package/.grimoire/product/data/roi-calculation-guide.md +142 -0
- package/.grimoire/product/data/supabase-patterns.md +330 -0
- package/.grimoire/product/data/test-levels-framework.md +149 -0
- package/.grimoire/product/data/test-priorities-matrix.md +175 -0
- package/.grimoire/product/data/wcag-compliance-guide.md +267 -0
- package/.grimoire/product/templates/activation-instructions-inline-greeting.yaml +64 -0
- package/.grimoire/product/templates/activation-instructions-template.md +260 -0
- package/.grimoire/product/templates/adr.hbs +126 -0
- package/.grimoire/product/templates/agent-template.yaml +122 -0
- package/.grimoire/product/templates/architecture-tmpl.yaml +651 -0
- package/.grimoire/product/templates/brainstorming-output-tmpl.yaml +156 -0
- package/.grimoire/product/templates/brownfield-architecture-tmpl.yaml +476 -0
- package/.grimoire/product/templates/brownfield-prd-tmpl.yaml +280 -0
- package/.grimoire/product/templates/brownfield-risk-report-tmpl.yaml +278 -0
- package/.grimoire/product/templates/changelog-template.md +134 -0
- package/.grimoire/product/templates/command-rationalization-matrix.md +154 -0
- package/.grimoire/product/templates/competitor-analysis-tmpl.yaml +293 -0
- package/.grimoire/product/templates/component-react-tmpl.tsx +98 -0
- package/.grimoire/product/templates/current-approach-tmpl.md +56 -0
- package/.grimoire/product/templates/dbdr.hbs +242 -0
- package/.grimoire/product/templates/design-story-tmpl.yaml +588 -0
- package/.grimoire/product/templates/ds-artifact-analysis.md +70 -0
- package/.grimoire/product/templates/engine/elicitation.js +298 -0
- package/.grimoire/product/templates/engine/index.js +310 -0
- package/.grimoire/product/templates/engine/loader.js +232 -0
- package/.grimoire/product/templates/engine/renderer.js +343 -0
- package/.grimoire/product/templates/engine/schemas/adr.schema.json +102 -0
- package/.grimoire/product/templates/engine/schemas/dbdr.schema.json +205 -0
- package/.grimoire/product/templates/engine/schemas/epic.schema.json +175 -0
- package/.grimoire/product/templates/engine/schemas/pmdr.schema.json +175 -0
- package/.grimoire/product/templates/engine/schemas/prd-v2.schema.json +300 -0
- package/.grimoire/product/templates/engine/schemas/prd.schema.json +152 -0
- package/.grimoire/product/templates/engine/schemas/story.schema.json +222 -0
- package/.grimoire/product/templates/engine/schemas/task.schema.json +154 -0
- package/.grimoire/product/templates/engine/validator.js +295 -0
- package/.grimoire/product/templates/epic.hbs +213 -0
- package/.grimoire/product/templates/eslintrc-security.json +32 -0
- package/.grimoire/product/templates/front-end-architecture-tmpl.yaml +206 -0
- package/.grimoire/product/templates/front-end-spec-tmpl.yaml +349 -0
- package/.grimoire/product/templates/fullstack-architecture-tmpl.yaml +805 -0
- package/.grimoire/product/templates/gemini/settings.json +81 -0
- package/.grimoire/product/templates/github-actions-cd.yml +213 -0
- package/.grimoire/product/templates/github-actions-ci.yml +173 -0
- package/.grimoire/product/templates/github-pr-template.md +68 -0
- package/.grimoire/product/templates/gordon-mcp.yaml +141 -0
- package/.grimoire/product/templates/grimoire-ai-config.yaml +107 -0
- package/.grimoire/product/templates/ide-rules/antigravity-rules.md +117 -0
- package/.grimoire/product/templates/ide-rules/claude-rules.md +233 -0
- package/.grimoire/product/templates/ide-rules/codex-rules.md +67 -0
- package/.grimoire/product/templates/ide-rules/copilot-rules.md +94 -0
- package/.grimoire/product/templates/ide-rules/cursor-rules.md +116 -0
- package/.grimoire/product/templates/ide-rules/gemini-rules.md +89 -0
- package/.grimoire/product/templates/index-strategy-tmpl.yaml +53 -0
- package/.grimoire/product/templates/market-research-tmpl.yaml +252 -0
- package/.grimoire/product/templates/mcp-workflow.js +273 -0
- package/.grimoire/product/templates/migration-plan-tmpl.yaml +1022 -0
- package/.grimoire/product/templates/migration-strategy-tmpl.md +524 -0
- package/.grimoire/product/templates/personalized-agent-template.md +260 -0
- package/.grimoire/product/templates/personalized-checklist-template.md +341 -0
- package/.grimoire/product/templates/personalized-task-template-v2.md +907 -0
- package/.grimoire/product/templates/personalized-task-template.md +345 -0
- package/.grimoire/product/templates/personalized-template-file.yaml +323 -0
- package/.grimoire/product/templates/personalized-workflow-template.yaml +461 -0
- package/.grimoire/product/templates/pmdr.hbs +187 -0
- package/.grimoire/product/templates/prd-tmpl.yaml +202 -0
- package/.grimoire/product/templates/prd-v2.0.hbs +217 -0
- package/.grimoire/product/templates/prd.hbs +202 -0
- package/.grimoire/product/templates/project-brief-tmpl.yaml +221 -0
- package/.grimoire/product/templates/qa-gate-tmpl.yaml +240 -0
- package/.grimoire/product/templates/qa-report-tmpl.md +235 -0
- package/.grimoire/product/templates/rls-policies-tmpl.yaml +1203 -0
- package/.grimoire/product/templates/schema-design-tmpl.yaml +428 -0
- package/.grimoire/product/templates/shock-report-tmpl.html +502 -0
- package/.grimoire/product/templates/spec-tmpl.md +235 -0
- package/.grimoire/product/templates/state-persistence-tmpl.yaml +219 -0
- package/.grimoire/product/templates/statusline/statusline-script.js +190 -0
- package/.grimoire/product/templates/statusline/track-agent.sh +70 -0
- package/.grimoire/product/templates/story-tmpl.yaml +369 -0
- package/.grimoire/product/templates/story.hbs +264 -0
- package/.grimoire/product/templates/task-execution-report.md +496 -0
- package/.grimoire/product/templates/task-template.md +123 -0
- package/.grimoire/product/templates/task.hbs +171 -0
- package/.grimoire/product/templates/tmpl-comment-on-examples.sql +158 -0
- package/.grimoire/product/templates/tmpl-migration-script.sql +91 -0
- package/.grimoire/product/templates/tmpl-rls-granular-policies.sql +104 -0
- package/.grimoire/product/templates/tmpl-rls-kiss-policy.sql +10 -0
- package/.grimoire/product/templates/tmpl-rls-roles.sql +135 -0
- package/.grimoire/product/templates/tmpl-rls-simple.sql +77 -0
- package/.grimoire/product/templates/tmpl-rls-tenant.sql +152 -0
- package/.grimoire/product/templates/tmpl-rollback-script.sql +77 -0
- package/.grimoire/product/templates/tmpl-seed-data.sql +140 -0
- package/.grimoire/product/templates/tmpl-smoke-test.sql +16 -0
- package/.grimoire/product/templates/tmpl-staging-copy-merge.sql +139 -0
- package/.grimoire/product/templates/tmpl-stored-proc.sql +140 -0
- package/.grimoire/product/templates/tmpl-trigger.sql +152 -0
- package/.grimoire/product/templates/tmpl-view-materialized.sql +133 -0
- package/.grimoire/product/templates/tmpl-view.sql +177 -0
- package/.grimoire/product/templates/token-exports-css-tmpl.css +240 -0
- package/.grimoire/product/templates/token-exports-tailwind-tmpl.js +395 -0
- package/.grimoire/product/templates/tokens-schema-tmpl.yaml +305 -0
- package/.grimoire/product/templates/workflow-template.yaml +152 -0
- package/.grimoire/project-config.yaml +166 -0
- package/.grimoire/quality/metrics-collector.js +601 -0
- package/.grimoire/quality/metrics-hook.js +261 -0
- package/.grimoire/quality/schemas/quality-metrics.schema.json +234 -0
- package/.grimoire/quality/seed-metrics.js +336 -0
- package/.grimoire/schemas/README.md +405 -0
- package/.grimoire/schemas/agent-v3-schema.json +395 -0
- package/.grimoire/schemas/squad-design-schema.json +300 -0
- package/.grimoire/schemas/squad-schema.json +187 -0
- package/.grimoire/schemas/task-v3-schema.json +354 -0
- package/.grimoire/schemas/validate-v3-schema.js +431 -0
- package/.grimoire/scripts/README.md +124 -0
- package/.grimoire/scripts/batch-migrate-phase1.ps1 +37 -0
- package/.grimoire/scripts/batch-migrate-phase2.ps1 +89 -0
- package/.grimoire/scripts/batch-migrate-phase3.ps1 +46 -0
- package/.grimoire/scripts/command-execution-hook.js +202 -0
- package/.grimoire/scripts/diagnostics/diagnose-installation.js +276 -0
- package/.grimoire/scripts/diagnostics/diagnose-npx-issue.ps1 +98 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/README.md +123 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/index.html +14 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/package-lock.json +5262 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/package.json +25 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/public/favicon.svg +10 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/App.jsx +22 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/AutoFixLog.css +122 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/AutoFixLog.jsx +72 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/DomainCard.css +121 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/DomainCard.jsx +116 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/HealthScore.css +80 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/HealthScore.jsx +81 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/IssuesList.css +184 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/IssuesList.jsx +145 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/TechDebtList.css +114 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/TechDebtList.jsx +72 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/index.js +9 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/shared/Card.css +44 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/shared/Card.jsx +25 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/shared/Chart.css +14 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/shared/Chart.jsx +138 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/shared/Header.css +54 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/shared/Header.jsx +22 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/shared/StatusBadge.css +77 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/shared/StatusBadge.jsx +45 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/components/shared/index.js +4 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/hooks/index.js +2 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/hooks/useAutoRefresh.js +89 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/hooks/useHealthData.js +308 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/main.jsx +13 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/pages/Dashboard.css +238 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/pages/Dashboard.jsx +154 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/pages/DomainDetail.css +259 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/pages/DomainDetail.jsx +164 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/pages/index.js +2 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/styles/App.css +19 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/src/styles/index.css +67 -0
- package/.grimoire/scripts/diagnostics/health-dashboard/vite.config.js +23 -0
- package/.grimoire/scripts/diagnostics/quick-diagnose.cmd +86 -0
- package/.grimoire/scripts/diagnostics/quick-diagnose.ps1 +118 -0
- package/.grimoire/scripts/grimoire-doc-template.md +326 -0
- package/.grimoire/scripts/migrate-framework-docs.sh +302 -0
- package/.grimoire/scripts/pm.sh +455 -0
- package/.grimoire/scripts/session-context-loader.js +46 -0
- package/.grimoire/scripts/test-template-system.js +942 -0
- package/.grimoire/scripts/update-grimoire.sh +176 -0
- package/.grimoire/scripts/validate-phase1.ps1 +36 -0
- package/.grimoire/scripts/workflow-management.md +70 -0
- package/.grimoire/user-guide.md +1411 -0
- package/.grimoire/utils/format-duration.js +95 -0
- package/.grimoire/utils/grimoire-validator.js +27 -0
- package/.grimoire/workflow-intelligence/__tests__/confidence-scorer.test.js +334 -0
- package/.grimoire/workflow-intelligence/__tests__/integration.test.js +339 -0
- package/.grimoire/workflow-intelligence/__tests__/suggestion-engine.test.js +437 -0
- package/.grimoire/workflow-intelligence/__tests__/wave-analyzer.test.js +447 -0
- package/.grimoire/workflow-intelligence/__tests__/workflow-registry.test.js +302 -0
- package/.grimoire/workflow-intelligence/engine/confidence-scorer.js +306 -0
- package/.grimoire/workflow-intelligence/engine/output-formatter.js +299 -0
- package/.grimoire/workflow-intelligence/engine/suggestion-engine.js +798 -0
- package/.grimoire/workflow-intelligence/engine/wave-analyzer.js +683 -0
- package/.grimoire/workflow-intelligence/index.js +330 -0
- package/.grimoire/workflow-intelligence/learning/capture-hook.js +148 -0
- package/.grimoire/workflow-intelligence/learning/gotcha-registry.js +654 -0
- package/.grimoire/workflow-intelligence/learning/index.js +306 -0
- package/.grimoire/workflow-intelligence/learning/pattern-capture.js +330 -0
- package/.grimoire/workflow-intelligence/learning/pattern-store.js +497 -0
- package/.grimoire/workflow-intelligence/learning/pattern-validator.js +310 -0
- package/.grimoire/workflow-intelligence/learning/qa-feedback.js +586 -0
- package/.grimoire/workflow-intelligence/learning/semantic-search.js +521 -0
- package/.grimoire/workflow-intelligence/registry/workflow-registry.js +357 -0
- package/.grimoire/working-in-the-brownfield.md +362 -0
- package/LICENSE +25 -0
- package/README.md +59 -0
- package/bin/grimoire-ids.js +560 -0
- package/bin/grimoire-init.js +1232 -0
- package/bin/grimoire-minimal.js +40 -0
- package/bin/grimoire.js +1118 -0
- package/bin/modules/env-config.js +436 -0
- package/bin/modules/mcp-installer.js +384 -0
- package/bin/utils/install-errors.js +340 -0
- package/bin/utils/install-transaction.js +447 -0
- package/bin/utils/pro-detector.js +110 -0
- package/package.json +158 -0
- package/packages/gemini-grimoire-extension/README.md +55 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-agent.js +7 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-agents.js +51 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-analyst.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-architect.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-data-engineer.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-dev.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-devops.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-master.js +7 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-menu.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-pm.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-po.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-qa.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-sm.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-squad-creator.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-status.js +68 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-ux-design-expert.js +6 -0
- package/packages/gemini-grimoire-extension/commands/grimoire-validate.js +35 -0
- package/packages/gemini-grimoire-extension/commands/lib/agent-launcher.js +147 -0
- package/packages/gemini-grimoire-extension/extension.json +149 -0
- package/packages/gemini-grimoire-extension/gemini-extension.json +149 -0
- package/packages/gemini-grimoire-extension/hooks/hooks.json +72 -0
- package/packages/grimoire-install/.releaserc.json +39 -0
- package/packages/grimoire-install/CHANGELOG.md +33 -0
- package/packages/grimoire-install/README.md +119 -0
- package/packages/grimoire-install/bin/edmcp.js +80 -0
- package/packages/grimoire-install/bin/grimoire-install.js +51 -0
- package/packages/grimoire-install/jest.config.js +27 -0
- package/packages/grimoire-install/package.json +68 -0
- package/packages/grimoire-install/src/dep-checker.js +306 -0
- package/packages/grimoire-install/src/edmcp/index.js +382 -0
- package/packages/grimoire-install/src/installer.js +487 -0
- package/packages/grimoire-install/src/os-detector.js +280 -0
- package/packages/grimoire-pro-cli/bin/grimoire-pro.js +233 -0
- package/packages/grimoire-pro-cli/package.json +38 -0
- package/packages/grimoire-pro-cli/src/recover.js +101 -0
- package/packages/installer/package.json +40 -0
- package/packages/installer/src/__tests__/performance-benchmark.js +384 -0
- package/packages/installer/src/config/configure-environment.js +373 -0
- package/packages/installer/src/config/ide-configs.js +161 -0
- package/packages/installer/src/config/templates/core-config-template.js +199 -0
- package/packages/installer/src/config/templates/env-template.js +272 -0
- package/packages/installer/src/config/validation/config-validator.js +244 -0
- package/packages/installer/src/detection/detect-project-type.js +83 -0
- package/packages/installer/src/installer/brownfield-upgrader.js +440 -0
- package/packages/installer/src/installer/dependency-installer.js +335 -0
- package/packages/installer/src/installer/file-hasher.js +234 -0
- package/packages/installer/src/installer/grimoire-core-installer.js +428 -0
- package/packages/installer/src/installer/manifest-signature.js +380 -0
- package/packages/installer/src/installer/post-install-validator.js +1524 -0
- package/packages/installer/src/merger/index.js +72 -0
- package/packages/installer/src/merger/parsers/env-parser.js +153 -0
- package/packages/installer/src/merger/parsers/markdown-section-parser.js +199 -0
- package/packages/installer/src/merger/strategies/base-merger.js +61 -0
- package/packages/installer/src/merger/strategies/env-merger.js +138 -0
- package/packages/installer/src/merger/strategies/index.js +105 -0
- package/packages/installer/src/merger/strategies/markdown-merger.js +208 -0
- package/packages/installer/src/merger/strategies/replace-merger.js +68 -0
- package/packages/installer/src/merger/types.js +72 -0
- package/packages/installer/src/pro/pro-scaffolder.js +387 -0
- package/packages/installer/src/updater/index.js +814 -0
- package/packages/installer/src/utils/grimoire-colors.js +235 -0
- package/packages/installer/src/wizard/feedback.js +232 -0
- package/packages/installer/src/wizard/i18n.js +230 -0
- package/packages/installer/src/wizard/ide-config-generator.js +993 -0
- package/packages/installer/src/wizard/ide-selector.js +86 -0
- package/packages/installer/src/wizard/index.js +831 -0
- package/packages/installer/src/wizard/pro-setup.js +1223 -0
- package/packages/installer/src/wizard/questions.js +336 -0
- package/packages/installer/src/wizard/validation/index.js +121 -0
- package/packages/installer/src/wizard/validation/report-generator.js +254 -0
- package/packages/installer/src/wizard/validation/troubleshooting-system.js +348 -0
- package/packages/installer/src/wizard/validation/validators/config-validator.js +364 -0
- package/packages/installer/src/wizard/validation/validators/dependency-validator.js +333 -0
- package/packages/installer/src/wizard/validation/validators/file-structure-validator.js +175 -0
- package/packages/installer/src/wizard/validation/validators/mcp-health-checker.js +310 -0
- package/packages/installer/src/wizard/validators.js +274 -0
- package/packages/installer/src/wizard/wizard.js +246 -0
- package/packages/installer/tests/integration/environment-configuration.test.js +331 -0
- package/packages/installer/tests/integration/wizard-detection.test.js +353 -0
- package/packages/installer/tests/unit/config-validator.test.js +316 -0
- package/packages/installer/tests/unit/detection/detect-project-type.test.js +403 -0
- package/packages/installer/tests/unit/env-template.test.js +189 -0
- package/packages/installer/tests/unit/merger/env-merger.test.js +192 -0
- package/packages/installer/tests/unit/merger/markdown-merger.test.js +262 -0
- package/packages/installer/tests/unit/merger/strategies.test.js +153 -0
- package/scripts/check-markdown-links.py +353 -0
- package/scripts/code-intel-health-check.js +344 -0
- package/scripts/dashboard-parallel-dev.sh +184 -0
- package/scripts/dashboard-parallel-phase3.sh +130 -0
- package/scripts/dashboard-parallel-phase4.sh +131 -0
- package/scripts/ensure-manifest.js +59 -0
- package/scripts/generate-install-manifest.js +368 -0
- package/scripts/install-monitor-hooks.sh +83 -0
- package/scripts/package-synapse.js +325 -0
- package/scripts/semantic-lint.js +191 -0
- package/scripts/sign-manifest.ps1 +132 -0
- package/scripts/sign-manifest.sh +122 -0
- package/scripts/validate-manifest.js +267 -0
- package/scripts/validate-package-completeness.js +319 -0
|
@@ -0,0 +1,1524 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-Installation Validator
|
|
3
|
+
* Validates installation integrity by comparing installed files against SIGNED manifest
|
|
4
|
+
*
|
|
5
|
+
* @module src/installer/post-install-validator
|
|
6
|
+
* @story 6.19 - Post-Installation Validation & Integrity Verification
|
|
7
|
+
* @version 2.0.0 - Security hardened
|
|
8
|
+
*
|
|
9
|
+
* SECURITY MODEL:
|
|
10
|
+
* - Manifest MUST be cryptographically signed before any file access
|
|
11
|
+
* - All paths are validated for containment before filesystem operations
|
|
12
|
+
* - Symlinks are explicitly rejected
|
|
13
|
+
* - Repair operations require source file hash verification
|
|
14
|
+
* - Fail closed on any security violation
|
|
15
|
+
*
|
|
16
|
+
* Features:
|
|
17
|
+
* - Validates all installed files against signed install-manifest.yaml
|
|
18
|
+
* - Verifies SHA256 hashes for integrity checking
|
|
19
|
+
* - Detects missing, corrupted, and extra files
|
|
20
|
+
* - Provides detailed reports with actionable remediation
|
|
21
|
+
* - Supports automatic repair of missing files (with verification)
|
|
22
|
+
* - Cross-platform compatible (Windows, macOS, Linux)
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
27
|
+
const fs = require('fs-extra');
|
|
28
|
+
const path = require('path');
|
|
29
|
+
const yaml = require('js-yaml');
|
|
30
|
+
const { hashFile, hashesMatch } = require('./file-hasher');
|
|
31
|
+
const { loadAndVerifyManifest } = require('./manifest-signature');
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Validation result severity levels
|
|
35
|
+
* @enum {string}
|
|
36
|
+
*/
|
|
37
|
+
const Severity = {
|
|
38
|
+
CRITICAL: 'critical',
|
|
39
|
+
HIGH: 'high',
|
|
40
|
+
MEDIUM: 'medium',
|
|
41
|
+
LOW: 'low',
|
|
42
|
+
INFO: 'info',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Validation issue types
|
|
47
|
+
* @enum {string}
|
|
48
|
+
*/
|
|
49
|
+
const IssueType = {
|
|
50
|
+
MISSING_FILE: 'MISSING_FILE',
|
|
51
|
+
CORRUPTED_FILE: 'CORRUPTED_FILE',
|
|
52
|
+
EXTRA_FILE: 'EXTRA_FILE',
|
|
53
|
+
MISSING_MANIFEST: 'MISSING_MANIFEST',
|
|
54
|
+
INVALID_MANIFEST: 'INVALID_MANIFEST',
|
|
55
|
+
PERMISSION_ERROR: 'PERMISSION_ERROR',
|
|
56
|
+
SIZE_MISMATCH: 'SIZE_MISMATCH',
|
|
57
|
+
INVALID_PATH: 'INVALID_PATH',
|
|
58
|
+
SYMLINK_REJECTED: 'SYMLINK_REJECTED',
|
|
59
|
+
SIGNATURE_MISSING: 'SIGNATURE_MISSING',
|
|
60
|
+
SIGNATURE_INVALID: 'SIGNATURE_INVALID',
|
|
61
|
+
HASH_ERROR: 'HASH_ERROR',
|
|
62
|
+
SCHEMA_VIOLATION: 'SCHEMA_VIOLATION',
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* File categories for prioritized reporting
|
|
67
|
+
* @enum {string}
|
|
68
|
+
*/
|
|
69
|
+
const FileCategory = {
|
|
70
|
+
CORE: 'core',
|
|
71
|
+
CLI: 'cli',
|
|
72
|
+
DEVELOPMENT: 'development',
|
|
73
|
+
INFRASTRUCTURE: 'infrastructure',
|
|
74
|
+
PRODUCT: 'product',
|
|
75
|
+
WORKFLOW: 'workflow',
|
|
76
|
+
WORKFLOW_INTELLIGENCE: 'workflow-intelligence',
|
|
77
|
+
MONITOR: 'monitor',
|
|
78
|
+
OTHER: 'other',
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Security limits to prevent DoS attacks
|
|
83
|
+
*/
|
|
84
|
+
const SecurityLimits = {
|
|
85
|
+
MAX_MANIFEST_SIZE: 10 * 1024 * 1024, // 10MB
|
|
86
|
+
MAX_FILE_COUNT: 50000,
|
|
87
|
+
MAX_SCAN_DEPTH: 50,
|
|
88
|
+
MAX_SCAN_FILES: 100000,
|
|
89
|
+
MAX_PATH_LENGTH: 1024,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Allowed fields in manifest entries (reject unknown fields)
|
|
94
|
+
*/
|
|
95
|
+
const ALLOWED_MANIFEST_FIELDS = ['path', 'hash', 'size', 'type'];
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Allowed type values in manifest entries
|
|
99
|
+
* These represent file categories, not filesystem types
|
|
100
|
+
* Based on actual types used in install-manifest.yaml
|
|
101
|
+
*/
|
|
102
|
+
const ALLOWED_TYPE_VALUES = [
|
|
103
|
+
// General types
|
|
104
|
+
'file',
|
|
105
|
+
'other',
|
|
106
|
+
// Structural categories
|
|
107
|
+
'cli',
|
|
108
|
+
'core',
|
|
109
|
+
'development',
|
|
110
|
+
'infrastructure',
|
|
111
|
+
'product',
|
|
112
|
+
'workflow',
|
|
113
|
+
'workflow-intelligence',
|
|
114
|
+
'monitor',
|
|
115
|
+
'data',
|
|
116
|
+
'docs',
|
|
117
|
+
'documentation',
|
|
118
|
+
'template',
|
|
119
|
+
'script',
|
|
120
|
+
'config',
|
|
121
|
+
// Content types
|
|
122
|
+
'task',
|
|
123
|
+
'agent',
|
|
124
|
+
'tool',
|
|
125
|
+
'checklist',
|
|
126
|
+
'elicitation',
|
|
127
|
+
'code',
|
|
128
|
+
'manifest',
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Categorize a file path into its functional category
|
|
133
|
+
* @param {string} filePath - Relative file path
|
|
134
|
+
* @returns {FileCategory} - File category
|
|
135
|
+
*/
|
|
136
|
+
function categorizeFile(filePath) {
|
|
137
|
+
const normalized = filePath.replace(/\\/g, '/').toLowerCase();
|
|
138
|
+
|
|
139
|
+
if (normalized.startsWith('core/')) return FileCategory.CORE;
|
|
140
|
+
if (normalized.startsWith('cli/')) return FileCategory.CLI;
|
|
141
|
+
if (normalized.startsWith('development/')) return FileCategory.DEVELOPMENT;
|
|
142
|
+
if (normalized.startsWith('infrastructure/')) return FileCategory.INFRASTRUCTURE;
|
|
143
|
+
if (normalized.startsWith('product/')) return FileCategory.PRODUCT;
|
|
144
|
+
if (normalized.startsWith('workflow-intelligence/')) return FileCategory.WORKFLOW_INTELLIGENCE;
|
|
145
|
+
if (normalized.startsWith('monitor/')) return FileCategory.MONITOR;
|
|
146
|
+
if (normalized.includes('workflow')) return FileCategory.WORKFLOW;
|
|
147
|
+
|
|
148
|
+
return FileCategory.OTHER;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get severity based on file category
|
|
153
|
+
* @param {FileCategory} category - File category
|
|
154
|
+
* @returns {Severity} - Severity level
|
|
155
|
+
*/
|
|
156
|
+
function getSeverityForCategory(category) {
|
|
157
|
+
const severityMap = {
|
|
158
|
+
[FileCategory.CORE]: Severity.CRITICAL,
|
|
159
|
+
[FileCategory.CLI]: Severity.HIGH,
|
|
160
|
+
[FileCategory.DEVELOPMENT]: Severity.HIGH,
|
|
161
|
+
[FileCategory.INFRASTRUCTURE]: Severity.MEDIUM,
|
|
162
|
+
[FileCategory.PRODUCT]: Severity.MEDIUM,
|
|
163
|
+
[FileCategory.WORKFLOW]: Severity.MEDIUM,
|
|
164
|
+
[FileCategory.WORKFLOW_INTELLIGENCE]: Severity.HIGH,
|
|
165
|
+
[FileCategory.MONITOR]: Severity.MEDIUM,
|
|
166
|
+
[FileCategory.OTHER]: Severity.LOW,
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
return severityMap[category] || Severity.LOW;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Validate that a resolved path is contained within the root directory
|
|
174
|
+
* Prevents path traversal attacks via malicious manifest entries
|
|
175
|
+
*
|
|
176
|
+
* SECURITY: Handles Windows case-insensitivity and alternate data streams
|
|
177
|
+
*
|
|
178
|
+
* @param {string} absolutePath - The resolved absolute path to check
|
|
179
|
+
* @param {string} rootDir - The root directory that should contain the path
|
|
180
|
+
* @returns {boolean} - True if path is safely contained within root
|
|
181
|
+
*/
|
|
182
|
+
function isPathContained(absolutePath, rootDir) {
|
|
183
|
+
const normalizedRoot = path.resolve(rootDir);
|
|
184
|
+
const normalizedPath = path.resolve(absolutePath);
|
|
185
|
+
|
|
186
|
+
// SECURITY: Case-insensitive comparison on Windows
|
|
187
|
+
const comparableRoot =
|
|
188
|
+
process.platform === 'win32' ? normalizedRoot.toLowerCase() : normalizedRoot;
|
|
189
|
+
const comparablePath =
|
|
190
|
+
process.platform === 'win32' ? normalizedPath.toLowerCase() : normalizedPath;
|
|
191
|
+
|
|
192
|
+
// SECURITY: Reject alternate data streams (Windows)
|
|
193
|
+
// Valid format: drive letter at start only (e.g., "C:\")
|
|
194
|
+
// Reject any other ':' in the path (indicates ADS like "file.txt:stream")
|
|
195
|
+
const colonCount = (absolutePath.match(/:/g) || []).length;
|
|
196
|
+
if (process.platform === 'win32') {
|
|
197
|
+
// Windows: allow exactly one colon at position 1 (drive letter)
|
|
198
|
+
if (colonCount > 1 || (colonCount === 1 && !absolutePath.match(/^[a-zA-Z]:[/\\]/))) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
// Unix: reject any colon (could indicate ADS-like attacks)
|
|
203
|
+
if (colonCount > 0) {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Path must be equal to root or start with root + separator
|
|
209
|
+
return comparablePath === comparableRoot || comparablePath.startsWith(comparableRoot + path.sep);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Validate a manifest entry against strict schema
|
|
214
|
+
* SECURITY: Rejects unknown fields and invalid types
|
|
215
|
+
*
|
|
216
|
+
* @param {*} entry - Manifest entry to validate
|
|
217
|
+
* @param {number} index - Entry index for error reporting
|
|
218
|
+
* @returns {{ valid: boolean, error: string|null, sanitized: Object|null }}
|
|
219
|
+
*/
|
|
220
|
+
function validateManifestEntry(entry, index) {
|
|
221
|
+
// Must be a plain object
|
|
222
|
+
if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {
|
|
223
|
+
return { valid: false, error: `Entry ${index}: not an object`, sanitized: null };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// SECURITY: Reject unknown fields
|
|
227
|
+
for (const key of Object.keys(entry)) {
|
|
228
|
+
if (!ALLOWED_MANIFEST_FIELDS.includes(key)) {
|
|
229
|
+
return { valid: false, error: `Entry ${index}: unknown field '${key}'`, sanitized: null };
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// path: required, string, non-empty
|
|
234
|
+
if (typeof entry.path !== 'string' || entry.path.length === 0) {
|
|
235
|
+
return { valid: false, error: `Entry ${index}: missing or invalid 'path'`, sanitized: null };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// SECURITY: Path validation
|
|
239
|
+
const pathVal = entry.path;
|
|
240
|
+
|
|
241
|
+
// Reject null bytes
|
|
242
|
+
if (pathVal.includes('\0')) {
|
|
243
|
+
return { valid: false, error: `Entry ${index}: path contains null byte`, sanitized: null };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Reject path traversal sequences
|
|
247
|
+
if (pathVal.includes('..')) {
|
|
248
|
+
return {
|
|
249
|
+
valid: false,
|
|
250
|
+
error: `Entry ${index}: path contains '..' traversal`,
|
|
251
|
+
sanitized: null,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Reject absolute paths
|
|
256
|
+
if (path.isAbsolute(pathVal)) {
|
|
257
|
+
return { valid: false, error: `Entry ${index}: absolute path not allowed`, sanitized: null };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Reject excessively long paths
|
|
261
|
+
if (pathVal.length > SecurityLimits.MAX_PATH_LENGTH) {
|
|
262
|
+
return { valid: false, error: `Entry ${index}: path exceeds maximum length`, sanitized: null };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// SECURITY: Reject alternate data streams (Windows ADS) and colons in paths
|
|
266
|
+
// Colons are not valid in filenames on Windows and could indicate ADS attacks
|
|
267
|
+
if (pathVal.includes(':')) {
|
|
268
|
+
return {
|
|
269
|
+
valid: false,
|
|
270
|
+
error: `Entry ${index}: path contains ':' (potential ADS attack)`,
|
|
271
|
+
sanitized: null,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// hash: optional, but if present must be valid format
|
|
276
|
+
if (entry.hash !== undefined && entry.hash !== null) {
|
|
277
|
+
if (typeof entry.hash !== 'string') {
|
|
278
|
+
return { valid: false, error: `Entry ${index}: hash must be a string`, sanitized: null };
|
|
279
|
+
}
|
|
280
|
+
if (!entry.hash.match(/^sha256:[a-f0-9]{64}$/i)) {
|
|
281
|
+
return { valid: false, error: `Entry ${index}: invalid hash format`, sanitized: null };
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// size: optional, but if present must be non-negative integer
|
|
286
|
+
if (entry.size !== undefined && entry.size !== null) {
|
|
287
|
+
if (typeof entry.size !== 'number' || !Number.isInteger(entry.size) || entry.size < 0) {
|
|
288
|
+
return {
|
|
289
|
+
valid: false,
|
|
290
|
+
error: `Entry ${index}: size must be non-negative integer`,
|
|
291
|
+
sanitized: null,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// type: optional, if present must be from allowed list
|
|
297
|
+
if (entry.type !== undefined && entry.type !== null) {
|
|
298
|
+
if (!ALLOWED_TYPE_VALUES.includes(entry.type)) {
|
|
299
|
+
return {
|
|
300
|
+
valid: false,
|
|
301
|
+
error: `Entry ${index}: invalid type '${entry.type}'`,
|
|
302
|
+
sanitized: null,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Return sanitized entry with normalized path
|
|
308
|
+
return {
|
|
309
|
+
valid: true,
|
|
310
|
+
error: null,
|
|
311
|
+
sanitized: {
|
|
312
|
+
path: pathVal.replace(/\\/g, '/'),
|
|
313
|
+
hash: entry.hash ? String(entry.hash).toLowerCase() : null,
|
|
314
|
+
size: typeof entry.size === 'number' ? entry.size : null,
|
|
315
|
+
type: entry.type || 'file',
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Post-Installation Validator Class
|
|
322
|
+
* Comprehensive validation of grimoire installation with security hardening
|
|
323
|
+
*/
|
|
324
|
+
class PostInstallValidator {
|
|
325
|
+
/**
|
|
326
|
+
* Create a new PostInstallValidator instance
|
|
327
|
+
*
|
|
328
|
+
* @param {string} targetDir - Directory where grimoire was installed (project root)
|
|
329
|
+
* @param {string} [sourceDir] - Source directory for repairs (optional)
|
|
330
|
+
* @param {Object} [options] - Validation options
|
|
331
|
+
* @param {boolean} [options.verifyHashes=true] - Whether to verify file hashes
|
|
332
|
+
* @param {boolean} [options.detectExtras=false] - Whether to detect extra files
|
|
333
|
+
* @param {boolean} [options.verbose=false] - Enable verbose logging
|
|
334
|
+
* @param {boolean} [options.requireSignature=true] - Require manifest signature
|
|
335
|
+
* @param {Function} [options.onProgress] - Progress callback (current, total, file)
|
|
336
|
+
*/
|
|
337
|
+
constructor(targetDir, sourceDir = null, options = {}) {
|
|
338
|
+
this.targetDir = path.resolve(targetDir);
|
|
339
|
+
this.sourceDir = sourceDir ? path.resolve(sourceDir) : null;
|
|
340
|
+
this.grimoireCoreTarget = path.join(this.targetDir, '.grimoire');
|
|
341
|
+
this.grimoireCoreSource = this.sourceDir ? path.join(this.sourceDir, '.grimoire') : null;
|
|
342
|
+
|
|
343
|
+
this.options = {
|
|
344
|
+
verifyHashes: options.verifyHashes !== false,
|
|
345
|
+
detectExtras: options.detectExtras === true,
|
|
346
|
+
verbose: options.verbose === true,
|
|
347
|
+
requireSignature: options.requireSignature !== false,
|
|
348
|
+
onProgress: options.onProgress || (() => {}),
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
this.manifest = null;
|
|
352
|
+
this.manifestVerified = false;
|
|
353
|
+
this.issues = [];
|
|
354
|
+
this.stats = {
|
|
355
|
+
totalFiles: 0,
|
|
356
|
+
validFiles: 0,
|
|
357
|
+
missingFiles: 0,
|
|
358
|
+
corruptedFiles: 0,
|
|
359
|
+
extraFiles: 0,
|
|
360
|
+
skippedFiles: 0,
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
// INS-2 Performance: Cache realpath of target directory (computed once, used for all files)
|
|
364
|
+
// This eliminates redundant fs.realpathSync() calls - 50% reduction in syscalls
|
|
365
|
+
this._realTargetDirCache = null;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Get the real path of the target directory (cached)
|
|
370
|
+
* INS-2 Performance Optimization: Reduces syscalls from 2 to 1 per file validation
|
|
371
|
+
* @returns {string|null} - Real path or null if resolution fails
|
|
372
|
+
*/
|
|
373
|
+
_getRealTargetDir() {
|
|
374
|
+
if (this._realTargetDirCache === null) {
|
|
375
|
+
try {
|
|
376
|
+
this._realTargetDirCache = fs.realpathSync(this.grimoireCoreTarget);
|
|
377
|
+
} catch {
|
|
378
|
+
// Will be handled by caller
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return this._realTargetDirCache;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Load, verify signature, and parse the install manifest
|
|
387
|
+
* SECURITY: Signature is verified BEFORE parsing YAML
|
|
388
|
+
*
|
|
389
|
+
* @returns {Promise<Object|null>} - Parsed manifest or null if verification fails
|
|
390
|
+
*/
|
|
391
|
+
async loadManifest() {
|
|
392
|
+
// Determine manifest path
|
|
393
|
+
const sourceManifestPath = this.grimoireCoreSource
|
|
394
|
+
? path.join(this.grimoireCoreSource, 'install-manifest.yaml')
|
|
395
|
+
: null;
|
|
396
|
+
const targetManifestPath = path.join(this.grimoireCoreTarget, 'install-manifest.yaml');
|
|
397
|
+
|
|
398
|
+
let manifestPath = targetManifestPath;
|
|
399
|
+
|
|
400
|
+
// Prefer source manifest (has hashes)
|
|
401
|
+
if (sourceManifestPath && fs.existsSync(sourceManifestPath)) {
|
|
402
|
+
manifestPath = sourceManifestPath;
|
|
403
|
+
this.log(`Using source manifest: ${sourceManifestPath}`);
|
|
404
|
+
} else if (!fs.existsSync(targetManifestPath)) {
|
|
405
|
+
this.issues.push({
|
|
406
|
+
type: IssueType.MISSING_MANIFEST,
|
|
407
|
+
severity: Severity.CRITICAL,
|
|
408
|
+
message: 'Install manifest not found',
|
|
409
|
+
details: `Expected at: ${targetManifestPath}`,
|
|
410
|
+
remediation: 'Re-run installation or copy manifest from source package',
|
|
411
|
+
relativePath: null,
|
|
412
|
+
});
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// SECURITY [C1]: Verify signature BEFORE parsing
|
|
417
|
+
if (this.options.requireSignature) {
|
|
418
|
+
const verifyResult = loadAndVerifyManifest(manifestPath, {
|
|
419
|
+
requireSignature: true,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
if (verifyResult.error) {
|
|
423
|
+
const issueType = verifyResult.error.includes('not found')
|
|
424
|
+
? IssueType.SIGNATURE_MISSING
|
|
425
|
+
: IssueType.SIGNATURE_INVALID;
|
|
426
|
+
|
|
427
|
+
this.issues.push({
|
|
428
|
+
type: issueType,
|
|
429
|
+
severity: Severity.CRITICAL,
|
|
430
|
+
message: `Manifest signature verification failed: ${verifyResult.error}`,
|
|
431
|
+
details: 'The manifest cannot be trusted without a valid signature',
|
|
432
|
+
remediation: 'Obtain a properly signed manifest from the official source',
|
|
433
|
+
relativePath: null,
|
|
434
|
+
});
|
|
435
|
+
return null; // HARD FAIL
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
this.manifestVerified = verifyResult.verified;
|
|
439
|
+
|
|
440
|
+
// Parse verified content
|
|
441
|
+
try {
|
|
442
|
+
return this.parseManifestContent(verifyResult.content.toString('utf8'));
|
|
443
|
+
} catch (error) {
|
|
444
|
+
this.issues.push({
|
|
445
|
+
type: IssueType.INVALID_MANIFEST,
|
|
446
|
+
severity: Severity.CRITICAL,
|
|
447
|
+
message: 'Failed to parse verified manifest',
|
|
448
|
+
details: error.message,
|
|
449
|
+
remediation: 'Re-download manifest from trusted source',
|
|
450
|
+
relativePath: null,
|
|
451
|
+
});
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Development mode: signature not required (NOT for production)
|
|
457
|
+
this.log('WARNING: Signature verification disabled - development mode only');
|
|
458
|
+
try {
|
|
459
|
+
// SECURITY [DOS-3]: Check file size BEFORE reading into memory
|
|
460
|
+
const manifestStat = fs.statSync(manifestPath);
|
|
461
|
+
if (manifestStat.size > SecurityLimits.MAX_MANIFEST_SIZE) {
|
|
462
|
+
this.issues.push({
|
|
463
|
+
type: IssueType.INVALID_MANIFEST,
|
|
464
|
+
severity: Severity.CRITICAL,
|
|
465
|
+
message: 'Manifest file exceeds maximum size',
|
|
466
|
+
details: `Size: ${manifestStat.size} bytes, Max: ${SecurityLimits.MAX_MANIFEST_SIZE} bytes`,
|
|
467
|
+
remediation: 'Use a valid manifest file from the official source',
|
|
468
|
+
relativePath: null,
|
|
469
|
+
});
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const content = fs.readFileSync(manifestPath, 'utf8');
|
|
474
|
+
return this.parseManifestContent(content);
|
|
475
|
+
} catch (error) {
|
|
476
|
+
this.issues.push({
|
|
477
|
+
type: IssueType.INVALID_MANIFEST,
|
|
478
|
+
severity: Severity.CRITICAL,
|
|
479
|
+
message: 'Failed to read manifest',
|
|
480
|
+
details: error.message,
|
|
481
|
+
remediation: 'Re-run installation',
|
|
482
|
+
relativePath: null,
|
|
483
|
+
});
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Parse manifest content with strict validation
|
|
490
|
+
* SECURITY [C2]: Uses FAILSAFE_SCHEMA to prevent code execution
|
|
491
|
+
* SECURITY [H5]: Validates schema strictly
|
|
492
|
+
*
|
|
493
|
+
* @param {string} content - Raw manifest content
|
|
494
|
+
* @returns {Object} Parsed and validated manifest
|
|
495
|
+
*/
|
|
496
|
+
parseManifestContent(content) {
|
|
497
|
+
// SECURITY [DOS-4]: Size limit using byte length, not character length
|
|
498
|
+
// String.length counts Unicode characters, not bytes. A string with multibyte
|
|
499
|
+
// characters (emojis, CJK) would have fewer characters than bytes.
|
|
500
|
+
// Example: "🔒" has length 2 but is 4 bytes in UTF-8
|
|
501
|
+
const byteLength = Buffer.byteLength(content, 'utf8');
|
|
502
|
+
if (byteLength > SecurityLimits.MAX_MANIFEST_SIZE) {
|
|
503
|
+
throw new Error(
|
|
504
|
+
`Manifest exceeds maximum size (${byteLength} bytes > ${SecurityLimits.MAX_MANIFEST_SIZE} bytes)`,
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// SECURITY [C2]: Use FAILSAFE_SCHEMA - no custom types, no code execution
|
|
509
|
+
const parsed = yaml.load(content, { schema: yaml.FAILSAFE_SCHEMA });
|
|
510
|
+
|
|
511
|
+
// Validate root structure
|
|
512
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
513
|
+
throw new Error('Manifest must be a valid YAML object');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (!Array.isArray(parsed.files)) {
|
|
517
|
+
throw new Error('Manifest missing required "files" array');
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// SECURITY: File count limit
|
|
521
|
+
if (parsed.files.length > SecurityLimits.MAX_FILE_COUNT) {
|
|
522
|
+
throw new Error(
|
|
523
|
+
`Manifest contains too many files (${parsed.files.length} > ${SecurityLimits.MAX_FILE_COUNT})`,
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// SECURITY [H5]: Validate and sanitize each entry
|
|
528
|
+
const sanitizedFiles = [];
|
|
529
|
+
for (let i = 0; i < parsed.files.length; i++) {
|
|
530
|
+
const entry = parsed.files[i];
|
|
531
|
+
|
|
532
|
+
// Handle string format (simple manifest)
|
|
533
|
+
if (typeof entry === 'string') {
|
|
534
|
+
const validation = validateManifestEntry({ path: entry }, i);
|
|
535
|
+
if (!validation.valid) {
|
|
536
|
+
throw new Error(validation.error);
|
|
537
|
+
}
|
|
538
|
+
sanitizedFiles.push(validation.sanitized);
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// SECURITY [H5-PRE]: Reject unknown fields BEFORE normalization
|
|
543
|
+
// This prevents malicious fields from being silently dropped
|
|
544
|
+
if (typeof entry === 'object' && entry !== null) {
|
|
545
|
+
for (const key of Object.keys(entry)) {
|
|
546
|
+
if (!ALLOWED_MANIFEST_FIELDS.includes(key)) {
|
|
547
|
+
throw new Error(`Entry ${i}: unknown field '${key}' in manifest`);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// SECURITY [H5-SIZE]: Fail fast on malformed sizes instead of silently nulling
|
|
553
|
+
// When size is present but invalid, reject the manifest entirely
|
|
554
|
+
if (entry.size !== undefined && entry.size !== null) {
|
|
555
|
+
const sizeNum = Number(entry.size);
|
|
556
|
+
if (Number.isNaN(sizeNum) || !Number.isInteger(sizeNum) || sizeNum < 0) {
|
|
557
|
+
throw new Error(
|
|
558
|
+
`Entry ${i}: invalid size '${entry.size}' for path '${entry.path}' (must be non-negative integer)`,
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// Object format - convert FAILSAFE_SCHEMA strings to proper types
|
|
564
|
+
const normalizedEntry = {
|
|
565
|
+
path: entry.path,
|
|
566
|
+
hash: entry.hash,
|
|
567
|
+
// FAILSAFE_SCHEMA returns all values as strings, convert size to number
|
|
568
|
+
// Size already validated above, safe to convert
|
|
569
|
+
size: entry.size !== undefined && entry.size !== null ? Number(entry.size) : null,
|
|
570
|
+
type: entry.type,
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
const validation = validateManifestEntry(normalizedEntry, i);
|
|
574
|
+
if (!validation.valid) {
|
|
575
|
+
throw new Error(validation.error);
|
|
576
|
+
}
|
|
577
|
+
sanitizedFiles.push(validation.sanitized);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
this.manifest = {
|
|
581
|
+
...parsed,
|
|
582
|
+
files: sanitizedFiles,
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
this.log(
|
|
586
|
+
`Loaded manifest v${this.manifest.version || 'unknown'} with ${this.manifest.files.length} files`,
|
|
587
|
+
);
|
|
588
|
+
|
|
589
|
+
return this.manifest;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Validate a single file against manifest entry
|
|
594
|
+
* SECURITY [C3]: Rejects symlinks and non-regular files
|
|
595
|
+
* SECURITY [H1]: Validates path containment
|
|
596
|
+
* SECURITY [H2]: Requires size in quick mode
|
|
597
|
+
* SECURITY [H3]: Treats hash errors as failures
|
|
598
|
+
*
|
|
599
|
+
* @param {Object} entry - Validated manifest entry
|
|
600
|
+
* @returns {Promise<Object>} - Validation result
|
|
601
|
+
*/
|
|
602
|
+
async validateFile(entry) {
|
|
603
|
+
const relativePath = entry.path;
|
|
604
|
+
const absolutePath = path.resolve(this.grimoireCoreTarget, relativePath);
|
|
605
|
+
const category = categorizeFile(relativePath);
|
|
606
|
+
|
|
607
|
+
const result = {
|
|
608
|
+
path: relativePath,
|
|
609
|
+
category,
|
|
610
|
+
exists: false,
|
|
611
|
+
hashValid: null,
|
|
612
|
+
sizeValid: null,
|
|
613
|
+
issue: null,
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
// SECURITY [H1]: Validate path containment
|
|
617
|
+
if (!isPathContained(absolutePath, this.grimoireCoreTarget)) {
|
|
618
|
+
this.log(`SECURITY: Path traversal blocked: ${relativePath}`);
|
|
619
|
+
result.issue = {
|
|
620
|
+
type: IssueType.INVALID_PATH,
|
|
621
|
+
severity: Severity.CRITICAL,
|
|
622
|
+
message: 'Path traversal attempt blocked',
|
|
623
|
+
details: 'Manifest entry attempts to access outside installation directory',
|
|
624
|
+
category,
|
|
625
|
+
remediation: 'This indicates a malicious or corrupted manifest',
|
|
626
|
+
relativePath,
|
|
627
|
+
};
|
|
628
|
+
this.stats.skippedFiles++;
|
|
629
|
+
return result;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Check file existence
|
|
633
|
+
let lstat;
|
|
634
|
+
try {
|
|
635
|
+
lstat = fs.lstatSync(absolutePath);
|
|
636
|
+
} catch (error) {
|
|
637
|
+
if (error.code === 'ENOENT') {
|
|
638
|
+
result.issue = {
|
|
639
|
+
type: IssueType.MISSING_FILE,
|
|
640
|
+
severity: getSeverityForCategory(category),
|
|
641
|
+
message: `Missing file: ${relativePath}`,
|
|
642
|
+
details: `Expected at: ${absolutePath}`,
|
|
643
|
+
category,
|
|
644
|
+
remediation: this.sourceDir
|
|
645
|
+
? "Run 'grimoire validate --repair' to restore"
|
|
646
|
+
: 'Re-run installation',
|
|
647
|
+
relativePath,
|
|
648
|
+
};
|
|
649
|
+
this.stats.missingFiles++;
|
|
650
|
+
return result;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
result.issue = {
|
|
654
|
+
type: IssueType.PERMISSION_ERROR,
|
|
655
|
+
severity: Severity.HIGH,
|
|
656
|
+
message: `Cannot access file: ${relativePath}`,
|
|
657
|
+
details: error.message,
|
|
658
|
+
category,
|
|
659
|
+
remediation: 'Check file permissions',
|
|
660
|
+
relativePath,
|
|
661
|
+
};
|
|
662
|
+
this.stats.skippedFiles++;
|
|
663
|
+
return result;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// SECURITY [C3]: Reject symlinks
|
|
667
|
+
if (lstat.isSymbolicLink()) {
|
|
668
|
+
result.issue = {
|
|
669
|
+
type: IssueType.SYMLINK_REJECTED,
|
|
670
|
+
severity: Severity.CRITICAL,
|
|
671
|
+
message: `Symlink not allowed: ${relativePath}`,
|
|
672
|
+
details: 'Symlinks are rejected to prevent path escape attacks',
|
|
673
|
+
category,
|
|
674
|
+
remediation: 'Replace symlink with actual file',
|
|
675
|
+
relativePath,
|
|
676
|
+
};
|
|
677
|
+
this.stats.skippedFiles++;
|
|
678
|
+
return result;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// SECURITY [C3]: Reject non-regular files
|
|
682
|
+
if (!lstat.isFile()) {
|
|
683
|
+
result.issue = {
|
|
684
|
+
type: IssueType.INVALID_PATH,
|
|
685
|
+
severity: Severity.HIGH,
|
|
686
|
+
message: `Not a regular file: ${relativePath}`,
|
|
687
|
+
details: `Found ${lstat.isDirectory() ? 'directory' : 'special file'} instead of file`,
|
|
688
|
+
category,
|
|
689
|
+
remediation: 'Only regular files are allowed',
|
|
690
|
+
relativePath,
|
|
691
|
+
};
|
|
692
|
+
this.stats.skippedFiles++;
|
|
693
|
+
return result;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// SECURITY [C3-REALPATH]: Detect symlinks in intermediate directory components
|
|
697
|
+
// A file may not be a symlink itself, but a parent directory could be,
|
|
698
|
+
// allowing path traversal attacks (e.g., /install/.grimoire/symlinked-dir/../../../etc/passwd)
|
|
699
|
+
//
|
|
700
|
+
// NOTE: On macOS, /tmp is a symlink to /private/tmp. This is a system-level
|
|
701
|
+
// symlink that shouldn't trigger security alerts. We handle this by resolving
|
|
702
|
+
// both the file path AND the target directory to their real paths, then
|
|
703
|
+
// comparing containment. The key security check is: does the real path of the
|
|
704
|
+
// file stay within the real path of the target directory?
|
|
705
|
+
//
|
|
706
|
+
// INS-2 Performance: realTargetDir is now cached via _getRealTargetDir()
|
|
707
|
+
// This reduces syscalls from 2 to 1 per file (50% reduction)
|
|
708
|
+
try {
|
|
709
|
+
const realPath = fs.realpathSync(absolutePath);
|
|
710
|
+
const realTargetDir = this._getRealTargetDir();
|
|
711
|
+
|
|
712
|
+
// Handle case where target dir resolution failed
|
|
713
|
+
if (realTargetDir === null) {
|
|
714
|
+
this.log('SECURITY: Cannot resolve realpath for target directory');
|
|
715
|
+
result.issue = {
|
|
716
|
+
type: IssueType.PERMISSION_ERROR,
|
|
717
|
+
severity: Severity.CRITICAL,
|
|
718
|
+
message: 'Cannot resolve real path for target directory',
|
|
719
|
+
details: 'Target directory realpath resolution failed',
|
|
720
|
+
category,
|
|
721
|
+
remediation: 'Check directory permissions',
|
|
722
|
+
relativePath,
|
|
723
|
+
};
|
|
724
|
+
this.stats.skippedFiles++;
|
|
725
|
+
return result;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// SECURITY: Verify realpath is still contained within REAL target directory
|
|
729
|
+
// This handles system symlinks like /tmp -> /private/tmp correctly
|
|
730
|
+
if (!isPathContained(realPath, realTargetDir)) {
|
|
731
|
+
this.log(`SECURITY: Realpath escapes target directory: ${relativePath}`);
|
|
732
|
+
result.issue = {
|
|
733
|
+
type: IssueType.INVALID_PATH,
|
|
734
|
+
severity: Severity.CRITICAL,
|
|
735
|
+
message: `Path escape via symlink detected: ${relativePath}`,
|
|
736
|
+
details: `Real path ${realPath} is outside installation directory ${realTargetDir}`,
|
|
737
|
+
category,
|
|
738
|
+
remediation: 'This indicates a path traversal attack via symlinked directories',
|
|
739
|
+
relativePath,
|
|
740
|
+
};
|
|
741
|
+
this.stats.skippedFiles++;
|
|
742
|
+
return result;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// SECURITY: Detect symlinks in the RELATIVE portion of the path
|
|
746
|
+
// Compare the relative path from target to file with the relative path
|
|
747
|
+
// from realTarget to realPath. If they differ, there's a symlink attack.
|
|
748
|
+
const expectedRelative = path.relative(this.grimoireCoreTarget, absolutePath);
|
|
749
|
+
const actualRelative = path.relative(realTargetDir, realPath);
|
|
750
|
+
|
|
751
|
+
// Platform-aware comparison (case-insensitive on Windows)
|
|
752
|
+
const comparableExpected =
|
|
753
|
+
process.platform === 'win32' ? expectedRelative.toLowerCase() : expectedRelative;
|
|
754
|
+
const comparableActual =
|
|
755
|
+
process.platform === 'win32' ? actualRelative.toLowerCase() : actualRelative;
|
|
756
|
+
|
|
757
|
+
if (comparableExpected !== comparableActual) {
|
|
758
|
+
this.log(`SECURITY: Symlinked path component detected: ${relativePath}`);
|
|
759
|
+
result.issue = {
|
|
760
|
+
type: IssueType.SYMLINK_REJECTED,
|
|
761
|
+
severity: Severity.CRITICAL,
|
|
762
|
+
message: `Symlinked path component detected: ${relativePath}`,
|
|
763
|
+
details: `Resolved relative path differs: expected '${expectedRelative}', got '${actualRelative}'`,
|
|
764
|
+
category,
|
|
765
|
+
remediation: 'Remove symlinks from directory structure',
|
|
766
|
+
relativePath,
|
|
767
|
+
};
|
|
768
|
+
this.stats.skippedFiles++;
|
|
769
|
+
return result;
|
|
770
|
+
}
|
|
771
|
+
} catch (error) {
|
|
772
|
+
// realpathSync can fail if file doesn't exist or permission denied
|
|
773
|
+
// File existence already checked via lstat, so this indicates permission issue
|
|
774
|
+
this.log(`SECURITY: Cannot resolve realpath for: ${relativePath} - ${error.message}`);
|
|
775
|
+
result.issue = {
|
|
776
|
+
type: IssueType.PERMISSION_ERROR,
|
|
777
|
+
severity: Severity.HIGH,
|
|
778
|
+
message: `Cannot resolve real path: ${relativePath}`,
|
|
779
|
+
details: error.message,
|
|
780
|
+
category,
|
|
781
|
+
remediation: 'Check file and directory permissions',
|
|
782
|
+
relativePath,
|
|
783
|
+
};
|
|
784
|
+
this.stats.skippedFiles++;
|
|
785
|
+
return result;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
result.exists = true;
|
|
789
|
+
|
|
790
|
+
// SECURITY [H2]: In quick mode (no hash), size MUST be present
|
|
791
|
+
if (!this.options.verifyHashes) {
|
|
792
|
+
if (entry.size === null || entry.size === undefined) {
|
|
793
|
+
result.issue = {
|
|
794
|
+
type: IssueType.SCHEMA_VIOLATION,
|
|
795
|
+
severity: Severity.HIGH,
|
|
796
|
+
message: `Missing size in manifest: ${relativePath}`,
|
|
797
|
+
details: 'Size is required when hash verification is disabled',
|
|
798
|
+
category,
|
|
799
|
+
remediation: 'Use full validation mode or update manifest with size information',
|
|
800
|
+
relativePath,
|
|
801
|
+
};
|
|
802
|
+
this.stats.skippedFiles++;
|
|
803
|
+
return result;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// Verify file size
|
|
808
|
+
const actualSize = lstat.size;
|
|
809
|
+
if (entry.size !== null && entry.size !== undefined) {
|
|
810
|
+
result.sizeValid = actualSize === entry.size;
|
|
811
|
+
|
|
812
|
+
if (!result.sizeValid) {
|
|
813
|
+
this.log(`Size mismatch: ${relativePath} (expected ${entry.size}, got ${actualSize})`);
|
|
814
|
+
|
|
815
|
+
// In quick mode, size mismatch is a failure
|
|
816
|
+
if (!this.options.verifyHashes) {
|
|
817
|
+
result.issue = {
|
|
818
|
+
type: IssueType.SIZE_MISMATCH,
|
|
819
|
+
severity: getSeverityForCategory(category),
|
|
820
|
+
message: `File size mismatch: ${relativePath}`,
|
|
821
|
+
details: `Expected: ${entry.size} bytes, Got: ${actualSize} bytes`,
|
|
822
|
+
category,
|
|
823
|
+
remediation: this.sourceDir
|
|
824
|
+
? "Run 'grimoire validate --repair' to restore"
|
|
825
|
+
: 'Re-run installation',
|
|
826
|
+
relativePath,
|
|
827
|
+
};
|
|
828
|
+
this.stats.corruptedFiles++;
|
|
829
|
+
return result;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// SECURITY [H7]: Missing hash when hash verification is enabled is a schema violation
|
|
835
|
+
// This MUST be checked BEFORE the hash verification block to prevent bypass
|
|
836
|
+
if (this.options.verifyHashes && !entry.hash) {
|
|
837
|
+
result.issue = {
|
|
838
|
+
type: IssueType.SCHEMA_VIOLATION,
|
|
839
|
+
severity: getSeverityForCategory(category),
|
|
840
|
+
message: `Missing hash in manifest: ${relativePath}`,
|
|
841
|
+
details: 'Hash verification enabled but no hash provided in manifest',
|
|
842
|
+
category,
|
|
843
|
+
remediation: 'Update manifest with file hashes or disable hash verification',
|
|
844
|
+
relativePath,
|
|
845
|
+
};
|
|
846
|
+
this.stats.corruptedFiles++;
|
|
847
|
+
return result;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Verify hash (full validation)
|
|
851
|
+
if (this.options.verifyHashes && entry.hash) {
|
|
852
|
+
try {
|
|
853
|
+
const actualHash = `sha256:${hashFile(absolutePath)}`;
|
|
854
|
+
result.hashValid = hashesMatch(actualHash, entry.hash);
|
|
855
|
+
|
|
856
|
+
if (!result.hashValid) {
|
|
857
|
+
result.issue = {
|
|
858
|
+
type: IssueType.CORRUPTED_FILE,
|
|
859
|
+
severity: getSeverityForCategory(category),
|
|
860
|
+
message: `Hash mismatch: ${relativePath}`,
|
|
861
|
+
details: `Expected: ${entry.hash.substring(0, 24)}..., Got: ${actualHash.substring(0, 24)}...`,
|
|
862
|
+
category,
|
|
863
|
+
remediation: this.sourceDir
|
|
864
|
+
? "Run 'grimoire validate --repair' to restore"
|
|
865
|
+
: 'Re-run installation',
|
|
866
|
+
relativePath,
|
|
867
|
+
};
|
|
868
|
+
this.stats.corruptedFiles++;
|
|
869
|
+
return result;
|
|
870
|
+
}
|
|
871
|
+
} catch (error) {
|
|
872
|
+
// SECURITY [H3]: Hash errors are failures, not skips
|
|
873
|
+
result.issue = {
|
|
874
|
+
type: IssueType.HASH_ERROR,
|
|
875
|
+
severity: Severity.HIGH,
|
|
876
|
+
message: `Hash verification error: ${relativePath}`,
|
|
877
|
+
details: error.message,
|
|
878
|
+
category,
|
|
879
|
+
remediation: 'Check file accessibility and try again',
|
|
880
|
+
relativePath,
|
|
881
|
+
};
|
|
882
|
+
this.stats.corruptedFiles++;
|
|
883
|
+
return result;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// File is valid
|
|
888
|
+
this.stats.validFiles++;
|
|
889
|
+
return result;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Scan for extra files not in manifest
|
|
894
|
+
* SECURITY [H6]: Implements depth and file count limits
|
|
895
|
+
*
|
|
896
|
+
* @returns {Promise<Array>} - List of extra file paths
|
|
897
|
+
*/
|
|
898
|
+
async detectExtraFiles() {
|
|
899
|
+
if (!this.options.detectExtras || !this.manifest) {
|
|
900
|
+
return [];
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// SECURITY: Only use case-insensitive comparison on Windows
|
|
904
|
+
// On case-sensitive filesystems (Linux/macOS), preserve case to detect
|
|
905
|
+
// malicious files that differ only by case (e.g., Malicious.js vs malicious.js)
|
|
906
|
+
const isWindows = process.platform === 'win32';
|
|
907
|
+
const normalizePath = (p) => (isWindows ? p.toLowerCase() : p);
|
|
908
|
+
const manifestPaths = new Set(this.manifest.files.map((f) => normalizePath(f.path)));
|
|
909
|
+
const extraFiles = [];
|
|
910
|
+
let filesScanned = 0;
|
|
911
|
+
|
|
912
|
+
const scanDir = async (dir, basePath, depth = 0) => {
|
|
913
|
+
// SECURITY [H6]: Depth limit
|
|
914
|
+
if (depth > SecurityLimits.MAX_SCAN_DEPTH) {
|
|
915
|
+
this.log(`SECURITY: Max scan depth exceeded at ${dir}`);
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// SECURITY [H6]: File count limit
|
|
920
|
+
if (filesScanned >= SecurityLimits.MAX_SCAN_FILES) {
|
|
921
|
+
this.log('SECURITY: Max scan file count exceeded');
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
if (!fs.existsSync(dir)) return;
|
|
926
|
+
|
|
927
|
+
let entries;
|
|
928
|
+
try {
|
|
929
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
930
|
+
} catch (error) {
|
|
931
|
+
this.log(`Cannot read directory: ${dir} - ${error.message}`);
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
for (const entry of entries) {
|
|
936
|
+
if (filesScanned >= SecurityLimits.MAX_SCAN_FILES) break;
|
|
937
|
+
|
|
938
|
+
const fullPath = path.join(dir, entry.name);
|
|
939
|
+
const relativePath = path.relative(basePath, fullPath).replace(/\\/g, '/');
|
|
940
|
+
|
|
941
|
+
filesScanned++;
|
|
942
|
+
|
|
943
|
+
if (entry.isDirectory()) {
|
|
944
|
+
await scanDir(fullPath, basePath, depth + 1);
|
|
945
|
+
} else if (entry.isFile()) {
|
|
946
|
+
// Skip manifests
|
|
947
|
+
if (
|
|
948
|
+
relativePath === 'install-manifest.yaml' ||
|
|
949
|
+
relativePath === 'install-manifest.yaml.minisig' ||
|
|
950
|
+
relativePath === '.installed-manifest.yaml'
|
|
951
|
+
) {
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (!manifestPaths.has(normalizePath(relativePath))) {
|
|
956
|
+
extraFiles.push(relativePath);
|
|
957
|
+
this.stats.extraFiles++;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
// Symlinks and special files are silently ignored in extra detection
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
|
|
964
|
+
await scanDir(this.grimoireCoreTarget, this.grimoireCoreTarget);
|
|
965
|
+
return extraFiles;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* Run full validation
|
|
970
|
+
*
|
|
971
|
+
* @returns {Promise<Object>} - Comprehensive validation report
|
|
972
|
+
*/
|
|
973
|
+
async validate() {
|
|
974
|
+
const startTime = Date.now();
|
|
975
|
+
|
|
976
|
+
this.log('Starting post-installation validation...');
|
|
977
|
+
|
|
978
|
+
// Reset state
|
|
979
|
+
this.issues = [];
|
|
980
|
+
this.manifestVerified = false;
|
|
981
|
+
this.stats = {
|
|
982
|
+
totalFiles: 0,
|
|
983
|
+
validFiles: 0,
|
|
984
|
+
missingFiles: 0,
|
|
985
|
+
corruptedFiles: 0,
|
|
986
|
+
extraFiles: 0,
|
|
987
|
+
skippedFiles: 0,
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
// Check target directory
|
|
991
|
+
if (!fs.existsSync(this.grimoireCoreTarget)) {
|
|
992
|
+
this.issues.push({
|
|
993
|
+
type: IssueType.MISSING_FILE,
|
|
994
|
+
severity: Severity.CRITICAL,
|
|
995
|
+
message: 'grimoire directory not found',
|
|
996
|
+
details: `Expected at: ${this.grimoireCoreTarget}`,
|
|
997
|
+
remediation: 'Run `npx grimoire install`',
|
|
998
|
+
relativePath: null,
|
|
999
|
+
});
|
|
1000
|
+
return this.generateReport(startTime);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
// Load and verify manifest
|
|
1004
|
+
const manifest = await this.loadManifest();
|
|
1005
|
+
if (!manifest) {
|
|
1006
|
+
return this.generateReport(startTime);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
this.stats.totalFiles = manifest.files.length;
|
|
1010
|
+
|
|
1011
|
+
// Validate each file
|
|
1012
|
+
const fileResults = [];
|
|
1013
|
+
for (let i = 0; i < manifest.files.length; i++) {
|
|
1014
|
+
const entry = manifest.files[i];
|
|
1015
|
+
this.options.onProgress(i + 1, manifest.files.length, entry.path);
|
|
1016
|
+
|
|
1017
|
+
const result = await this.validateFile(entry);
|
|
1018
|
+
fileResults.push(result);
|
|
1019
|
+
|
|
1020
|
+
if (result.issue) {
|
|
1021
|
+
this.issues.push(result.issue);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
// Detect extra files
|
|
1026
|
+
const extraFiles = await this.detectExtraFiles();
|
|
1027
|
+
for (const extraPath of extraFiles) {
|
|
1028
|
+
this.issues.push({
|
|
1029
|
+
type: IssueType.EXTRA_FILE,
|
|
1030
|
+
severity: Severity.INFO,
|
|
1031
|
+
message: `Extra file: ${extraPath}`,
|
|
1032
|
+
details: 'File not in manifest',
|
|
1033
|
+
category: categorizeFile(extraPath),
|
|
1034
|
+
remediation: 'Review if this file should be kept',
|
|
1035
|
+
relativePath: extraPath,
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
return this.generateReport(startTime, fileResults);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Generate validation report
|
|
1044
|
+
*
|
|
1045
|
+
* @param {number} startTime - Start timestamp
|
|
1046
|
+
* @param {Array} [fileResults] - File validation results
|
|
1047
|
+
* @returns {Object} - Report
|
|
1048
|
+
*/
|
|
1049
|
+
generateReport(startTime, _fileResults = []) {
|
|
1050
|
+
const duration = Date.now() - startTime;
|
|
1051
|
+
|
|
1052
|
+
// Group by severity
|
|
1053
|
+
const issuesBySeverity = {
|
|
1054
|
+
[Severity.CRITICAL]: [],
|
|
1055
|
+
[Severity.HIGH]: [],
|
|
1056
|
+
[Severity.MEDIUM]: [],
|
|
1057
|
+
[Severity.LOW]: [],
|
|
1058
|
+
[Severity.INFO]: [],
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1061
|
+
for (const issue of this.issues) {
|
|
1062
|
+
issuesBySeverity[issue.severity].push(issue);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// Group missing by category
|
|
1066
|
+
const missingByCategory = {};
|
|
1067
|
+
for (const issue of this.issues.filter((i) => i.type === IssueType.MISSING_FILE)) {
|
|
1068
|
+
const category = issue.category || FileCategory.OTHER;
|
|
1069
|
+
if (!missingByCategory[category]) {
|
|
1070
|
+
missingByCategory[category] = [];
|
|
1071
|
+
}
|
|
1072
|
+
missingByCategory[category].push(issue.relativePath);
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
// Determine status
|
|
1076
|
+
let status = 'success';
|
|
1077
|
+
if (issuesBySeverity[Severity.CRITICAL].length > 0) {
|
|
1078
|
+
status = 'failed';
|
|
1079
|
+
} else if (
|
|
1080
|
+
issuesBySeverity[Severity.HIGH].length > 0 ||
|
|
1081
|
+
issuesBySeverity[Severity.MEDIUM].length > 0
|
|
1082
|
+
) {
|
|
1083
|
+
status = 'warning';
|
|
1084
|
+
} else if (this.issues.length > 0) {
|
|
1085
|
+
status = 'info';
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// Integrity score
|
|
1089
|
+
const integrityScore =
|
|
1090
|
+
this.stats.totalFiles > 0
|
|
1091
|
+
? Math.round((this.stats.validFiles / this.stats.totalFiles) * 100)
|
|
1092
|
+
: 0;
|
|
1093
|
+
|
|
1094
|
+
return {
|
|
1095
|
+
status,
|
|
1096
|
+
integrityScore,
|
|
1097
|
+
manifestVerified: this.manifestVerified,
|
|
1098
|
+
timestamp: new Date().toISOString(),
|
|
1099
|
+
duration: `${duration}ms`,
|
|
1100
|
+
manifest: this.manifest
|
|
1101
|
+
? {
|
|
1102
|
+
version: this.manifest.version,
|
|
1103
|
+
generatedAt: this.manifest.generated_at,
|
|
1104
|
+
totalFiles: this.manifest.files.length,
|
|
1105
|
+
}
|
|
1106
|
+
: null,
|
|
1107
|
+
stats: { ...this.stats },
|
|
1108
|
+
issues: this.issues,
|
|
1109
|
+
issuesBySeverity,
|
|
1110
|
+
missingByCategory,
|
|
1111
|
+
summary: {
|
|
1112
|
+
total: this.stats.totalFiles,
|
|
1113
|
+
valid: this.stats.validFiles,
|
|
1114
|
+
missing: this.stats.missingFiles,
|
|
1115
|
+
corrupted: this.stats.corruptedFiles,
|
|
1116
|
+
extra: this.stats.extraFiles,
|
|
1117
|
+
skipped: this.stats.skippedFiles,
|
|
1118
|
+
},
|
|
1119
|
+
recommendations: this.generateRecommendations(),
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* Generate recommendations
|
|
1125
|
+
*
|
|
1126
|
+
* @returns {Array<string>} - Recommendations
|
|
1127
|
+
*/
|
|
1128
|
+
generateRecommendations() {
|
|
1129
|
+
const recommendations = [];
|
|
1130
|
+
|
|
1131
|
+
if (!this.manifestVerified && this.options.requireSignature) {
|
|
1132
|
+
recommendations.push(
|
|
1133
|
+
'CRITICAL: Manifest signature verification failed. Do not trust validation results.',
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
if (this.stats.missingFiles > 0) {
|
|
1138
|
+
if (this.stats.missingFiles > 50) {
|
|
1139
|
+
recommendations.push('Consider re-running full installation.');
|
|
1140
|
+
} else {
|
|
1141
|
+
recommendations.push(
|
|
1142
|
+
`${this.stats.missingFiles} file(s) missing. Run 'grimoire validate --repair'.`,
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
if (this.stats.corruptedFiles > 0) {
|
|
1148
|
+
recommendations.push(
|
|
1149
|
+
`${this.stats.corruptedFiles} file(s) corrupted. Run 'grimoire validate --repair'.`,
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
if (this.stats.validFiles === this.stats.totalFiles && this.stats.totalFiles > 0) {
|
|
1154
|
+
recommendations.push('Installation verified successfully.');
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
return recommendations;
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
/**
|
|
1161
|
+
* Repair installation by copying missing/corrupted files
|
|
1162
|
+
* SECURITY [C4]: Verifies source file hash before copying
|
|
1163
|
+
*
|
|
1164
|
+
* @param {Object} [options] - Repair options
|
|
1165
|
+
* @param {boolean} [options.dryRun=false] - Only report, don't copy
|
|
1166
|
+
* @param {Function} [options.onProgress] - Progress callback
|
|
1167
|
+
* @returns {Promise<Object>} - Repair result
|
|
1168
|
+
*/
|
|
1169
|
+
async repair(options = {}) {
|
|
1170
|
+
const dryRun = options.dryRun === true;
|
|
1171
|
+
const onProgress = options.onProgress || (() => {});
|
|
1172
|
+
|
|
1173
|
+
// SECURITY [C4]: Repair requires hash verification enabled
|
|
1174
|
+
if (!this.options.verifyHashes) {
|
|
1175
|
+
return {
|
|
1176
|
+
success: false,
|
|
1177
|
+
error: 'Repair requires hash verification to be enabled',
|
|
1178
|
+
repaired: [],
|
|
1179
|
+
failed: [],
|
|
1180
|
+
skipped: [],
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// SECURITY [C4]: Repair requires verified manifest
|
|
1185
|
+
if (this.options.requireSignature && !this.manifestVerified) {
|
|
1186
|
+
return {
|
|
1187
|
+
success: false,
|
|
1188
|
+
error: 'Repair requires a verified manifest signature',
|
|
1189
|
+
repaired: [],
|
|
1190
|
+
failed: [],
|
|
1191
|
+
skipped: [],
|
|
1192
|
+
};
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
if (!this.sourceDir || !fs.existsSync(this.grimoireCoreSource)) {
|
|
1196
|
+
return {
|
|
1197
|
+
success: false,
|
|
1198
|
+
error: 'Source directory not available',
|
|
1199
|
+
repaired: [],
|
|
1200
|
+
failed: [],
|
|
1201
|
+
skipped: [],
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// Run validation first if needed
|
|
1206
|
+
if (this.issues.length === 0 && this.stats.totalFiles === 0) {
|
|
1207
|
+
await this.validate();
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
const repairableIssues = this.issues.filter(
|
|
1211
|
+
(i) =>
|
|
1212
|
+
i.type === IssueType.MISSING_FILE ||
|
|
1213
|
+
i.type === IssueType.CORRUPTED_FILE ||
|
|
1214
|
+
i.type === IssueType.SIZE_MISMATCH,
|
|
1215
|
+
);
|
|
1216
|
+
|
|
1217
|
+
const result = {
|
|
1218
|
+
success: true,
|
|
1219
|
+
dryRun,
|
|
1220
|
+
repaired: [],
|
|
1221
|
+
failed: [],
|
|
1222
|
+
skipped: [],
|
|
1223
|
+
};
|
|
1224
|
+
|
|
1225
|
+
for (let i = 0; i < repairableIssues.length; i++) {
|
|
1226
|
+
const issue = repairableIssues[i];
|
|
1227
|
+
// SECURITY [H4]: Use relativePath from issue, not parsed from message
|
|
1228
|
+
const relativePath = issue.relativePath;
|
|
1229
|
+
|
|
1230
|
+
if (!relativePath) {
|
|
1231
|
+
result.failed.push({ path: 'unknown', reason: 'Missing path in issue' });
|
|
1232
|
+
continue;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
const sourcePath = path.resolve(this.grimoireCoreSource, relativePath);
|
|
1236
|
+
const targetPath = path.resolve(this.grimoireCoreTarget, relativePath);
|
|
1237
|
+
|
|
1238
|
+
onProgress(i + 1, repairableIssues.length, relativePath);
|
|
1239
|
+
|
|
1240
|
+
// SECURITY: Path containment for source
|
|
1241
|
+
if (!isPathContained(sourcePath, this.grimoireCoreSource)) {
|
|
1242
|
+
result.skipped.push({ path: relativePath, reason: 'Source path traversal blocked' });
|
|
1243
|
+
continue;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// SECURITY: Path containment for target
|
|
1247
|
+
if (!isPathContained(targetPath, this.grimoireCoreTarget)) {
|
|
1248
|
+
result.skipped.push({ path: relativePath, reason: 'Target path traversal blocked' });
|
|
1249
|
+
continue;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
// Check source exists
|
|
1253
|
+
let sourceLstat;
|
|
1254
|
+
try {
|
|
1255
|
+
sourceLstat = fs.lstatSync(sourcePath);
|
|
1256
|
+
} catch (_error) {
|
|
1257
|
+
result.failed.push({ path: relativePath, reason: 'Source file not found' });
|
|
1258
|
+
result.success = false;
|
|
1259
|
+
continue;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// SECURITY [C3]: Reject source symlinks
|
|
1263
|
+
if (sourceLstat.isSymbolicLink()) {
|
|
1264
|
+
result.skipped.push({ path: relativePath, reason: 'Source is symlink' });
|
|
1265
|
+
continue;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
if (!sourceLstat.isFile()) {
|
|
1269
|
+
result.skipped.push({ path: relativePath, reason: 'Source is not a regular file' });
|
|
1270
|
+
continue;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// SECURITY [C4]: Verify source file hash matches manifest
|
|
1274
|
+
const manifestEntry = this.manifest.files.find((f) => f.path === relativePath);
|
|
1275
|
+
if (!manifestEntry || !manifestEntry.hash) {
|
|
1276
|
+
result.failed.push({ path: relativePath, reason: 'No hash in manifest for verification' });
|
|
1277
|
+
result.success = false;
|
|
1278
|
+
continue;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
try {
|
|
1282
|
+
const sourceHash = `sha256:${hashFile(sourcePath)}`;
|
|
1283
|
+
if (!hashesMatch(sourceHash, manifestEntry.hash)) {
|
|
1284
|
+
result.failed.push({
|
|
1285
|
+
path: relativePath,
|
|
1286
|
+
reason: 'Source file hash does not match signed manifest',
|
|
1287
|
+
});
|
|
1288
|
+
result.success = false;
|
|
1289
|
+
continue;
|
|
1290
|
+
}
|
|
1291
|
+
} catch (error) {
|
|
1292
|
+
result.failed.push({ path: relativePath, reason: `Cannot hash source: ${error.message}` });
|
|
1293
|
+
result.success = false;
|
|
1294
|
+
continue;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// Dry run - just report
|
|
1298
|
+
if (dryRun) {
|
|
1299
|
+
result.repaired.push({
|
|
1300
|
+
path: relativePath,
|
|
1301
|
+
action: issue.type === IssueType.MISSING_FILE ? 'would_copy' : 'would_replace',
|
|
1302
|
+
});
|
|
1303
|
+
continue;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
// SECURITY [TOCTOU]: Verify target path has no symlinks in any component
|
|
1307
|
+
// This prevents race condition attacks where a directory is replaced with a symlink
|
|
1308
|
+
// between the containment check and the actual copy operation
|
|
1309
|
+
try {
|
|
1310
|
+
const targetDir = path.dirname(targetPath);
|
|
1311
|
+
|
|
1312
|
+
// Walk each path component from grimoireCoreTarget to targetDir
|
|
1313
|
+
// and verify none are symlinks
|
|
1314
|
+
let currentPath = this.grimoireCoreTarget;
|
|
1315
|
+
const relativeParts = path.relative(this.grimoireCoreTarget, targetDir).split(path.sep);
|
|
1316
|
+
|
|
1317
|
+
for (const part of relativeParts) {
|
|
1318
|
+
if (!part || part === '.') continue;
|
|
1319
|
+
currentPath = path.join(currentPath, part);
|
|
1320
|
+
|
|
1321
|
+
// Check if this path component exists and is a symlink
|
|
1322
|
+
try {
|
|
1323
|
+
const componentStat = fs.lstatSync(currentPath);
|
|
1324
|
+
if (componentStat.isSymbolicLink()) {
|
|
1325
|
+
result.skipped.push({
|
|
1326
|
+
path: relativePath,
|
|
1327
|
+
reason: `Symlink detected in path component: ${path.relative(this.grimoireCoreTarget, currentPath)}`,
|
|
1328
|
+
});
|
|
1329
|
+
continue;
|
|
1330
|
+
}
|
|
1331
|
+
} catch (_statError) {
|
|
1332
|
+
// Path component doesn't exist yet, will be created by ensureDir
|
|
1333
|
+
// This is OK - we'll create it as a real directory
|
|
1334
|
+
break;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
// Final realpath verification: ensure resolved target stays within resolved grimoireCoreTarget
|
|
1339
|
+
// This catches any symlinks that might have been missed or created during the check
|
|
1340
|
+
if (fs.existsSync(targetDir)) {
|
|
1341
|
+
const realTargetDir = fs.realpathSync(targetDir);
|
|
1342
|
+
const realgrimoireCoreTarget = fs.realpathSync(this.grimoireCoreTarget);
|
|
1343
|
+
|
|
1344
|
+
if (!isPathContained(realTargetDir, realgrimoireCoreTarget)) {
|
|
1345
|
+
result.skipped.push({
|
|
1346
|
+
path: relativePath,
|
|
1347
|
+
reason: `Realpath escapes target directory: ${realTargetDir} is outside ${realgrimoireCoreTarget}`,
|
|
1348
|
+
});
|
|
1349
|
+
continue;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
} catch (toctouError) {
|
|
1353
|
+
result.skipped.push({
|
|
1354
|
+
path: relativePath,
|
|
1355
|
+
reason: `TOCTOU verification failed: ${toctouError.message}`,
|
|
1356
|
+
});
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
// Perform copy
|
|
1361
|
+
try {
|
|
1362
|
+
await fs.ensureDir(path.dirname(targetPath));
|
|
1363
|
+
await fs.copy(sourcePath, targetPath, { overwrite: true });
|
|
1364
|
+
result.repaired.push({
|
|
1365
|
+
path: relativePath,
|
|
1366
|
+
action: issue.type === IssueType.MISSING_FILE ? 'copied' : 'replaced',
|
|
1367
|
+
});
|
|
1368
|
+
} catch (error) {
|
|
1369
|
+
result.failed.push({ path: relativePath, reason: error.message });
|
|
1370
|
+
result.success = false;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
return result;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
/**
|
|
1378
|
+
* Log if verbose
|
|
1379
|
+
* @param {string} message - Message
|
|
1380
|
+
*/
|
|
1381
|
+
log(message) {
|
|
1382
|
+
if (this.options.verbose) {
|
|
1383
|
+
console.log(`[PostInstallValidator] ${message}`);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
/**
|
|
1389
|
+
* Format report for console
|
|
1390
|
+
*
|
|
1391
|
+
* @param {Object} report - Validation report
|
|
1392
|
+
* @param {Object} [options] - Format options
|
|
1393
|
+
* @returns {string} - Formatted report
|
|
1394
|
+
*/
|
|
1395
|
+
function formatReport(report, options = {}) {
|
|
1396
|
+
const useColors = options.colors !== false;
|
|
1397
|
+
// Note: detailed option is parsed from CLI but detailed view is handled by caller
|
|
1398
|
+
// eslint-disable-next-line no-unused-vars
|
|
1399
|
+
const detailed = options.detailed === true;
|
|
1400
|
+
|
|
1401
|
+
const c = {
|
|
1402
|
+
reset: useColors ? '\x1b[0m' : '',
|
|
1403
|
+
bold: useColors ? '\x1b[1m' : '',
|
|
1404
|
+
dim: useColors ? '\x1b[2m' : '',
|
|
1405
|
+
red: useColors ? '\x1b[31m' : '',
|
|
1406
|
+
green: useColors ? '\x1b[32m' : '',
|
|
1407
|
+
yellow: useColors ? '\x1b[33m' : '',
|
|
1408
|
+
blue: useColors ? '\x1b[34m' : '',
|
|
1409
|
+
cyan: useColors ? '\x1b[36m' : '',
|
|
1410
|
+
gray: useColors ? '\x1b[90m' : '',
|
|
1411
|
+
};
|
|
1412
|
+
|
|
1413
|
+
const lines = [];
|
|
1414
|
+
|
|
1415
|
+
lines.push('');
|
|
1416
|
+
lines.push(`${c.bold}grimoire Installation Validation Report${c.reset}`);
|
|
1417
|
+
lines.push(`${c.gray}${'─'.repeat(50)}${c.reset}`);
|
|
1418
|
+
|
|
1419
|
+
// Signature status
|
|
1420
|
+
if (report.manifestVerified) {
|
|
1421
|
+
lines.push(`${c.green}✓${c.reset} Manifest signature: ${c.green}VERIFIED${c.reset}`);
|
|
1422
|
+
} else {
|
|
1423
|
+
lines.push(`${c.red}✗${c.reset} Manifest signature: ${c.red}NOT VERIFIED${c.reset}`);
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
// Status
|
|
1427
|
+
const statusIcon =
|
|
1428
|
+
{
|
|
1429
|
+
success: `${c.green}✓${c.reset}`,
|
|
1430
|
+
warning: `${c.yellow}⚠${c.reset}`,
|
|
1431
|
+
failed: `${c.red}✗${c.reset}`,
|
|
1432
|
+
info: `${c.blue}ℹ${c.reset}`,
|
|
1433
|
+
}[report.status] || '?';
|
|
1434
|
+
|
|
1435
|
+
const statusText =
|
|
1436
|
+
{
|
|
1437
|
+
success: `${c.green}PASSED${c.reset}`,
|
|
1438
|
+
warning: `${c.yellow}WARNING${c.reset}`,
|
|
1439
|
+
failed: `${c.red}FAILED${c.reset}`,
|
|
1440
|
+
info: `${c.blue}INFO${c.reset}`,
|
|
1441
|
+
}[report.status] || 'UNKNOWN';
|
|
1442
|
+
|
|
1443
|
+
lines.push(`${statusIcon} Status: ${statusText}`);
|
|
1444
|
+
lines.push(`${c.dim} Integrity Score: ${report.integrityScore}%${c.reset}`);
|
|
1445
|
+
|
|
1446
|
+
lines.push('');
|
|
1447
|
+
lines.push(`${c.bold}Summary${c.reset}`);
|
|
1448
|
+
lines.push(` Total files: ${report.summary.total}`);
|
|
1449
|
+
lines.push(` ${c.green}Valid:${c.reset} ${report.summary.valid}`);
|
|
1450
|
+
|
|
1451
|
+
if (report.summary.missing > 0) {
|
|
1452
|
+
lines.push(` ${c.red}Missing:${c.reset} ${report.summary.missing}`);
|
|
1453
|
+
}
|
|
1454
|
+
if (report.summary.corrupted > 0) {
|
|
1455
|
+
lines.push(` ${c.yellow}Corrupted:${c.reset} ${report.summary.corrupted}`);
|
|
1456
|
+
}
|
|
1457
|
+
if (report.summary.extra > 0) {
|
|
1458
|
+
lines.push(` ${c.cyan}Extra:${c.reset} ${report.summary.extra}`);
|
|
1459
|
+
}
|
|
1460
|
+
if (report.summary.skipped > 0) {
|
|
1461
|
+
lines.push(` ${c.gray}Skipped:${c.reset} ${report.summary.skipped}`);
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
// Critical issues
|
|
1465
|
+
const criticalIssues = report.issuesBySeverity[Severity.CRITICAL] || [];
|
|
1466
|
+
if (criticalIssues.length > 0) {
|
|
1467
|
+
lines.push('');
|
|
1468
|
+
lines.push(`${c.red}${c.bold}Critical Issues${c.reset}`);
|
|
1469
|
+
for (const issue of criticalIssues.slice(0, 5)) {
|
|
1470
|
+
lines.push(` ${c.red}✗${c.reset} ${issue.message}`);
|
|
1471
|
+
if (issue.remediation) {
|
|
1472
|
+
lines.push(` ${c.dim}→ ${issue.remediation}${c.reset}`);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
// Recommendations
|
|
1478
|
+
if (report.recommendations && report.recommendations.length > 0) {
|
|
1479
|
+
lines.push('');
|
|
1480
|
+
lines.push(`${c.bold}Recommendations${c.reset}`);
|
|
1481
|
+
for (const rec of report.recommendations) {
|
|
1482
|
+
lines.push(` ${c.cyan}→${c.reset} ${rec}`);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
lines.push('');
|
|
1487
|
+
lines.push(`${c.dim}Completed in ${report.duration}${c.reset}`);
|
|
1488
|
+
lines.push('');
|
|
1489
|
+
|
|
1490
|
+
return lines.join('\n');
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
/**
|
|
1494
|
+
* Quick validation helper
|
|
1495
|
+
*
|
|
1496
|
+
* @param {string} targetDir - Target directory
|
|
1497
|
+
* @param {Object} [options] - Options
|
|
1498
|
+
* @returns {Promise<Object>} - Report
|
|
1499
|
+
*/
|
|
1500
|
+
async function quickValidate(targetDir, options = {}) {
|
|
1501
|
+
const validator = new PostInstallValidator(targetDir, options.sourceDir, {
|
|
1502
|
+
verifyHashes: options.verifyHashes !== false,
|
|
1503
|
+
detectExtras: options.detectExtras === true,
|
|
1504
|
+
verbose: options.verbose === true,
|
|
1505
|
+
requireSignature: options.requireSignature !== false,
|
|
1506
|
+
onProgress: options.onProgress,
|
|
1507
|
+
});
|
|
1508
|
+
|
|
1509
|
+
return validator.validate();
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
module.exports = {
|
|
1513
|
+
PostInstallValidator,
|
|
1514
|
+
formatReport,
|
|
1515
|
+
quickValidate,
|
|
1516
|
+
Severity,
|
|
1517
|
+
IssueType,
|
|
1518
|
+
FileCategory,
|
|
1519
|
+
SecurityLimits,
|
|
1520
|
+
isPathContained,
|
|
1521
|
+
validateManifestEntry,
|
|
1522
|
+
};
|
|
1523
|
+
|
|
1524
|
+
|