@wazir-dev/cli 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/AGENTS.md +111 -0
- package/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +101 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/assets/composition-engine.mmd +34 -0
- package/assets/demo-script.sh +17 -0
- package/assets/logo-dark.svg +14 -0
- package/assets/logo.svg +14 -0
- package/assets/pipeline.mmd +39 -0
- package/assets/record-demo.sh +51 -0
- package/docs/README.md +51 -0
- package/docs/adapters/context-mode.md +60 -0
- package/docs/concepts/architecture.md +87 -0
- package/docs/concepts/artifact-model.md +60 -0
- package/docs/concepts/composition-engine.md +36 -0
- package/docs/concepts/indexing-and-recall.md +160 -0
- package/docs/concepts/observability.md +41 -0
- package/docs/concepts/roles-and-workflows.md +59 -0
- package/docs/concepts/terminology-policy.md +27 -0
- package/docs/getting-started/01-installation.md +78 -0
- package/docs/getting-started/02-first-run.md +102 -0
- package/docs/getting-started/03-adding-to-project.md +15 -0
- package/docs/getting-started/04-host-setup.md +15 -0
- package/docs/guides/ci-integration.md +15 -0
- package/docs/guides/creating-skills.md +15 -0
- package/docs/guides/expertise-module-authoring.md +15 -0
- package/docs/guides/hook-development.md +15 -0
- package/docs/guides/memory-and-learnings.md +34 -0
- package/docs/guides/multi-host-export.md +15 -0
- package/docs/guides/troubleshooting.md +101 -0
- package/docs/guides/writing-custom-roles.md +15 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-design.md +592 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-plan.md +598 -0
- package/docs/plans/2026-03-15-docs-enforcement-plan.md +238 -0
- package/docs/readmes/INDEX.md +99 -0
- package/docs/readmes/features/expertise/README.md +171 -0
- package/docs/readmes/features/exports/README.md +222 -0
- package/docs/readmes/features/hooks/README.md +103 -0
- package/docs/readmes/features/hooks/loop-cap-guard.md +133 -0
- package/docs/readmes/features/hooks/post-tool-capture.md +121 -0
- package/docs/readmes/features/hooks/post-tool-lint.md +130 -0
- package/docs/readmes/features/hooks/pre-compact-summary.md +122 -0
- package/docs/readmes/features/hooks/pre-tool-capture-route.md +100 -0
- package/docs/readmes/features/hooks/protected-path-write-guard.md +128 -0
- package/docs/readmes/features/hooks/session-start.md +119 -0
- package/docs/readmes/features/hooks/stop-handoff-harvest.md +125 -0
- package/docs/readmes/features/roles/README.md +157 -0
- package/docs/readmes/features/roles/clarifier.md +152 -0
- package/docs/readmes/features/roles/content-author.md +190 -0
- package/docs/readmes/features/roles/designer.md +193 -0
- package/docs/readmes/features/roles/executor.md +184 -0
- package/docs/readmes/features/roles/learner.md +210 -0
- package/docs/readmes/features/roles/planner.md +182 -0
- package/docs/readmes/features/roles/researcher.md +164 -0
- package/docs/readmes/features/roles/reviewer.md +184 -0
- package/docs/readmes/features/roles/specifier.md +162 -0
- package/docs/readmes/features/roles/verifier.md +215 -0
- package/docs/readmes/features/schemas/README.md +178 -0
- package/docs/readmes/features/skills/README.md +63 -0
- package/docs/readmes/features/skills/brainstorming.md +96 -0
- package/docs/readmes/features/skills/debugging.md +148 -0
- package/docs/readmes/features/skills/design.md +120 -0
- package/docs/readmes/features/skills/prepare-next.md +109 -0
- package/docs/readmes/features/skills/run-audit.md +159 -0
- package/docs/readmes/features/skills/scan-project.md +109 -0
- package/docs/readmes/features/skills/self-audit.md +176 -0
- package/docs/readmes/features/skills/tdd.md +137 -0
- package/docs/readmes/features/skills/using-skills.md +92 -0
- package/docs/readmes/features/skills/verification.md +120 -0
- package/docs/readmes/features/skills/writing-plans.md +104 -0
- package/docs/readmes/features/tooling/README.md +320 -0
- package/docs/readmes/features/workflows/README.md +186 -0
- package/docs/readmes/features/workflows/author.md +181 -0
- package/docs/readmes/features/workflows/clarify.md +154 -0
- package/docs/readmes/features/workflows/design-review.md +171 -0
- package/docs/readmes/features/workflows/design.md +169 -0
- package/docs/readmes/features/workflows/discover.md +162 -0
- package/docs/readmes/features/workflows/execute.md +173 -0
- package/docs/readmes/features/workflows/learn.md +167 -0
- package/docs/readmes/features/workflows/plan-review.md +165 -0
- package/docs/readmes/features/workflows/plan.md +170 -0
- package/docs/readmes/features/workflows/prepare-next.md +167 -0
- package/docs/readmes/features/workflows/review.md +169 -0
- package/docs/readmes/features/workflows/run-audit.md +191 -0
- package/docs/readmes/features/workflows/spec-challenge.md +159 -0
- package/docs/readmes/features/workflows/specify.md +160 -0
- package/docs/readmes/features/workflows/verify.md +177 -0
- package/docs/readmes/packages/README.md +50 -0
- package/docs/readmes/packages/ajv.md +117 -0
- package/docs/readmes/packages/context-mode.md +118 -0
- package/docs/readmes/packages/gray-matter.md +116 -0
- package/docs/readmes/packages/node-test.md +137 -0
- package/docs/readmes/packages/yaml.md +112 -0
- package/docs/reference/configuration-reference.md +159 -0
- package/docs/reference/expertise-index.md +52 -0
- package/docs/reference/git-flow.md +43 -0
- package/docs/reference/hooks.md +87 -0
- package/docs/reference/host-exports.md +50 -0
- package/docs/reference/launch-checklist.md +172 -0
- package/docs/reference/marketplace-listings.md +76 -0
- package/docs/reference/release-process.md +34 -0
- package/docs/reference/roles-reference.md +77 -0
- package/docs/reference/skills.md +33 -0
- package/docs/reference/templates.md +29 -0
- package/docs/reference/tooling-cli.md +94 -0
- package/docs/truth-claims.yaml +222 -0
- package/expertise/PROGRESS.md +63 -0
- package/expertise/README.md +18 -0
- package/expertise/antipatterns/PROGRESS.md +56 -0
- package/expertise/antipatterns/backend/api-design-antipatterns.md +1271 -0
- package/expertise/antipatterns/backend/auth-antipatterns.md +1195 -0
- package/expertise/antipatterns/backend/caching-antipatterns.md +622 -0
- package/expertise/antipatterns/backend/database-antipatterns.md +1038 -0
- package/expertise/antipatterns/backend/index.md +24 -0
- package/expertise/antipatterns/backend/microservices-antipatterns.md +850 -0
- package/expertise/antipatterns/code/architecture-antipatterns.md +919 -0
- package/expertise/antipatterns/code/async-antipatterns.md +622 -0
- package/expertise/antipatterns/code/code-smells.md +1186 -0
- package/expertise/antipatterns/code/dependency-antipatterns.md +1209 -0
- package/expertise/antipatterns/code/error-handling-antipatterns.md +1360 -0
- package/expertise/antipatterns/code/index.md +27 -0
- package/expertise/antipatterns/code/naming-and-abstraction.md +1118 -0
- package/expertise/antipatterns/code/state-management-antipatterns.md +1076 -0
- package/expertise/antipatterns/code/testing-antipatterns.md +1053 -0
- package/expertise/antipatterns/design/accessibility-antipatterns.md +1136 -0
- package/expertise/antipatterns/design/dark-patterns.md +1121 -0
- package/expertise/antipatterns/design/index.md +22 -0
- package/expertise/antipatterns/design/ui-antipatterns.md +1202 -0
- package/expertise/antipatterns/design/ux-antipatterns.md +680 -0
- package/expertise/antipatterns/frontend/css-layout-antipatterns.md +691 -0
- package/expertise/antipatterns/frontend/flutter-antipatterns.md +1827 -0
- package/expertise/antipatterns/frontend/index.md +23 -0
- package/expertise/antipatterns/frontend/mobile-antipatterns.md +573 -0
- package/expertise/antipatterns/frontend/react-antipatterns.md +1128 -0
- package/expertise/antipatterns/frontend/spa-antipatterns.md +1235 -0
- package/expertise/antipatterns/index.md +31 -0
- package/expertise/antipatterns/performance/index.md +20 -0
- package/expertise/antipatterns/performance/performance-antipatterns.md +1013 -0
- package/expertise/antipatterns/performance/premature-optimization.md +623 -0
- package/expertise/antipatterns/performance/scaling-antipatterns.md +785 -0
- package/expertise/antipatterns/process/ai-coding-antipatterns.md +853 -0
- package/expertise/antipatterns/process/code-review-antipatterns.md +656 -0
- package/expertise/antipatterns/process/deployment-antipatterns.md +920 -0
- package/expertise/antipatterns/process/index.md +23 -0
- package/expertise/antipatterns/process/technical-debt-antipatterns.md +647 -0
- package/expertise/antipatterns/security/index.md +20 -0
- package/expertise/antipatterns/security/secrets-antipatterns.md +849 -0
- package/expertise/antipatterns/security/security-theater.md +843 -0
- package/expertise/antipatterns/security/vulnerability-patterns.md +801 -0
- package/expertise/architecture/PROGRESS.md +70 -0
- package/expertise/architecture/data/caching-architecture.md +671 -0
- package/expertise/architecture/data/data-consistency.md +574 -0
- package/expertise/architecture/data/data-modeling.md +536 -0
- package/expertise/architecture/data/event-streams-and-queues.md +634 -0
- package/expertise/architecture/data/index.md +25 -0
- package/expertise/architecture/data/search-architecture.md +663 -0
- package/expertise/architecture/data/sql-vs-nosql.md +708 -0
- package/expertise/architecture/decisions/architecture-decision-records.md +640 -0
- package/expertise/architecture/decisions/build-vs-buy.md +616 -0
- package/expertise/architecture/decisions/index.md +23 -0
- package/expertise/architecture/decisions/monolith-to-microservices.md +790 -0
- package/expertise/architecture/decisions/technology-selection.md +616 -0
- package/expertise/architecture/distributed/cap-theorem-and-tradeoffs.md +800 -0
- package/expertise/architecture/distributed/circuit-breaker-bulkhead.md +741 -0
- package/expertise/architecture/distributed/consensus-and-coordination.md +796 -0
- package/expertise/architecture/distributed/distributed-systems-fundamentals.md +564 -0
- package/expertise/architecture/distributed/idempotency-and-retry.md +796 -0
- package/expertise/architecture/distributed/index.md +25 -0
- package/expertise/architecture/distributed/saga-pattern.md +797 -0
- package/expertise/architecture/foundations/architectural-thinking.md +460 -0
- package/expertise/architecture/foundations/coupling-and-cohesion.md +770 -0
- package/expertise/architecture/foundations/design-principles-solid.md +649 -0
- package/expertise/architecture/foundations/domain-driven-design.md +719 -0
- package/expertise/architecture/foundations/index.md +25 -0
- package/expertise/architecture/foundations/separation-of-concerns.md +472 -0
- package/expertise/architecture/foundations/twelve-factor-app.md +797 -0
- package/expertise/architecture/index.md +34 -0
- package/expertise/architecture/integration/api-design-graphql.md +638 -0
- package/expertise/architecture/integration/api-design-grpc.md +804 -0
- package/expertise/architecture/integration/api-design-rest.md +892 -0
- package/expertise/architecture/integration/index.md +25 -0
- package/expertise/architecture/integration/third-party-integration.md +795 -0
- package/expertise/architecture/integration/webhooks-and-callbacks.md +1152 -0
- package/expertise/architecture/integration/websockets-realtime.md +791 -0
- package/expertise/architecture/mobile-architecture/index.md +22 -0
- package/expertise/architecture/mobile-architecture/mobile-app-architecture.md +780 -0
- package/expertise/architecture/mobile-architecture/mobile-backend-for-frontend.md +670 -0
- package/expertise/architecture/mobile-architecture/offline-first.md +719 -0
- package/expertise/architecture/mobile-architecture/push-and-sync.md +782 -0
- package/expertise/architecture/patterns/cqrs-event-sourcing.md +717 -0
- package/expertise/architecture/patterns/event-driven.md +797 -0
- package/expertise/architecture/patterns/hexagonal-clean-architecture.md +870 -0
- package/expertise/architecture/patterns/index.md +27 -0
- package/expertise/architecture/patterns/layered-architecture.md +736 -0
- package/expertise/architecture/patterns/microservices.md +753 -0
- package/expertise/architecture/patterns/modular-monolith.md +692 -0
- package/expertise/architecture/patterns/monolith.md +626 -0
- package/expertise/architecture/patterns/plugin-architecture.md +735 -0
- package/expertise/architecture/patterns/serverless.md +780 -0
- package/expertise/architecture/scaling/database-scaling.md +615 -0
- package/expertise/architecture/scaling/feature-flags-and-rollouts.md +757 -0
- package/expertise/architecture/scaling/horizontal-vs-vertical.md +606 -0
- package/expertise/architecture/scaling/index.md +24 -0
- package/expertise/architecture/scaling/multi-tenancy.md +800 -0
- package/expertise/architecture/scaling/stateless-design.md +787 -0
- package/expertise/backend/embedded-firmware.md +625 -0
- package/expertise/backend/go.md +853 -0
- package/expertise/backend/index.md +24 -0
- package/expertise/backend/java-spring.md +448 -0
- package/expertise/backend/node-typescript.md +625 -0
- package/expertise/backend/python-fastapi.md +724 -0
- package/expertise/backend/rust.md +458 -0
- package/expertise/backend/solidity.md +711 -0
- package/expertise/composition-map.yaml +443 -0
- package/expertise/content/foundations/content-modeling.md +395 -0
- package/expertise/content/foundations/editorial-standards.md +449 -0
- package/expertise/content/foundations/index.md +24 -0
- package/expertise/content/foundations/microcopy.md +455 -0
- package/expertise/content/foundations/terminology-governance.md +509 -0
- package/expertise/content/index.md +34 -0
- package/expertise/content/patterns/accessibility-copy.md +518 -0
- package/expertise/content/patterns/index.md +24 -0
- package/expertise/content/patterns/notification-content.md +433 -0
- package/expertise/content/patterns/sample-content.md +486 -0
- package/expertise/content/patterns/state-copy.md +439 -0
- package/expertise/design/PROGRESS.md +58 -0
- package/expertise/design/disciplines/dark-mode-theming.md +577 -0
- package/expertise/design/disciplines/design-systems.md +595 -0
- package/expertise/design/disciplines/index.md +25 -0
- package/expertise/design/disciplines/information-architecture.md +800 -0
- package/expertise/design/disciplines/interaction-design.md +788 -0
- package/expertise/design/disciplines/responsive-design.md +552 -0
- package/expertise/design/disciplines/usability-testing.md +516 -0
- package/expertise/design/disciplines/user-research.md +792 -0
- package/expertise/design/foundations/accessibility-design.md +796 -0
- package/expertise/design/foundations/color-theory.md +797 -0
- package/expertise/design/foundations/iconography.md +795 -0
- package/expertise/design/foundations/index.md +26 -0
- package/expertise/design/foundations/motion-and-animation.md +653 -0
- package/expertise/design/foundations/rtl-design.md +585 -0
- package/expertise/design/foundations/spacing-and-layout.md +607 -0
- package/expertise/design/foundations/typography.md +800 -0
- package/expertise/design/foundations/visual-hierarchy.md +761 -0
- package/expertise/design/index.md +32 -0
- package/expertise/design/patterns/authentication-flows.md +474 -0
- package/expertise/design/patterns/content-consumption.md +789 -0
- package/expertise/design/patterns/data-display.md +618 -0
- package/expertise/design/patterns/e-commerce.md +1494 -0
- package/expertise/design/patterns/feedback-and-states.md +642 -0
- package/expertise/design/patterns/forms-and-input.md +819 -0
- package/expertise/design/patterns/gamification.md +801 -0
- package/expertise/design/patterns/index.md +31 -0
- package/expertise/design/patterns/microinteractions.md +449 -0
- package/expertise/design/patterns/navigation.md +800 -0
- package/expertise/design/patterns/notifications.md +705 -0
- package/expertise/design/patterns/onboarding.md +700 -0
- package/expertise/design/patterns/search-and-filter.md +601 -0
- package/expertise/design/patterns/settings-and-preferences.md +768 -0
- package/expertise/design/patterns/social-and-community.md +748 -0
- package/expertise/design/platforms/desktop-native.md +612 -0
- package/expertise/design/platforms/index.md +25 -0
- package/expertise/design/platforms/mobile-android.md +825 -0
- package/expertise/design/platforms/mobile-cross-platform.md +983 -0
- package/expertise/design/platforms/mobile-ios.md +699 -0
- package/expertise/design/platforms/tablet.md +794 -0
- package/expertise/design/platforms/web-dashboard.md +790 -0
- package/expertise/design/platforms/web-responsive.md +550 -0
- package/expertise/design/psychology/behavioral-nudges.md +449 -0
- package/expertise/design/psychology/cognitive-load.md +1191 -0
- package/expertise/design/psychology/error-psychology.md +778 -0
- package/expertise/design/psychology/index.md +22 -0
- package/expertise/design/psychology/persuasive-design.md +736 -0
- package/expertise/design/psychology/user-mental-models.md +623 -0
- package/expertise/design/tooling/open-pencil.md +266 -0
- package/expertise/frontend/angular.md +1073 -0
- package/expertise/frontend/desktop-electron.md +546 -0
- package/expertise/frontend/flutter.md +782 -0
- package/expertise/frontend/index.md +27 -0
- package/expertise/frontend/native-android.md +409 -0
- package/expertise/frontend/native-ios.md +490 -0
- package/expertise/frontend/react-native.md +1160 -0
- package/expertise/frontend/react.md +808 -0
- package/expertise/frontend/vue.md +1089 -0
- package/expertise/humanize/domain-rules-code.md +79 -0
- package/expertise/humanize/domain-rules-content.md +67 -0
- package/expertise/humanize/domain-rules-technical-docs.md +56 -0
- package/expertise/humanize/index.md +35 -0
- package/expertise/humanize/self-audit-checklist.md +87 -0
- package/expertise/humanize/sentence-patterns.md +218 -0
- package/expertise/humanize/vocabulary-blacklist.md +105 -0
- package/expertise/i18n/PROGRESS.md +65 -0
- package/expertise/i18n/advanced/accessibility-and-i18n.md +28 -0
- package/expertise/i18n/advanced/bidirectional-text-algorithm.md +38 -0
- package/expertise/i18n/advanced/complex-scripts.md +30 -0
- package/expertise/i18n/advanced/performance-and-i18n.md +27 -0
- package/expertise/i18n/advanced/testing-i18n.md +28 -0
- package/expertise/i18n/content/content-adaptation.md +23 -0
- package/expertise/i18n/content/locale-specific-formatting.md +23 -0
- package/expertise/i18n/content/machine-translation-integration.md +28 -0
- package/expertise/i18n/content/translation-management.md +29 -0
- package/expertise/i18n/foundations/date-time-calendars.md +67 -0
- package/expertise/i18n/foundations/i18n-architecture.md +272 -0
- package/expertise/i18n/foundations/locale-and-language-tags.md +79 -0
- package/expertise/i18n/foundations/numbers-currency-units.md +61 -0
- package/expertise/i18n/foundations/pluralization-and-gender.md +109 -0
- package/expertise/i18n/foundations/string-externalization.md +236 -0
- package/expertise/i18n/foundations/text-direction-bidi.md +241 -0
- package/expertise/i18n/foundations/unicode-and-encoding.md +86 -0
- package/expertise/i18n/index.md +38 -0
- package/expertise/i18n/platform/backend-i18n.md +31 -0
- package/expertise/i18n/platform/flutter-i18n.md +148 -0
- package/expertise/i18n/platform/native-android-i18n.md +36 -0
- package/expertise/i18n/platform/native-ios-i18n.md +36 -0
- package/expertise/i18n/platform/react-i18n.md +103 -0
- package/expertise/i18n/platform/web-css-i18n.md +81 -0
- package/expertise/i18n/rtl/arabic-specific.md +175 -0
- package/expertise/i18n/rtl/hebrew-specific.md +149 -0
- package/expertise/i18n/rtl/rtl-animations-and-transitions.md +111 -0
- package/expertise/i18n/rtl/rtl-forms-and-input.md +161 -0
- package/expertise/i18n/rtl/rtl-fundamentals.md +211 -0
- package/expertise/i18n/rtl/rtl-icons-and-images.md +181 -0
- package/expertise/i18n/rtl/rtl-layout-mirroring.md +252 -0
- package/expertise/i18n/rtl/rtl-navigation-and-gestures.md +107 -0
- package/expertise/i18n/rtl/rtl-testing-and-qa.md +147 -0
- package/expertise/i18n/rtl/rtl-typography.md +160 -0
- package/expertise/index.md +113 -0
- package/expertise/index.yaml +216 -0
- package/expertise/infrastructure/cloud-aws.md +597 -0
- package/expertise/infrastructure/cloud-gcp.md +599 -0
- package/expertise/infrastructure/cybersecurity.md +816 -0
- package/expertise/infrastructure/database-mongodb.md +447 -0
- package/expertise/infrastructure/database-postgres.md +400 -0
- package/expertise/infrastructure/devops-cicd.md +787 -0
- package/expertise/infrastructure/index.md +27 -0
- package/expertise/performance/PROGRESS.md +50 -0
- package/expertise/performance/backend/api-latency.md +1204 -0
- package/expertise/performance/backend/background-jobs.md +506 -0
- package/expertise/performance/backend/connection-pooling.md +1209 -0
- package/expertise/performance/backend/database-query-optimization.md +515 -0
- package/expertise/performance/backend/index.md +23 -0
- package/expertise/performance/backend/rate-limiting-and-throttling.md +971 -0
- package/expertise/performance/foundations/algorithmic-complexity.md +954 -0
- package/expertise/performance/foundations/caching-strategies.md +489 -0
- package/expertise/performance/foundations/concurrency-and-parallelism.md +847 -0
- package/expertise/performance/foundations/index.md +24 -0
- package/expertise/performance/foundations/measuring-and-profiling.md +440 -0
- package/expertise/performance/foundations/memory-management.md +964 -0
- package/expertise/performance/foundations/performance-budgets.md +1314 -0
- package/expertise/performance/index.md +31 -0
- package/expertise/performance/infrastructure/auto-scaling.md +1059 -0
- package/expertise/performance/infrastructure/cdn-and-edge.md +1081 -0
- package/expertise/performance/infrastructure/index.md +22 -0
- package/expertise/performance/infrastructure/load-balancing.md +1081 -0
- package/expertise/performance/infrastructure/observability.md +1079 -0
- package/expertise/performance/mobile/index.md +23 -0
- package/expertise/performance/mobile/mobile-animations.md +544 -0
- package/expertise/performance/mobile/mobile-memory-battery.md +416 -0
- package/expertise/performance/mobile/mobile-network.md +452 -0
- package/expertise/performance/mobile/mobile-rendering.md +599 -0
- package/expertise/performance/mobile/mobile-startup-time.md +505 -0
- package/expertise/performance/platform-specific/flutter-performance.md +647 -0
- package/expertise/performance/platform-specific/index.md +22 -0
- package/expertise/performance/platform-specific/node-performance.md +1307 -0
- package/expertise/performance/platform-specific/postgres-performance.md +1366 -0
- package/expertise/performance/platform-specific/react-performance.md +1403 -0
- package/expertise/performance/web/bundle-optimization.md +1239 -0
- package/expertise/performance/web/image-and-media.md +636 -0
- package/expertise/performance/web/index.md +24 -0
- package/expertise/performance/web/network-optimization.md +1133 -0
- package/expertise/performance/web/rendering-performance.md +1098 -0
- package/expertise/performance/web/ssr-and-hydration.md +918 -0
- package/expertise/performance/web/web-vitals.md +1374 -0
- package/expertise/quality/accessibility.md +985 -0
- package/expertise/quality/evidence-based-verification.md +499 -0
- package/expertise/quality/index.md +24 -0
- package/expertise/quality/ml-model-audit.md +614 -0
- package/expertise/quality/performance.md +600 -0
- package/expertise/quality/testing-api.md +891 -0
- package/expertise/quality/testing-mobile.md +496 -0
- package/expertise/quality/testing-web.md +849 -0
- package/expertise/security/PROGRESS.md +54 -0
- package/expertise/security/agentic-identity.md +540 -0
- package/expertise/security/compliance-frameworks.md +601 -0
- package/expertise/security/data/data-encryption.md +364 -0
- package/expertise/security/data/data-privacy-gdpr.md +692 -0
- package/expertise/security/data/database-security.md +1171 -0
- package/expertise/security/data/index.md +22 -0
- package/expertise/security/data/pii-handling.md +531 -0
- package/expertise/security/foundations/authentication.md +1041 -0
- package/expertise/security/foundations/authorization.md +603 -0
- package/expertise/security/foundations/cryptography.md +1001 -0
- package/expertise/security/foundations/index.md +25 -0
- package/expertise/security/foundations/owasp-top-10.md +1354 -0
- package/expertise/security/foundations/secrets-management.md +1217 -0
- package/expertise/security/foundations/secure-sdlc.md +700 -0
- package/expertise/security/foundations/supply-chain-security.md +698 -0
- package/expertise/security/index.md +31 -0
- package/expertise/security/infrastructure/cloud-security-aws.md +1296 -0
- package/expertise/security/infrastructure/cloud-security-gcp.md +1376 -0
- package/expertise/security/infrastructure/container-security.md +721 -0
- package/expertise/security/infrastructure/incident-response.md +1295 -0
- package/expertise/security/infrastructure/index.md +24 -0
- package/expertise/security/infrastructure/logging-and-monitoring.md +1618 -0
- package/expertise/security/infrastructure/network-security.md +1337 -0
- package/expertise/security/mobile/index.md +23 -0
- package/expertise/security/mobile/mobile-android-security.md +1218 -0
- package/expertise/security/mobile/mobile-binary-protection.md +1229 -0
- package/expertise/security/mobile/mobile-data-storage.md +1265 -0
- package/expertise/security/mobile/mobile-ios-security.md +1401 -0
- package/expertise/security/mobile/mobile-network-security.md +1520 -0
- package/expertise/security/smart-contract-security.md +594 -0
- package/expertise/security/testing/index.md +22 -0
- package/expertise/security/testing/penetration-testing.md +1258 -0
- package/expertise/security/testing/security-code-review.md +1765 -0
- package/expertise/security/testing/threat-modeling.md +1074 -0
- package/expertise/security/testing/vulnerability-scanning.md +1062 -0
- package/expertise/security/web/api-security.md +586 -0
- package/expertise/security/web/cors-and-headers.md +433 -0
- package/expertise/security/web/csrf.md +562 -0
- package/expertise/security/web/file-upload.md +1477 -0
- package/expertise/security/web/index.md +25 -0
- package/expertise/security/web/injection.md +1375 -0
- package/expertise/security/web/session-management.md +1101 -0
- package/expertise/security/web/xss.md +1158 -0
- package/exports/README.md +17 -0
- package/exports/hosts/claude/.claude/agents/clarifier.md +42 -0
- package/exports/hosts/claude/.claude/agents/content-author.md +63 -0
- package/exports/hosts/claude/.claude/agents/designer.md +55 -0
- package/exports/hosts/claude/.claude/agents/executor.md +55 -0
- package/exports/hosts/claude/.claude/agents/learner.md +51 -0
- package/exports/hosts/claude/.claude/agents/planner.md +53 -0
- package/exports/hosts/claude/.claude/agents/researcher.md +43 -0
- package/exports/hosts/claude/.claude/agents/reviewer.md +54 -0
- package/exports/hosts/claude/.claude/agents/specifier.md +47 -0
- package/exports/hosts/claude/.claude/agents/verifier.md +71 -0
- package/exports/hosts/claude/.claude/commands/author.md +42 -0
- package/exports/hosts/claude/.claude/commands/clarify.md +38 -0
- package/exports/hosts/claude/.claude/commands/design-review.md +46 -0
- package/exports/hosts/claude/.claude/commands/design.md +44 -0
- package/exports/hosts/claude/.claude/commands/discover.md +37 -0
- package/exports/hosts/claude/.claude/commands/execute.md +48 -0
- package/exports/hosts/claude/.claude/commands/learn.md +38 -0
- package/exports/hosts/claude/.claude/commands/plan-review.md +42 -0
- package/exports/hosts/claude/.claude/commands/plan.md +39 -0
- package/exports/hosts/claude/.claude/commands/prepare-next.md +37 -0
- package/exports/hosts/claude/.claude/commands/review.md +40 -0
- package/exports/hosts/claude/.claude/commands/run-audit.md +41 -0
- package/exports/hosts/claude/.claude/commands/spec-challenge.md +41 -0
- package/exports/hosts/claude/.claude/commands/specify.md +38 -0
- package/exports/hosts/claude/.claude/commands/verify.md +37 -0
- package/exports/hosts/claude/.claude/settings.json +34 -0
- package/exports/hosts/claude/CLAUDE.md +19 -0
- package/exports/hosts/claude/export.manifest.json +38 -0
- package/exports/hosts/claude/host-package.json +67 -0
- package/exports/hosts/codex/AGENTS.md +19 -0
- package/exports/hosts/codex/export.manifest.json +38 -0
- package/exports/hosts/codex/host-package.json +41 -0
- package/exports/hosts/cursor/.cursor/hooks.json +16 -0
- package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +19 -0
- package/exports/hosts/cursor/export.manifest.json +38 -0
- package/exports/hosts/cursor/host-package.json +42 -0
- package/exports/hosts/gemini/GEMINI.md +19 -0
- package/exports/hosts/gemini/export.manifest.json +38 -0
- package/exports/hosts/gemini/host-package.json +41 -0
- package/hooks/README.md +18 -0
- package/hooks/definitions/loop_cap_guard.yaml +21 -0
- package/hooks/definitions/post_tool_capture.yaml +24 -0
- package/hooks/definitions/pre_compact_summary.yaml +19 -0
- package/hooks/definitions/pre_tool_capture_route.yaml +19 -0
- package/hooks/definitions/protected_path_write_guard.yaml +19 -0
- package/hooks/definitions/session_start.yaml +19 -0
- package/hooks/definitions/stop_handoff_harvest.yaml +20 -0
- package/hooks/loop-cap-guard +17 -0
- package/hooks/post-tool-lint +36 -0
- package/hooks/protected-path-write-guard +17 -0
- package/hooks/session-start +41 -0
- package/llms-full.txt +2355 -0
- package/llms.txt +43 -0
- package/package.json +79 -0
- package/roles/README.md +20 -0
- package/roles/clarifier.md +42 -0
- package/roles/content-author.md +63 -0
- package/roles/designer.md +55 -0
- package/roles/executor.md +55 -0
- package/roles/learner.md +51 -0
- package/roles/planner.md +53 -0
- package/roles/researcher.md +43 -0
- package/roles/reviewer.md +54 -0
- package/roles/specifier.md +47 -0
- package/roles/verifier.md +71 -0
- package/schemas/README.md +24 -0
- package/schemas/accepted-learning.schema.json +20 -0
- package/schemas/author-artifact.schema.json +156 -0
- package/schemas/clarification.schema.json +19 -0
- package/schemas/design-artifact.schema.json +80 -0
- package/schemas/docs-claim.schema.json +18 -0
- package/schemas/export-manifest.schema.json +20 -0
- package/schemas/hook.schema.json +67 -0
- package/schemas/host-export-package.schema.json +18 -0
- package/schemas/implementation-plan.schema.json +19 -0
- package/schemas/proposed-learning.schema.json +19 -0
- package/schemas/research.schema.json +18 -0
- package/schemas/review.schema.json +29 -0
- package/schemas/run-manifest.schema.json +18 -0
- package/schemas/spec-challenge.schema.json +18 -0
- package/schemas/spec.schema.json +20 -0
- package/schemas/usage.schema.json +102 -0
- package/schemas/verification-proof.schema.json +29 -0
- package/schemas/wazir-manifest.schema.json +173 -0
- package/skills/README.md +40 -0
- package/skills/brainstorming/SKILL.md +77 -0
- package/skills/debugging/SKILL.md +50 -0
- package/skills/design/SKILL.md +61 -0
- package/skills/dispatching-parallel-agents/SKILL.md +128 -0
- package/skills/executing-plans/SKILL.md +70 -0
- package/skills/finishing-a-development-branch/SKILL.md +169 -0
- package/skills/humanize/SKILL.md +123 -0
- package/skills/init-pipeline/SKILL.md +124 -0
- package/skills/prepare-next/SKILL.md +20 -0
- package/skills/receiving-code-review/SKILL.md +123 -0
- package/skills/requesting-code-review/SKILL.md +105 -0
- package/skills/requesting-code-review/code-reviewer.md +108 -0
- package/skills/run-audit/SKILL.md +197 -0
- package/skills/scan-project/SKILL.md +41 -0
- package/skills/self-audit/SKILL.md +153 -0
- package/skills/subagent-driven-development/SKILL.md +154 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
- package/skills/subagent-driven-development/implementer-prompt.md +102 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/tdd/SKILL.md +23 -0
- package/skills/using-git-worktrees/SKILL.md +163 -0
- package/skills/using-skills/SKILL.md +95 -0
- package/skills/verification/SKILL.md +22 -0
- package/skills/wazir/SKILL.md +463 -0
- package/skills/writing-plans/SKILL.md +30 -0
- package/skills/writing-skills/SKILL.md +157 -0
- package/skills/writing-skills/anthropic-best-practices.md +122 -0
- package/skills/writing-skills/persuasion-principles.md +50 -0
- package/templates/README.md +20 -0
- package/templates/artifacts/README.md +10 -0
- package/templates/artifacts/accepted-learning.md +19 -0
- package/templates/artifacts/accepted-learning.template.json +12 -0
- package/templates/artifacts/author.md +74 -0
- package/templates/artifacts/author.template.json +19 -0
- package/templates/artifacts/clarification.md +21 -0
- package/templates/artifacts/clarification.template.json +12 -0
- package/templates/artifacts/execute-notes.md +19 -0
- package/templates/artifacts/implementation-plan.md +21 -0
- package/templates/artifacts/implementation-plan.template.json +11 -0
- package/templates/artifacts/learning-proposal.md +19 -0
- package/templates/artifacts/next-run-handoff.md +21 -0
- package/templates/artifacts/plan-review.md +19 -0
- package/templates/artifacts/proposed-learning.template.json +12 -0
- package/templates/artifacts/research.md +21 -0
- package/templates/artifacts/research.template.json +12 -0
- package/templates/artifacts/review-findings.md +19 -0
- package/templates/artifacts/review.template.json +11 -0
- package/templates/artifacts/run-manifest.template.json +8 -0
- package/templates/artifacts/spec-challenge.md +19 -0
- package/templates/artifacts/spec-challenge.template.json +11 -0
- package/templates/artifacts/spec.md +21 -0
- package/templates/artifacts/spec.template.json +12 -0
- package/templates/artifacts/verification-proof.md +19 -0
- package/templates/artifacts/verification-proof.template.json +11 -0
- package/templates/examples/accepted-learning.example.json +14 -0
- package/templates/examples/author.example.json +152 -0
- package/templates/examples/clarification.example.json +15 -0
- package/templates/examples/docs-claim.example.json +8 -0
- package/templates/examples/export-manifest.example.json +7 -0
- package/templates/examples/host-export-package.example.json +11 -0
- package/templates/examples/implementation-plan.example.json +17 -0
- package/templates/examples/proposed-learning.example.json +13 -0
- package/templates/examples/research.example.json +15 -0
- package/templates/examples/research.example.md +6 -0
- package/templates/examples/review.example.json +17 -0
- package/templates/examples/run-manifest.example.json +9 -0
- package/templates/examples/spec-challenge.example.json +14 -0
- package/templates/examples/spec.example.json +21 -0
- package/templates/examples/verification-proof.example.json +21 -0
- package/templates/examples/wazir-manifest.example.yaml +65 -0
- package/templates/task-definition-schema.md +99 -0
- package/tooling/README.md +20 -0
- package/tooling/src/adapters/context-mode.js +50 -0
- package/tooling/src/capture/command.js +376 -0
- package/tooling/src/capture/store.js +99 -0
- package/tooling/src/capture/usage.js +270 -0
- package/tooling/src/checks/branches.js +50 -0
- package/tooling/src/checks/brand-truth.js +110 -0
- package/tooling/src/checks/changelog.js +231 -0
- package/tooling/src/checks/command-registry.js +36 -0
- package/tooling/src/checks/commits.js +102 -0
- package/tooling/src/checks/docs-drift.js +103 -0
- package/tooling/src/checks/docs-truth.js +201 -0
- package/tooling/src/checks/runtime-surface.js +156 -0
- package/tooling/src/cli.js +116 -0
- package/tooling/src/command-options.js +56 -0
- package/tooling/src/commands/validate.js +320 -0
- package/tooling/src/doctor/command.js +91 -0
- package/tooling/src/export/command.js +77 -0
- package/tooling/src/export/compiler.js +498 -0
- package/tooling/src/guards/loop-cap-guard.js +52 -0
- package/tooling/src/guards/protected-path-write-guard.js +67 -0
- package/tooling/src/index/command.js +152 -0
- package/tooling/src/index/storage.js +1061 -0
- package/tooling/src/index/summarizers.js +261 -0
- package/tooling/src/loaders.js +18 -0
- package/tooling/src/project-root.js +22 -0
- package/tooling/src/recall/command.js +225 -0
- package/tooling/src/schema-validator.js +30 -0
- package/tooling/src/state-root.js +40 -0
- package/tooling/src/status/command.js +71 -0
- package/wazir.manifest.yaml +135 -0
- package/workflows/README.md +19 -0
- package/workflows/author.md +42 -0
- package/workflows/clarify.md +38 -0
- package/workflows/design-review.md +46 -0
- package/workflows/design.md +44 -0
- package/workflows/discover.md +37 -0
- package/workflows/execute.md +48 -0
- package/workflows/learn.md +38 -0
- package/workflows/plan-review.md +42 -0
- package/workflows/plan.md +39 -0
- package/workflows/prepare-next.md +37 -0
- package/workflows/review.md +40 -0
- package/workflows/run-audit.md +41 -0
- package/workflows/spec-challenge.md +41 -0
- package/workflows/specify.md +38 -0
- package/workflows/verify.md +37 -0
|
@@ -0,0 +1,1061 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
5
|
+
|
|
6
|
+
import { getIndexDatabasePath } from '../state-root.js';
|
|
7
|
+
import {
|
|
8
|
+
generateFileL0,
|
|
9
|
+
generateFileL1,
|
|
10
|
+
generateSymbolL0,
|
|
11
|
+
generateSymbolL1,
|
|
12
|
+
isBinaryContent,
|
|
13
|
+
} from './summarizers.js';
|
|
14
|
+
|
|
15
|
+
const INDEXABLE_EXTENSIONS = new Set([
|
|
16
|
+
'.js',
|
|
17
|
+
'.cjs',
|
|
18
|
+
'.mjs',
|
|
19
|
+
'.jsx',
|
|
20
|
+
'.ts',
|
|
21
|
+
'.tsx',
|
|
22
|
+
'.py',
|
|
23
|
+
'.go',
|
|
24
|
+
'.rs',
|
|
25
|
+
'.java',
|
|
26
|
+
'.sql',
|
|
27
|
+
'.json',
|
|
28
|
+
'.yaml',
|
|
29
|
+
'.yml',
|
|
30
|
+
'.md',
|
|
31
|
+
'.txt',
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
const IGNORED_DIRECTORIES = new Set([
|
|
35
|
+
'.git',
|
|
36
|
+
'.worktrees',
|
|
37
|
+
'node_modules',
|
|
38
|
+
'dist',
|
|
39
|
+
'build',
|
|
40
|
+
'coverage',
|
|
41
|
+
'.next',
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
function createId(parts) {
|
|
45
|
+
return crypto.createHash('sha1').update(parts.join('::')).digest('hex').slice(0, 16);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function hashContent(content) {
|
|
49
|
+
return crypto.createHash('sha256').update(content).digest('hex');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function countLineOccurrences(line, needle) {
|
|
53
|
+
return (line.match(new RegExp(`\\${needle}`, 'g')) ?? []).length;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function estimateBraceBlockEnd(lines, startIndex) {
|
|
57
|
+
let depth = 0;
|
|
58
|
+
let sawBrace = false;
|
|
59
|
+
|
|
60
|
+
for (let index = startIndex; index < lines.length; index += 1) {
|
|
61
|
+
const line = lines[index];
|
|
62
|
+
depth += countLineOccurrences(line, '{');
|
|
63
|
+
depth -= countLineOccurrences(line, '}');
|
|
64
|
+
|
|
65
|
+
if (line.includes('{')) {
|
|
66
|
+
sawBrace = true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (sawBrace && depth <= 0 && index > startIndex) {
|
|
70
|
+
return index + 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return sawBrace ? lines.length : startIndex + 1;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function detectLanguage(relativePath) {
|
|
78
|
+
const extension = path.extname(relativePath).toLowerCase();
|
|
79
|
+
|
|
80
|
+
switch (extension) {
|
|
81
|
+
case '.js':
|
|
82
|
+
case '.cjs':
|
|
83
|
+
case '.mjs':
|
|
84
|
+
case '.jsx':
|
|
85
|
+
return 'javascript';
|
|
86
|
+
case '.ts':
|
|
87
|
+
case '.tsx':
|
|
88
|
+
return 'typescript';
|
|
89
|
+
case '.py':
|
|
90
|
+
return 'python';
|
|
91
|
+
case '.go':
|
|
92
|
+
return 'go';
|
|
93
|
+
case '.rs':
|
|
94
|
+
return 'rust';
|
|
95
|
+
case '.java':
|
|
96
|
+
return 'java';
|
|
97
|
+
case '.sql':
|
|
98
|
+
return 'sql';
|
|
99
|
+
case '.json':
|
|
100
|
+
return 'json';
|
|
101
|
+
case '.yaml':
|
|
102
|
+
case '.yml':
|
|
103
|
+
return 'yaml';
|
|
104
|
+
case '.md':
|
|
105
|
+
return 'markdown';
|
|
106
|
+
case '.txt':
|
|
107
|
+
return 'text';
|
|
108
|
+
default:
|
|
109
|
+
return 'text';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function extractMarkdownEntries(lines, relativePath) {
|
|
114
|
+
const outlines = [];
|
|
115
|
+
|
|
116
|
+
lines.forEach((line, index) => {
|
|
117
|
+
const match = line.match(/^(#{1,6})\s+(.+?)\s*$/);
|
|
118
|
+
|
|
119
|
+
if (!match) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
outlines.push({
|
|
124
|
+
outline_id: createId([relativePath, 'heading', match[2], String(index + 1)]),
|
|
125
|
+
label: match[2],
|
|
126
|
+
kind: 'heading',
|
|
127
|
+
level: match[1].length,
|
|
128
|
+
line_start: index + 1,
|
|
129
|
+
line_end: index + 1,
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
outlines,
|
|
135
|
+
symbols: [],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function extractJsonEntries(lines, relativePath) {
|
|
140
|
+
const outlines = [];
|
|
141
|
+
const symbols = [];
|
|
142
|
+
|
|
143
|
+
lines.forEach((line, index) => {
|
|
144
|
+
const jsonMatch = line.match(/^\s*"([^"]+)"\s*:\s*/);
|
|
145
|
+
const yamlMatch = line.match(/^([A-Za-z0-9_-]+):\s*/);
|
|
146
|
+
const key = jsonMatch?.[1] ?? yamlMatch?.[1];
|
|
147
|
+
|
|
148
|
+
if (!key) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const entry = {
|
|
153
|
+
label: key,
|
|
154
|
+
kind: 'key',
|
|
155
|
+
level: 1,
|
|
156
|
+
line_start: index + 1,
|
|
157
|
+
line_end: index + 1,
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
outlines.push({
|
|
161
|
+
outline_id: createId([relativePath, 'outline', key, String(index + 1)]),
|
|
162
|
+
...entry,
|
|
163
|
+
});
|
|
164
|
+
symbols.push({
|
|
165
|
+
symbol_id: createId([relativePath, 'symbol', key, 'key', String(index + 1)]),
|
|
166
|
+
name: key,
|
|
167
|
+
kind: 'key',
|
|
168
|
+
signature: line.trim(),
|
|
169
|
+
line_start: index + 1,
|
|
170
|
+
line_end: index + 1,
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
outlines,
|
|
176
|
+
symbols,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function extractCodeEntries(lines, relativePath, language) {
|
|
181
|
+
const outlines = [];
|
|
182
|
+
const symbols = [];
|
|
183
|
+
const patterns = [
|
|
184
|
+
{ kind: 'function', regex: /^\s*export\s+async\s+function\s+([A-Za-z_$][\w$]*)\s*\(/ },
|
|
185
|
+
{ kind: 'function', regex: /^\s*export\s+function\s+([A-Za-z_$][\w$]*)\s*\(/ },
|
|
186
|
+
{ kind: 'function', regex: /^\s*async\s+function\s+([A-Za-z_$][\w$]*)\s*\(/ },
|
|
187
|
+
{ kind: 'function', regex: /^\s*function\s+([A-Za-z_$][\w$]*)\s*\(/ },
|
|
188
|
+
{ kind: 'function', regex: /^\s*(?:export\s+)?const\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?\(/ },
|
|
189
|
+
{ kind: 'class', regex: /^\s*export\s+class\s+([A-Za-z_$][\w$]*)\b/ },
|
|
190
|
+
{ kind: 'class', regex: /^\s*class\s+([A-Za-z_$][\w$]*)\b/ },
|
|
191
|
+
{ kind: 'function', regex: /^\s*def\s+([A-Za-z_][\w]*)\s*\(/ },
|
|
192
|
+
{ kind: 'class', regex: /^\s*class\s+([A-Za-z_][\w]*)\b/ },
|
|
193
|
+
{ kind: 'function', regex: /^\s*func\s+([A-Za-z_][\w]*)\s*\(/ },
|
|
194
|
+
{ kind: 'type', regex: /^\s*type\s+([A-Za-z_][\w]*)\s+(?:struct|interface)\b/ },
|
|
195
|
+
{ kind: 'function', regex: /^\s*pub\s+fn\s+([A-Za-z_][\w]*)\s*\(/ },
|
|
196
|
+
{ kind: 'function', regex: /^\s*fn\s+([A-Za-z_][\w]*)\s*\(/ },
|
|
197
|
+
{ kind: 'type', regex: /^\s*pub\s+(?:struct|enum|trait)\s+([A-Za-z_][\w]*)\b/ },
|
|
198
|
+
{ kind: 'type', regex: /^\s*(?:struct|enum|trait)\s+([A-Za-z_][\w]*)\b/ },
|
|
199
|
+
{ kind: 'type', regex: /^\s*public\s+(?:class|interface|enum|record)\s+([A-Za-z_][\w]*)\b/ },
|
|
200
|
+
{ kind: 'type', regex: /^\s*(?:class|interface|enum|record)\s+([A-Za-z_][\w]*)\b/ },
|
|
201
|
+
{ kind: 'sql', regex: /^\s*create\s+(?:or\s+replace\s+)?(?:table|view|function|procedure)\s+([A-Za-z_][\w]*)/i },
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
lines.forEach((line, index) => {
|
|
205
|
+
const pattern = patterns.find((candidate) => candidate.regex.test(line));
|
|
206
|
+
|
|
207
|
+
if (!pattern) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const match = line.match(pattern.regex);
|
|
212
|
+
const name = match?.[1];
|
|
213
|
+
|
|
214
|
+
if (!name) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const lineEnd = ['javascript', 'typescript', 'go', 'rust', 'java'].includes(language)
|
|
219
|
+
? estimateBraceBlockEnd(lines, index)
|
|
220
|
+
: index + 1;
|
|
221
|
+
|
|
222
|
+
outlines.push({
|
|
223
|
+
outline_id: createId([relativePath, 'outline', name, pattern.kind, String(index + 1)]),
|
|
224
|
+
label: name,
|
|
225
|
+
kind: pattern.kind,
|
|
226
|
+
level: 1,
|
|
227
|
+
line_start: index + 1,
|
|
228
|
+
line_end: lineEnd,
|
|
229
|
+
});
|
|
230
|
+
symbols.push({
|
|
231
|
+
symbol_id: createId([relativePath, 'symbol', name, pattern.kind, String(index + 1)]),
|
|
232
|
+
name,
|
|
233
|
+
kind: pattern.kind,
|
|
234
|
+
signature: line.trim(),
|
|
235
|
+
line_start: index + 1,
|
|
236
|
+
line_end: lineEnd,
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
outlines,
|
|
242
|
+
symbols,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function extractEntries(relativePath, content) {
|
|
247
|
+
const language = detectLanguage(relativePath);
|
|
248
|
+
const lines = content.split('\n');
|
|
249
|
+
|
|
250
|
+
if (language === 'markdown') {
|
|
251
|
+
return {
|
|
252
|
+
language,
|
|
253
|
+
...extractMarkdownEntries(lines, relativePath),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (language === 'json' || language === 'yaml') {
|
|
258
|
+
return {
|
|
259
|
+
language,
|
|
260
|
+
...extractJsonEntries(lines, relativePath),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (language === 'text') {
|
|
265
|
+
return {
|
|
266
|
+
language,
|
|
267
|
+
outlines: [],
|
|
268
|
+
symbols: [],
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
language,
|
|
274
|
+
...extractCodeEntries(lines, relativePath, language),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function isStateRootInsideProject(projectRoot, stateRoot, absolutePath) {
|
|
279
|
+
const normalizedStateRoot = path.resolve(stateRoot);
|
|
280
|
+
const normalizedAbsolutePath = path.resolve(absolutePath);
|
|
281
|
+
|
|
282
|
+
return normalizedAbsolutePath === normalizedStateRoot
|
|
283
|
+
|| normalizedAbsolutePath.startsWith(`${normalizedStateRoot}${path.sep}`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function collectFiles(projectRoot, stateRoot) {
|
|
287
|
+
const files = [];
|
|
288
|
+
|
|
289
|
+
function walk(currentDir) {
|
|
290
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
291
|
+
|
|
292
|
+
for (const entry of entries) {
|
|
293
|
+
const absolutePath = path.join(currentDir, entry.name);
|
|
294
|
+
|
|
295
|
+
if (entry.isDirectory()) {
|
|
296
|
+
if (IGNORED_DIRECTORIES.has(entry.name)) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (isStateRootInsideProject(projectRoot, stateRoot, absolutePath)) {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
walk(absolutePath);
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (!entry.isFile()) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const relativePath = path.relative(projectRoot, absolutePath);
|
|
313
|
+
const extension = path.extname(relativePath).toLowerCase();
|
|
314
|
+
|
|
315
|
+
if (!INDEXABLE_EXTENSIONS.has(extension)) {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
files.push(relativePath);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
walk(projectRoot);
|
|
324
|
+
files.sort();
|
|
325
|
+
return files;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function ensureSchema(db) {
|
|
329
|
+
db.exec(`
|
|
330
|
+
CREATE TABLE IF NOT EXISTS files (
|
|
331
|
+
file_id TEXT PRIMARY KEY,
|
|
332
|
+
relative_path TEXT NOT NULL UNIQUE,
|
|
333
|
+
language TEXT NOT NULL,
|
|
334
|
+
size_bytes INTEGER NOT NULL,
|
|
335
|
+
line_count INTEGER NOT NULL,
|
|
336
|
+
content_hash TEXT NOT NULL,
|
|
337
|
+
indexed_at TEXT NOT NULL
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
CREATE TABLE IF NOT EXISTS symbols (
|
|
341
|
+
symbol_id TEXT PRIMARY KEY,
|
|
342
|
+
file_id TEXT NOT NULL,
|
|
343
|
+
relative_path TEXT NOT NULL,
|
|
344
|
+
name TEXT NOT NULL,
|
|
345
|
+
kind TEXT NOT NULL,
|
|
346
|
+
signature TEXT NOT NULL,
|
|
347
|
+
line_start INTEGER NOT NULL,
|
|
348
|
+
line_end INTEGER NOT NULL
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
CREATE TABLE IF NOT EXISTS outlines (
|
|
352
|
+
outline_id TEXT PRIMARY KEY,
|
|
353
|
+
file_id TEXT NOT NULL,
|
|
354
|
+
relative_path TEXT NOT NULL,
|
|
355
|
+
label TEXT NOT NULL,
|
|
356
|
+
kind TEXT NOT NULL,
|
|
357
|
+
level INTEGER NOT NULL,
|
|
358
|
+
line_start INTEGER NOT NULL,
|
|
359
|
+
line_end INTEGER NOT NULL
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
CREATE TABLE IF NOT EXISTS hashes (
|
|
363
|
+
file_id TEXT PRIMARY KEY,
|
|
364
|
+
content_hash TEXT NOT NULL,
|
|
365
|
+
updated_at TEXT NOT NULL
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
CREATE TABLE IF NOT EXISTS ingestion_runs (
|
|
369
|
+
run_id TEXT PRIMARY KEY,
|
|
370
|
+
mode TEXT NOT NULL,
|
|
371
|
+
started_at TEXT NOT NULL,
|
|
372
|
+
completed_at TEXT,
|
|
373
|
+
file_count INTEGER NOT NULL,
|
|
374
|
+
updated_file_count INTEGER NOT NULL,
|
|
375
|
+
removed_file_count INTEGER NOT NULL,
|
|
376
|
+
symbol_count INTEGER NOT NULL,
|
|
377
|
+
outline_count INTEGER NOT NULL
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
CREATE TABLE IF NOT EXISTS retrieval_logs (
|
|
381
|
+
log_id TEXT PRIMARY KEY,
|
|
382
|
+
type TEXT NOT NULL,
|
|
383
|
+
query TEXT NOT NULL,
|
|
384
|
+
result_count INTEGER NOT NULL,
|
|
385
|
+
created_at TEXT NOT NULL
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
CREATE TABLE IF NOT EXISTS summaries (
|
|
389
|
+
summary_id TEXT PRIMARY KEY,
|
|
390
|
+
file_id TEXT NOT NULL REFERENCES files(file_id) ON DELETE CASCADE,
|
|
391
|
+
tier TEXT NOT NULL CHECK (tier IN ('L0', 'L1')),
|
|
392
|
+
content TEXT NOT NULL,
|
|
393
|
+
content_hash TEXT NOT NULL,
|
|
394
|
+
source_hash TEXT NOT NULL,
|
|
395
|
+
generator TEXT NOT NULL,
|
|
396
|
+
generated_at TEXT NOT NULL,
|
|
397
|
+
UNIQUE(file_id, tier)
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
CREATE TABLE IF NOT EXISTS symbol_summaries (
|
|
401
|
+
summary_id TEXT PRIMARY KEY,
|
|
402
|
+
symbol_id TEXT NOT NULL REFERENCES symbols(symbol_id) ON DELETE CASCADE,
|
|
403
|
+
file_id TEXT NOT NULL REFERENCES files(file_id) ON DELETE CASCADE,
|
|
404
|
+
tier TEXT NOT NULL CHECK (tier IN ('L0', 'L1')),
|
|
405
|
+
content TEXT NOT NULL,
|
|
406
|
+
content_hash TEXT NOT NULL,
|
|
407
|
+
source_hash TEXT NOT NULL,
|
|
408
|
+
generator TEXT NOT NULL,
|
|
409
|
+
generated_at TEXT NOT NULL,
|
|
410
|
+
UNIQUE(symbol_id, tier)
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name);
|
|
414
|
+
CREATE INDEX IF NOT EXISTS idx_outlines_relative_path ON outlines(relative_path);
|
|
415
|
+
CREATE INDEX IF NOT EXISTS idx_files_relative_path ON files(relative_path);
|
|
416
|
+
CREATE INDEX IF NOT EXISTS idx_summaries_file_id ON summaries(file_id);
|
|
417
|
+
CREATE INDEX IF NOT EXISTS idx_symbol_summaries_file_id ON symbol_summaries(file_id);
|
|
418
|
+
`);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export function openIndexDatabase(stateRoot) {
|
|
422
|
+
const databasePath = getIndexDatabasePath(stateRoot);
|
|
423
|
+
fs.mkdirSync(path.dirname(databasePath), { recursive: true });
|
|
424
|
+
const db = new DatabaseSync(databasePath, { timeout: 5000 });
|
|
425
|
+
ensureSchema(db);
|
|
426
|
+
return db;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function getCounts(db) {
|
|
430
|
+
return {
|
|
431
|
+
file_count: db.prepare('SELECT COUNT(*) AS count FROM files').get().count,
|
|
432
|
+
symbol_count: db.prepare('SELECT COUNT(*) AS count FROM symbols').get().count,
|
|
433
|
+
outline_count: db.prepare('SELECT COUNT(*) AS count FROM outlines').get().count,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function upsertFileIndex(db, record) {
|
|
438
|
+
const insertFile = db.prepare(`
|
|
439
|
+
INSERT INTO files (file_id, relative_path, language, size_bytes, line_count, content_hash, indexed_at)
|
|
440
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
441
|
+
ON CONFLICT(relative_path) DO UPDATE SET
|
|
442
|
+
file_id = excluded.file_id,
|
|
443
|
+
language = excluded.language,
|
|
444
|
+
size_bytes = excluded.size_bytes,
|
|
445
|
+
line_count = excluded.line_count,
|
|
446
|
+
content_hash = excluded.content_hash,
|
|
447
|
+
indexed_at = excluded.indexed_at
|
|
448
|
+
`);
|
|
449
|
+
const insertHash = db.prepare(`
|
|
450
|
+
INSERT INTO hashes (file_id, content_hash, updated_at)
|
|
451
|
+
VALUES (?, ?, ?)
|
|
452
|
+
ON CONFLICT(file_id) DO UPDATE SET
|
|
453
|
+
content_hash = excluded.content_hash,
|
|
454
|
+
updated_at = excluded.updated_at
|
|
455
|
+
`);
|
|
456
|
+
const deleteSymbols = db.prepare('DELETE FROM symbols WHERE file_id = ?');
|
|
457
|
+
const deleteOutlines = db.prepare('DELETE FROM outlines WHERE file_id = ?');
|
|
458
|
+
const insertSymbol = db.prepare(`
|
|
459
|
+
INSERT INTO symbols (symbol_id, file_id, relative_path, name, kind, signature, line_start, line_end)
|
|
460
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
461
|
+
`);
|
|
462
|
+
const insertOutline = db.prepare(`
|
|
463
|
+
INSERT INTO outlines (outline_id, file_id, relative_path, label, kind, level, line_start, line_end)
|
|
464
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
465
|
+
`);
|
|
466
|
+
|
|
467
|
+
insertFile.run(
|
|
468
|
+
record.file_id,
|
|
469
|
+
record.relative_path,
|
|
470
|
+
record.language,
|
|
471
|
+
record.size_bytes,
|
|
472
|
+
record.line_count,
|
|
473
|
+
record.content_hash,
|
|
474
|
+
record.indexed_at,
|
|
475
|
+
);
|
|
476
|
+
insertHash.run(record.file_id, record.content_hash, record.indexed_at);
|
|
477
|
+
deleteSymbols.run(record.file_id);
|
|
478
|
+
deleteOutlines.run(record.file_id);
|
|
479
|
+
|
|
480
|
+
for (const symbol of record.symbols) {
|
|
481
|
+
insertSymbol.run(
|
|
482
|
+
symbol.symbol_id,
|
|
483
|
+
record.file_id,
|
|
484
|
+
record.relative_path,
|
|
485
|
+
symbol.name,
|
|
486
|
+
symbol.kind,
|
|
487
|
+
symbol.signature,
|
|
488
|
+
symbol.line_start,
|
|
489
|
+
symbol.line_end,
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
for (const outline of record.outlines) {
|
|
494
|
+
insertOutline.run(
|
|
495
|
+
outline.outline_id,
|
|
496
|
+
record.file_id,
|
|
497
|
+
record.relative_path,
|
|
498
|
+
outline.label,
|
|
499
|
+
outline.kind,
|
|
500
|
+
outline.level,
|
|
501
|
+
outline.line_start,
|
|
502
|
+
outline.line_end,
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function deleteRemovedFiles(db, missingRelativePaths) {
|
|
508
|
+
const selectFile = db.prepare('SELECT file_id FROM files WHERE relative_path = ?');
|
|
509
|
+
const deleteSymbols = db.prepare('DELETE FROM symbols WHERE file_id = ?');
|
|
510
|
+
const deleteOutlines = db.prepare('DELETE FROM outlines WHERE file_id = ?');
|
|
511
|
+
const deleteHashes = db.prepare('DELETE FROM hashes WHERE file_id = ?');
|
|
512
|
+
const deleteFile = db.prepare('DELETE FROM files WHERE file_id = ?');
|
|
513
|
+
|
|
514
|
+
for (const relativePath of missingRelativePaths) {
|
|
515
|
+
const row = selectFile.get(relativePath);
|
|
516
|
+
|
|
517
|
+
if (!row) {
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
deleteSymbols.run(row.file_id);
|
|
522
|
+
deleteOutlines.run(row.file_id);
|
|
523
|
+
deleteHashes.run(row.file_id);
|
|
524
|
+
deleteFile.run(row.file_id);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function readExistingHashes(db) {
|
|
529
|
+
const rows = db.prepare('SELECT relative_path, content_hash FROM files').all();
|
|
530
|
+
return new Map(rows.map((row) => [row.relative_path, row.content_hash]));
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
export function buildOrRefreshIndex(projectRoot, stateRoot, mode) {
|
|
534
|
+
const db = openIndexDatabase(stateRoot);
|
|
535
|
+
const runId = createId([mode, new Date().toISOString(), projectRoot]);
|
|
536
|
+
const startedAt = new Date().toISOString();
|
|
537
|
+
const filesToScan = collectFiles(projectRoot, stateRoot);
|
|
538
|
+
const existingHashes = mode === 'refresh' ? readExistingHashes(db) : new Map();
|
|
539
|
+
const seenPaths = new Set();
|
|
540
|
+
let updatedFileCount = 0;
|
|
541
|
+
|
|
542
|
+
db.exec('BEGIN');
|
|
543
|
+
|
|
544
|
+
try {
|
|
545
|
+
if (mode === 'build') {
|
|
546
|
+
db.exec('DELETE FROM symbols; DELETE FROM outlines; DELETE FROM hashes; DELETE FROM files;');
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
for (const relativePath of filesToScan) {
|
|
550
|
+
const absolutePath = path.join(projectRoot, relativePath);
|
|
551
|
+
const content = fs.readFileSync(absolutePath, 'utf8');
|
|
552
|
+
const contentHash = hashContent(content);
|
|
553
|
+
seenPaths.add(relativePath);
|
|
554
|
+
|
|
555
|
+
if (mode === 'refresh' && existingHashes.get(relativePath) === contentHash) {
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
const extracted = extractEntries(relativePath, content);
|
|
560
|
+
const fileId = createId([relativePath]);
|
|
561
|
+
|
|
562
|
+
upsertFileIndex(db, {
|
|
563
|
+
file_id: fileId,
|
|
564
|
+
relative_path: relativePath,
|
|
565
|
+
language: extracted.language,
|
|
566
|
+
size_bytes: Buffer.byteLength(content),
|
|
567
|
+
line_count: content.split('\n').length,
|
|
568
|
+
content_hash: contentHash,
|
|
569
|
+
indexed_at: new Date().toISOString(),
|
|
570
|
+
symbols: extracted.symbols,
|
|
571
|
+
outlines: extracted.outlines,
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
updatedFileCount += 1;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const missingRelativePaths = mode === 'refresh'
|
|
578
|
+
? [...existingHashes.keys()].filter((relativePath) => !seenPaths.has(relativePath))
|
|
579
|
+
: [];
|
|
580
|
+
|
|
581
|
+
deleteRemovedFiles(db, missingRelativePaths);
|
|
582
|
+
|
|
583
|
+
const counts = getCounts(db);
|
|
584
|
+
const completedAt = new Date().toISOString();
|
|
585
|
+
db.prepare(`
|
|
586
|
+
INSERT INTO ingestion_runs (
|
|
587
|
+
run_id,
|
|
588
|
+
mode,
|
|
589
|
+
started_at,
|
|
590
|
+
completed_at,
|
|
591
|
+
file_count,
|
|
592
|
+
updated_file_count,
|
|
593
|
+
removed_file_count,
|
|
594
|
+
symbol_count,
|
|
595
|
+
outline_count
|
|
596
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
597
|
+
`).run(
|
|
598
|
+
runId,
|
|
599
|
+
mode,
|
|
600
|
+
startedAt,
|
|
601
|
+
completedAt,
|
|
602
|
+
counts.file_count,
|
|
603
|
+
updatedFileCount,
|
|
604
|
+
missingRelativePaths.length,
|
|
605
|
+
counts.symbol_count,
|
|
606
|
+
counts.outline_count,
|
|
607
|
+
);
|
|
608
|
+
db.exec('COMMIT');
|
|
609
|
+
|
|
610
|
+
return {
|
|
611
|
+
run_id: runId,
|
|
612
|
+
mode,
|
|
613
|
+
file_count: counts.file_count,
|
|
614
|
+
updated_file_count: updatedFileCount,
|
|
615
|
+
removed_file_count: missingRelativePaths.length,
|
|
616
|
+
symbol_count: counts.symbol_count,
|
|
617
|
+
outline_count: counts.outline_count,
|
|
618
|
+
database_path: getIndexDatabasePath(stateRoot),
|
|
619
|
+
};
|
|
620
|
+
} catch (error) {
|
|
621
|
+
db.exec('ROLLBACK');
|
|
622
|
+
throw error;
|
|
623
|
+
} finally {
|
|
624
|
+
db.close();
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
export function readIndexStats(stateRoot) {
|
|
629
|
+
const db = openIndexDatabase(stateRoot);
|
|
630
|
+
|
|
631
|
+
try {
|
|
632
|
+
const stats = {
|
|
633
|
+
...getCounts(db),
|
|
634
|
+
last_run: db.prepare(`
|
|
635
|
+
SELECT run_id, mode, completed_at
|
|
636
|
+
FROM ingestion_runs
|
|
637
|
+
ORDER BY completed_at DESC
|
|
638
|
+
LIMIT 1
|
|
639
|
+
`).get() ?? null,
|
|
640
|
+
database_path: getIndexDatabasePath(stateRoot),
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
const summaryCounts = readSummaryStats(db);
|
|
644
|
+
if (summaryCounts) {
|
|
645
|
+
stats.summary_counts = summaryCounts;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
return stats;
|
|
649
|
+
} finally {
|
|
650
|
+
db.close();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
export function readFileOutline(stateRoot, relativePath) {
|
|
655
|
+
const db = openIndexDatabase(stateRoot);
|
|
656
|
+
|
|
657
|
+
try {
|
|
658
|
+
const entries = db.prepare(`
|
|
659
|
+
SELECT label, kind, level, line_start, line_end
|
|
660
|
+
FROM outlines
|
|
661
|
+
WHERE relative_path = ?
|
|
662
|
+
ORDER BY line_start, label
|
|
663
|
+
`).all(relativePath);
|
|
664
|
+
|
|
665
|
+
return {
|
|
666
|
+
relative_path: relativePath,
|
|
667
|
+
entries,
|
|
668
|
+
};
|
|
669
|
+
} finally {
|
|
670
|
+
db.close();
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
export function searchSymbols(stateRoot, query) {
|
|
675
|
+
const db = openIndexDatabase(stateRoot);
|
|
676
|
+
|
|
677
|
+
try {
|
|
678
|
+
const results = db.prepare(`
|
|
679
|
+
SELECT symbol_id, relative_path, name, kind, signature, line_start, line_end
|
|
680
|
+
FROM symbols
|
|
681
|
+
WHERE LOWER(name) LIKE LOWER(?)
|
|
682
|
+
ORDER BY CASE WHEN LOWER(name) = LOWER(?) THEN 0 ELSE 1 END, name, line_start
|
|
683
|
+
`).all(`%${query}%`, query);
|
|
684
|
+
|
|
685
|
+
db.prepare(`
|
|
686
|
+
INSERT INTO retrieval_logs (log_id, type, query, result_count, created_at)
|
|
687
|
+
VALUES (?, ?, ?, ?, ?)
|
|
688
|
+
`).run(
|
|
689
|
+
createId(['search-symbols', query, new Date().toISOString()]),
|
|
690
|
+
'search-symbols',
|
|
691
|
+
query,
|
|
692
|
+
results.length,
|
|
693
|
+
new Date().toISOString(),
|
|
694
|
+
);
|
|
695
|
+
|
|
696
|
+
return {
|
|
697
|
+
query,
|
|
698
|
+
results,
|
|
699
|
+
};
|
|
700
|
+
} finally {
|
|
701
|
+
db.close();
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
export function findSymbol(stateRoot, query) {
|
|
706
|
+
const db = openIndexDatabase(stateRoot);
|
|
707
|
+
|
|
708
|
+
try {
|
|
709
|
+
const exactId = db.prepare(`
|
|
710
|
+
SELECT symbol_id, file_id, relative_path, name, kind, signature, line_start, line_end
|
|
711
|
+
FROM symbols
|
|
712
|
+
WHERE symbol_id = ?
|
|
713
|
+
LIMIT 1
|
|
714
|
+
`).get(query);
|
|
715
|
+
|
|
716
|
+
if (exactId) {
|
|
717
|
+
return exactId;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
const exactName = db.prepare(`
|
|
721
|
+
SELECT symbol_id, file_id, relative_path, name, kind, signature, line_start, line_end
|
|
722
|
+
FROM symbols
|
|
723
|
+
WHERE LOWER(name) = LOWER(?)
|
|
724
|
+
ORDER BY line_start
|
|
725
|
+
LIMIT 1
|
|
726
|
+
`).get(query);
|
|
727
|
+
|
|
728
|
+
if (exactName) {
|
|
729
|
+
return exactName;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
return db.prepare(`
|
|
733
|
+
SELECT symbol_id, file_id, relative_path, name, kind, signature, line_start, line_end
|
|
734
|
+
FROM symbols
|
|
735
|
+
WHERE LOWER(name) LIKE LOWER(?)
|
|
736
|
+
ORDER BY name, line_start
|
|
737
|
+
LIMIT 1
|
|
738
|
+
`).get(`%${query}%`) ?? null;
|
|
739
|
+
} finally {
|
|
740
|
+
db.close();
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
export function readIndexedFile(stateRoot, relativePath) {
|
|
745
|
+
const db = openIndexDatabase(stateRoot);
|
|
746
|
+
|
|
747
|
+
try {
|
|
748
|
+
return db.prepare(`
|
|
749
|
+
SELECT file_id, relative_path, language, size_bytes, line_count, content_hash
|
|
750
|
+
FROM files
|
|
751
|
+
WHERE relative_path = ?
|
|
752
|
+
LIMIT 1
|
|
753
|
+
`).get(relativePath) ?? null;
|
|
754
|
+
} finally {
|
|
755
|
+
db.close();
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
export function upsertFileSummary(dbOrStateRoot, fileId, tier, content, sourceHash, generator) {
|
|
760
|
+
const ownConnection = typeof dbOrStateRoot === 'string';
|
|
761
|
+
const db = ownConnection ? openIndexDatabase(dbOrStateRoot) : dbOrStateRoot;
|
|
762
|
+
|
|
763
|
+
try {
|
|
764
|
+
const summaryId = createId([fileId, tier]);
|
|
765
|
+
const contentHash = hashContent(content);
|
|
766
|
+
const generatedAt = new Date().toISOString();
|
|
767
|
+
|
|
768
|
+
db.prepare(`
|
|
769
|
+
INSERT INTO summaries (summary_id, file_id, tier, content, content_hash, source_hash, generator, generated_at)
|
|
770
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
771
|
+
ON CONFLICT(file_id, tier) DO UPDATE SET
|
|
772
|
+
summary_id = excluded.summary_id,
|
|
773
|
+
content = excluded.content,
|
|
774
|
+
content_hash = excluded.content_hash,
|
|
775
|
+
source_hash = excluded.source_hash,
|
|
776
|
+
generator = excluded.generator,
|
|
777
|
+
generated_at = excluded.generated_at
|
|
778
|
+
`).run(summaryId, fileId, tier, content, contentHash, sourceHash, generator, generatedAt);
|
|
779
|
+
} finally {
|
|
780
|
+
if (ownConnection) db.close();
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
export function readFileSummary(dbOrStateRoot, fileId, tier) {
|
|
785
|
+
const ownConnection = typeof dbOrStateRoot === 'string';
|
|
786
|
+
const db = ownConnection ? openIndexDatabase(dbOrStateRoot) : dbOrStateRoot;
|
|
787
|
+
|
|
788
|
+
try {
|
|
789
|
+
return db.prepare(`
|
|
790
|
+
SELECT summary_id, file_id, tier, content, content_hash, source_hash, generator, generated_at
|
|
791
|
+
FROM summaries
|
|
792
|
+
WHERE file_id = ? AND tier = ?
|
|
793
|
+
`).get(fileId, tier) ?? null;
|
|
794
|
+
} finally {
|
|
795
|
+
if (ownConnection) db.close();
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
export function upsertSymbolSummary(dbOrStateRoot, symbolId, tier, content, sourceHash, generator) {
|
|
800
|
+
const ownConnection = typeof dbOrStateRoot === 'string';
|
|
801
|
+
const db = ownConnection ? openIndexDatabase(dbOrStateRoot) : dbOrStateRoot;
|
|
802
|
+
|
|
803
|
+
try {
|
|
804
|
+
const fileRow = db.prepare('SELECT file_id FROM symbols WHERE symbol_id = ?').get(symbolId);
|
|
805
|
+
|
|
806
|
+
if (!fileRow) {
|
|
807
|
+
throw new Error(`Symbol not found: ${symbolId}`);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
const summaryId = createId([symbolId, tier]);
|
|
811
|
+
const contentHash = hashContent(content);
|
|
812
|
+
const generatedAt = new Date().toISOString();
|
|
813
|
+
|
|
814
|
+
db.prepare(`
|
|
815
|
+
INSERT INTO symbol_summaries (summary_id, symbol_id, file_id, tier, content, content_hash, source_hash, generator, generated_at)
|
|
816
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
817
|
+
ON CONFLICT(symbol_id, tier) DO UPDATE SET
|
|
818
|
+
summary_id = excluded.summary_id,
|
|
819
|
+
file_id = excluded.file_id,
|
|
820
|
+
content = excluded.content,
|
|
821
|
+
content_hash = excluded.content_hash,
|
|
822
|
+
source_hash = excluded.source_hash,
|
|
823
|
+
generator = excluded.generator,
|
|
824
|
+
generated_at = excluded.generated_at
|
|
825
|
+
`).run(summaryId, symbolId, fileRow.file_id, tier, content, contentHash, sourceHash, generator, generatedAt);
|
|
826
|
+
} finally {
|
|
827
|
+
if (ownConnection) db.close();
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
export function readSymbolSummary(dbOrStateRoot, symbolId, tier) {
|
|
832
|
+
const ownConnection = typeof dbOrStateRoot === 'string';
|
|
833
|
+
const db = ownConnection ? openIndexDatabase(dbOrStateRoot) : dbOrStateRoot;
|
|
834
|
+
|
|
835
|
+
try {
|
|
836
|
+
return db.prepare(`
|
|
837
|
+
SELECT summary_id, symbol_id, file_id, tier, content, content_hash, source_hash, generator, generated_at
|
|
838
|
+
FROM symbol_summaries
|
|
839
|
+
WHERE symbol_id = ? AND tier = ?
|
|
840
|
+
`).get(symbolId, tier) ?? null;
|
|
841
|
+
} finally {
|
|
842
|
+
if (ownConnection) db.close();
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
export function readSummaryStats(dbOrStateRoot) {
|
|
847
|
+
const ownConnection = typeof dbOrStateRoot === 'string';
|
|
848
|
+
const db = ownConnection ? openIndexDatabase(dbOrStateRoot) : dbOrStateRoot;
|
|
849
|
+
|
|
850
|
+
try {
|
|
851
|
+
const totalCount = db.prepare('SELECT COUNT(*) AS c FROM summaries').get().c
|
|
852
|
+
+ db.prepare('SELECT COUNT(*) AS c FROM symbol_summaries').get().c;
|
|
853
|
+
|
|
854
|
+
if (totalCount === 0) {
|
|
855
|
+
return null;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
const fileTiers = db.prepare('SELECT tier, COUNT(*) AS c FROM summaries GROUP BY tier').all();
|
|
859
|
+
const symTiers = db.prepare('SELECT tier, COUNT(*) AS c FROM symbol_summaries GROUP BY tier').all();
|
|
860
|
+
|
|
861
|
+
const fileSummaries = { L0: 0, L1: 0 };
|
|
862
|
+
for (const row of fileTiers) {
|
|
863
|
+
fileSummaries[row.tier] = row.c;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
const symbolSummaries = { L0: 0, L1: 0 };
|
|
867
|
+
for (const row of symTiers) {
|
|
868
|
+
symbolSummaries[row.tier] = row.c;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
const genRows = db.prepare(`
|
|
872
|
+
SELECT generator, COUNT(*) AS c FROM (
|
|
873
|
+
SELECT generator FROM summaries
|
|
874
|
+
UNION ALL
|
|
875
|
+
SELECT generator FROM symbol_summaries
|
|
876
|
+
) GROUP BY generator
|
|
877
|
+
`).all();
|
|
878
|
+
|
|
879
|
+
const generators = {};
|
|
880
|
+
for (const row of genRows) {
|
|
881
|
+
generators[row.generator] = row.c;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
return { file_summaries: fileSummaries, symbol_summaries: symbolSummaries, generators };
|
|
885
|
+
} finally {
|
|
886
|
+
if (ownConnection) db.close();
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
export function listIndexedFiles(dbOrStateRoot) {
|
|
891
|
+
const ownConnection = typeof dbOrStateRoot === 'string';
|
|
892
|
+
const db = ownConnection ? openIndexDatabase(dbOrStateRoot) : dbOrStateRoot;
|
|
893
|
+
|
|
894
|
+
try {
|
|
895
|
+
return db.prepare(`
|
|
896
|
+
SELECT file_id, relative_path, content_hash, language, line_count
|
|
897
|
+
FROM files
|
|
898
|
+
ORDER BY relative_path
|
|
899
|
+
`).all();
|
|
900
|
+
} finally {
|
|
901
|
+
if (ownConnection) db.close();
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
export function listSymbolsForFile(dbOrStateRoot, fileId) {
|
|
906
|
+
const ownConnection = typeof dbOrStateRoot === 'string';
|
|
907
|
+
const db = ownConnection ? openIndexDatabase(dbOrStateRoot) : dbOrStateRoot;
|
|
908
|
+
|
|
909
|
+
try {
|
|
910
|
+
return db.prepare(`
|
|
911
|
+
SELECT symbol_id, file_id, relative_path, name, kind, signature, line_start, line_end
|
|
912
|
+
FROM symbols
|
|
913
|
+
WHERE file_id = ?
|
|
914
|
+
ORDER BY line_start
|
|
915
|
+
`).all(fileId);
|
|
916
|
+
} finally {
|
|
917
|
+
if (ownConnection) db.close();
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
export function listFilesNeedingSummaries(dbOrStateRoot) {
|
|
922
|
+
const ownConnection = typeof dbOrStateRoot === 'string';
|
|
923
|
+
const db = ownConnection ? openIndexDatabase(dbOrStateRoot) : dbOrStateRoot;
|
|
924
|
+
|
|
925
|
+
try {
|
|
926
|
+
return db.prepare(`
|
|
927
|
+
SELECT DISTINCT f.file_id, f.relative_path, f.content_hash
|
|
928
|
+
FROM files f
|
|
929
|
+
LEFT JOIN summaries s_l0 ON f.file_id = s_l0.file_id AND s_l0.tier = 'L0'
|
|
930
|
+
LEFT JOIN summaries s_l1 ON f.file_id = s_l1.file_id AND s_l1.tier = 'L1'
|
|
931
|
+
WHERE s_l0.summary_id IS NULL
|
|
932
|
+
OR s_l1.summary_id IS NULL
|
|
933
|
+
OR s_l0.source_hash != f.content_hash
|
|
934
|
+
OR s_l1.source_hash != f.content_hash
|
|
935
|
+
ORDER BY f.relative_path
|
|
936
|
+
`).all();
|
|
937
|
+
} finally {
|
|
938
|
+
if (ownConnection) db.close();
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
export function logRetrieval(stateRoot, type, query, resultCount) {
|
|
943
|
+
const db = openIndexDatabase(stateRoot);
|
|
944
|
+
|
|
945
|
+
try {
|
|
946
|
+
db.prepare(`
|
|
947
|
+
INSERT INTO retrieval_logs (log_id, type, query, result_count, created_at)
|
|
948
|
+
VALUES (?, ?, ?, ?, ?)
|
|
949
|
+
`).run(
|
|
950
|
+
createId([type, query, new Date().toISOString()]),
|
|
951
|
+
type,
|
|
952
|
+
query,
|
|
953
|
+
resultCount,
|
|
954
|
+
new Date().toISOString(),
|
|
955
|
+
);
|
|
956
|
+
} finally {
|
|
957
|
+
db.close();
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
export function summarizeIndex(projectRoot, stateRoot, options = {}) {
|
|
962
|
+
const tier = options.tier ?? 'all';
|
|
963
|
+
const refresh = options.refresh ?? false;
|
|
964
|
+
const db = openIndexDatabase(stateRoot);
|
|
965
|
+
|
|
966
|
+
let summarizedFiles = 0;
|
|
967
|
+
let summarizedSymbols = 0;
|
|
968
|
+
let skippedStale = 0;
|
|
969
|
+
let skippedMissing = 0;
|
|
970
|
+
let skippedBinary = 0;
|
|
971
|
+
|
|
972
|
+
try {
|
|
973
|
+
db.exec('BEGIN');
|
|
974
|
+
|
|
975
|
+
const files = refresh
|
|
976
|
+
? listFilesNeedingSummaries(db)
|
|
977
|
+
: listIndexedFiles(db);
|
|
978
|
+
|
|
979
|
+
// In refresh mode, we need full file info (language, line_count) — listFilesNeedingSummaries only
|
|
980
|
+
// returns file_id, relative_path, content_hash. Get full info for each file.
|
|
981
|
+
const fileInfoMap = new Map();
|
|
982
|
+
if (refresh) {
|
|
983
|
+
const allFiles = listIndexedFiles(db);
|
|
984
|
+
for (const f of allFiles) {
|
|
985
|
+
fileInfoMap.set(f.file_id, f);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
for (const file of files) {
|
|
990
|
+
const fileInfo = refresh ? (fileInfoMap.get(file.file_id) ?? file) : file;
|
|
991
|
+
const absolutePath = path.join(projectRoot, fileInfo.relative_path);
|
|
992
|
+
|
|
993
|
+
let content;
|
|
994
|
+
try {
|
|
995
|
+
content = fs.readFileSync(absolutePath, 'utf-8');
|
|
996
|
+
} catch {
|
|
997
|
+
skippedMissing += 1;
|
|
998
|
+
continue;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
const liveHash = hashContent(content);
|
|
1002
|
+
if (liveHash !== fileInfo.content_hash) {
|
|
1003
|
+
skippedStale += 1;
|
|
1004
|
+
continue;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
if (isBinaryContent(content)) {
|
|
1008
|
+
skippedBinary += 1;
|
|
1009
|
+
continue;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
const symbols = listSymbolsForFile(db, fileInfo.file_id);
|
|
1013
|
+
|
|
1014
|
+
if (tier === 'L0' || tier === 'all') {
|
|
1015
|
+
const l0 = generateFileL0(fileInfo.language, fileInfo.line_count, symbols, content);
|
|
1016
|
+
upsertFileSummary(db, fileInfo.file_id, 'L0', l0, liveHash, 'heuristic');
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
if (tier === 'L1' || tier === 'all') {
|
|
1020
|
+
const l1 = generateFileL1(fileInfo.language, symbols, content);
|
|
1021
|
+
upsertFileSummary(db, fileInfo.file_id, 'L1', l1, liveHash, 'heuristic');
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
for (const symbol of symbols) {
|
|
1025
|
+
if (tier === 'L0' || tier === 'all') {
|
|
1026
|
+
const sl0 = generateSymbolL0(symbol);
|
|
1027
|
+
upsertSymbolSummary(db, symbol.symbol_id, 'L0', sl0, liveHash, 'heuristic');
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
if (tier === 'L1' || tier === 'all') {
|
|
1031
|
+
const sl1 = generateSymbolL1(symbol, content);
|
|
1032
|
+
upsertSymbolSummary(db, symbol.symbol_id, 'L1', sl1, liveHash, 'heuristic');
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
summarizedSymbols += 1;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
summarizedFiles += 1;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
db.exec('COMMIT');
|
|
1042
|
+
|
|
1043
|
+
if (summarizedFiles === 0) {
|
|
1044
|
+
throw new Error("No files summarized. Run 'index refresh' first.");
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
return {
|
|
1048
|
+
summarized_files: summarizedFiles,
|
|
1049
|
+
summarized_symbols: summarizedSymbols,
|
|
1050
|
+
skipped_stale: skippedStale,
|
|
1051
|
+
skipped_missing: skippedMissing,
|
|
1052
|
+
skipped_binary: skippedBinary,
|
|
1053
|
+
total_files: files.length,
|
|
1054
|
+
};
|
|
1055
|
+
} catch (error) {
|
|
1056
|
+
try { db.exec('ROLLBACK'); } catch { /* already committed or no transaction */ }
|
|
1057
|
+
throw error;
|
|
1058
|
+
} finally {
|
|
1059
|
+
db.close();
|
|
1060
|
+
}
|
|
1061
|
+
}
|