mustflow 1.15.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +16 -0
- package/README.md +422 -0
- package/dist/cli/commands/check.js +73 -0
- package/dist/cli/commands/classify.js +104 -0
- package/dist/cli/commands/context.js +95 -0
- package/dist/cli/commands/contract-lint.js +74 -0
- package/dist/cli/commands/dashboard.js +654 -0
- package/dist/cli/commands/docs.js +382 -0
- package/dist/cli/commands/doctor.js +232 -0
- package/dist/cli/commands/explain.js +293 -0
- package/dist/cli/commands/help.js +148 -0
- package/dist/cli/commands/impact.js +120 -0
- package/dist/cli/commands/index.js +70 -0
- package/dist/cli/commands/init.js +986 -0
- package/dist/cli/commands/line-endings.js +102 -0
- package/dist/cli/commands/map.js +95 -0
- package/dist/cli/commands/run.js +442 -0
- package/dist/cli/commands/search.js +166 -0
- package/dist/cli/commands/status.js +65 -0
- package/dist/cli/commands/update.js +443 -0
- package/dist/cli/commands/verify.js +448 -0
- package/dist/cli/commands/version-sources.js +79 -0
- package/dist/cli/commands/version.js +57 -0
- package/dist/cli/i18n/en.js +702 -0
- package/dist/cli/i18n/es.js +702 -0
- package/dist/cli/i18n/fr.js +702 -0
- package/dist/cli/i18n/hi.js +702 -0
- package/dist/cli/i18n/ko.js +702 -0
- package/dist/cli/i18n/zh.js +702 -0
- package/dist/cli/index.js +218 -0
- package/dist/cli/lib/agent-context.js +342 -0
- package/dist/cli/lib/browser-open.js +58 -0
- package/dist/cli/lib/cli-output.js +36 -0
- package/dist/cli/lib/command-contract.js +1 -0
- package/dist/cli/lib/command-registry.js +107 -0
- package/dist/cli/lib/dashboard-html.js +1866 -0
- package/dist/cli/lib/dashboard-locale.js +309 -0
- package/dist/cli/lib/dashboard-preferences.js +405 -0
- package/dist/cli/lib/doc-review-ledger.js +226 -0
- package/dist/cli/lib/filesystem.js +125 -0
- package/dist/cli/lib/git-changes.js +13 -0
- package/dist/cli/lib/i18n.js +55 -0
- package/dist/cli/lib/local-index.js +1014 -0
- package/dist/cli/lib/locale-tags.js +4 -0
- package/dist/cli/lib/manifest-lock.js +131 -0
- package/dist/cli/lib/npm-version-check.js +97 -0
- package/dist/cli/lib/package-info.js +13 -0
- package/dist/cli/lib/preferences-options.js +8 -0
- package/dist/cli/lib/project-root.js +23 -0
- package/dist/cli/lib/repo-map.js +635 -0
- package/dist/cli/lib/reporter.js +8 -0
- package/dist/cli/lib/run-receipt.js +1 -0
- package/dist/cli/lib/template-i18n.js +265 -0
- package/dist/cli/lib/templates.js +188 -0
- package/dist/cli/lib/toml.js +1 -0
- package/dist/cli/lib/validation.js +1639 -0
- package/dist/cli/lib/version-sources.js +1 -0
- package/dist/core/authority-resolution.js +155 -0
- package/dist/core/change-classification.js +122 -0
- package/dist/core/change-verification.js +80 -0
- package/dist/core/check-issues.js +67 -0
- package/dist/core/command-classification.js +22 -0
- package/dist/core/command-contract-rules.js +27 -0
- package/dist/core/command-contract-validation.js +197 -0
- package/dist/core/command-cwd.js +12 -0
- package/dist/core/command-effects.js +182 -0
- package/dist/core/command-explanation.js +135 -0
- package/dist/core/command-intent-eligibility.js +76 -0
- package/dist/core/config-loading.js +54 -0
- package/dist/core/contract-lint.js +110 -0
- package/dist/core/contract-models.js +53 -0
- package/dist/core/dashboard-verification.js +132 -0
- package/dist/core/doc-review-triage.js +92 -0
- package/dist/core/line-endings.js +144 -0
- package/dist/core/public-json-contracts.js +112 -0
- package/dist/core/public-surface-explanation.js +49 -0
- package/dist/core/release-version-validation.js +53 -0
- package/dist/core/retention-explanation.js +74 -0
- package/dist/core/retention-policy.js +57 -0
- package/dist/core/run-receipt.js +77 -0
- package/dist/core/skill-route-alignment.js +100 -0
- package/dist/core/skill-route-explanation.js +117 -0
- package/dist/core/source-anchor-explanation.js +33 -0
- package/dist/core/source-anchor-status.js +269 -0
- package/dist/core/source-anchor-symbols.js +181 -0
- package/dist/core/source-anchor-validation.js +158 -0
- package/dist/core/source-anchors.js +194 -0
- package/dist/core/surface-decision-model.js +18 -0
- package/dist/core/toml.js +11 -0
- package/dist/core/verification-plan.js +41 -0
- package/dist/core/verification-scheduler.js +92 -0
- package/dist/core/version-impact.js +54 -0
- package/dist/core/version-sources.js +235 -0
- package/dist/core/version-sync-policy.js +85 -0
- package/examples/README.md +13 -0
- package/examples/docs-only/README.md +72 -0
- package/examples/host-instruction-conflicts/README.md +47 -0
- package/examples/minimal-js/README.md +98 -0
- package/examples/missing-command-contracts/README.md +70 -0
- package/examples/nested-repos/README.md +62 -0
- package/package.json +80 -0
- package/schemas/README.md +32 -0
- package/schemas/change-verification-report.schema.json +319 -0
- package/schemas/classify-report.schema.json +113 -0
- package/schemas/commands.schema.json +116 -0
- package/schemas/context-report.schema.json +341 -0
- package/schemas/contract-lint-report.schema.json +61 -0
- package/schemas/docs-review-list.schema.json +72 -0
- package/schemas/doctor-report.schema.json +175 -0
- package/schemas/explain-report.schema.json +471 -0
- package/schemas/impact-report.schema.json +121 -0
- package/schemas/line-endings-report.schema.json +63 -0
- package/schemas/run-receipt.schema.json +75 -0
- package/schemas/verify-report.schema.json +67 -0
- package/schemas/version-sources-report.schema.json +42 -0
- package/templates/default/common/.mustflow/config/commands.toml +251 -0
- package/templates/default/common/.mustflow/config/mustflow.toml +424 -0
- package/templates/default/common/.mustflow/config/preferences.toml +125 -0
- package/templates/default/common/gitignore.mustflow +9 -0
- package/templates/default/i18n.toml +483 -0
- package/templates/default/locales/en/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/en/.mustflow/context/PROJECT.md +66 -0
- package/templates/default/locales/en/.mustflow/docs/agent-workflow.md +345 -0
- package/templates/default/locales/en/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/en/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/en/.mustflow/skills/artifact-integrity-check/SKILL.md +121 -0
- package/templates/default/locales/en/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/en/.mustflow/skills/code-review/SKILL.md +115 -0
- package/templates/default/locales/en/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/en/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/en/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/en/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/en/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/en/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/en/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/en/.mustflow/skills/diff-risk-review/SKILL.md +143 -0
- package/templates/default/locales/en/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/en/.mustflow/skills/docs-update/SKILL.md +100 -0
- package/templates/default/locales/en/.mustflow/skills/external-prompt-injection-defense/SKILL.md +124 -0
- package/templates/default/locales/en/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/en/.mustflow/skills/failure-triage/SKILL.md +97 -0
- package/templates/default/locales/en/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/en/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/en/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/en/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
- package/templates/default/locales/en/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/en/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/en/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/en/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/en/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/en/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/en/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/en/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/en/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/en/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/en/.mustflow/skills/security-privacy-review/SKILL.md +130 -0
- package/templates/default/locales/en/.mustflow/skills/security-regression-tests/SKILL.md +157 -0
- package/templates/default/locales/en/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/en/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/en/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/en/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/en/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/en/.mustflow/skills/test-maintenance/SKILL.md +122 -0
- package/templates/default/locales/en/.mustflow/skills/ui-quality-gate/SKILL.md +119 -0
- package/templates/default/locales/en/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/en/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/en/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/en/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/en/AGENTS.md +114 -0
- package/templates/default/locales/es/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/es/.mustflow/context/PROJECT.md +63 -0
- package/templates/default/locales/es/.mustflow/docs/agent-workflow.md +365 -0
- package/templates/default/locales/es/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/es/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/es/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
- package/templates/default/locales/es/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/es/.mustflow/skills/code-review/SKILL.md +115 -0
- package/templates/default/locales/es/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/es/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/es/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/es/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/es/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/es/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/es/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/es/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
- package/templates/default/locales/es/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/es/.mustflow/skills/docs-update/SKILL.md +97 -0
- package/templates/default/locales/es/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
- package/templates/default/locales/es/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/es/.mustflow/skills/failure-triage/SKILL.md +97 -0
- package/templates/default/locales/es/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/es/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/es/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/es/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
- package/templates/default/locales/es/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/es/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/es/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/es/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/es/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/es/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/es/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/es/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/es/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/es/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/es/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
- package/templates/default/locales/es/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
- package/templates/default/locales/es/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/es/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/es/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/es/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/es/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/es/.mustflow/skills/test-maintenance/SKILL.md +122 -0
- package/templates/default/locales/es/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
- package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/es/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/es/AGENTS.md +83 -0
- package/templates/default/locales/fr/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/fr/.mustflow/context/PROJECT.md +63 -0
- package/templates/default/locales/fr/.mustflow/docs/agent-workflow.md +368 -0
- package/templates/default/locales/fr/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/fr/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/fr/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
- package/templates/default/locales/fr/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/fr/.mustflow/skills/code-review/SKILL.md +115 -0
- package/templates/default/locales/fr/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/fr/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/fr/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/fr/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/fr/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/fr/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/fr/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/fr/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
- package/templates/default/locales/fr/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/fr/.mustflow/skills/docs-update/SKILL.md +97 -0
- package/templates/default/locales/fr/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
- package/templates/default/locales/fr/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/fr/.mustflow/skills/failure-triage/SKILL.md +97 -0
- package/templates/default/locales/fr/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/fr/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/fr/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/fr/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
- package/templates/default/locales/fr/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/fr/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/fr/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/fr/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/fr/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/fr/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/fr/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/fr/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/fr/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/fr/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/fr/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
- package/templates/default/locales/fr/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
- package/templates/default/locales/fr/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/fr/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/fr/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/fr/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/fr/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/fr/.mustflow/skills/test-maintenance/SKILL.md +122 -0
- package/templates/default/locales/fr/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
- package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/fr/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/fr/AGENTS.md +84 -0
- package/templates/default/locales/hi/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/hi/.mustflow/context/PROJECT.md +65 -0
- package/templates/default/locales/hi/.mustflow/docs/agent-workflow.md +359 -0
- package/templates/default/locales/hi/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/hi/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/hi/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
- package/templates/default/locales/hi/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/hi/.mustflow/skills/code-review/SKILL.md +115 -0
- package/templates/default/locales/hi/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/hi/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/hi/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/hi/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/hi/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/hi/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/hi/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/hi/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
- package/templates/default/locales/hi/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/hi/.mustflow/skills/docs-update/SKILL.md +97 -0
- package/templates/default/locales/hi/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
- package/templates/default/locales/hi/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/hi/.mustflow/skills/failure-triage/SKILL.md +97 -0
- package/templates/default/locales/hi/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/hi/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/hi/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/hi/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
- package/templates/default/locales/hi/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/hi/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/hi/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/hi/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/hi/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/hi/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/hi/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/hi/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/hi/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/hi/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/hi/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
- package/templates/default/locales/hi/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
- package/templates/default/locales/hi/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/hi/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/hi/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/hi/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/hi/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/hi/.mustflow/skills/test-maintenance/SKILL.md +122 -0
- package/templates/default/locales/hi/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
- package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/hi/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/hi/AGENTS.md +83 -0
- package/templates/default/locales/ko/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/ko/.mustflow/context/PROJECT.md +66 -0
- package/templates/default/locales/ko/.mustflow/docs/agent-workflow.md +506 -0
- package/templates/default/locales/ko/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/ko/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/ko/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
- package/templates/default/locales/ko/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/ko/.mustflow/skills/code-review/SKILL.md +118 -0
- package/templates/default/locales/ko/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/ko/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/ko/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/ko/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/ko/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/ko/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/ko/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/ko/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
- package/templates/default/locales/ko/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/ko/.mustflow/skills/docs-update/SKILL.md +107 -0
- package/templates/default/locales/ko/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
- package/templates/default/locales/ko/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/ko/.mustflow/skills/failure-triage/SKILL.md +119 -0
- package/templates/default/locales/ko/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/ko/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/ko/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/ko/.mustflow/skills/multi-agent-work-coordination/SKILL.md +259 -0
- package/templates/default/locales/ko/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/ko/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/ko/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/ko/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/ko/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/ko/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/ko/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/ko/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/ko/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/ko/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/ko/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
- package/templates/default/locales/ko/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
- package/templates/default/locales/ko/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/ko/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/ko/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/ko/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/ko/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/ko/.mustflow/skills/test-maintenance/SKILL.md +130 -0
- package/templates/default/locales/ko/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
- package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/ko/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/ko/AGENTS.md +85 -0
- package/templates/default/locales/zh/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/zh/.mustflow/context/PROJECT.md +64 -0
- package/templates/default/locales/zh/.mustflow/docs/agent-workflow.md +310 -0
- package/templates/default/locales/zh/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/zh/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/zh/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
- package/templates/default/locales/zh/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/zh/.mustflow/skills/code-review/SKILL.md +115 -0
- package/templates/default/locales/zh/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/zh/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/zh/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/zh/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/zh/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/zh/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/zh/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/zh/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
- package/templates/default/locales/zh/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/zh/.mustflow/skills/docs-update/SKILL.md +97 -0
- package/templates/default/locales/zh/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
- package/templates/default/locales/zh/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/zh/.mustflow/skills/failure-triage/SKILL.md +96 -0
- package/templates/default/locales/zh/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/zh/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/zh/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/zh/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
- package/templates/default/locales/zh/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/zh/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/zh/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/zh/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/zh/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/zh/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/zh/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/zh/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/zh/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/zh/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/zh/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
- package/templates/default/locales/zh/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
- package/templates/default/locales/zh/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/zh/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/zh/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/zh/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/zh/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/zh/.mustflow/skills/test-maintenance/SKILL.md +122 -0
- package/templates/default/locales/zh/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
- package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/zh/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/zh/AGENTS.md +86 -0
- package/templates/default/manifest.toml +339 -0
|
@@ -0,0 +1,1014 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { isRecord, readCommandContract, readString, readStringArray } from './command-contract.js';
|
|
6
|
+
import { listFilesRecursive, toPosixPath } from './filesystem.js';
|
|
7
|
+
import { readTomlFile } from './toml.js';
|
|
8
|
+
import { collectSourceAnchorIndexRecords, } from '../../core/source-anchor-status.js';
|
|
9
|
+
import { normalizeCommandEffects } from '../../core/command-effects.js';
|
|
10
|
+
const LOCAL_INDEX_SCHEMA_VERSION = '7';
|
|
11
|
+
const DEFAULT_DATABASE_RELATIVE_PATH = '.mustflow/cache/mustflow.sqlite';
|
|
12
|
+
const LOCAL_INDEX_CONTENT_MODE = 'metadata_and_snippets';
|
|
13
|
+
const LOCAL_INDEX_STORE_FULL_CONTENT = false;
|
|
14
|
+
const MAX_SNIPPET_BYTES_PER_DOCUMENT = 2048;
|
|
15
|
+
const MUSTFLOW_RELATIVE_PATH = '.mustflow/config/mustflow.toml';
|
|
16
|
+
const DEFAULT_PROMPT_CACHE_STABLE_READ = [
|
|
17
|
+
'AGENTS.md',
|
|
18
|
+
'.mustflow/docs/agent-workflow.md',
|
|
19
|
+
'.mustflow/config/mustflow.toml',
|
|
20
|
+
'.mustflow/config/commands.toml',
|
|
21
|
+
'.mustflow/skills/INDEX.md',
|
|
22
|
+
];
|
|
23
|
+
const DEFAULT_PROMPT_CACHE_TASK_SOURCES = [
|
|
24
|
+
'.mustflow/context/INDEX.md',
|
|
25
|
+
'REPO_MAP.md',
|
|
26
|
+
'matching_skill',
|
|
27
|
+
'relevant_source_files',
|
|
28
|
+
];
|
|
29
|
+
const DEFAULT_PROMPT_CACHE_VOLATILE_SOURCES = [
|
|
30
|
+
'.mustflow/state/runs/latest.json',
|
|
31
|
+
'changed_files',
|
|
32
|
+
'command_output_tail',
|
|
33
|
+
'current_user_task',
|
|
34
|
+
];
|
|
35
|
+
export function getLocalIndexDatabasePath(projectRoot) {
|
|
36
|
+
return path.join(projectRoot, ...DEFAULT_DATABASE_RELATIVE_PATH.split('/'));
|
|
37
|
+
}
|
|
38
|
+
function getExistingIndexablePaths(projectRoot) {
|
|
39
|
+
const paths = new Set();
|
|
40
|
+
const addIfExists = (relativePath) => {
|
|
41
|
+
if (existsSync(path.join(projectRoot, ...relativePath.split('/')))) {
|
|
42
|
+
paths.add(relativePath);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
addIfExists('AGENTS.md');
|
|
46
|
+
for (const relativePath of listFilesRecursive(path.join(projectRoot, '.mustflow', 'docs'))) {
|
|
47
|
+
if (relativePath.endsWith('.md')) {
|
|
48
|
+
paths.add(toPosixPath(path.join('.mustflow', 'docs', relativePath)));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const relativePath of listFilesRecursive(path.join(projectRoot, '.mustflow', 'context'))) {
|
|
52
|
+
if (relativePath.endsWith('.md')) {
|
|
53
|
+
paths.add(toPosixPath(path.join('.mustflow', 'context', relativePath)));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (const relativePath of listFilesRecursive(path.join(projectRoot, '.mustflow', 'skills'))) {
|
|
57
|
+
if (relativePath === 'INDEX.md' || relativePath.endsWith('/SKILL.md')) {
|
|
58
|
+
paths.add(toPosixPath(path.join('.mustflow', 'skills', relativePath)));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const relativePath of listFilesRecursive(path.join(projectRoot, '.mustflow', 'config'))) {
|
|
62
|
+
if (relativePath.endsWith('.toml')) {
|
|
63
|
+
paths.add(toPosixPath(path.join('.mustflow', 'config', relativePath)));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return Array.from(paths).sort((left, right) => left.localeCompare(right));
|
|
67
|
+
}
|
|
68
|
+
function readText(projectRoot, relativePath) {
|
|
69
|
+
return readFileSync(path.join(projectRoot, ...relativePath.split('/')), 'utf8');
|
|
70
|
+
}
|
|
71
|
+
function readMustflowToml(projectRoot) {
|
|
72
|
+
const mustflowPath = path.join(projectRoot, ...MUSTFLOW_RELATIVE_PATH.split('/'));
|
|
73
|
+
if (!existsSync(mustflowPath)) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
const parsed = readTomlFile(mustflowPath);
|
|
77
|
+
return isRecord(parsed) ? parsed : undefined;
|
|
78
|
+
}
|
|
79
|
+
function readNestedTable(table, key) {
|
|
80
|
+
if (!table || !isRecord(table[key])) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
return table[key];
|
|
84
|
+
}
|
|
85
|
+
function readOptionalStringArray(table, key) {
|
|
86
|
+
return table ? readStringArray(table, key) ?? null : null;
|
|
87
|
+
}
|
|
88
|
+
function sha256Text(content) {
|
|
89
|
+
return `sha256:${createHash('sha256').update(content).digest('hex')}`;
|
|
90
|
+
}
|
|
91
|
+
function getDocumentType(relativePath) {
|
|
92
|
+
if (relativePath === 'AGENTS.md') {
|
|
93
|
+
return 'agent_rules';
|
|
94
|
+
}
|
|
95
|
+
if (relativePath.startsWith('.mustflow/config/')) {
|
|
96
|
+
return 'config';
|
|
97
|
+
}
|
|
98
|
+
if (relativePath === '.mustflow/skills/INDEX.md') {
|
|
99
|
+
return 'skill_index';
|
|
100
|
+
}
|
|
101
|
+
if (relativePath === '.mustflow/context/INDEX.md') {
|
|
102
|
+
return 'context_index';
|
|
103
|
+
}
|
|
104
|
+
if (relativePath.startsWith('.mustflow/context/')) {
|
|
105
|
+
return 'context';
|
|
106
|
+
}
|
|
107
|
+
if (relativePath.endsWith('/SKILL.md')) {
|
|
108
|
+
return 'skill';
|
|
109
|
+
}
|
|
110
|
+
if (relativePath.startsWith('.mustflow/docs/')) {
|
|
111
|
+
return 'workflow_doc';
|
|
112
|
+
}
|
|
113
|
+
return 'document';
|
|
114
|
+
}
|
|
115
|
+
function parseFrontmatter(content) {
|
|
116
|
+
if (!content.startsWith('---')) {
|
|
117
|
+
return {};
|
|
118
|
+
}
|
|
119
|
+
const end = content.indexOf('\n---', 3);
|
|
120
|
+
if (end === -1) {
|
|
121
|
+
return {};
|
|
122
|
+
}
|
|
123
|
+
const result = {};
|
|
124
|
+
const rawFrontmatter = content.slice(3, end);
|
|
125
|
+
for (const line of rawFrontmatter.split(/\r?\n/)) {
|
|
126
|
+
const separatorIndex = line.indexOf(':');
|
|
127
|
+
if (separatorIndex === -1) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const key = line.slice(0, separatorIndex).trim();
|
|
131
|
+
const value = line.slice(separatorIndex + 1).trim();
|
|
132
|
+
if (key.length > 0 && value.length > 0) {
|
|
133
|
+
result[key] = value;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
function getTitle(relativePath, content) {
|
|
139
|
+
const heading = content.match(/^#\s+(.+)$/mu)?.[1]?.trim();
|
|
140
|
+
return heading && heading.length > 0 ? heading : path.posix.basename(relativePath);
|
|
141
|
+
}
|
|
142
|
+
function getSections(content) {
|
|
143
|
+
return [...content.matchAll(/^##\s+(.+)$/gmu)].map((match) => match[1]?.trim()).filter((value) => Boolean(value));
|
|
144
|
+
}
|
|
145
|
+
function truncateUtf8(value, maxBytes) {
|
|
146
|
+
const buffer = Buffer.from(value, 'utf8');
|
|
147
|
+
if (buffer.byteLength <= maxBytes) {
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
return buffer.subarray(0, maxBytes).toString('utf8').replace(/\uFFFD$/u, '');
|
|
151
|
+
}
|
|
152
|
+
function collectDocuments(projectRoot) {
|
|
153
|
+
return getExistingIndexablePaths(projectRoot).map((relativePath) => {
|
|
154
|
+
const content = readText(projectRoot, relativePath);
|
|
155
|
+
const frontmatter = parseFrontmatter(content);
|
|
156
|
+
const revision = Number.parseInt(frontmatter.revision ?? '', 10);
|
|
157
|
+
return {
|
|
158
|
+
path: relativePath,
|
|
159
|
+
type: getDocumentType(relativePath),
|
|
160
|
+
title: getTitle(relativePath, content),
|
|
161
|
+
locale: frontmatter.locale ?? null,
|
|
162
|
+
revision: Number.isInteger(revision) ? revision : null,
|
|
163
|
+
contentHash: sha256Text(content),
|
|
164
|
+
contentSnippet: truncateUtf8(content, MAX_SNIPPET_BYTES_PER_DOCUMENT),
|
|
165
|
+
sections: getSections(content),
|
|
166
|
+
};
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function collectSkills(documents) {
|
|
170
|
+
return documents
|
|
171
|
+
.filter((document) => document.type === 'skill')
|
|
172
|
+
.map((document) => ({
|
|
173
|
+
name: document.path.split('/').at(-2) ?? document.title,
|
|
174
|
+
path: document.path,
|
|
175
|
+
title: document.title,
|
|
176
|
+
}))
|
|
177
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
178
|
+
}
|
|
179
|
+
function normalizeMarkdownCell(value) {
|
|
180
|
+
return value
|
|
181
|
+
.replace(/<br\s*\/?>/giu, ' ')
|
|
182
|
+
.replace(/`([^`]+)`/gu, '$1')
|
|
183
|
+
.replace(/\s+/gu, ' ')
|
|
184
|
+
.trim();
|
|
185
|
+
}
|
|
186
|
+
function parseMarkdownTableRow(line) {
|
|
187
|
+
return line
|
|
188
|
+
.trim()
|
|
189
|
+
.replace(/^\|/u, '')
|
|
190
|
+
.replace(/\|$/u, '')
|
|
191
|
+
.split('|')
|
|
192
|
+
.map((cell) => normalizeMarkdownCell(cell));
|
|
193
|
+
}
|
|
194
|
+
function isMarkdownSeparatorRow(cells) {
|
|
195
|
+
return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/u.test(cell));
|
|
196
|
+
}
|
|
197
|
+
function skillNameFromPath(skillPath) {
|
|
198
|
+
return skillPath.split('/').at(-2) ?? path.posix.basename(skillPath, '.md');
|
|
199
|
+
}
|
|
200
|
+
function splitVerificationIntents(value) {
|
|
201
|
+
return value
|
|
202
|
+
.split(',')
|
|
203
|
+
.map((item) => item.trim())
|
|
204
|
+
.filter(Boolean)
|
|
205
|
+
.sort((left, right) => left.localeCompare(right));
|
|
206
|
+
}
|
|
207
|
+
function collectSkillRoutes(projectRoot) {
|
|
208
|
+
const indexPath = path.join(projectRoot, '.mustflow', 'skills', 'INDEX.md');
|
|
209
|
+
if (!existsSync(indexPath)) {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
const content = readFileSync(indexPath, 'utf8');
|
|
213
|
+
const routes = [];
|
|
214
|
+
let inRouteTable = false;
|
|
215
|
+
for (const line of content.split(/\r?\n/u)) {
|
|
216
|
+
if (!line.trim().startsWith('|')) {
|
|
217
|
+
if (inRouteTable && line.trim() === '') {
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const cells = parseMarkdownTableRow(line);
|
|
223
|
+
if (cells.includes('Skill Document') && cells.includes('Trigger')) {
|
|
224
|
+
inRouteTable = true;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (!inRouteTable || isMarkdownSeparatorRow(cells) || cells.length < 7) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const [trigger, skillPath, requiredInput, editScope, risk, verificationIntents, expectedOutput] = cells;
|
|
231
|
+
if (!skillPath?.startsWith('.mustflow/skills/') || !skillPath.endsWith('/SKILL.md')) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
routes.push({
|
|
235
|
+
skillName: skillNameFromPath(skillPath),
|
|
236
|
+
skillPath,
|
|
237
|
+
trigger: trigger ?? '',
|
|
238
|
+
requiredInput: requiredInput ?? '',
|
|
239
|
+
editScope: editScope ?? '',
|
|
240
|
+
risk: risk ?? '',
|
|
241
|
+
verificationIntents: splitVerificationIntents(verificationIntents ?? ''),
|
|
242
|
+
expectedOutput: expectedOutput ?? '',
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return routes.sort((left, right) => {
|
|
246
|
+
const skillOrder = left.skillName.localeCompare(right.skillName);
|
|
247
|
+
return skillOrder === 0 ? left.trigger.localeCompare(right.trigger) : skillOrder;
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
function collectCommandIntents(projectRoot) {
|
|
251
|
+
if (!existsSync(path.join(projectRoot, '.mustflow', 'config', 'commands.toml'))) {
|
|
252
|
+
return [];
|
|
253
|
+
}
|
|
254
|
+
const contract = readCommandContract(projectRoot);
|
|
255
|
+
const intents = [];
|
|
256
|
+
for (const [name, intent] of Object.entries(contract.intents).sort(([left], [right]) => left.localeCompare(right))) {
|
|
257
|
+
if (!isRecord(intent)) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
intents.push({
|
|
261
|
+
name,
|
|
262
|
+
status: readString(intent, 'status') ?? 'unknown',
|
|
263
|
+
lifecycle: readString(intent, 'lifecycle') ?? null,
|
|
264
|
+
runPolicy: readString(intent, 'run_policy') ?? null,
|
|
265
|
+
description: readString(intent, 'description') ?? null,
|
|
266
|
+
effects: normalizeCommandEffects(projectRoot, contract, name),
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
return intents;
|
|
270
|
+
}
|
|
271
|
+
async function loadSqlJs() {
|
|
272
|
+
const require = createRequire(import.meta.url);
|
|
273
|
+
const wasmPath = require.resolve('sql.js/dist/sql-wasm.wasm');
|
|
274
|
+
const sqlJsModule = (await import('sql.js'));
|
|
275
|
+
const initSqlJs = typeof sqlJsModule === 'function' ? sqlJsModule : sqlJsModule.default;
|
|
276
|
+
if (!initSqlJs) {
|
|
277
|
+
throw new Error('Unable to load sql.js');
|
|
278
|
+
}
|
|
279
|
+
return initSqlJs({
|
|
280
|
+
locateFile(fileName) {
|
|
281
|
+
return fileName.endsWith('.wasm') ? wasmPath : fileName;
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
function normalizeSearchText(value) {
|
|
286
|
+
return value.trim().replace(/\s+/g, ' ');
|
|
287
|
+
}
|
|
288
|
+
function toSearchString(value) {
|
|
289
|
+
if (value === null || value === undefined) {
|
|
290
|
+
return '';
|
|
291
|
+
}
|
|
292
|
+
if (value instanceof Uint8Array) {
|
|
293
|
+
return '';
|
|
294
|
+
}
|
|
295
|
+
return String(value);
|
|
296
|
+
}
|
|
297
|
+
function queryRows(database, sql, params = []) {
|
|
298
|
+
const [result] = database.exec(sql, params);
|
|
299
|
+
if (!result) {
|
|
300
|
+
return [];
|
|
301
|
+
}
|
|
302
|
+
return result.values.map((values) => {
|
|
303
|
+
const row = {};
|
|
304
|
+
result.columns.forEach((column, index) => {
|
|
305
|
+
row[column] = values[index] ?? null;
|
|
306
|
+
});
|
|
307
|
+
return row;
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
function toNullableNumber(value) {
|
|
311
|
+
if (typeof value !== 'number') {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
return Number.isFinite(value) ? value : null;
|
|
315
|
+
}
|
|
316
|
+
async function readPreviousSourceAnchorSnapshots(databasePath) {
|
|
317
|
+
if (!existsSync(databasePath)) {
|
|
318
|
+
return [];
|
|
319
|
+
}
|
|
320
|
+
const SQL = await loadSqlJs();
|
|
321
|
+
const database = new SQL.Database(readFileSync(databasePath));
|
|
322
|
+
try {
|
|
323
|
+
const rows = queryRows(database, `
|
|
324
|
+
SELECT
|
|
325
|
+
source_anchors.id,
|
|
326
|
+
source_anchors.path,
|
|
327
|
+
source_anchors.line_start,
|
|
328
|
+
source_anchors.purpose,
|
|
329
|
+
source_anchors.search_terms,
|
|
330
|
+
source_anchors.invariant,
|
|
331
|
+
source_anchors.risk,
|
|
332
|
+
source_anchor_fingerprints.anchor_metadata_hash,
|
|
333
|
+
source_anchor_fingerprints.anchor_text_hash,
|
|
334
|
+
source_anchor_fingerprints.context_hash,
|
|
335
|
+
source_anchor_fingerprints.search_terms_hash,
|
|
336
|
+
source_anchor_fingerprints.invariant_hash,
|
|
337
|
+
source_anchor_fingerprints.risk_hash,
|
|
338
|
+
source_anchor_fingerprints.symbol_kind,
|
|
339
|
+
source_anchor_fingerprints.symbol_name,
|
|
340
|
+
source_anchor_fingerprints.symbol_exported,
|
|
341
|
+
source_anchor_fingerprints.signature_hash,
|
|
342
|
+
source_anchor_fingerprints.body_hash,
|
|
343
|
+
source_anchor_fingerprints.symbol_start_line,
|
|
344
|
+
source_anchor_fingerprints.symbol_end_line
|
|
345
|
+
FROM source_anchors
|
|
346
|
+
JOIN source_anchor_fingerprints ON source_anchor_fingerprints.anchor_id = source_anchors.id
|
|
347
|
+
`);
|
|
348
|
+
return rows.map((row) => {
|
|
349
|
+
const symbol = {
|
|
350
|
+
kind: toSearchString(row.symbol_kind),
|
|
351
|
+
name: toSearchString(row.symbol_name) || null,
|
|
352
|
+
exported: Number(row.symbol_exported) === 1,
|
|
353
|
+
signatureHash: toSearchString(row.signature_hash) || null,
|
|
354
|
+
bodyHash: toSearchString(row.body_hash) || null,
|
|
355
|
+
startLine: toNullableNumber(row.symbol_start_line),
|
|
356
|
+
endLine: toNullableNumber(row.symbol_end_line),
|
|
357
|
+
};
|
|
358
|
+
return {
|
|
359
|
+
id: toSearchString(row.id),
|
|
360
|
+
path: toSearchString(row.path),
|
|
361
|
+
lineStart: Number(row.line_start),
|
|
362
|
+
purpose: toSearchString(row.purpose) || null,
|
|
363
|
+
search: toSearchString(row.search_terms)
|
|
364
|
+
.split(/[,;]/u)
|
|
365
|
+
.map((value) => value.trim())
|
|
366
|
+
.filter((value) => value.length > 0),
|
|
367
|
+
invariant: toSearchString(row.invariant) || null,
|
|
368
|
+
risk: toSearchString(row.risk)
|
|
369
|
+
.split(/[,;]/u)
|
|
370
|
+
.map((value) => value.trim())
|
|
371
|
+
.filter((value) => value.length > 0),
|
|
372
|
+
navigationOnly: true,
|
|
373
|
+
canInstructAgent: false,
|
|
374
|
+
fingerprint: {
|
|
375
|
+
anchorMetadataHash: toSearchString(row.anchor_metadata_hash),
|
|
376
|
+
anchorTextHash: toSearchString(row.anchor_text_hash),
|
|
377
|
+
contextHash: toSearchString(row.context_hash),
|
|
378
|
+
searchTermsHash: toSearchString(row.search_terms_hash) || null,
|
|
379
|
+
invariantHash: toSearchString(row.invariant_hash) || null,
|
|
380
|
+
riskHash: toSearchString(row.risk_hash),
|
|
381
|
+
symbol,
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
return [];
|
|
388
|
+
}
|
|
389
|
+
finally {
|
|
390
|
+
database.close();
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function readCacheLayerSets(projectRoot) {
|
|
394
|
+
const mustflow = readMustflowToml(projectRoot);
|
|
395
|
+
const promptCache = readNestedTable(mustflow, 'prompt_cache');
|
|
396
|
+
const layers = readNestedTable(promptCache, 'layers');
|
|
397
|
+
const stable = readNestedTable(layers, 'stable');
|
|
398
|
+
const task = readNestedTable(layers, 'task');
|
|
399
|
+
const volatile = readNestedTable(layers, 'volatile');
|
|
400
|
+
const normalize = (values) => new Set(values.map((value) => toPosixPath(value)));
|
|
401
|
+
return {
|
|
402
|
+
stable: normalize(readOptionalStringArray(stable, 'read') ?? [...DEFAULT_PROMPT_CACHE_STABLE_READ]),
|
|
403
|
+
task: normalize(readOptionalStringArray(task, 'sources') ?? [...DEFAULT_PROMPT_CACHE_TASK_SOURCES]),
|
|
404
|
+
volatile: normalize(readOptionalStringArray(volatile, 'sources') ?? [...DEFAULT_PROMPT_CACHE_VOLATILE_SOURCES]),
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
function inferCacheLayer(relativePath, kind, cacheLayers) {
|
|
408
|
+
const normalized = relativePath ? toPosixPath(relativePath) : null;
|
|
409
|
+
if (normalized && cacheLayers.volatile.has(normalized)) {
|
|
410
|
+
return 'volatile';
|
|
411
|
+
}
|
|
412
|
+
if (normalized && cacheLayers.stable.has(normalized)) {
|
|
413
|
+
return 'stable';
|
|
414
|
+
}
|
|
415
|
+
if (kind === 'command_intent' && cacheLayers.stable.has('.mustflow/config/commands.toml')) {
|
|
416
|
+
return 'stable';
|
|
417
|
+
}
|
|
418
|
+
if (normalized &&
|
|
419
|
+
(cacheLayers.task.has(normalized) || normalized.startsWith('.mustflow/context/') || normalized.endsWith('/SKILL.md'))) {
|
|
420
|
+
return 'task';
|
|
421
|
+
}
|
|
422
|
+
if (normalized?.startsWith('.mustflow/state/') || normalized?.startsWith('.mustflow/cache/')) {
|
|
423
|
+
return 'volatile';
|
|
424
|
+
}
|
|
425
|
+
return 'task';
|
|
426
|
+
}
|
|
427
|
+
function withCacheHint(item, cacheLayers) {
|
|
428
|
+
const layer = inferCacheLayer(item.path ?? null, item.kind, cacheLayers);
|
|
429
|
+
return {
|
|
430
|
+
...item,
|
|
431
|
+
cache_layer: layer,
|
|
432
|
+
volatile: layer === 'volatile',
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
function workflowAuthorityForDocument(documentType) {
|
|
436
|
+
if (documentType === 'agent_rules' || documentType === 'config' || documentType === 'workflow_doc') {
|
|
437
|
+
return {
|
|
438
|
+
authority_rank: 2,
|
|
439
|
+
authority_label: 'workflow_authority',
|
|
440
|
+
source_scope: 'workflow',
|
|
441
|
+
navigation_only: false,
|
|
442
|
+
can_instruct_agent: true,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
return {
|
|
446
|
+
authority_rank: 4,
|
|
447
|
+
authority_label: 'workflow_context',
|
|
448
|
+
source_scope: 'workflow',
|
|
449
|
+
navigation_only: false,
|
|
450
|
+
can_instruct_agent: false,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
function skillAuthority() {
|
|
454
|
+
return {
|
|
455
|
+
authority_rank: 3,
|
|
456
|
+
authority_label: 'skill_procedure',
|
|
457
|
+
source_scope: 'workflow',
|
|
458
|
+
navigation_only: false,
|
|
459
|
+
can_instruct_agent: true,
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function commandIntentAuthority() {
|
|
463
|
+
return {
|
|
464
|
+
authority_rank: 1,
|
|
465
|
+
authority_label: 'command_contract',
|
|
466
|
+
source_scope: 'workflow',
|
|
467
|
+
navigation_only: false,
|
|
468
|
+
can_instruct_agent: true,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
function sourceAnchorAuthority() {
|
|
472
|
+
return {
|
|
473
|
+
authority_rank: 5,
|
|
474
|
+
authority_label: 'source_navigation_hint',
|
|
475
|
+
source_scope: 'source',
|
|
476
|
+
navigation_only: true,
|
|
477
|
+
can_instruct_agent: false,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
function getMatchSnippet(fields, query) {
|
|
481
|
+
const normalized = normalizeSearchText(fields.join(' '));
|
|
482
|
+
const lower = normalized.toLowerCase();
|
|
483
|
+
const start = lower.indexOf(query.toLowerCase());
|
|
484
|
+
if (start === -1) {
|
|
485
|
+
return normalized.slice(0, 160);
|
|
486
|
+
}
|
|
487
|
+
const from = Math.max(0, start - 48);
|
|
488
|
+
const to = Math.min(normalized.length, start + query.length + 96);
|
|
489
|
+
const prefix = from > 0 ? '...' : '';
|
|
490
|
+
const suffix = to < normalized.length ? '...' : '';
|
|
491
|
+
return `${prefix}${normalized.slice(from, to)}${suffix}`;
|
|
492
|
+
}
|
|
493
|
+
function scoreMatch(primaryFields, secondaryFields, query) {
|
|
494
|
+
const lowerQuery = query.toLowerCase();
|
|
495
|
+
if (primaryFields.some((field) => field.toLowerCase() === lowerQuery)) {
|
|
496
|
+
return 100;
|
|
497
|
+
}
|
|
498
|
+
if (primaryFields.some((field) => field.toLowerCase().includes(lowerQuery))) {
|
|
499
|
+
return 80;
|
|
500
|
+
}
|
|
501
|
+
if (secondaryFields.some((field) => field.toLowerCase().includes(lowerQuery))) {
|
|
502
|
+
return 40;
|
|
503
|
+
}
|
|
504
|
+
return 0;
|
|
505
|
+
}
|
|
506
|
+
function isMatched(fields, query) {
|
|
507
|
+
const lowerQuery = query.toLowerCase();
|
|
508
|
+
return fields.some((field) => field.toLowerCase().includes(lowerQuery));
|
|
509
|
+
}
|
|
510
|
+
function createSchema(database) {
|
|
511
|
+
database.run(`
|
|
512
|
+
CREATE TABLE metadata (
|
|
513
|
+
key TEXT PRIMARY KEY,
|
|
514
|
+
value TEXT NOT NULL
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
CREATE TABLE documents (
|
|
518
|
+
path TEXT PRIMARY KEY,
|
|
519
|
+
type TEXT NOT NULL,
|
|
520
|
+
title TEXT NOT NULL,
|
|
521
|
+
locale TEXT,
|
|
522
|
+
revision INTEGER,
|
|
523
|
+
content_hash TEXT NOT NULL,
|
|
524
|
+
content_snippet TEXT NOT NULL
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
CREATE TABLE sections (
|
|
528
|
+
document_path TEXT NOT NULL,
|
|
529
|
+
ordinal INTEGER NOT NULL,
|
|
530
|
+
heading TEXT NOT NULL,
|
|
531
|
+
PRIMARY KEY (document_path, ordinal)
|
|
532
|
+
);
|
|
533
|
+
|
|
534
|
+
CREATE TABLE document_terms (
|
|
535
|
+
document_path TEXT NOT NULL,
|
|
536
|
+
term TEXT NOT NULL,
|
|
537
|
+
source TEXT NOT NULL,
|
|
538
|
+
PRIMARY KEY (document_path, term, source)
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
CREATE TABLE skills (
|
|
542
|
+
name TEXT PRIMARY KEY,
|
|
543
|
+
path TEXT NOT NULL,
|
|
544
|
+
title TEXT NOT NULL
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
CREATE TABLE skill_routes (
|
|
548
|
+
skill_name TEXT NOT NULL,
|
|
549
|
+
skill_path TEXT NOT NULL,
|
|
550
|
+
trigger TEXT NOT NULL,
|
|
551
|
+
required_input TEXT NOT NULL,
|
|
552
|
+
edit_scope TEXT NOT NULL,
|
|
553
|
+
risk TEXT NOT NULL,
|
|
554
|
+
verification_intents TEXT NOT NULL,
|
|
555
|
+
expected_output TEXT NOT NULL,
|
|
556
|
+
PRIMARY KEY (skill_name, trigger)
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
CREATE TABLE command_intents (
|
|
560
|
+
name TEXT PRIMARY KEY,
|
|
561
|
+
status TEXT NOT NULL,
|
|
562
|
+
lifecycle TEXT,
|
|
563
|
+
run_policy TEXT,
|
|
564
|
+
description TEXT
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
CREATE TABLE command_effects (
|
|
568
|
+
intent TEXT NOT NULL,
|
|
569
|
+
source TEXT NOT NULL,
|
|
570
|
+
access TEXT NOT NULL,
|
|
571
|
+
mode TEXT NOT NULL,
|
|
572
|
+
path TEXT NOT NULL,
|
|
573
|
+
lock TEXT NOT NULL,
|
|
574
|
+
concurrency TEXT NOT NULL,
|
|
575
|
+
PRIMARY KEY (intent, source, access, mode, path, lock, concurrency)
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
CREATE TABLE source_anchors (
|
|
579
|
+
id TEXT PRIMARY KEY,
|
|
580
|
+
path TEXT NOT NULL,
|
|
581
|
+
line_start INTEGER NOT NULL,
|
|
582
|
+
purpose TEXT,
|
|
583
|
+
search_terms TEXT NOT NULL,
|
|
584
|
+
invariant TEXT,
|
|
585
|
+
risk TEXT NOT NULL,
|
|
586
|
+
navigation_only INTEGER NOT NULL,
|
|
587
|
+
can_instruct_agent INTEGER NOT NULL
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
CREATE TABLE source_anchor_fingerprints (
|
|
591
|
+
anchor_id TEXT PRIMARY KEY,
|
|
592
|
+
path TEXT NOT NULL,
|
|
593
|
+
line_start INTEGER NOT NULL,
|
|
594
|
+
anchor_metadata_hash TEXT NOT NULL,
|
|
595
|
+
anchor_text_hash TEXT NOT NULL,
|
|
596
|
+
context_hash TEXT NOT NULL,
|
|
597
|
+
search_terms_hash TEXT,
|
|
598
|
+
invariant_hash TEXT,
|
|
599
|
+
risk_hash TEXT NOT NULL,
|
|
600
|
+
symbol_kind TEXT NOT NULL,
|
|
601
|
+
symbol_name TEXT,
|
|
602
|
+
symbol_exported INTEGER NOT NULL,
|
|
603
|
+
signature_hash TEXT,
|
|
604
|
+
body_hash TEXT,
|
|
605
|
+
symbol_start_line INTEGER,
|
|
606
|
+
symbol_end_line INTEGER
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
CREATE TABLE source_anchor_status (
|
|
610
|
+
anchor_id TEXT PRIMARY KEY,
|
|
611
|
+
status TEXT NOT NULL,
|
|
612
|
+
confidence REAL NOT NULL,
|
|
613
|
+
identity_signal TEXT NOT NULL,
|
|
614
|
+
location_signal TEXT NOT NULL,
|
|
615
|
+
symbol_signal TEXT NOT NULL,
|
|
616
|
+
body_signal TEXT NOT NULL,
|
|
617
|
+
metadata_signal TEXT NOT NULL,
|
|
618
|
+
semantic_signal TEXT NOT NULL,
|
|
619
|
+
risk_signal TEXT NOT NULL,
|
|
620
|
+
navigation_only INTEGER NOT NULL,
|
|
621
|
+
can_instruct_agent INTEGER NOT NULL
|
|
622
|
+
);
|
|
623
|
+
`);
|
|
624
|
+
}
|
|
625
|
+
function insertDocumentTerm(database, documentPath, term, source) {
|
|
626
|
+
const normalized = normalizeSearchText(term ?? '');
|
|
627
|
+
if (normalized.length === 0) {
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
database.run('INSERT OR IGNORE INTO document_terms (document_path, term, source) VALUES (?, ?, ?)', [
|
|
631
|
+
documentPath,
|
|
632
|
+
normalized,
|
|
633
|
+
source,
|
|
634
|
+
]);
|
|
635
|
+
}
|
|
636
|
+
function populateDatabase(database, documents, skills, skillRoutes, commandIntents, sourceAnchors) {
|
|
637
|
+
database.run('INSERT INTO metadata (key, value) VALUES (?, ?)', ['schema_version', LOCAL_INDEX_SCHEMA_VERSION]);
|
|
638
|
+
database.run('INSERT INTO metadata (key, value) VALUES (?, ?)', ['content_mode', LOCAL_INDEX_CONTENT_MODE]);
|
|
639
|
+
database.run('INSERT INTO metadata (key, value) VALUES (?, ?)', [
|
|
640
|
+
'store_full_content',
|
|
641
|
+
String(LOCAL_INDEX_STORE_FULL_CONTENT),
|
|
642
|
+
]);
|
|
643
|
+
database.run('INSERT INTO metadata (key, value) VALUES (?, ?)', [
|
|
644
|
+
'max_snippet_bytes_per_document',
|
|
645
|
+
String(MAX_SNIPPET_BYTES_PER_DOCUMENT),
|
|
646
|
+
]);
|
|
647
|
+
for (const document of documents) {
|
|
648
|
+
database.run('INSERT INTO documents (path, type, title, locale, revision, content_hash, content_snippet) VALUES (?, ?, ?, ?, ?, ?, ?)', [
|
|
649
|
+
document.path,
|
|
650
|
+
document.type,
|
|
651
|
+
document.title,
|
|
652
|
+
document.locale,
|
|
653
|
+
document.revision,
|
|
654
|
+
document.contentHash,
|
|
655
|
+
document.contentSnippet,
|
|
656
|
+
]);
|
|
657
|
+
document.sections.forEach((heading, index) => {
|
|
658
|
+
database.run('INSERT INTO sections (document_path, ordinal, heading) VALUES (?, ?, ?)', [
|
|
659
|
+
document.path,
|
|
660
|
+
index + 1,
|
|
661
|
+
heading,
|
|
662
|
+
]);
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
for (const skill of skills) {
|
|
666
|
+
database.run('INSERT INTO skills (name, path, title) VALUES (?, ?, ?)', [skill.name, skill.path, skill.title]);
|
|
667
|
+
}
|
|
668
|
+
for (const route of skillRoutes) {
|
|
669
|
+
const verificationIntents = route.verificationIntents.join(', ');
|
|
670
|
+
database.run('INSERT INTO skill_routes (skill_name, skill_path, trigger, required_input, edit_scope, risk, verification_intents, expected_output) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [
|
|
671
|
+
route.skillName,
|
|
672
|
+
route.skillPath,
|
|
673
|
+
route.trigger,
|
|
674
|
+
route.requiredInput,
|
|
675
|
+
route.editScope,
|
|
676
|
+
route.risk,
|
|
677
|
+
verificationIntents,
|
|
678
|
+
route.expectedOutput,
|
|
679
|
+
]);
|
|
680
|
+
insertDocumentTerm(database, '.mustflow/skills/INDEX.md', route.skillName, 'skill_route_name');
|
|
681
|
+
insertDocumentTerm(database, '.mustflow/skills/INDEX.md', route.trigger, 'skill_route_trigger');
|
|
682
|
+
insertDocumentTerm(database, '.mustflow/skills/INDEX.md', route.risk, 'skill_route_risk');
|
|
683
|
+
insertDocumentTerm(database, '.mustflow/skills/INDEX.md', route.requiredInput, 'skill_route_required_input');
|
|
684
|
+
insertDocumentTerm(database, '.mustflow/skills/INDEX.md', route.editScope, 'skill_route_edit_scope');
|
|
685
|
+
insertDocumentTerm(database, '.mustflow/skills/INDEX.md', verificationIntents, 'skill_route_verification_intents');
|
|
686
|
+
}
|
|
687
|
+
for (const intent of commandIntents) {
|
|
688
|
+
database.run('INSERT INTO command_intents (name, status, lifecycle, run_policy, description) VALUES (?, ?, ?, ?, ?)', [intent.name, intent.status, intent.lifecycle, intent.runPolicy, intent.description]);
|
|
689
|
+
insertDocumentTerm(database, '.mustflow/config/commands.toml', intent.name, 'command_intent');
|
|
690
|
+
insertDocumentTerm(database, '.mustflow/config/commands.toml', intent.status, 'command_status');
|
|
691
|
+
insertDocumentTerm(database, '.mustflow/config/commands.toml', intent.lifecycle, 'command_lifecycle');
|
|
692
|
+
insertDocumentTerm(database, '.mustflow/config/commands.toml', intent.runPolicy, 'command_run_policy');
|
|
693
|
+
insertDocumentTerm(database, '.mustflow/config/commands.toml', intent.description, 'command_description');
|
|
694
|
+
for (const effect of intent.effects) {
|
|
695
|
+
database.run('INSERT INTO command_effects (intent, source, access, mode, path, lock, concurrency) VALUES (?, ?, ?, ?, ?, ?, ?)', [effect.intent, effect.source, effect.access, effect.mode, effect.path, effect.lock, effect.concurrency]);
|
|
696
|
+
insertDocumentTerm(database, '.mustflow/config/commands.toml', effect.path, 'command_effect_path');
|
|
697
|
+
insertDocumentTerm(database, '.mustflow/config/commands.toml', effect.lock, 'command_effect_lock');
|
|
698
|
+
insertDocumentTerm(database, '.mustflow/config/commands.toml', effect.mode, 'command_effect_mode');
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
for (const anchor of sourceAnchors) {
|
|
702
|
+
database.run('INSERT INTO source_anchors (id, path, line_start, purpose, search_terms, invariant, risk, navigation_only, can_instruct_agent) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', [
|
|
703
|
+
anchor.id,
|
|
704
|
+
anchor.path,
|
|
705
|
+
anchor.lineStart,
|
|
706
|
+
anchor.purpose,
|
|
707
|
+
anchor.search.join(', '),
|
|
708
|
+
anchor.invariant,
|
|
709
|
+
anchor.risk.join(', '),
|
|
710
|
+
anchor.navigationOnly ? 1 : 0,
|
|
711
|
+
anchor.canInstructAgent ? 1 : 0,
|
|
712
|
+
]);
|
|
713
|
+
database.run('INSERT INTO source_anchor_fingerprints (anchor_id, path, line_start, anchor_metadata_hash, anchor_text_hash, context_hash, search_terms_hash, invariant_hash, risk_hash, symbol_kind, symbol_name, symbol_exported, signature_hash, body_hash, symbol_start_line, symbol_end_line) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [
|
|
714
|
+
anchor.id,
|
|
715
|
+
anchor.path,
|
|
716
|
+
anchor.lineStart,
|
|
717
|
+
anchor.fingerprint.anchorMetadataHash,
|
|
718
|
+
anchor.fingerprint.anchorTextHash,
|
|
719
|
+
anchor.fingerprint.contextHash,
|
|
720
|
+
anchor.fingerprint.searchTermsHash,
|
|
721
|
+
anchor.fingerprint.invariantHash,
|
|
722
|
+
anchor.fingerprint.riskHash,
|
|
723
|
+
anchor.fingerprint.symbol.kind,
|
|
724
|
+
anchor.fingerprint.symbol.name,
|
|
725
|
+
anchor.fingerprint.symbol.exported ? 1 : 0,
|
|
726
|
+
anchor.fingerprint.symbol.signatureHash,
|
|
727
|
+
anchor.fingerprint.symbol.bodyHash,
|
|
728
|
+
anchor.fingerprint.symbol.startLine,
|
|
729
|
+
anchor.fingerprint.symbol.endLine,
|
|
730
|
+
]);
|
|
731
|
+
database.run('INSERT INTO source_anchor_status (anchor_id, status, confidence, identity_signal, location_signal, symbol_signal, body_signal, metadata_signal, semantic_signal, risk_signal, navigation_only, can_instruct_agent) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [
|
|
732
|
+
anchor.id,
|
|
733
|
+
anchor.status,
|
|
734
|
+
anchor.confidence,
|
|
735
|
+
anchor.signals.identity,
|
|
736
|
+
anchor.signals.location,
|
|
737
|
+
anchor.signals.symbol,
|
|
738
|
+
anchor.signals.body,
|
|
739
|
+
anchor.signals.metadata,
|
|
740
|
+
anchor.signals.semantic,
|
|
741
|
+
anchor.signals.risk,
|
|
742
|
+
anchor.navigationOnly ? 1 : 0,
|
|
743
|
+
anchor.canInstructAgent ? 1 : 0,
|
|
744
|
+
]);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* mf:anchor cli.index.create
|
|
749
|
+
* purpose: Build the local SQLite index for workflow documents and optional source anchors.
|
|
750
|
+
* search: mf index, local index, sqlite, source anchors, workflow documents
|
|
751
|
+
* invariant: Source anchors are indexed only when source indexing is explicitly requested.
|
|
752
|
+
* risk: cache, config
|
|
753
|
+
*/
|
|
754
|
+
export async function createLocalIndex(projectRoot, options = {}) {
|
|
755
|
+
const databasePath = getLocalIndexDatabasePath(projectRoot);
|
|
756
|
+
const documents = collectDocuments(projectRoot);
|
|
757
|
+
const skills = collectSkills(documents);
|
|
758
|
+
const skillRoutes = collectSkillRoutes(projectRoot);
|
|
759
|
+
const commandIntents = collectCommandIntents(projectRoot);
|
|
760
|
+
const includeSource = options.includeSource === true;
|
|
761
|
+
const previousSourceAnchors = includeSource ? await readPreviousSourceAnchorSnapshots(databasePath) : [];
|
|
762
|
+
const sourceAnchors = includeSource ? collectSourceAnchorIndexRecords(projectRoot, previousSourceAnchors) : [];
|
|
763
|
+
const dryRun = options.dryRun === true;
|
|
764
|
+
if (!dryRun) {
|
|
765
|
+
const SQL = await loadSqlJs();
|
|
766
|
+
const database = new SQL.Database();
|
|
767
|
+
createSchema(database);
|
|
768
|
+
populateDatabase(database, documents, skills, skillRoutes, commandIntents, sourceAnchors);
|
|
769
|
+
mkdirSync(path.dirname(databasePath), { recursive: true });
|
|
770
|
+
writeFileSync(databasePath, database.export());
|
|
771
|
+
database.close();
|
|
772
|
+
}
|
|
773
|
+
return {
|
|
774
|
+
schema_version: LOCAL_INDEX_SCHEMA_VERSION,
|
|
775
|
+
command: 'index',
|
|
776
|
+
ok: true,
|
|
777
|
+
mustflow_root: path.resolve(projectRoot),
|
|
778
|
+
database_path: databasePath,
|
|
779
|
+
dry_run: dryRun,
|
|
780
|
+
wrote_files: !dryRun,
|
|
781
|
+
document_count: documents.length,
|
|
782
|
+
skill_count: skills.length,
|
|
783
|
+
skill_route_count: skillRoutes.length,
|
|
784
|
+
command_intent_count: commandIntents.length,
|
|
785
|
+
command_effect_count: commandIntents.reduce((count, intent) => count + intent.effects.length, 0),
|
|
786
|
+
source_index_enabled: includeSource,
|
|
787
|
+
source_anchor_count: sourceAnchors.length,
|
|
788
|
+
content_mode: LOCAL_INDEX_CONTENT_MODE,
|
|
789
|
+
store_full_content: LOCAL_INDEX_STORE_FULL_CONTENT,
|
|
790
|
+
max_snippet_bytes_per_document: MAX_SNIPPET_BYTES_PER_DOCUMENT,
|
|
791
|
+
indexed_paths: documents.map((document) => document.path),
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
function readStoredSchemaVersion(database) {
|
|
795
|
+
return toSearchString(queryRows(database, 'SELECT value FROM metadata WHERE key = "schema_version"')[0]?.value) || undefined;
|
|
796
|
+
}
|
|
797
|
+
function getStalePaths(projectRoot, database) {
|
|
798
|
+
const schemaVersion = readStoredSchemaVersion(database);
|
|
799
|
+
if (schemaVersion !== LOCAL_INDEX_SCHEMA_VERSION) {
|
|
800
|
+
return ['.mustflow/cache/mustflow.sqlite'];
|
|
801
|
+
}
|
|
802
|
+
const indexedRows = queryRows(database, 'SELECT path, content_hash FROM documents');
|
|
803
|
+
const indexedHashes = new Map(indexedRows.map((row) => [toSearchString(row.path), toSearchString(row.content_hash)]));
|
|
804
|
+
const currentDocuments = collectDocuments(projectRoot);
|
|
805
|
+
const currentHashes = new Map(currentDocuments.map((document) => [document.path, document.contentHash]));
|
|
806
|
+
const stalePaths = new Set();
|
|
807
|
+
for (const [indexedPath, indexedHash] of indexedHashes) {
|
|
808
|
+
if (currentHashes.get(indexedPath) !== indexedHash) {
|
|
809
|
+
stalePaths.add(indexedPath);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
for (const currentPath of currentHashes.keys()) {
|
|
813
|
+
if (!indexedHashes.has(currentPath)) {
|
|
814
|
+
stalePaths.add(currentPath);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
return Array.from(stalePaths).sort((left, right) => left.localeCompare(right));
|
|
818
|
+
}
|
|
819
|
+
function getSectionHeadings(database, documentPath) {
|
|
820
|
+
return queryRows(database, 'SELECT heading FROM sections WHERE document_path = ? ORDER BY ordinal', [documentPath]).map((row) => toSearchString(row.heading));
|
|
821
|
+
}
|
|
822
|
+
function getDocumentTerms(database, documentPath) {
|
|
823
|
+
return queryRows(database, 'SELECT term FROM document_terms WHERE document_path = ? ORDER BY term', [documentPath]).map((row) => toSearchString(row.term));
|
|
824
|
+
}
|
|
825
|
+
function getCommandEffects(database, intent) {
|
|
826
|
+
return queryRows(database, 'SELECT intent, source, access, mode, path, lock, concurrency FROM command_effects WHERE intent = ? ORDER BY lock, path, mode', [intent]).map((row) => ({
|
|
827
|
+
intent: toSearchString(row.intent),
|
|
828
|
+
source: toSearchString(row.source),
|
|
829
|
+
access: toSearchString(row.access),
|
|
830
|
+
mode: toSearchString(row.mode),
|
|
831
|
+
path: toSearchString(row.path),
|
|
832
|
+
lock: toSearchString(row.lock),
|
|
833
|
+
concurrency: toSearchString(row.concurrency),
|
|
834
|
+
}));
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* mf:anchor cli.search.local-index
|
|
838
|
+
* purpose: Search the local index while preserving workflow authority above source navigation hints.
|
|
839
|
+
* search: mf search, scope workflow source all, authority rank, navigation only
|
|
840
|
+
* invariant: Source anchor results remain navigation-only and cannot outrank command or workflow authority.
|
|
841
|
+
* risk: cache, config
|
|
842
|
+
*/
|
|
843
|
+
export async function searchLocalIndex(projectRoot, query, options = {}) {
|
|
844
|
+
const normalizedQuery = normalizeSearchText(query);
|
|
845
|
+
const limit = Math.max(1, Math.min(options.limit ?? 10, 50));
|
|
846
|
+
const scope = options.scope ?? 'workflow';
|
|
847
|
+
const databasePath = getLocalIndexDatabasePath(projectRoot);
|
|
848
|
+
if (!existsSync(databasePath)) {
|
|
849
|
+
throw new Error('Local mustflow index not found. Run `mf index` before searching.');
|
|
850
|
+
}
|
|
851
|
+
if (normalizedQuery.length === 0) {
|
|
852
|
+
throw new Error('Search query must not be empty.');
|
|
853
|
+
}
|
|
854
|
+
const SQL = await loadSqlJs();
|
|
855
|
+
const database = new SQL.Database(readFileSync(databasePath));
|
|
856
|
+
const cacheLayers = readCacheLayerSets(projectRoot);
|
|
857
|
+
const results = [];
|
|
858
|
+
try {
|
|
859
|
+
const stalePaths = getStalePaths(projectRoot, database);
|
|
860
|
+
if (stalePaths.length > 0) {
|
|
861
|
+
throw new Error(`Local mustflow index is stale: ${stalePaths.join(', ')}. Run \`mf index\` before searching. Refresh command: mf index`);
|
|
862
|
+
}
|
|
863
|
+
if (scope === 'workflow' || scope === 'all') {
|
|
864
|
+
for (const row of queryRows(database, 'SELECT path, type, title, content_snippet FROM documents')) {
|
|
865
|
+
const pathValue = toSearchString(row.path);
|
|
866
|
+
const typeValue = toSearchString(row.type);
|
|
867
|
+
const title = toSearchString(row.title);
|
|
868
|
+
const contentSnippet = toSearchString(row.content_snippet);
|
|
869
|
+
const sectionHeadings = getSectionHeadings(database, pathValue);
|
|
870
|
+
const documentTerms = getDocumentTerms(database, pathValue);
|
|
871
|
+
const primaryFields = [pathValue, title];
|
|
872
|
+
const secondaryFields = [typeValue, contentSnippet, ...sectionHeadings, ...documentTerms];
|
|
873
|
+
if (!isMatched([...primaryFields, ...secondaryFields], normalizedQuery)) {
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
876
|
+
results.push(withCacheHint({
|
|
877
|
+
kind: 'document',
|
|
878
|
+
path: pathValue,
|
|
879
|
+
title,
|
|
880
|
+
document_type: typeValue,
|
|
881
|
+
...workflowAuthorityForDocument(typeValue),
|
|
882
|
+
match: getMatchSnippet([...primaryFields, ...secondaryFields], normalizedQuery),
|
|
883
|
+
score: scoreMatch(primaryFields, secondaryFields, normalizedQuery),
|
|
884
|
+
}, cacheLayers));
|
|
885
|
+
}
|
|
886
|
+
for (const row of queryRows(database, 'SELECT name, path, title FROM skills')) {
|
|
887
|
+
const name = toSearchString(row.name);
|
|
888
|
+
const pathValue = toSearchString(row.path);
|
|
889
|
+
const title = toSearchString(row.title);
|
|
890
|
+
const fields = [name, pathValue, title];
|
|
891
|
+
if (!isMatched(fields, normalizedQuery)) {
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
results.push(withCacheHint({
|
|
895
|
+
kind: 'skill',
|
|
896
|
+
name,
|
|
897
|
+
path: pathValue,
|
|
898
|
+
title,
|
|
899
|
+
...skillAuthority(),
|
|
900
|
+
match: getMatchSnippet(fields, normalizedQuery),
|
|
901
|
+
score: scoreMatch([name, pathValue, title], [], normalizedQuery),
|
|
902
|
+
}, cacheLayers));
|
|
903
|
+
}
|
|
904
|
+
for (const row of queryRows(database, 'SELECT skill_name, skill_path, trigger, required_input, edit_scope, risk, verification_intents, expected_output FROM skill_routes')) {
|
|
905
|
+
const name = toSearchString(row.skill_name);
|
|
906
|
+
const pathValue = toSearchString(row.skill_path);
|
|
907
|
+
const trigger = toSearchString(row.trigger);
|
|
908
|
+
const requiredInput = toSearchString(row.required_input);
|
|
909
|
+
const editScope = toSearchString(row.edit_scope);
|
|
910
|
+
const risk = toSearchString(row.risk);
|
|
911
|
+
const verificationIntents = splitVerificationIntents(toSearchString(row.verification_intents));
|
|
912
|
+
const expectedOutput = toSearchString(row.expected_output);
|
|
913
|
+
const primaryFields = [name, trigger];
|
|
914
|
+
const secondaryFields = [pathValue, requiredInput, editScope, risk, expectedOutput];
|
|
915
|
+
if (!isMatched([...primaryFields, ...secondaryFields], normalizedQuery)) {
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
results.push(withCacheHint({
|
|
919
|
+
kind: 'skill_route',
|
|
920
|
+
name,
|
|
921
|
+
path: pathValue,
|
|
922
|
+
title: name,
|
|
923
|
+
route_trigger: trigger,
|
|
924
|
+
route_risk: risk,
|
|
925
|
+
verification_intents: verificationIntents,
|
|
926
|
+
...skillAuthority(),
|
|
927
|
+
match: getMatchSnippet([...primaryFields, ...secondaryFields], normalizedQuery),
|
|
928
|
+
score: scoreMatch(primaryFields, secondaryFields, normalizedQuery),
|
|
929
|
+
}, cacheLayers));
|
|
930
|
+
}
|
|
931
|
+
for (const row of queryRows(database, 'SELECT name, status, lifecycle, run_policy, description FROM command_intents')) {
|
|
932
|
+
const name = toSearchString(row.name);
|
|
933
|
+
const status = toSearchString(row.status);
|
|
934
|
+
const lifecycle = toSearchString(row.lifecycle);
|
|
935
|
+
const runPolicy = toSearchString(row.run_policy);
|
|
936
|
+
const description = toSearchString(row.description);
|
|
937
|
+
const effects = getCommandEffects(database, name);
|
|
938
|
+
const effectLocks = [...new Set(effects.map((effect) => effect.lock))].sort((left, right) => left.localeCompare(right));
|
|
939
|
+
const effectPaths = [...new Set(effects.map((effect) => effect.path))].sort((left, right) => left.localeCompare(right));
|
|
940
|
+
const effectModes = [...new Set(effects.map((effect) => effect.mode))].sort((left, right) => left.localeCompare(right));
|
|
941
|
+
const primaryFields = [name];
|
|
942
|
+
const secondaryFields = [status, lifecycle, runPolicy, description, ...effectLocks, ...effectPaths, ...effectModes];
|
|
943
|
+
if (!isMatched([...primaryFields, ...secondaryFields], normalizedQuery)) {
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
results.push(withCacheHint({
|
|
947
|
+
kind: 'command_intent',
|
|
948
|
+
name,
|
|
949
|
+
title: description || name,
|
|
950
|
+
effect_locks: effectLocks,
|
|
951
|
+
effect_paths: effectPaths,
|
|
952
|
+
effect_modes: effectModes,
|
|
953
|
+
...commandIntentAuthority(),
|
|
954
|
+
match: getMatchSnippet([...primaryFields, ...secondaryFields], normalizedQuery),
|
|
955
|
+
score: scoreMatch(primaryFields, secondaryFields, normalizedQuery),
|
|
956
|
+
}, cacheLayers));
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
if (scope === 'source' || scope === 'all') {
|
|
960
|
+
for (const row of queryRows(database, 'SELECT source_anchors.id, path, line_start, purpose, search_terms, invariant, risk, source_anchors.navigation_only, source_anchors.can_instruct_agent, status, confidence FROM source_anchors LEFT JOIN source_anchor_status ON source_anchor_status.anchor_id = source_anchors.id')) {
|
|
961
|
+
const id = toSearchString(row.id);
|
|
962
|
+
const pathValue = toSearchString(row.path);
|
|
963
|
+
const purpose = toSearchString(row.purpose);
|
|
964
|
+
const searchTerms = toSearchString(row.search_terms);
|
|
965
|
+
const invariant = toSearchString(row.invariant);
|
|
966
|
+
const risk = toSearchString(row.risk);
|
|
967
|
+
const primaryFields = [id, pathValue];
|
|
968
|
+
const secondaryFields = [purpose, searchTerms, invariant, risk];
|
|
969
|
+
if (!isMatched([...primaryFields, ...secondaryFields], normalizedQuery)) {
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
results.push(withCacheHint({
|
|
973
|
+
kind: 'source_anchor',
|
|
974
|
+
anchor_id: id,
|
|
975
|
+
name: id,
|
|
976
|
+
path: pathValue,
|
|
977
|
+
line_start: Number(row.line_start),
|
|
978
|
+
title: purpose || id,
|
|
979
|
+
risk,
|
|
980
|
+
...sourceAnchorAuthority(),
|
|
981
|
+
stale_status: toSearchString(row.status),
|
|
982
|
+
stale_confidence: Number(row.confidence),
|
|
983
|
+
match: getMatchSnippet([...primaryFields, ...secondaryFields], normalizedQuery),
|
|
984
|
+
score: scoreMatch(primaryFields, secondaryFields, normalizedQuery),
|
|
985
|
+
}, cacheLayers));
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
finally {
|
|
990
|
+
database.close();
|
|
991
|
+
}
|
|
992
|
+
const sortedResults = results
|
|
993
|
+
.sort((left, right) => {
|
|
994
|
+
if (scope === 'all' && left.authority_rank !== right.authority_rank) {
|
|
995
|
+
return left.authority_rank - right.authority_rank;
|
|
996
|
+
}
|
|
997
|
+
return right.score - left.score || (left.path ?? left.name ?? '').localeCompare(right.path ?? right.name ?? '');
|
|
998
|
+
})
|
|
999
|
+
.slice(0, limit);
|
|
1000
|
+
return {
|
|
1001
|
+
schema_version: LOCAL_INDEX_SCHEMA_VERSION,
|
|
1002
|
+
command: 'search',
|
|
1003
|
+
ok: true,
|
|
1004
|
+
mustflow_root: path.resolve(projectRoot),
|
|
1005
|
+
database_path: databasePath,
|
|
1006
|
+
query: normalizedQuery,
|
|
1007
|
+
limit,
|
|
1008
|
+
scope,
|
|
1009
|
+
index_fresh: true,
|
|
1010
|
+
stale_paths: [],
|
|
1011
|
+
result_count: sortedResults.length,
|
|
1012
|
+
results: sortedResults,
|
|
1013
|
+
};
|
|
1014
|
+
}
|