mdcontext 0.1.0 → 0.2.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/.changeset/config.json +9 -9
- package/.claude/settings.local.json +25 -0
- package/.github/workflows/claude-code-review.yml +44 -0
- package/.github/workflows/claude.yml +85 -0
- package/CONTRIBUTING.md +186 -0
- package/NOTES/NOTES +44 -0
- package/README.md +206 -3
- package/biome.json +1 -1
- package/dist/chunk-23UPXDNL.js +3044 -0
- package/dist/chunk-2W7MO2DL.js +1366 -0
- package/dist/chunk-3NUAZGMA.js +1689 -0
- package/dist/chunk-7TOWB2XB.js +366 -0
- package/dist/chunk-7XOTOADQ.js +3065 -0
- package/dist/chunk-AH2PDM2K.js +3042 -0
- package/dist/chunk-BNXWSZ63.js +3742 -0
- package/dist/chunk-BTL5DJVU.js +3222 -0
- package/dist/chunk-HDHYG7E4.js +104 -0
- package/dist/chunk-HLR4KZBP.js +3234 -0
- package/dist/chunk-IP3FRFEB.js +1045 -0
- package/dist/chunk-KHU56VDO.js +3042 -0
- package/dist/chunk-KRYIFLQR.js +85 -89
- package/dist/chunk-LBSDNLEM.js +287 -0
- package/dist/chunk-MNTQ7HCP.js +2643 -0
- package/dist/chunk-MUJELQQ6.js +1387 -0
- package/dist/chunk-MXJGMSLV.js +2199 -0
- package/dist/chunk-N6QJGC3Z.js +2636 -0
- package/dist/chunk-OBELGBPM.js +1713 -0
- package/dist/chunk-OT7R5XTA.js +3192 -0
- package/dist/chunk-P7X4RA2T.js +106 -0
- package/dist/chunk-PIDUQNC2.js +3185 -0
- package/dist/chunk-POGCDIH4.js +3187 -0
- package/dist/chunk-PSIEOQGZ.js +3043 -0
- package/dist/chunk-PVRT3IHA.js +3238 -0
- package/dist/chunk-QNN4TT23.js +1430 -0
- package/dist/chunk-RE3R45RJ.js +3042 -0
- package/dist/chunk-S7E6TFX6.js +718 -657
- package/dist/chunk-SG6GLU4U.js +1378 -0
- package/dist/chunk-SJCDV2ST.js +274 -0
- package/dist/chunk-SYE5XLF3.js +104 -0
- package/dist/chunk-T5VLYBZD.js +103 -0
- package/dist/chunk-TOQB7VWU.js +3238 -0
- package/dist/chunk-VFNMZ4ZQ.js +3228 -0
- package/dist/chunk-VVTGZNBT.js +1533 -1423
- package/dist/chunk-W7Q4RFEV.js +104 -0
- package/dist/chunk-XTYYVRLO.js +3190 -0
- package/dist/chunk-Y6MDYVJD.js +3063 -0
- package/dist/cli/main.js +4072 -629
- package/dist/index.d.ts +420 -33
- package/dist/index.js +8 -15
- package/dist/mcp/server.js +103 -7
- package/dist/schema-BAWSG7KY.js +22 -0
- package/dist/schema-E3QUPL26.js +20 -0
- package/dist/schema-EHL7WUT6.js +20 -0
- package/docs/019-USAGE.md +44 -5
- package/docs/020-current-implementation.md +8 -8
- package/docs/021-DOGFOODING-FINDINGS.md +1 -1
- package/docs/CONFIG.md +1123 -0
- package/docs/ERRORS.md +383 -0
- package/docs/summarization.md +320 -0
- package/justfile +40 -0
- package/package.json +39 -33
- package/research/INDEX.md +315 -0
- package/research/code-review/README.md +90 -0
- package/research/code-review/cli-error-handling-review.md +979 -0
- package/research/code-review/code-review-validation-report.md +464 -0
- package/research/code-review/main-ts-review.md +1128 -0
- package/research/config-docs/SUMMARY.md +357 -0
- package/research/config-docs/TEST-RESULTS.md +776 -0
- package/research/config-docs/TODO.md +542 -0
- package/research/config-docs/analysis.md +744 -0
- package/research/config-docs/fix-validation.md +502 -0
- package/research/config-docs/help-audit.md +264 -0
- package/research/config-docs/help-system-analysis.md +890 -0
- package/research/frontmatter/COMMENTS-ARE-SKIPPED.md +149 -0
- package/research/frontmatter/LLM-CODE-NAVIGATION.md +276 -0
- package/research/issue-review.md +603 -0
- package/research/llm-summarization/agent-cli-tools-2026.md +1082 -0
- package/research/llm-summarization/alternative-providers-2026.md +1428 -0
- package/research/llm-summarization/anthropic-2026.md +367 -0
- package/research/llm-summarization/claude-cli-integration.md +1706 -0
- package/research/llm-summarization/cli-integration-patterns.md +3155 -0
- package/research/llm-summarization/openai-2026.md +473 -0
- package/research/llm-summarization/openai-compatible-providers-2026.md +1022 -0
- package/research/llm-summarization/opencode-cli-integration.md +1552 -0
- package/research/llm-summarization/prompt-engineering-2026.md +1426 -0
- package/research/llm-summarization/prototype-results.md +56 -0
- package/research/llm-summarization/provider-switching-patterns-2026.md +2153 -0
- package/research/llm-summarization/typescript-llm-libraries-2026.md +2436 -0
- package/research/mdcontext-pudding/00-EXECUTIVE-SUMMARY.md +282 -0
- package/research/mdcontext-pudding/01-index-embed.md +956 -0
- package/research/mdcontext-pudding/02-search-COMMANDS.md +142 -0
- package/research/mdcontext-pudding/02-search-SUMMARY.md +146 -0
- package/research/mdcontext-pudding/02-search.md +970 -0
- package/research/mdcontext-pudding/03-context.md +779 -0
- package/research/mdcontext-pudding/04-navigation-and-analytics.md +803 -0
- package/research/mdcontext-pudding/04-tree.md +704 -0
- package/research/mdcontext-pudding/05-config.md +1038 -0
- package/research/mdcontext-pudding/06-links-summary.txt +87 -0
- package/research/mdcontext-pudding/06-links.md +679 -0
- package/research/mdcontext-pudding/07-stats.md +693 -0
- package/research/mdcontext-pudding/BUG-FIX-PLAN.md +388 -0
- package/research/mdcontext-pudding/P0-BUG-VALIDATION.md +167 -0
- package/research/mdcontext-pudding/README.md +168 -0
- package/research/mdcontext-pudding/TESTING-SUMMARY.md +128 -0
- package/research/research-quality-review.md +834 -0
- package/research/semantic-search/embedding-text-analysis.md +156 -0
- package/research/semantic-search/multi-word-failure-reproduction.md +171 -0
- package/research/semantic-search/query-processing-analysis.md +207 -0
- package/research/semantic-search/root-cause-and-solution.md +114 -0
- package/research/semantic-search/threshold-validation-report.md +69 -0
- package/research/semantic-search/vector-search-analysis.md +63 -0
- package/research/test-path-issues.md +276 -0
- package/review/ALP-76/1-error-type-design.md +962 -0
- package/review/ALP-76/2-error-handling-patterns.md +906 -0
- package/review/ALP-76/3-error-presentation.md +624 -0
- package/review/ALP-76/4-test-coverage.md +625 -0
- package/review/ALP-76/5-migration-completeness.md +440 -0
- package/review/ALP-76/6-effect-best-practices.md +755 -0
- package/scripts/apply-branch-protection.sh +47 -0
- package/scripts/branch-protection-templates.json +79 -0
- package/scripts/prototype-summarization.ts +346 -0
- package/scripts/rebuild-hnswlib.js +32 -37
- package/scripts/setup-branch-protection.sh +64 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/active-provider.json +7 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.json +541 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.meta.json +5 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/config.json +8 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/documents.json +60 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/links.json +13 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/sections.json +1197 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/configuration-management.md +99 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/distributed-systems.md +92 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/error-handling.md +78 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/failure-automation.md +55 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/job-context.md +69 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/process-orchestration.md +99 -0
- package/src/cli/argv-preprocessor.test.ts +2 -2
- package/src/cli/cli.test.ts +230 -33
- package/src/cli/commands/config-cmd.ts +642 -0
- package/src/cli/commands/context.ts +97 -9
- package/src/cli/commands/duplicates.ts +122 -0
- package/src/cli/commands/embeddings.ts +529 -0
- package/src/cli/commands/index-cmd.ts +210 -30
- package/src/cli/commands/index.ts +3 -0
- package/src/cli/commands/search.ts +894 -64
- package/src/cli/commands/stats.ts +3 -0
- package/src/cli/commands/tree.ts +26 -5
- package/src/cli/config-layer.ts +176 -0
- package/src/cli/error-handler.test.ts +235 -0
- package/src/cli/error-handler.ts +655 -0
- package/src/cli/flag-schemas.ts +66 -0
- package/src/cli/help.ts +209 -7
- package/src/cli/main.ts +348 -58
- package/src/cli/options.ts +10 -0
- package/src/cli/shared-error-handling.ts +199 -0
- package/src/cli/utils.ts +150 -17
- package/src/config/file-provider.test.ts +320 -0
- package/src/config/file-provider.ts +273 -0
- package/src/config/index.ts +72 -0
- package/src/config/integration.test.ts +667 -0
- package/src/config/precedence.test.ts +277 -0
- package/src/config/precedence.ts +451 -0
- package/src/config/schema.test.ts +414 -0
- package/src/config/schema.ts +603 -0
- package/src/config/service.test.ts +320 -0
- package/src/config/service.ts +243 -0
- package/src/config/testing.test.ts +264 -0
- package/src/config/testing.ts +110 -0
- package/src/core/types.ts +6 -33
- package/src/duplicates/detector.test.ts +183 -0
- package/src/duplicates/detector.ts +414 -0
- package/src/duplicates/index.ts +18 -0
- package/src/embeddings/embedding-namespace.test.ts +300 -0
- package/src/embeddings/embedding-namespace.ts +947 -0
- package/src/embeddings/heading-boost.test.ts +222 -0
- package/src/embeddings/hnsw-build-options.test.ts +198 -0
- package/src/embeddings/hyde.test.ts +272 -0
- package/src/embeddings/hyde.ts +264 -0
- package/src/embeddings/index.ts +2 -0
- package/src/embeddings/openai-provider.ts +332 -83
- package/src/embeddings/pricing.json +22 -0
- package/src/embeddings/provider-constants.ts +204 -0
- package/src/embeddings/provider-errors.test.ts +967 -0
- package/src/embeddings/provider-errors.ts +565 -0
- package/src/embeddings/provider-factory.test.ts +240 -0
- package/src/embeddings/provider-factory.ts +225 -0
- package/src/embeddings/provider-integration.test.ts +788 -0
- package/src/embeddings/query-preprocessing.test.ts +187 -0
- package/src/embeddings/semantic-search-threshold.test.ts +508 -0
- package/src/embeddings/semantic-search.ts +780 -93
- package/src/embeddings/types.ts +293 -16
- package/src/embeddings/vector-store.ts +486 -77
- package/src/embeddings/voyage-provider.ts +313 -0
- package/src/errors/errors.test.ts +845 -0
- package/src/errors/index.ts +533 -0
- package/src/index/ignore-patterns.test.ts +354 -0
- package/src/index/ignore-patterns.ts +305 -0
- package/src/index/indexer.ts +286 -48
- package/src/index/storage.ts +94 -30
- package/src/index/types.ts +40 -2
- package/src/index/watcher.ts +67 -9
- package/src/index.ts +22 -0
- package/src/integration/search-keyword.test.ts +678 -0
- package/src/mcp/server.ts +135 -6
- package/src/parser/parser.ts +18 -19
- package/src/parser/section-filter.test.ts +277 -0
- package/src/parser/section-filter.ts +125 -3
- package/src/search/__tests__/hybrid-search.test.ts +650 -0
- package/src/search/bm25-store.ts +366 -0
- package/src/search/cross-encoder.test.ts +253 -0
- package/src/search/cross-encoder.ts +406 -0
- package/src/search/fuzzy-search.test.ts +419 -0
- package/src/search/fuzzy-search.ts +273 -0
- package/src/search/hybrid-search.ts +448 -0
- package/src/search/path-matcher.test.ts +276 -0
- package/src/search/path-matcher.ts +33 -0
- package/src/search/searcher.test.ts +99 -1
- package/src/search/searcher.ts +189 -67
- package/src/search/wink-bm25.d.ts +30 -0
- package/src/summarization/cli-providers/claude.ts +202 -0
- package/src/summarization/cli-providers/detection.test.ts +273 -0
- package/src/summarization/cli-providers/detection.ts +118 -0
- package/src/summarization/cli-providers/index.ts +8 -0
- package/src/summarization/cost.test.ts +139 -0
- package/src/summarization/cost.ts +102 -0
- package/src/summarization/error-handler.test.ts +127 -0
- package/src/summarization/error-handler.ts +111 -0
- package/src/summarization/index.ts +102 -0
- package/src/summarization/pipeline.test.ts +498 -0
- package/src/summarization/pipeline.ts +231 -0
- package/src/summarization/prompts.test.ts +269 -0
- package/src/summarization/prompts.ts +133 -0
- package/src/summarization/provider-factory.test.ts +396 -0
- package/src/summarization/provider-factory.ts +178 -0
- package/src/summarization/types.ts +184 -0
- package/src/summarize/summarizer.ts +104 -35
- package/src/types/huggingface-transformers.d.ts +66 -0
- package/tests/fixtures/cli/.mdcontext/active-provider.json +7 -0
- package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
- package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
- package/tests/fixtures/cli/.mdcontext/indexes/documents.json +4 -4
- package/tests/fixtures/cli/.mdcontext/indexes/sections.json +14 -0
- package/tests/integration/embed-index.test.ts +712 -0
- package/tests/integration/search-context.test.ts +469 -0
- package/tests/integration/search-semantic.test.ts +522 -0
- package/vitest.config.ts +1 -6
- package/AGENTS.md +0 -46
- package/tests/fixtures/cli/.mdcontext/vectors.bin +0 -0
- package/tests/fixtures/cli/.mdcontext/vectors.meta.json +0 -1264
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Apply branch protection from a template
|
|
3
|
+
# Usage: ./apply-branch-protection.sh owner/repo template [branch]
|
|
4
|
+
#
|
|
5
|
+
# Templates: full-ci-matrix, simple, minimal, strict
|
|
6
|
+
#
|
|
7
|
+
# Examples:
|
|
8
|
+
# ./apply-branch-protection.sh mdcontext/mdcontext full-ci-matrix
|
|
9
|
+
# ./apply-branch-protection.sh myorg/myrepo simple main
|
|
10
|
+
# ./apply-branch-protection.sh myorg/myrepo minimal develop
|
|
11
|
+
|
|
12
|
+
set -e
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
TEMPLATES_FILE="$SCRIPT_DIR/branch-protection-templates.json"
|
|
16
|
+
|
|
17
|
+
REPO="${1:?Usage: $0 owner/repo template [branch]}"
|
|
18
|
+
TEMPLATE="${2:?Usage: $0 owner/repo template [branch] (templates: full-ci-matrix, simple, minimal, strict)}"
|
|
19
|
+
BRANCH="${3:-main}"
|
|
20
|
+
|
|
21
|
+
if [[ ! -f "$TEMPLATES_FILE" ]]; then
|
|
22
|
+
echo "Error: Templates file not found at $TEMPLATES_FILE"
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# Extract template (remove description field for API)
|
|
27
|
+
CONFIG=$(jq -r ".[\"$TEMPLATE\"] | del(.description)" "$TEMPLATES_FILE")
|
|
28
|
+
|
|
29
|
+
if [[ "$CONFIG" == "null" ]]; then
|
|
30
|
+
echo "Error: Template '$TEMPLATE' not found"
|
|
31
|
+
echo "Available templates:"
|
|
32
|
+
jq -r 'keys[]' "$TEMPLATES_FILE"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
DESCRIPTION=$(jq -r ".[\"$TEMPLATE\"].description // \"\"" "$TEMPLATES_FILE")
|
|
37
|
+
|
|
38
|
+
echo "Applying branch protection to $REPO ($BRANCH branch)"
|
|
39
|
+
echo "Template: $TEMPLATE"
|
|
40
|
+
[[ -n "$DESCRIPTION" ]] && echo " $DESCRIPTION"
|
|
41
|
+
echo ""
|
|
42
|
+
|
|
43
|
+
echo "$CONFIG" | gh api "repos/$REPO/branches/$BRANCH/protection" -X PUT --input - > /dev/null
|
|
44
|
+
|
|
45
|
+
echo "Done! Branch protection configured."
|
|
46
|
+
echo ""
|
|
47
|
+
echo "View settings: https://github.com/$REPO/settings/branches"
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"full-ci-matrix": {
|
|
3
|
+
"description": "For projects with quality + multi-platform test matrix (Node 20/22, ubuntu/macos/windows)",
|
|
4
|
+
"required_status_checks": {
|
|
5
|
+
"strict": true,
|
|
6
|
+
"contexts": [
|
|
7
|
+
"quality",
|
|
8
|
+
"test (ubuntu-latest, 20)",
|
|
9
|
+
"test (ubuntu-latest, 22)",
|
|
10
|
+
"test (macos-latest, 20)",
|
|
11
|
+
"test (macos-latest, 22)",
|
|
12
|
+
"test (windows-latest, 20)",
|
|
13
|
+
"test (windows-latest, 22)"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"enforce_admins": false,
|
|
17
|
+
"required_pull_request_reviews": {
|
|
18
|
+
"required_approving_review_count": 1,
|
|
19
|
+
"dismiss_stale_reviews": true,
|
|
20
|
+
"require_code_owner_reviews": false
|
|
21
|
+
},
|
|
22
|
+
"restrictions": null,
|
|
23
|
+
"required_linear_history": true,
|
|
24
|
+
"allow_force_pushes": false,
|
|
25
|
+
"allow_deletions": false
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
"simple": {
|
|
29
|
+
"description": "For simple projects with build + test jobs",
|
|
30
|
+
"required_status_checks": {
|
|
31
|
+
"strict": true,
|
|
32
|
+
"contexts": ["build", "test"]
|
|
33
|
+
},
|
|
34
|
+
"enforce_admins": false,
|
|
35
|
+
"required_pull_request_reviews": {
|
|
36
|
+
"required_approving_review_count": 1,
|
|
37
|
+
"dismiss_stale_reviews": true,
|
|
38
|
+
"require_code_owner_reviews": false
|
|
39
|
+
},
|
|
40
|
+
"restrictions": null,
|
|
41
|
+
"required_linear_history": true,
|
|
42
|
+
"allow_force_pushes": false,
|
|
43
|
+
"allow_deletions": false
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
"minimal": {
|
|
47
|
+
"description": "Minimal protection - just require PR reviews",
|
|
48
|
+
"required_status_checks": null,
|
|
49
|
+
"enforce_admins": false,
|
|
50
|
+
"required_pull_request_reviews": {
|
|
51
|
+
"required_approving_review_count": 1,
|
|
52
|
+
"dismiss_stale_reviews": true,
|
|
53
|
+
"require_code_owner_reviews": false
|
|
54
|
+
},
|
|
55
|
+
"restrictions": null,
|
|
56
|
+
"required_linear_history": false,
|
|
57
|
+
"allow_force_pushes": false,
|
|
58
|
+
"allow_deletions": false
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
"strict": {
|
|
62
|
+
"description": "Strict protection with admin enforcement and code owners",
|
|
63
|
+
"required_status_checks": {
|
|
64
|
+
"strict": true,
|
|
65
|
+
"contexts": ["ci"]
|
|
66
|
+
},
|
|
67
|
+
"enforce_admins": true,
|
|
68
|
+
"required_pull_request_reviews": {
|
|
69
|
+
"required_approving_review_count": 2,
|
|
70
|
+
"dismiss_stale_reviews": true,
|
|
71
|
+
"require_code_owner_reviews": true,
|
|
72
|
+
"require_last_push_approval": true
|
|
73
|
+
},
|
|
74
|
+
"restrictions": null,
|
|
75
|
+
"required_linear_history": true,
|
|
76
|
+
"allow_force_pushes": false,
|
|
77
|
+
"allow_deletions": false
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
/**
|
|
3
|
+
* Prototype: AI Summarization of Search Results
|
|
4
|
+
*
|
|
5
|
+
* Quick validation script to test the summarization approach.
|
|
6
|
+
* Uses the actual mdcontext search and Claude CLI integration.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx tsx scripts/prototype-summarization.ts
|
|
10
|
+
* npx tsx scripts/prototype-summarization.ts "your query here"
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { spawn } from 'node:child_process'
|
|
14
|
+
import * as path from 'node:path'
|
|
15
|
+
import * as fs from 'node:fs'
|
|
16
|
+
|
|
17
|
+
// Test queries to validate the approach
|
|
18
|
+
const TEST_QUERIES = [
|
|
19
|
+
'error handling',
|
|
20
|
+
'configuration',
|
|
21
|
+
'search',
|
|
22
|
+
'embeddings',
|
|
23
|
+
'Effect patterns',
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
interface SearchResult {
|
|
27
|
+
path: string
|
|
28
|
+
heading: string
|
|
29
|
+
score?: number
|
|
30
|
+
similarity?: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface SummaryResult {
|
|
34
|
+
query: string
|
|
35
|
+
searchResults: SearchResult[]
|
|
36
|
+
summary: string
|
|
37
|
+
durationMs: number
|
|
38
|
+
provider: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Run mdcontext search and get JSON results
|
|
43
|
+
*/
|
|
44
|
+
async function runSearch(query: string, dir: string): Promise<SearchResult[]> {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
const proc = spawn('node', [
|
|
47
|
+
path.join(dir, 'dist/cli/main.js'),
|
|
48
|
+
'search',
|
|
49
|
+
query,
|
|
50
|
+
dir,
|
|
51
|
+
'--json',
|
|
52
|
+
'--limit', '5',
|
|
53
|
+
], {
|
|
54
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
let stdout = ''
|
|
58
|
+
let stderr = ''
|
|
59
|
+
|
|
60
|
+
proc.stdout.on('data', (data: Buffer) => {
|
|
61
|
+
stdout += data.toString()
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
proc.stderr.on('data', (data: Buffer) => {
|
|
65
|
+
stderr += data.toString()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
proc.on('close', (code: number | null) => {
|
|
69
|
+
if (code !== 0) {
|
|
70
|
+
// If search fails (no index), return empty results
|
|
71
|
+
console.log(` Search returned code ${code}, using empty results`)
|
|
72
|
+
resolve([])
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const parsed = JSON.parse(stdout)
|
|
78
|
+
const results = (parsed.results || []).map((r: any) => ({
|
|
79
|
+
path: r.path,
|
|
80
|
+
heading: r.heading,
|
|
81
|
+
score: r.score,
|
|
82
|
+
similarity: r.similarity,
|
|
83
|
+
}))
|
|
84
|
+
resolve(results)
|
|
85
|
+
} catch (e) {
|
|
86
|
+
console.log(` Failed to parse search results: ${e}`)
|
|
87
|
+
resolve([])
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
proc.on('error', (err) => {
|
|
92
|
+
reject(err)
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Format search results for LLM input
|
|
99
|
+
*/
|
|
100
|
+
function formatResultsForLLM(query: string, results: SearchResult[]): string {
|
|
101
|
+
if (results.length === 0) {
|
|
102
|
+
return `Query: "${query}"\n\nNo search results found. The index may need to be built.`
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const resultsText = results.map((r, i) => {
|
|
106
|
+
const score = r.similarity
|
|
107
|
+
? `${(r.similarity * 100).toFixed(1)}% similarity`
|
|
108
|
+
: r.score
|
|
109
|
+
? `score: ${r.score.toFixed(2)}`
|
|
110
|
+
: ''
|
|
111
|
+
return `${i + 1}. ${r.path}\n Section: ${r.heading}\n ${score}`
|
|
112
|
+
}).join('\n\n')
|
|
113
|
+
|
|
114
|
+
return `Query: "${query}"
|
|
115
|
+
|
|
116
|
+
Search Results (${results.length} found):
|
|
117
|
+
|
|
118
|
+
${resultsText}
|
|
119
|
+
|
|
120
|
+
Please provide a concise summary of what these results tell us about "${query}" in this codebase.
|
|
121
|
+
Focus on:
|
|
122
|
+
1. Key patterns and approaches found
|
|
123
|
+
2. Important files to look at
|
|
124
|
+
3. Actionable next steps for the developer`
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Call Claude CLI for summarization
|
|
129
|
+
* SECURITY: Uses spawn() with argument arrays - never exec() with strings
|
|
130
|
+
*/
|
|
131
|
+
async function callClaudeCLI(prompt: string): Promise<{ summary: string; durationMs: number }> {
|
|
132
|
+
const startTime = Date.now()
|
|
133
|
+
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
// SECURITY: spawn() with argument array - safe from shell injection
|
|
136
|
+
const proc = spawn('claude', [
|
|
137
|
+
'-p', prompt,
|
|
138
|
+
'--output-format', 'text',
|
|
139
|
+
], {
|
|
140
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
let stdout = ''
|
|
144
|
+
let stderr = ''
|
|
145
|
+
|
|
146
|
+
proc.stdout.on('data', (data: Buffer) => {
|
|
147
|
+
stdout += data.toString()
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
proc.stderr.on('data', (data: Buffer) => {
|
|
151
|
+
stderr += data.toString()
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
// Timeout after 60 seconds
|
|
155
|
+
const timeout = setTimeout(() => {
|
|
156
|
+
proc.kill('SIGTERM')
|
|
157
|
+
reject(new Error('Claude CLI timeout after 60s'))
|
|
158
|
+
}, 60000)
|
|
159
|
+
|
|
160
|
+
proc.on('close', (code: number | null) => {
|
|
161
|
+
clearTimeout(timeout)
|
|
162
|
+
const durationMs = Date.now() - startTime
|
|
163
|
+
|
|
164
|
+
if (code !== 0) {
|
|
165
|
+
reject(new Error(`Claude CLI exited with code ${code}: ${stderr}`))
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
resolve({
|
|
170
|
+
summary: stdout.trim(),
|
|
171
|
+
durationMs,
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
proc.on('error', (err) => {
|
|
176
|
+
clearTimeout(timeout)
|
|
177
|
+
reject(new Error(`Failed to spawn Claude CLI: ${err.message}`))
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Check if Claude CLI is available
|
|
184
|
+
*/
|
|
185
|
+
async function checkClaudeCLI(): Promise<boolean> {
|
|
186
|
+
return new Promise((resolve) => {
|
|
187
|
+
const proc = spawn('which', ['claude'], {
|
|
188
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
proc.on('close', (code) => {
|
|
192
|
+
resolve(code === 0)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
proc.on('error', () => {
|
|
196
|
+
resolve(false)
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Run a single test query
|
|
203
|
+
*/
|
|
204
|
+
async function testQuery(query: string, projectDir: string): Promise<SummaryResult> {
|
|
205
|
+
console.log(`\n${'='.repeat(60)}`)
|
|
206
|
+
console.log(`Query: "${query}"`)
|
|
207
|
+
console.log('='.repeat(60))
|
|
208
|
+
|
|
209
|
+
// 1. Run search
|
|
210
|
+
console.log('\n1. Running search...')
|
|
211
|
+
const searchResults = await runSearch(query, projectDir)
|
|
212
|
+
console.log(` Found ${searchResults.length} results`)
|
|
213
|
+
|
|
214
|
+
// 2. Format for LLM
|
|
215
|
+
const prompt = formatResultsForLLM(query, searchResults)
|
|
216
|
+
|
|
217
|
+
// 3. Call Claude CLI
|
|
218
|
+
console.log('\n2. Calling Claude CLI for summary...')
|
|
219
|
+
const { summary, durationMs } = await callClaudeCLI(prompt)
|
|
220
|
+
|
|
221
|
+
// 4. Display result
|
|
222
|
+
console.log(`\n3. Summary (${durationMs}ms):`)
|
|
223
|
+
console.log('-'.repeat(40))
|
|
224
|
+
console.log(summary)
|
|
225
|
+
console.log('-'.repeat(40))
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
query,
|
|
229
|
+
searchResults,
|
|
230
|
+
summary,
|
|
231
|
+
durationMs,
|
|
232
|
+
provider: 'claude',
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Main prototype function
|
|
238
|
+
*/
|
|
239
|
+
async function main() {
|
|
240
|
+
const projectDir = path.resolve(import.meta.dirname, '..')
|
|
241
|
+
console.log('Prototype: AI Summarization of Search Results')
|
|
242
|
+
console.log(`Project: ${projectDir}`)
|
|
243
|
+
|
|
244
|
+
// Check Claude CLI
|
|
245
|
+
const hasClaudeCLI = await checkClaudeCLI()
|
|
246
|
+
if (!hasClaudeCLI) {
|
|
247
|
+
console.error('\nError: Claude CLI not found.')
|
|
248
|
+
console.error('Install it from: https://claude.ai/download')
|
|
249
|
+
process.exit(1)
|
|
250
|
+
}
|
|
251
|
+
console.log('Claude CLI: available')
|
|
252
|
+
|
|
253
|
+
// Get query from args or use test queries
|
|
254
|
+
const args = process.argv.slice(2)
|
|
255
|
+
const queries = args.length > 0 ? args : TEST_QUERIES
|
|
256
|
+
|
|
257
|
+
// Run tests
|
|
258
|
+
const results: SummaryResult[] = []
|
|
259
|
+
for (const query of queries) {
|
|
260
|
+
try {
|
|
261
|
+
const result = await testQuery(query, projectDir)
|
|
262
|
+
results.push(result)
|
|
263
|
+
} catch (err) {
|
|
264
|
+
console.error(`\nError testing "${query}":`, err)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Summary
|
|
269
|
+
console.log('\n' + '='.repeat(60))
|
|
270
|
+
console.log('PROTOTYPE RESULTS SUMMARY')
|
|
271
|
+
console.log('='.repeat(60))
|
|
272
|
+
console.log(`\nQueries tested: ${results.length}`)
|
|
273
|
+
console.log(`Total duration: ${results.reduce((sum, r) => sum + r.durationMs, 0)}ms`)
|
|
274
|
+
console.log(`Average duration: ${Math.round(results.reduce((sum, r) => sum + r.durationMs, 0) / results.length)}ms`)
|
|
275
|
+
|
|
276
|
+
// Write results to file
|
|
277
|
+
const outputPath = path.join(projectDir, 'research/llm-summarization/prototype-results.md')
|
|
278
|
+
const outputDir = path.dirname(outputPath)
|
|
279
|
+
|
|
280
|
+
if (!fs.existsSync(outputDir)) {
|
|
281
|
+
fs.mkdirSync(outputDir, { recursive: true })
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const markdown = generateResultsMarkdown(results)
|
|
285
|
+
fs.writeFileSync(outputPath, markdown)
|
|
286
|
+
console.log(`\nResults written to: ${outputPath}`)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Generate markdown report from results
|
|
291
|
+
*/
|
|
292
|
+
function generateResultsMarkdown(results: SummaryResult[]): string {
|
|
293
|
+
const timestamp = new Date().toISOString()
|
|
294
|
+
const totalDuration = results.reduce((sum, r) => sum + r.durationMs, 0)
|
|
295
|
+
const avgDuration = Math.round(totalDuration / results.length)
|
|
296
|
+
|
|
297
|
+
let md = `# Prototype Results: AI Summarization
|
|
298
|
+
|
|
299
|
+
Generated: ${timestamp}
|
|
300
|
+
|
|
301
|
+
## Summary
|
|
302
|
+
|
|
303
|
+
- **Queries tested:** ${results.length}
|
|
304
|
+
- **Total duration:** ${totalDuration}ms
|
|
305
|
+
- **Average duration:** ${avgDuration}ms
|
|
306
|
+
- **Provider:** Claude CLI (free with subscription)
|
|
307
|
+
|
|
308
|
+
## Results
|
|
309
|
+
|
|
310
|
+
`
|
|
311
|
+
|
|
312
|
+
for (const result of results) {
|
|
313
|
+
md += `### Query: "${result.query}"
|
|
314
|
+
|
|
315
|
+
**Search Results:** ${result.searchResults.length} found
|
|
316
|
+
**Duration:** ${result.durationMs}ms
|
|
317
|
+
|
|
318
|
+
#### Summary
|
|
319
|
+
|
|
320
|
+
${result.summary}
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
`
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
md += `## Findings
|
|
328
|
+
|
|
329
|
+
### What Works Well
|
|
330
|
+
|
|
331
|
+
- [ ] Add observations here after running prototype
|
|
332
|
+
|
|
333
|
+
### Issues Discovered
|
|
334
|
+
|
|
335
|
+
- [ ] Add issues here after running prototype
|
|
336
|
+
|
|
337
|
+
### Recommendations
|
|
338
|
+
|
|
339
|
+
- [ ] Add recommendations here after running prototype
|
|
340
|
+
`
|
|
341
|
+
|
|
342
|
+
return md
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Run
|
|
346
|
+
main().catch(console.error)
|
|
@@ -7,57 +7,52 @@ import { existsSync, readdirSync, statSync } from "node:fs";
|
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
|
|
9
9
|
function findHnswlibDir() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return null;
|
|
10
|
+
const pnpmDir = join(process.cwd(), "node_modules", ".pnpm");
|
|
11
|
+
|
|
12
|
+
if (!existsSync(pnpmDir)) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const entries = readdirSync(pnpmDir);
|
|
17
|
+
for (const entry of entries) {
|
|
18
|
+
if (entry.startsWith("hnswlib-node@")) {
|
|
19
|
+
const candidate = join(pnpmDir, entry, "node_modules", "hnswlib-node");
|
|
20
|
+
if (existsSync(candidate) && statSync(candidate).isDirectory()) {
|
|
21
|
+
return candidate;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return null;
|
|
32
27
|
}
|
|
33
28
|
|
|
34
29
|
const hnswlibDir = findHnswlibDir();
|
|
35
30
|
|
|
36
31
|
if (!hnswlibDir) {
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
console.log("hnswlib-node not found, skipping rebuild");
|
|
33
|
+
process.exit(0);
|
|
39
34
|
}
|
|
40
35
|
|
|
41
36
|
const addonPath = join(hnswlibDir, "build", "Release", "addon.node");
|
|
42
37
|
if (existsSync(addonPath)) {
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
console.log("hnswlib-node already built, skipping");
|
|
39
|
+
process.exit(0);
|
|
45
40
|
}
|
|
46
41
|
|
|
47
42
|
console.log("Building hnswlib-node native module...");
|
|
48
43
|
console.log(` Directory: ${hnswlibDir}`);
|
|
49
44
|
|
|
50
45
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
46
|
+
execSync("npx node-gyp rebuild", {
|
|
47
|
+
cwd: hnswlibDir,
|
|
48
|
+
stdio: "inherit",
|
|
49
|
+
});
|
|
50
|
+
console.log("hnswlib-node build complete");
|
|
56
51
|
} catch (error) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
52
|
+
console.error("Failed to build hnswlib-node:", error.message);
|
|
53
|
+
console.error("You may need to install build tools:");
|
|
54
|
+
console.error(" - macOS: xcode-select --install");
|
|
55
|
+
console.error(" - Ubuntu: apt install python3 make g++");
|
|
56
|
+
console.error(" - Windows: npm install -g windows-build-tools");
|
|
57
|
+
process.exit(1);
|
|
63
58
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Setup branch protection for a GitHub repository
|
|
3
|
+
# Usage: ./setup-branch-protection.sh owner/repo [branch]
|
|
4
|
+
#
|
|
5
|
+
# Example:
|
|
6
|
+
# ./setup-branch-protection.sh mdcontext/mdcontext main
|
|
7
|
+
# ./setup-branch-protection.sh myorg/myrepo
|
|
8
|
+
|
|
9
|
+
set -e
|
|
10
|
+
|
|
11
|
+
REPO="${1:?Usage: $0 owner/repo [branch]}"
|
|
12
|
+
BRANCH="${2:-main}"
|
|
13
|
+
|
|
14
|
+
echo "Setting up branch protection for $REPO ($BRANCH branch)..."
|
|
15
|
+
|
|
16
|
+
# Customize these status checks for your CI workflow
|
|
17
|
+
# Comment out or modify based on your needs
|
|
18
|
+
STATUS_CHECKS='[
|
|
19
|
+
"quality",
|
|
20
|
+
"test (ubuntu-latest, 20)",
|
|
21
|
+
"test (ubuntu-latest, 22)",
|
|
22
|
+
"test (macos-latest, 20)",
|
|
23
|
+
"test (macos-latest, 22)",
|
|
24
|
+
"test (windows-latest, 20)",
|
|
25
|
+
"test (windows-latest, 22)"
|
|
26
|
+
]'
|
|
27
|
+
|
|
28
|
+
# For simpler projects, you might use:
|
|
29
|
+
# STATUS_CHECKS='["build", "test"]'
|
|
30
|
+
|
|
31
|
+
cat << EOF | gh api "repos/$REPO/branches/$BRANCH/protection" -X PUT --input -
|
|
32
|
+
{
|
|
33
|
+
"required_status_checks": {
|
|
34
|
+
"strict": true,
|
|
35
|
+
"contexts": $STATUS_CHECKS
|
|
36
|
+
},
|
|
37
|
+
"enforce_admins": false,
|
|
38
|
+
"required_pull_request_reviews": {
|
|
39
|
+
"required_approving_review_count": 1,
|
|
40
|
+
"dismiss_stale_reviews": true,
|
|
41
|
+
"require_code_owner_reviews": false,
|
|
42
|
+
"require_last_push_approval": false
|
|
43
|
+
},
|
|
44
|
+
"restrictions": null,
|
|
45
|
+
"required_linear_history": true,
|
|
46
|
+
"allow_force_pushes": false,
|
|
47
|
+
"allow_deletions": false,
|
|
48
|
+
"block_creations": false,
|
|
49
|
+
"required_conversation_resolution": false,
|
|
50
|
+
"lock_branch": false,
|
|
51
|
+
"allow_fork_syncing": false
|
|
52
|
+
}
|
|
53
|
+
EOF
|
|
54
|
+
|
|
55
|
+
echo "Branch protection configured for $REPO ($BRANCH)"
|
|
56
|
+
echo ""
|
|
57
|
+
echo "Settings applied:"
|
|
58
|
+
echo " - Require status checks to pass before merging"
|
|
59
|
+
echo " - Require branches to be up to date before merging"
|
|
60
|
+
echo " - Require 1 approving review"
|
|
61
|
+
echo " - Dismiss stale reviews on new commits"
|
|
62
|
+
echo " - Require linear history (no merge commits)"
|
|
63
|
+
echo " - Block force pushes"
|
|
64
|
+
echo " - Block branch deletion"
|