@oriro/orirocli 0.1.11 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ATTRIBUTION.md +53 -53
- package/LICENSE +21 -21
- package/README.md +10 -9
- package/dist/cli.js +1866 -190
- package/package.json +65 -64
- package/skills/1password/SKILL.md +118 -118
- package/skills/1password/references/cli-examples.md +29 -29
- package/skills/1password/references/get-started.md +21 -21
- package/skills/21stdev/SKILL.md +64 -64
- package/skills/algorithmic-art/LICENSE +21 -21
- package/skills/algorithmic-art/SKILL.md +446 -446
- package/skills/algorithmic-art/templates/generator_template.js +223 -223
- package/skills/algorithmic-art/templates/viewer.html +598 -598
- package/skills/apple-notes/SKILL.md +81 -81
- package/skills/apple-reminders/SKILL.md +122 -122
- package/skills/bear-notes/SKILL.md +111 -111
- package/skills/blogwatcher/SKILL.md +73 -73
- package/skills/blucli/SKILL.md +51 -51
- package/skills/brand-guidelines/LICENSE +21 -21
- package/skills/brand-guidelines/SKILL.md +76 -76
- package/skills/business/biz-analysis/LICENSE +21 -21
- package/skills/business/biz-analysis/SKILL.md +103 -103
- package/skills/business/biz-corporate-strategy/LICENSE +21 -21
- package/skills/business/biz-corporate-strategy/SKILL.md +76 -76
- package/skills/business/biz-customer-success/LICENSE +21 -21
- package/skills/business/biz-customer-success/SKILL.md +55 -55
- package/skills/business/biz-entrepreneurship/LICENSE +21 -21
- package/skills/business/biz-entrepreneurship/SKILL.md +72 -72
- package/skills/business/biz-hr/LICENSE +21 -21
- package/skills/business/biz-hr/SKILL.md +67 -67
- package/skills/business/biz-international/LICENSE +21 -21
- package/skills/business/biz-international/SKILL.md +51 -51
- package/skills/business/biz-leadership/LICENSE +21 -21
- package/skills/business/biz-leadership/SKILL.md +106 -106
- package/skills/business/biz-marketing-strategy/LICENSE +21 -21
- package/skills/business/biz-marketing-strategy/SKILL.md +119 -119
- package/skills/business/biz-negotiation/LICENSE +21 -21
- package/skills/business/biz-negotiation/SKILL.md +152 -152
- package/skills/business/biz-operations/LICENSE +21 -21
- package/skills/business/biz-operations/SKILL.md +74 -74
- package/skills/business/biz-project/LICENSE +21 -21
- package/skills/business/biz-project/SKILL.md +203 -203
- package/skills/business/biz-risk/LICENSE +21 -21
- package/skills/business/biz-risk/SKILL.md +85 -85
- package/skills/business/biz-sales/LICENSE +21 -21
- package/skills/business/biz-sales/SKILL.md +92 -92
- package/skills/business/biz-startup-ops/LICENSE +21 -21
- package/skills/business/biz-startup-ops/SKILL.md +70 -70
- package/skills/business/biz-strategy/LICENSE +21 -21
- package/skills/business/biz-strategy/SKILL.md +233 -233
- package/skills/business/biz-supply-chain-advanced/LICENSE +21 -21
- package/skills/business/biz-supply-chain-advanced/SKILL.md +68 -68
- package/skills/business/fin-chartered-exams/LICENSE +21 -21
- package/skills/business/fin-chartered-exams/SKILL.md +69 -69
- package/skills/camsnap/SKILL.md +49 -49
- package/skills/canvas/SKILL.md +82 -82
- package/skills/canvas-design/LICENSE +21 -21
- package/skills/canvas-design/SKILL.md +140 -140
- package/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -94
- package/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/Jura-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -93
- package/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -93
- package/skills/coding-agent/SKILL.md +146 -146
- package/skills/communication/comm-business-writing/LICENSE +21 -21
- package/skills/communication/comm-business-writing/SKILL.md +67 -67
- package/skills/communication/comm-cross-cultural/LICENSE +21 -21
- package/skills/communication/comm-cross-cultural/SKILL.md +88 -88
- package/skills/communication/comm-journalism/LICENSE +21 -21
- package/skills/communication/comm-journalism/SKILL.md +81 -81
- package/skills/communication/comm-linguistics/LICENSE +21 -21
- package/skills/communication/comm-linguistics/SKILL.md +82 -82
- package/skills/communication/comm-negotiation/LICENSE +21 -21
- package/skills/communication/comm-negotiation/SKILL.md +120 -120
- package/skills/communication/comm-presentations/LICENSE +21 -21
- package/skills/communication/comm-presentations/SKILL.md +93 -93
- package/skills/communication/comm-public-speaking/LICENSE +21 -21
- package/skills/communication/comm-public-speaking/SKILL.md +68 -68
- package/skills/communication/comm-writing/LICENSE +21 -21
- package/skills/communication/comm-writing/SKILL.md +69 -69
- package/skills/craft/ai-engineering/LICENSE +21 -21
- package/skills/craft/ai-engineering/SKILL.md +828 -828
- package/skills/craft/app-builder-guide/LICENSE +21 -21
- package/skills/craft/app-builder-guide/SKILL.md +332 -332
- package/skills/craft/become-an-ai-engineer-26/CONTRIBUTING.md +46 -46
- package/skills/craft/become-an-ai-engineer-26/LICENSE +21 -21
- package/skills/craft/become-an-ai-engineer-26/README.md +270 -270
- package/skills/craft/become-an-ai-engineer-26/SKILL.md +667 -667
- package/skills/craft/become-an-ai-engineer-26/community/BUILDS.md +13 -13
- package/skills/craft/become-an-ai-engineer-26/community/DISCUSSIONS.md +8 -8
- package/skills/craft/become-an-ai-engineer-26/phases/phase-0-mental-models/README.md +14 -14
- package/skills/craft/become-an-ai-engineer-26/phases/phase-0-mental-models/project/TEMPLATE.md +33 -33
- package/skills/craft/become-an-ai-engineer-26/phases/phase-1-first-agent/README.md +25 -25
- package/skills/craft/become-an-ai-engineer-26/phases/phase-1-first-agent/code/raw_loop.py +126 -126
- package/skills/craft/become-an-ai-engineer-26/phases/phase-2-architecture/README.md +17 -17
- package/skills/craft/become-an-ai-engineer-26/phases/phase-3-harness/README.md +17 -17
- package/skills/craft/become-an-ai-engineer-26/phases/phase-4-evals/README.md +21 -21
- package/skills/craft/become-an-ai-engineer-26/phases/phase-4-evals/code/.github/workflows/eval.yml +40 -40
- package/skills/craft/become-an-ai-engineer-26/phases/phase-5-production/README.md +16 -16
- package/skills/craft/become-an-ai-engineer-26/projects/1-mobile-app-slm/README.md +11 -11
- package/skills/craft/become-an-ai-engineer-26/projects/2-self-improving-coder/README.md +11 -11
- package/skills/craft/become-an-ai-engineer-26/projects/3-video-editor-agent/README.md +11 -11
- package/skills/craft/become-an-ai-engineer-26/projects/4-personal-life-os/README.md +12 -12
- package/skills/craft/become-an-ai-engineer-26/projects/5-enterprise-workflow/README.md +12 -12
- package/skills/craft/become-an-ai-engineer-26/references/benchmark-numbers.md +41 -41
- package/skills/craft/become-an-ai-engineer-26/references/mhc-stable-training.md +73 -73
- package/skills/craft/become-an-ai-engineer-26/references/stack-decisions.md +37 -37
- package/skills/craft/become-an-ai-engineer-26/references/yarn-context-extension.md +123 -123
- package/skills/craft/codex-result-handling/LICENSE +21 -21
- package/skills/craft/codex-result-handling/SKILL.md +26 -26
- package/skills/craft/debug-and-build-methodology/LICENSE +21 -21
- package/skills/craft/debug-and-build-methodology/SKILL.md +432 -432
- package/skills/craft/design/LICENSE +21 -21
- package/skills/craft/design/SKILL.md +274 -274
- package/skills/craft/dev/LICENSE +21 -21
- package/skills/craft/dev/SKILL.md +12 -12
- package/skills/craft/dev/release.md +85 -85
- package/skills/craft/dev/roll.md +50 -50
- package/skills/craft/doc-coauthoring/LICENSE +21 -21
- package/skills/craft/doc-coauthoring/SKILL.md +397 -397
- package/skills/craft/focus/LICENSE +21 -21
- package/skills/craft/focus/SKILL.md +432 -432
- package/skills/craft/focus/UPSTREAM_README.md +233 -233
- package/skills/craft/gh/LICENSE +21 -21
- package/skills/craft/gh/SKILL.md +84 -84
- package/skills/craft/gh-skill/LICENSE +21 -21
- package/skills/craft/gh-skill/SKILL.md +121 -121
- package/skills/craft/godmode/LICENSE +21 -21
- package/skills/craft/godmode/SKILL.md +87 -87
- package/skills/craft/godmode/references/android-launch.md +680 -680
- package/skills/craft/godmode/references/data-gcp.md +1038 -1038
- package/skills/craft/godmode/references/expo-eas.md +816 -816
- package/skills/craft/godmode/references/ios-launch.md +734 -734
- package/skills/craft/google-ai-latest/LICENSE +21 -21
- package/skills/craft/google-ai-latest/SKILL.md +682 -682
- package/skills/craft/gpt-5-4-prompting/LICENSE +21 -21
- package/skills/craft/gpt-5-4-prompting/SKILL.md +63 -63
- package/skills/craft/gpt-5-4-prompting/references/codex-prompt-antipatterns.md +101 -101
- package/skills/craft/gpt-5-4-prompting/references/codex-prompt-recipes.md +150 -150
- package/skills/craft/gpt-5-4-prompting/references/prompt-blocks.md +172 -172
- package/skills/craft/grill-me/LICENSE +21 -21
- package/skills/craft/grill-me/SKILL.md +13 -13
- package/skills/craft/idea-to-deploy/LICENSE +21 -21
- package/skills/craft/idea-to-deploy/SKILL.md +292 -292
- package/skills/craft/idea-to-deploy/references/auth-playbook.md +195 -195
- package/skills/craft/idea-to-deploy/references/gcp-deployment.md +268 -268
- package/skills/craft/idea-to-deploy/references/stack-selection.md +117 -117
- package/skills/craft/image-generation-engineer/LICENSE +21 -21
- package/skills/craft/image-generation-engineer/SKILL.md +183 -183
- package/skills/craft/image-generation-engineer/references/architectures.md +260 -260
- package/skills/craft/image-generation-engineer/references/foundations.md +107 -107
- package/skills/craft/image-generation-engineer/references/inference-and-serving.md +253 -253
- package/skills/craft/image-generation-engineer/references/training.md +149 -149
- package/skills/craft/marketing/LICENSE +21 -21
- package/skills/craft/marketing/SKILL.md +1954 -1954
- package/skills/craft/master-architect/LICENSE +21 -21
- package/skills/craft/master-architect/SKILL.md +361 -361
- package/skills/craft/master-architect/references/ai-ml.md +317 -317
- package/skills/craft/master-architect/references/architecture.md +268 -268
- package/skills/craft/master-architect/references/auth-playbook.md +195 -195
- package/skills/craft/master-architect/references/cloud.md +323 -323
- package/skills/craft/master-architect/references/cyber.md +839 -839
- package/skills/craft/master-architect/references/data-eng.md +366 -366
- package/skills/craft/master-architect/references/devops.md +550 -550
- package/skills/craft/master-architect/references/gcp-deployment.md +268 -268
- package/skills/craft/master-architect/references/languages.md +748 -748
- package/skills/craft/master-architect/references/legacy.md +240 -240
- package/skills/craft/master-architect/references/mobile.md +447 -447
- package/skills/craft/master-architect/references/patterns.md +451 -451
- package/skills/craft/master-architect/references/saas-patterns.md +379 -379
- package/skills/craft/master-architect/references/sdlc.md +349 -349
- package/skills/craft/master-architect/references/stack-selection.md +117 -117
- package/skills/craft/oriro-ui-2026/LICENSE +21 -21
- package/skills/craft/oriro-ui-2026/SKILL.md +329 -329
- package/skills/craft/playwright-cli/LICENSE +21 -21
- package/skills/craft/playwright-cli/SKILL.md +393 -393
- package/skills/craft/playwright-cli/references/element-attributes.md +23 -23
- package/skills/craft/playwright-cli/references/playwright-tests.md +39 -39
- package/skills/craft/playwright-cli/references/request-mocking.md +87 -87
- package/skills/craft/playwright-cli/references/running-code.md +240 -240
- package/skills/craft/playwright-cli/references/session-management.md +226 -226
- package/skills/craft/playwright-cli/references/spec-driven-testing.md +312 -312
- package/skills/craft/playwright-cli/references/storage-state.md +275 -275
- package/skills/craft/playwright-cli/references/test-generation.md +134 -134
- package/skills/craft/playwright-cli/references/tracing.md +142 -142
- package/skills/craft/playwright-cli/references/video-recording.md +150 -150
- package/skills/craft/remotion-best-practices/LICENSE +21 -21
- package/skills/craft/remotion-best-practices/SKILL.md +345 -345
- package/skills/craft/remotion-best-practices/rules/3d.md +86 -86
- package/skills/craft/remotion-best-practices/rules/assets/charts-bar-chart.tsx +165 -165
- package/skills/craft/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +89 -89
- package/skills/craft/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +101 -101
- package/skills/craft/remotion-best-practices/rules/audio-visualization.md +195 -195
- package/skills/craft/remotion-best-practices/rules/audio.md +167 -167
- package/skills/craft/remotion-best-practices/rules/calculate-metadata.md +118 -118
- package/skills/craft/remotion-best-practices/rules/compositions.md +132 -132
- package/skills/craft/remotion-best-practices/rules/display-captions.md +176 -176
- package/skills/craft/remotion-best-practices/rules/ffmpeg.md +34 -34
- package/skills/craft/remotion-best-practices/rules/get-audio-duration.md +58 -58
- package/skills/craft/remotion-best-practices/rules/get-video-dimensions.md +68 -68
- package/skills/craft/remotion-best-practices/rules/get-video-duration.md +60 -60
- package/skills/craft/remotion-best-practices/rules/gifs.md +135 -135
- package/skills/craft/remotion-best-practices/rules/google-fonts.md +72 -72
- package/skills/craft/remotion-best-practices/rules/html-in-canvas.md +122 -122
- package/skills/craft/remotion-best-practices/rules/images.md +67 -67
- package/skills/craft/remotion-best-practices/rules/import-srt-captions.md +69 -69
- package/skills/craft/remotion-best-practices/rules/light-leaks.md +73 -73
- package/skills/craft/remotion-best-practices/rules/local-fonts.md +65 -65
- package/skills/craft/remotion-best-practices/rules/lottie.md +67 -67
- package/skills/craft/remotion-best-practices/rules/maplibre.md +441 -441
- package/skills/craft/remotion-best-practices/rules/measuring-dom-nodes.md +34 -34
- package/skills/craft/remotion-best-practices/rules/measuring-text.md +140 -140
- package/skills/craft/remotion-best-practices/rules/parameters.md +109 -109
- package/skills/craft/remotion-best-practices/rules/sequencing.md +144 -144
- package/skills/craft/remotion-best-practices/rules/sfx.md +30 -30
- package/skills/craft/remotion-best-practices/rules/silence-detection.md +73 -73
- package/skills/craft/remotion-best-practices/rules/subtitles.md +36 -36
- package/skills/craft/remotion-best-practices/rules/tailwind.md +11 -11
- package/skills/craft/remotion-best-practices/rules/text-animations.md +20 -20
- package/skills/craft/remotion-best-practices/rules/timing.md +130 -130
- package/skills/craft/remotion-best-practices/rules/transcribe-captions.md +70 -70
- package/skills/craft/remotion-best-practices/rules/transitions.md +193 -193
- package/skills/craft/remotion-best-practices/rules/transparent-videos.md +102 -102
- package/skills/craft/remotion-best-practices/rules/trimming.md +51 -51
- package/skills/craft/remotion-best-practices/rules/videos.md +169 -169
- package/skills/craft/remotion-best-practices/rules/voiceover.md +94 -94
- package/skills/craft/supabase-postgres-best-practices/CHANGELOG.md +25 -25
- package/skills/craft/supabase-postgres-best-practices/LICENSE +21 -21
- package/skills/craft/supabase-postgres-best-practices/SKILL.md +69 -69
- package/skills/craft/supabase-postgres-best-practices/references/_contributing.md +166 -166
- package/skills/craft/supabase-postgres-best-practices/references/_sections.md +47 -47
- package/skills/craft/supabase-postgres-best-practices/references/_template.md +34 -34
- package/skills/craft/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -55
- package/skills/craft/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -49
- package/skills/craft/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -46
- package/skills/craft/supabase-postgres-best-practices/references/conn-limits.md +44 -44
- package/skills/craft/supabase-postgres-best-practices/references/conn-pooling.md +41 -41
- package/skills/craft/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -46
- package/skills/craft/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -54
- package/skills/craft/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -53
- package/skills/craft/supabase-postgres-best-practices/references/data-pagination.md +50 -50
- package/skills/craft/supabase-postgres-best-practices/references/data-upsert.md +50 -50
- package/skills/craft/supabase-postgres-best-practices/references/lock-advisory.md +56 -56
- package/skills/craft/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -68
- package/skills/craft/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -50
- package/skills/craft/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -54
- package/skills/craft/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -45
- package/skills/craft/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -55
- package/skills/craft/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -55
- package/skills/craft/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -44
- package/skills/craft/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -40
- package/skills/craft/supabase-postgres-best-practices/references/query-index-types.md +48 -48
- package/skills/craft/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -43
- package/skills/craft/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -45
- package/skills/craft/supabase-postgres-best-practices/references/schema-constraints.md +80 -80
- package/skills/craft/supabase-postgres-best-practices/references/schema-data-types.md +46 -46
- package/skills/craft/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -59
- package/skills/craft/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -55
- package/skills/craft/supabase-postgres-best-practices/references/schema-partitioning.md +55 -55
- package/skills/craft/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -61
- package/skills/craft/supabase-postgres-best-practices/references/security-privileges.md +54 -54
- package/skills/craft/supabase-postgres-best-practices/references/security-rls-basics.md +50 -50
- package/skills/craft/supabase-postgres-best-practices/references/security-rls-performance.md +63 -63
- package/skills/craft/uipm-banner-design/LICENSE +21 -21
- package/skills/craft/uipm-banner-design/SKILL.md +201 -201
- package/skills/craft/uipm-banner-design/references/banner-sizes-and-styles.md +129 -129
- package/skills/craft/uipm-brand/LICENSE +21 -21
- package/skills/craft/uipm-brand/SKILL.md +104 -104
- package/skills/craft/uipm-brand/references/approval-checklist.md +184 -184
- package/skills/craft/uipm-brand/references/asset-organization.md +167 -167
- package/skills/craft/uipm-brand/references/brand-guideline-template.md +161 -161
- package/skills/craft/uipm-brand/references/color-palette-management.md +203 -203
- package/skills/craft/uipm-brand/references/consistency-checklist.md +105 -105
- package/skills/craft/uipm-brand/references/logo-usage-rules.md +204 -204
- package/skills/craft/uipm-brand/references/messaging-framework.md +91 -91
- package/skills/craft/uipm-brand/references/typography-specifications.md +265 -265
- package/skills/craft/uipm-brand/references/update.md +128 -128
- package/skills/craft/uipm-brand/references/visual-identity.md +109 -109
- package/skills/craft/uipm-brand/references/voice-framework.md +99 -99
- package/skills/craft/uipm-brand/scripts/extract-colors.cjs +333 -333
- package/skills/craft/uipm-brand/scripts/inject-brand-context.cjs +324 -324
- package/skills/craft/uipm-brand/scripts/sync-brand-to-tokens.cjs +269 -269
- package/skills/craft/uipm-brand/scripts/validate-asset.cjs +361 -361
- package/skills/craft/uipm-brand/templates/brand-guidelines-starter.md +280 -280
- package/skills/craft/uipm-design/LICENSE +21 -21
- package/skills/craft/uipm-design/SKILL.md +305 -305
- package/skills/craft/uipm-design/data/cip/deliverables.csv +50 -50
- package/skills/craft/uipm-design/data/cip/industries.csv +20 -20
- package/skills/craft/uipm-design/data/cip/mockup-contexts.csv +20 -20
- package/skills/craft/uipm-design/data/cip/styles.csv +20 -20
- package/skills/craft/uipm-design/data/icon/styles.csv +16 -16
- package/skills/craft/uipm-design/data/logo/colors.csv +56 -56
- package/skills/craft/uipm-design/data/logo/industries.csv +56 -56
- package/skills/craft/uipm-design/data/logo/styles.csv +56 -56
- package/skills/craft/uipm-design/references/banner-sizes-and-styles.md +129 -129
- package/skills/craft/uipm-design/references/cip-deliverable-guide.md +111 -111
- package/skills/craft/uipm-design/references/cip-design.md +121 -121
- package/skills/craft/uipm-design/references/cip-prompt-engineering.md +94 -94
- package/skills/craft/uipm-design/references/cip-style-guide.md +76 -76
- package/skills/craft/uipm-design/references/design-routing.md +226 -226
- package/skills/craft/uipm-design/references/icon-design.md +122 -122
- package/skills/craft/uipm-design/references/logo-color-psychology.md +113 -113
- package/skills/craft/uipm-design/references/logo-design.md +92 -92
- package/skills/craft/uipm-design/references/logo-prompt-engineering.md +176 -176
- package/skills/craft/uipm-design/references/logo-style-guide.md +129 -129
- package/skills/craft/uipm-design/references/slides-copywriting-formulas.md +92 -92
- package/skills/craft/uipm-design/references/slides-create.md +5 -5
- package/skills/craft/uipm-design/references/slides-html-template.md +374 -374
- package/skills/craft/uipm-design/references/slides-layout-patterns.md +155 -155
- package/skills/craft/uipm-design/references/slides-strategies.md +97 -97
- package/skills/craft/uipm-design/references/slides.md +42 -42
- package/skills/craft/uipm-design/references/social-photos-design.md +353 -353
- package/skills/craft/uipm-design/scripts/cip/core.py +215 -215
- package/skills/craft/uipm-design/scripts/cip/generate.py +484 -484
- package/skills/craft/uipm-design/scripts/cip/render-html.py +424 -424
- package/skills/craft/uipm-design/scripts/cip/search.py +127 -127
- package/skills/craft/uipm-design/scripts/icon/generate.py +487 -487
- package/skills/craft/uipm-design/scripts/logo/core.py +175 -175
- package/skills/craft/uipm-design/scripts/logo/generate.py +362 -362
- package/skills/craft/uipm-design/scripts/logo/search.py +114 -114
- package/skills/craft/uipm-design-system/LICENSE +21 -21
- package/skills/craft/uipm-design-system/SKILL.md +255 -255
- package/skills/craft/uipm-design-system/data/slide-backgrounds.csv +11 -11
- package/skills/craft/uipm-design-system/data/slide-charts.csv +26 -26
- package/skills/craft/uipm-design-system/data/slide-color-logic.csv +14 -14
- package/skills/craft/uipm-design-system/data/slide-copy.csv +26 -26
- package/skills/craft/uipm-design-system/data/slide-layout-logic.csv +16 -16
- package/skills/craft/uipm-design-system/data/slide-layouts.csv +26 -26
- package/skills/craft/uipm-design-system/data/slide-strategies.csv +16 -16
- package/skills/craft/uipm-design-system/data/slide-typography.csv +15 -15
- package/skills/craft/uipm-design-system/references/component-specs.md +236 -236
- package/skills/craft/uipm-design-system/references/component-tokens.md +214 -214
- package/skills/craft/uipm-design-system/references/primitive-tokens.md +199 -199
- package/skills/craft/uipm-design-system/references/semantic-tokens.md +215 -215
- package/skills/craft/uipm-design-system/references/states-and-variants.md +243 -243
- package/skills/craft/uipm-design-system/references/tailwind-integration.md +257 -257
- package/skills/craft/uipm-design-system/references/token-architecture.md +226 -226
- package/skills/craft/uipm-design-system/scripts/embed-tokens.cjs +97 -97
- package/skills/craft/uipm-design-system/scripts/fetch-background.py +317 -317
- package/skills/craft/uipm-design-system/scripts/generate-slide.py +753 -753
- package/skills/craft/uipm-design-system/scripts/generate-tokens.cjs +213 -213
- package/skills/craft/uipm-design-system/scripts/html-token-validator.py +327 -327
- package/skills/craft/uipm-design-system/scripts/search-slides.py +218 -218
- package/skills/craft/uipm-design-system/scripts/slide-token-validator.py +35 -35
- package/skills/craft/uipm-design-system/scripts/slide_search_core.py +453 -453
- package/skills/craft/uipm-design-system/scripts/validate-tokens.cjs +254 -254
- package/skills/craft/uipm-design-system/templates/design-tokens-starter.json +143 -143
- package/skills/craft/uipm-slides/LICENSE +21 -21
- package/skills/craft/uipm-slides/SKILL.md +45 -45
- package/skills/craft/uipm-slides/references/copywriting-formulas.md +92 -92
- package/skills/craft/uipm-slides/references/create.md +5 -5
- package/skills/craft/uipm-slides/references/html-template.md +374 -374
- package/skills/craft/uipm-slides/references/layout-patterns.md +155 -155
- package/skills/craft/uipm-slides/references/slide-strategies.md +97 -97
- package/skills/craft/uipm-ui-ux-pro-max/LICENSE +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/SKILL.md +678 -678
- package/skills/craft/uipm-ui-ux-pro-max/data/_sync_all.py +414 -414
- package/skills/craft/uipm-ui-ux-pro-max/data/app-interface.csv +30 -30
- package/skills/craft/uipm-ui-ux-pro-max/data/charts.csv +26 -26
- package/skills/craft/uipm-ui-ux-pro-max/data/colors.csv +161 -161
- package/skills/craft/uipm-ui-ux-pro-max/data/design.csv +1775 -1775
- package/skills/craft/uipm-ui-ux-pro-max/data/draft.csv +1778 -1778
- package/skills/craft/uipm-ui-ux-pro-max/data/google-fonts.csv +1924 -1924
- package/skills/craft/uipm-ui-ux-pro-max/data/icons.csv +105 -105
- package/skills/craft/uipm-ui-ux-pro-max/data/landing.csv +35 -35
- package/skills/craft/uipm-ui-ux-pro-max/data/products.csv +162 -162
- package/skills/craft/uipm-ui-ux-pro-max/data/react-performance.csv +45 -45
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/angular.csv +51 -51
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/astro.csv +54 -54
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/flutter.csv +53 -53
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -56
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -53
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/laravel.csv +51 -51
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/nextjs.csv +53 -53
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -51
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -59
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/react-native.csv +52 -52
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/react.csv +54 -54
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/shadcn.csv +61 -61
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/svelte.csv +54 -54
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/threejs.csv +54 -54
- package/skills/craft/uipm-ui-ux-pro-max/data/stacks/vue.csv +50 -50
- package/skills/craft/uipm-ui-ux-pro-max/data/styles.csv +85 -85
- package/skills/craft/uipm-ui-ux-pro-max/data/typography.csv +74 -74
- package/skills/craft/uipm-ui-ux-pro-max/data/ui-reasoning.csv +162 -162
- package/skills/craft/uipm-ui-ux-pro-max/data/ux-guidelines.csv +99 -99
- package/skills/craft/uipm-ui-ux-pro-max/scripts/core.py +262 -262
- package/skills/craft/uipm-ui-ux-pro-max/scripts/design_system.py +1148 -1148
- package/skills/craft/uipm-ui-ux-pro-max/scripts/search.py +114 -114
- package/skills/craft/uipm-ui-ux-pro-max/templates/base/quick-reference.md +297 -297
- package/skills/craft/uipm-ui-ux-pro-max/templates/base/skill-content.md +375 -375
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/agent.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/augment.json +18 -18
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/claude.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/codebuddy.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/codex.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/continue.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/copilot.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/cursor.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/droid.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/gemini.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/kilocode.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/kiro.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/opencode.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/qoder.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/roocode.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/trae.json +21 -21
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/warp.json +18 -18
- package/skills/craft/uipm-ui-ux-pro-max/templates/platforms/windsurf.json +21 -21
- package/skills/craft/vercel-optimize/AGENTS.md +48 -48
- package/skills/craft/vercel-optimize/CONTRIBUTING.md +41 -41
- package/skills/craft/vercel-optimize/LICENSE +21 -21
- package/skills/craft/vercel-optimize/README.md +91 -91
- package/skills/craft/vercel-optimize/SKILL.md +325 -325
- package/skills/craft/vercel-optimize/lib/auth-route.mjs +23 -23
- package/skills/craft/vercel-optimize/lib/budget-summary.mjs +208 -208
- package/skills/craft/vercel-optimize/lib/citations.mjs +147 -147
- package/skills/craft/vercel-optimize/lib/cost-coverage.mjs +162 -162
- package/skills/craft/vercel-optimize/lib/dedup-recs.mjs +340 -340
- package/skills/craft/vercel-optimize/lib/deep-dive.mjs +371 -371
- package/skills/craft/vercel-optimize/lib/display-labels.mjs +219 -219
- package/skills/craft/vercel-optimize/lib/extract-claims.mjs +640 -640
- package/skills/craft/vercel-optimize/lib/framework-support.mjs +69 -69
- package/skills/craft/vercel-optimize/lib/gates/build-minutes-fanout.mjs +73 -73
- package/skills/craft/vercel-optimize/lib/gates/cold-start.mjs +72 -72
- package/skills/craft/vercel-optimize/lib/gates/contract.mjs +82 -82
- package/skills/craft/vercel-optimize/lib/gates/cwv-poor.mjs +95 -95
- package/skills/craft/vercel-optimize/lib/gates/external-api-slow.mjs +60 -60
- package/skills/craft/vercel-optimize/lib/gates/hard-gates.mjs +70 -70
- package/skills/craft/vercel-optimize/lib/gates/index.mjs +45 -45
- package/skills/craft/vercel-optimize/lib/gates/isr-overrevalidation.mjs +62 -62
- package/skills/craft/vercel-optimize/lib/gates/middleware-heavy.mjs +53 -53
- package/skills/craft/vercel-optimize/lib/gates/observability-events-attribution.mjs +58 -58
- package/skills/craft/vercel-optimize/lib/gates/platform-bot-protection.mjs +123 -123
- package/skills/craft/vercel-optimize/lib/gates/platform-fluid-compute.mjs +94 -94
- package/skills/craft/vercel-optimize/lib/gates/region-misconfig.mjs +71 -71
- package/skills/craft/vercel-optimize/lib/gates/route-errors.mjs +95 -95
- package/skills/craft/vercel-optimize/lib/gates/scanner-driven.mjs +150 -150
- package/skills/craft/vercel-optimize/lib/gates/select-candidates.mjs +137 -137
- package/skills/craft/vercel-optimize/lib/gates/slow-route.mjs +97 -97
- package/skills/craft/vercel-optimize/lib/gates/types.d.ts +38 -38
- package/skills/craft/vercel-optimize/lib/gates/uncached-route.mjs +103 -103
- package/skills/craft/vercel-optimize/lib/gates/usage-spike-triage.mjs +122 -122
- package/skills/craft/vercel-optimize/lib/grade-recommendation.mjs +170 -170
- package/skills/craft/vercel-optimize/lib/impact-label.mjs +128 -128
- package/skills/craft/vercel-optimize/lib/impact-magnitude.mjs +66 -66
- package/skills/craft/vercel-optimize/lib/investigation-brief.mjs +751 -751
- package/skills/craft/vercel-optimize/lib/observation-safety.mjs +217 -217
- package/skills/craft/vercel-optimize/lib/project-facts.mjs +101 -101
- package/skills/craft/vercel-optimize/lib/queries.mjs +333 -333
- package/skills/craft/vercel-optimize/lib/reconcile-candidates.mjs +388 -388
- package/skills/craft/vercel-optimize/lib/render-report.mjs +1065 -1065
- package/skills/craft/vercel-optimize/lib/repo-root.mjs +97 -97
- package/skills/craft/vercel-optimize/lib/route-normalize.mjs +224 -224
- package/skills/craft/vercel-optimize/lib/sanitizers/bot-protection-certainty.mjs +56 -56
- package/skills/craft/vercel-optimize/lib/sanitizers/cache-tag-invalidation-certainty.mjs +33 -33
- package/skills/craft/vercel-optimize/lib/sanitizers/count-correct.mjs +53 -53
- package/skills/craft/vercel-optimize/lib/sanitizers/function-duration-invocations.mjs +32 -32
- package/skills/craft/vercel-optimize/lib/sanitizers/index.mjs +87 -87
- package/skills/craft/vercel-optimize/lib/sanitizers/middleware-conflict.mjs +37 -37
- package/skills/craft/vercel-optimize/lib/sanitizers/missing-citation.mjs +16 -16
- package/skills/craft/vercel-optimize/lib/sanitizers/pre-release.mjs +75 -75
- package/skills/craft/vercel-optimize/lib/sanitizers/rate-limit.mjs +73 -73
- package/skills/craft/vercel-optimize/lib/sanitizers/rendering-mode-mislabel.mjs +42 -42
- package/skills/craft/vercel-optimize/lib/sanitizers/undeclared-dep.mjs +110 -110
- package/skills/craft/vercel-optimize/lib/sanitizers/vercel-directive-strip.mjs +37 -37
- package/skills/craft/vercel-optimize/lib/sanitizers/window-units.mjs +26 -26
- package/skills/craft/vercel-optimize/lib/scanners/cache-components-suspense-dedupe.mjs +114 -114
- package/skills/craft/vercel-optimize/lib/scanners/edge-heavy-import.mjs +102 -102
- package/skills/craft/vercel-optimize/lib/scanners/force-dynamic.mjs +39 -39
- package/skills/craft/vercel-optimize/lib/scanners/headers-in-page.mjs +43 -43
- package/skills/craft/vercel-optimize/lib/scanners/index.mjs +35 -35
- package/skills/craft/vercel-optimize/lib/scanners/large-static-asset.mjs +93 -93
- package/skills/craft/vercel-optimize/lib/scanners/max-age-without-s-maxage.mjs +47 -47
- package/skills/craft/vercel-optimize/lib/scanners/middleware-broad-matcher.mjs +53 -53
- package/skills/craft/vercel-optimize/lib/scanners/missing-cache-headers.mjs +97 -97
- package/skills/craft/vercel-optimize/lib/scanners/prisma-include-tree.mjs +39 -39
- package/skills/craft/vercel-optimize/lib/scanners/region-pin-in-config.mjs +89 -89
- package/skills/craft/vercel-optimize/lib/scanners/source-maps-production.mjs +33 -33
- package/skills/craft/vercel-optimize/lib/scanners/sveltekit-prerender-missing.mjs +47 -47
- package/skills/craft/vercel-optimize/lib/scanners/turbo-force-bypass.mjs +136 -136
- package/skills/craft/vercel-optimize/lib/scanners/unoptimized-image.mjs +127 -127
- package/skills/craft/vercel-optimize/lib/scanners/use-cache-date-stamp.mjs +112 -112
- package/skills/craft/vercel-optimize/lib/support-topics.mjs +365 -365
- package/skills/craft/vercel-optimize/lib/throttle.mjs +280 -280
- package/skills/craft/vercel-optimize/lib/util.mjs +17 -17
- package/skills/craft/vercel-optimize/lib/vercel.mjs +855 -855
- package/skills/craft/vercel-optimize/lib/verify-claim.mjs +1843 -1843
- package/skills/craft/vercel-optimize/lib/workspace-resolver.mjs +552 -552
- package/skills/craft/vercel-optimize/metadata.json +14 -14
- package/skills/craft/vercel-optimize/references/candidates.md +176 -176
- package/skills/craft/vercel-optimize/references/data-collection.md +224 -224
- package/skills/craft/vercel-optimize/references/docs-library.json +683 -683
- package/skills/craft/vercel-optimize/references/doctrine.md +108 -108
- package/skills/craft/vercel-optimize/references/observability-plus.md +109 -109
- package/skills/craft/vercel-optimize/references/playbooks/README.md +57 -57
- package/skills/craft/vercel-optimize/references/playbooks/ai-application.md +32 -32
- package/skills/craft/vercel-optimize/references/playbooks/api-service.md +30 -30
- package/skills/craft/vercel-optimize/references/playbooks/content-site.md +30 -30
- package/skills/craft/vercel-optimize/references/playbooks/ecommerce.md +30 -30
- package/skills/craft/vercel-optimize/references/playbooks/marketing.md +30 -30
- package/skills/craft/vercel-optimize/references/playbooks/saas.md +31 -31
- package/skills/craft/vercel-optimize/references/playbooks/sveltekit.md +75 -75
- package/skills/craft/vercel-optimize/references/recommendations.md +214 -214
- package/skills/craft/vercel-optimize/references/scanner-patterns.md +266 -266
- package/skills/craft/vercel-optimize/references/scoring.md +208 -208
- package/skills/craft/vercel-optimize/references/support-topics/README.md +50 -50
- package/skills/craft/vercel-optimize/references/support-topics/astro-edge-middleware-scope.md +30 -30
- package/skills/craft/vercel-optimize/references/support-topics/astro-output-mode-and-isr.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/auth-preserving-parallelization.md +30 -30
- package/skills/craft/vercel-optimize/references/support-topics/bot-protection-product-guardrails.md +32 -32
- package/skills/craft/vercel-optimize/references/support-topics/build-minutes-monorepo-fanout.md +32 -32
- package/skills/craft/vercel-optimize/references/support-topics/cache-components-static-shell-boundaries.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/cache-components-suspense-dedupe-pitfall.md +32 -32
- package/skills/craft/vercel-optimize/references/support-topics/cdn-cache-auth-safety.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/cold-start-initialization-bundle.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/core-web-vitals-client-bottlenecks.md +33 -33
- package/skills/craft/vercel-optimize/references/support-topics/database-egress-pooling-region.md +32 -32
- package/skills/craft/vercel-optimize/references/support-topics/dynamic-rendering-traps.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/external-api-critical-path-platform.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/external-api-critical-path.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/fast-data-transfer-payloads.md +26 -26
- package/skills/craft/vercel-optimize/references/support-topics/fluid-compute-caveats.md +26 -26
- package/skills/craft/vercel-optimize/references/support-topics/function-duration-io-and-after.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/function-invocation-reduction.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/function-region-misconfiguration-ttfb.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/image-optimization-cost-control.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/isr-revalidation-static-generation.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/middleware-proxy-edge-cost.md +30 -30
- package/skills/craft/vercel-optimize/references/support-topics/next-fetch-revalidate-floor.md +30 -30
- package/skills/craft/vercel-optimize/references/support-topics/next-font-cls-self-hosting.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/next-heavy-ui-lazy-load-boundaries.md +28 -28
- package/skills/craft/vercel-optimize/references/support-topics/next-image-lcp-preload-sizes.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/next-route-handler-get-cache-defaults.md +30 -30
- package/skills/craft/vercel-optimize/references/support-topics/next-script-third-party-strategy.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/nextjs-version-cache-semantics.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/not-found-catchall-request-waste.md +33 -33
- package/skills/craft/vercel-optimize/references/support-topics/nuxt-route-rules-cache-isr.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/observability-events-cost-attribution.md +27 -27
- package/skills/craft/vercel-optimize/references/support-topics/post-response-work-waituntil.md +26 -26
- package/skills/craft/vercel-optimize/references/support-topics/route-error-durable-offload.md +33 -33
- package/skills/craft/vercel-optimize/references/support-topics/route-error-runtime-limits.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/runtime-cache-reusable-data.md +30 -30
- package/skills/craft/vercel-optimize/references/support-topics/sveltekit-isr-prerender-safety.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/sveltekit-split-cold-start-tradeoff.md +30 -30
- package/skills/craft/vercel-optimize/references/support-topics/usage-spike-triage.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/use-cache-date-stamp-isr-write-amplifier.md +31 -31
- package/skills/craft/vercel-optimize/references/support-topics/use-cache-remote-shared-origin-data.md +30 -30
- package/skills/craft/vercel-optimize/references/support-topics/workflow-resumable-stream-routes.md +32 -32
- package/skills/craft/vercel-optimize/references/verification.md +102 -102
- package/skills/craft/vercel-optimize/references/voice.md +76 -76
- package/skills/craft/vercel-optimize/scripts/budget-summary.mjs +58 -58
- package/skills/craft/vercel-optimize/scripts/build-docs.mjs +76 -76
- package/skills/craft/vercel-optimize/scripts/check-citations.mjs +91 -91
- package/skills/craft/vercel-optimize/scripts/check-docs-fresh.mjs +100 -100
- package/skills/craft/vercel-optimize/scripts/collect-signals.mjs +638 -638
- package/skills/craft/vercel-optimize/scripts/collect-sub-agent-outputs.mjs +306 -306
- package/skills/craft/vercel-optimize/scripts/deep-dive.mjs +358 -358
- package/skills/craft/vercel-optimize/scripts/gate-investigations.mjs +178 -178
- package/skills/craft/vercel-optimize/scripts/merge-signals.mjs +203 -203
- package/skills/craft/vercel-optimize/scripts/prepare-investigation-brief.mjs +249 -249
- package/skills/craft/vercel-optimize/scripts/reconcile-candidates.mjs +69 -69
- package/skills/craft/vercel-optimize/scripts/render-report.mjs +462 -462
- package/skills/craft/vercel-optimize/scripts/scan-codebase.mjs +361 -361
- package/skills/craft/vercel-optimize/scripts/verify-and-regen.mjs +379 -379
- package/skills/craft/vercel-optimize/scripts/verify-finding.mjs +21 -21
- package/skills/craft/web-design-guidelines/LICENSE +21 -21
- package/skills/craft/web-design-guidelines/SKILL.md +43 -43
- package/skills/craft/zero-to-live/LICENSE +21 -21
- package/skills/craft/zero-to-live/SKILL.md +422 -422
- package/skills/creative/creative-3d-modeling/LICENSE +21 -21
- package/skills/creative/creative-3d-modeling/SKILL.md +70 -70
- package/skills/creative/creative-architecture/LICENSE +21 -21
- package/skills/creative/creative-architecture/SKILL.md +94 -94
- package/skills/creative/creative-design-principles/LICENSE +21 -21
- package/skills/creative/creative-design-principles/SKILL.md +95 -95
- package/skills/creative/creative-fashion-advanced/LICENSE +21 -21
- package/skills/creative/creative-fashion-advanced/SKILL.md +68 -68
- package/skills/creative/creative-fashion-design/LICENSE +21 -21
- package/skills/creative/creative-fashion-design/SKILL.md +66 -66
- package/skills/creative/creative-game-design/LICENSE +21 -21
- package/skills/creative/creative-game-design/SKILL.md +77 -77
- package/skills/creative/creative-industrial-design/LICENSE +21 -21
- package/skills/creative/creative-industrial-design/SKILL.md +57 -57
- package/skills/creative/creative-interior-design/LICENSE +21 -21
- package/skills/creative/creative-interior-design/SKILL.md +59 -59
- package/skills/creative/creative-music-theory/LICENSE +21 -21
- package/skills/creative/creative-music-theory/SKILL.md +98 -98
- package/skills/creative/creative-photography/LICENSE +21 -21
- package/skills/creative/creative-photography/SKILL.md +87 -87
- package/skills/creative/creative-textile-science/LICENSE +21 -21
- package/skills/creative/creative-textile-science/SKILL.md +67 -67
- package/skills/creative/creative-ux/LICENSE +21 -21
- package/skills/creative/creative-ux/SKILL.md +81 -81
- package/skills/creative/creative-video/LICENSE +21 -21
- package/skills/creative/creative-video/SKILL.md +84 -84
- package/skills/creative/creative-writing-craft/LICENSE +21 -21
- package/skills/creative/creative-writing-craft/SKILL.md +91 -91
- package/skills/diagram-maker/SKILL.md +56 -56
- package/skills/diagram-maker/references/excalidraw-patterns.md +85 -85
- package/skills/diagram-maker/references/svg-template.md +112 -112
- package/skills/discord/SKILL.md +140 -140
- package/skills/education/edu-adult-learning/LICENSE +21 -21
- package/skills/education/edu-adult-learning/SKILL.md +81 -81
- package/skills/education/edu-africa-multilingual/LICENSE +21 -21
- package/skills/education/edu-africa-multilingual/SKILL.md +55 -55
- package/skills/education/edu-arabic/LICENSE +21 -21
- package/skills/education/edu-arabic/SKILL.md +60 -60
- package/skills/education/edu-australia-nz/LICENSE +21 -21
- package/skills/education/edu-australia-nz/SKILL.md +48 -48
- package/skills/education/edu-china-mandarin/LICENSE +21 -21
- package/skills/education/edu-china-mandarin/SKILL.md +58 -58
- package/skills/education/edu-critical-thinking/LICENSE +21 -21
- package/skills/education/edu-critical-thinking/SKILL.md +86 -86
- package/skills/education/edu-curriculum/LICENSE +21 -21
- package/skills/education/edu-curriculum/SKILL.md +87 -87
- package/skills/education/edu-ed-tech/LICENSE +21 -21
- package/skills/education/edu-ed-tech/SKILL.md +73 -73
- package/skills/education/edu-france/LICENSE +21 -21
- package/skills/education/edu-france/SKILL.md +42 -42
- package/skills/education/edu-germany/LICENSE +21 -21
- package/skills/education/edu-germany/SKILL.md +46 -46
- package/skills/education/edu-india-competitive/LICENSE +21 -21
- package/skills/education/edu-india-competitive/SKILL.md +159 -159
- package/skills/education/edu-india-east/LICENSE +21 -21
- package/skills/education/edu-india-east/SKILL.md +60 -60
- package/skills/education/edu-india-hindi/LICENSE +21 -21
- package/skills/education/edu-india-hindi/SKILL.md +107 -107
- package/skills/education/edu-india-south/LICENSE +21 -21
- package/skills/education/edu-india-south/SKILL.md +64 -64
- package/skills/education/edu-india-west/LICENSE +21 -21
- package/skills/education/edu-india-west/SKILL.md +68 -68
- package/skills/education/edu-indonesia-malay/LICENSE +21 -21
- package/skills/education/edu-indonesia-malay/SKILL.md +57 -57
- package/skills/education/edu-international-ib/LICENSE +21 -21
- package/skills/education/edu-international-ib/SKILL.md +61 -61
- package/skills/education/edu-japan/LICENSE +21 -21
- package/skills/education/edu-japan/SKILL.md +48 -48
- package/skills/education/edu-korea/LICENSE +21 -21
- package/skills/education/edu-korea/SKILL.md +48 -48
- package/skills/education/edu-learning-science/LICENSE +21 -21
- package/skills/education/edu-learning-science/SKILL.md +76 -76
- package/skills/education/edu-portuguese-brazil/LICENSE +21 -21
- package/skills/education/edu-portuguese-brazil/SKILL.md +51 -51
- package/skills/education/edu-russia/LICENSE +21 -21
- package/skills/education/edu-russia/SKILL.md +50 -50
- package/skills/education/edu-spain-latam/LICENSE +21 -21
- package/skills/education/edu-spain-latam/SKILL.md +55 -55
- package/skills/education/edu-special/LICENSE +21 -21
- package/skills/education/edu-special/SKILL.md +76 -76
- package/skills/education/edu-thailand/LICENSE +21 -21
- package/skills/education/edu-thailand/SKILL.md +55 -55
- package/skills/education/edu-turkey/LICENSE +21 -21
- package/skills/education/edu-turkey/SKILL.md +58 -58
- package/skills/education/edu-uk-gcse-alevel/LICENSE +21 -21
- package/skills/education/edu-uk-gcse-alevel/SKILL.md +51 -51
- package/skills/education/edu-usa-graduate/LICENSE +21 -21
- package/skills/education/edu-usa-graduate/SKILL.md +57 -57
- package/skills/education/edu-usa-sat-act/LICENSE +21 -21
- package/skills/education/edu-usa-sat-act/SKILL.md +55 -55
- package/skills/education/edu-vietnam/LICENSE +21 -21
- package/skills/education/edu-vietnam/SKILL.md +53 -53
- package/skills/eightctl/SKILL.md +54 -54
- package/skills/engineering/eng-aerospace/LICENSE +21 -21
- package/skills/engineering/eng-aerospace/SKILL.md +117 -117
- package/skills/engineering/eng-chemical/LICENSE +21 -21
- package/skills/engineering/eng-chemical/SKILL.md +63 -63
- package/skills/engineering/eng-civil/LICENSE +21 -21
- package/skills/engineering/eng-civil/SKILL.md +223 -223
- package/skills/engineering/eng-control-systems/LICENSE +21 -21
- package/skills/engineering/eng-control-systems/SKILL.md +158 -158
- package/skills/engineering/eng-cryogenics/LICENSE +21 -21
- package/skills/engineering/eng-cryogenics/SKILL.md +151 -151
- package/skills/engineering/eng-electrical/LICENSE +21 -21
- package/skills/engineering/eng-electrical/SKILL.md +70 -70
- package/skills/engineering/eng-electronics-embedded/LICENSE +21 -21
- package/skills/engineering/eng-electronics-embedded/SKILL.md +89 -89
- package/skills/engineering/eng-environmental/LICENSE +21 -21
- package/skills/engineering/eng-environmental/SKILL.md +66 -66
- package/skills/engineering/eng-manufacturing/LICENSE +21 -21
- package/skills/engineering/eng-manufacturing/SKILL.md +78 -78
- package/skills/engineering/eng-mechanical/LICENSE +21 -21
- package/skills/engineering/eng-mechanical/SKILL.md +66 -66
- package/skills/engineering/eng-project/LICENSE +21 -21
- package/skills/engineering/eng-project/SKILL.md +72 -72
- package/skills/engineering/eng-propulsion/LICENSE +21 -21
- package/skills/engineering/eng-propulsion/SKILL.md +133 -133
- package/skills/engineering/eng-robotics/LICENSE +21 -21
- package/skills/engineering/eng-robotics/SKILL.md +92 -92
- package/skills/engineering/eng-systems/LICENSE +21 -21
- package/skills/engineering/eng-systems/SKILL.md +81 -81
- package/skills/environment/env-biodiversity/LICENSE +21 -21
- package/skills/environment/env-biodiversity/SKILL.md +66 -66
- package/skills/environment/env-circular-economy/LICENSE +21 -21
- package/skills/environment/env-circular-economy/SKILL.md +71 -71
- package/skills/environment/env-climate-action/LICENSE +21 -21
- package/skills/environment/env-climate-action/SKILL.md +55 -55
- package/skills/environment/env-energy/LICENSE +21 -21
- package/skills/environment/env-energy/SKILL.md +83 -83
- package/skills/environment/env-sustainability-biz/LICENSE +21 -21
- package/skills/environment/env-sustainability-biz/SKILL.md +65 -65
- package/skills/environment/env-water/LICENSE +21 -21
- package/skills/environment/env-water/SKILL.md +67 -67
- package/skills/finance/finance-accounting/LICENSE +21 -21
- package/skills/finance/finance-accounting/SKILL.md +239 -239
- package/skills/finance/finance-banking/LICENSE +21 -21
- package/skills/finance/finance-banking/SKILL.md +54 -54
- package/skills/finance/finance-corporate/LICENSE +21 -21
- package/skills/finance/finance-corporate/SKILL.md +105 -105
- package/skills/finance/finance-crypto/LICENSE +21 -21
- package/skills/finance/finance-crypto/SKILL.md +94 -94
- package/skills/finance/finance-debt-management/LICENSE +21 -21
- package/skills/finance/finance-debt-management/SKILL.md +87 -87
- package/skills/finance/finance-insurance/LICENSE +21 -21
- package/skills/finance/finance-insurance/SKILL.md +91 -91
- package/skills/finance/finance-investing/LICENSE +21 -21
- package/skills/finance/finance-investing/SKILL.md +269 -269
- package/skills/finance/finance-options-derivatives/LICENSE +21 -21
- package/skills/finance/finance-options-derivatives/SKILL.md +68 -68
- package/skills/finance/finance-personal/LICENSE +21 -21
- package/skills/finance/finance-personal/SKILL.md +268 -268
- package/skills/finance/finance-real-estate/LICENSE +21 -21
- package/skills/finance/finance-real-estate/SKILL.md +110 -110
- package/skills/finance/finance-startup/LICENSE +21 -21
- package/skills/finance/finance-startup/SKILL.md +253 -253
- package/skills/finance/finance-tax-planning/LICENSE +21 -21
- package/skills/finance/finance-tax-planning/SKILL.md +89 -89
- package/skills/finance/finance-trading/LICENSE +21 -21
- package/skills/finance/finance-trading/SKILL.md +112 -112
- package/skills/gemini/SKILL.md +51 -51
- package/skills/gh-issues/SKILL.md +216 -216
- package/skills/gifgrep/SKILL.md +89 -89
- package/skills/github/SKILL.md +87 -87
- package/skills/gog/SKILL.md +120 -120
- package/skills/goplaces/SKILL.md +56 -56
- package/skills/health/health-aging/LICENSE +21 -21
- package/skills/health/health-aging/SKILL.md +82 -82
- package/skills/health/health-chronic/LICENSE +21 -21
- package/skills/health/health-chronic/SKILL.md +202 -202
- package/skills/health/health-dental/LICENSE +21 -21
- package/skills/health/health-dental/SKILL.md +41 -41
- package/skills/health/health-eye-care/LICENSE +21 -21
- package/skills/health/health-eye-care/SKILL.md +56 -56
- package/skills/health/health-first-aid/LICENSE +21 -21
- package/skills/health/health-first-aid/SKILL.md +201 -201
- package/skills/health/health-fitness/LICENSE +21 -21
- package/skills/health/health-fitness/SKILL.md +111 -111
- package/skills/health/health-general/LICENSE +21 -21
- package/skills/health/health-general/SKILL.md +277 -277
- package/skills/health/health-mens/LICENSE +21 -21
- package/skills/health/health-mens/SKILL.md +53 -53
- package/skills/health/health-mental/LICENSE +21 -21
- package/skills/health/health-mental/SKILL.md +221 -221
- package/skills/health/health-naturopathy-ayurveda/LICENSE +21 -21
- package/skills/health/health-naturopathy-ayurveda/SKILL.md +60 -60
- package/skills/health/health-nutrition/LICENSE +21 -21
- package/skills/health/health-nutrition/SKILL.md +262 -262
- package/skills/health/health-pediatric/LICENSE +21 -21
- package/skills/health/health-pediatric/SKILL.md +94 -94
- package/skills/health/health-pharmacology/LICENSE +21 -21
- package/skills/health/health-pharmacology/SKILL.md +87 -87
- package/skills/health/health-pregnancy/LICENSE +21 -21
- package/skills/health/health-pregnancy/SKILL.md +71 -71
- package/skills/health/health-skin/LICENSE +21 -21
- package/skills/health/health-skin/SKILL.md +71 -71
- package/skills/health/health-sleep/LICENSE +21 -21
- package/skills/health/health-sleep/SKILL.md +81 -81
- package/skills/health/health-womens/LICENSE +21 -21
- package/skills/health/health-womens/SKILL.md +72 -72
- package/skills/health/health-yoga-wellness/LICENSE +21 -21
- package/skills/health/health-yoga-wellness/SKILL.md +58 -58
- package/skills/healthcare-systems/health-sys-global/LICENSE +21 -21
- package/skills/healthcare-systems/health-sys-global/SKILL.md +69 -69
- package/skills/healthcare-systems/health-sys-management/LICENSE +21 -21
- package/skills/healthcare-systems/health-sys-management/SKILL.md +71 -71
- package/skills/healthcare-systems/health-sys-navigation/LICENSE +21 -21
- package/skills/healthcare-systems/health-sys-navigation/SKILL.md +60 -60
- package/skills/healthcare-systems/health-sys-public/LICENSE +21 -21
- package/skills/healthcare-systems/health-sys-public/SKILL.md +71 -71
- package/skills/healthcheck/SKILL.md +109 -109
- package/skills/himalaya/SKILL.md +84 -84
- package/skills/himalaya/references/configuration.md +184 -184
- package/skills/himalaya/references/message-composition.md +199 -199
- package/skills/humanities/humanities-history-world/LICENSE +21 -21
- package/skills/humanities/humanities-history-world/SKILL.md +59 -59
- package/skills/humanities/humanities-indian-classical/LICENSE +21 -21
- package/skills/humanities/humanities-indian-classical/SKILL.md +104 -104
- package/skills/humanities/humanities-philosophy/LICENSE +21 -21
- package/skills/humanities/humanities-philosophy/SKILL.md +105 -105
- package/skills/humanities/humanities-world-religions/LICENSE +21 -21
- package/skills/humanities/humanities-world-religions/SKILL.md +67 -67
- package/skills/impeccable/SKILL.md +185 -185
- package/skills/imsg/SKILL.md +126 -126
- package/skills/industry/industry-construction/LICENSE +21 -21
- package/skills/industry/industry-construction/SKILL.md +81 -81
- package/skills/industry/industry-education-sector/LICENSE +21 -21
- package/skills/industry/industry-education-sector/SKILL.md +49 -49
- package/skills/industry/industry-fashion/LICENSE +21 -21
- package/skills/industry/industry-fashion/SKILL.md +82 -82
- package/skills/industry/industry-food/LICENSE +21 -21
- package/skills/industry/industry-food/SKILL.md +79 -79
- package/skills/industry/industry-government/LICENSE +21 -21
- package/skills/industry/industry-government/SKILL.md +80 -80
- package/skills/industry/industry-hospitality/LICENSE +21 -21
- package/skills/industry/industry-hospitality/SKILL.md +73 -73
- package/skills/industry/industry-insurance-sector/LICENSE +21 -21
- package/skills/industry/industry-insurance-sector/SKILL.md +57 -57
- package/skills/industry/industry-logistics/LICENSE +21 -21
- package/skills/industry/industry-logistics/SKILL.md +80 -80
- package/skills/industry/industry-media/LICENSE +21 -21
- package/skills/industry/industry-media/SKILL.md +66 -66
- package/skills/industry/industry-nonprofit/LICENSE +21 -21
- package/skills/industry/industry-nonprofit/SKILL.md +77 -77
- package/skills/industry/industry-pharma/LICENSE +21 -21
- package/skills/industry/industry-pharma/SKILL.md +69 -69
- package/skills/industry/industry-real-estate/LICENSE +21 -21
- package/skills/industry/industry-real-estate/SKILL.md +61 -61
- package/skills/industry/industry-sports/LICENSE +21 -21
- package/skills/industry/industry-sports/SKILL.md +71 -71
- package/skills/industry/industry-tech-startup/LICENSE +21 -21
- package/skills/industry/industry-tech-startup/SKILL.md +82 -82
- package/skills/internal-comms/LICENSE +21 -21
- package/skills/internal-comms/SKILL.md +38 -38
- package/skills/internal-comms/examples/3p-updates.md +49 -49
- package/skills/internal-comms/examples/company-newsletter.md +76 -76
- package/skills/internal-comms/examples/faq-answers.md +35 -35
- package/skills/internal-comms/examples/general-comms.md +19 -19
- package/skills/legal/legal-business/LICENSE +21 -21
- package/skills/legal/legal-business/SKILL.md +227 -227
- package/skills/legal/legal-consumer/LICENSE +21 -21
- package/skills/legal/legal-consumer/SKILL.md +155 -155
- package/skills/legal/legal-contracts/LICENSE +21 -21
- package/skills/legal/legal-contracts/SKILL.md +268 -268
- package/skills/legal/legal-corporate-governance/LICENSE +21 -21
- package/skills/legal/legal-corporate-governance/SKILL.md +53 -53
- package/skills/legal/legal-employment/LICENSE +21 -21
- package/skills/legal/legal-employment/SKILL.md +291 -291
- package/skills/legal/legal-immigration/LICENSE +21 -21
- package/skills/legal/legal-immigration/SKILL.md +146 -146
- package/skills/legal/legal-international/LICENSE +21 -21
- package/skills/legal/legal-international/SKILL.md +51 -51
- package/skills/legal/legal-ip/LICENSE +21 -21
- package/skills/legal/legal-ip/SKILL.md +264 -264
- package/skills/legal/legal-privacy/LICENSE +21 -21
- package/skills/legal/legal-privacy/SKILL.md +161 -161
- package/skills/legal/legal-real-estate/LICENSE +21 -21
- package/skills/legal/legal-real-estate/SKILL.md +142 -142
- package/skills/legal/legal-startup/LICENSE +21 -21
- package/skills/legal/legal-startup/SKILL.md +182 -182
- package/skills/legal/legal-tax/LICENSE +21 -21
- package/skills/legal/legal-tax/SKILL.md +156 -156
- package/skills/mcp-builder/LICENSE +21 -21
- package/skills/mcp-builder/SKILL.md +257 -257
- package/skills/mcp-builder/reference/evaluation.md +630 -630
- package/skills/mcp-builder/reference/mcp_best_practices.md +269 -269
- package/skills/mcp-builder/reference/node_mcp_server.md +980 -980
- package/skills/mcp-builder/reference/python_mcp_server.md +737 -737
- package/skills/mcp-builder/scripts/connections.py +151 -151
- package/skills/mcp-builder/scripts/evaluation.py +373 -373
- package/skills/mcp-builder/scripts/example_evaluation.xml +22 -22
- package/skills/mcp-builder/scripts/requirements.txt +2 -2
- package/skills/mcporter/SKILL.md +65 -65
- package/skills/meme-maker/SKILL.md +46 -46
- package/skills/meme-maker/references/templates.json +358 -358
- package/skills/meme-maker/scripts/meme.mjs +398 -398
- package/skills/mental-health/mental-health-cbt/LICENSE +21 -21
- package/skills/mental-health/mental-health-cbt/SKILL.md +254 -254
- package/skills/mental-health/psych-addiction/LICENSE +21 -21
- package/skills/mental-health/psych-addiction/SKILL.md +79 -79
- package/skills/mental-health/psych-behavioral-econ/LICENSE +21 -21
- package/skills/mental-health/psych-behavioral-econ/SKILL.md +84 -84
- package/skills/mental-health/psych-child/LICENSE +21 -21
- package/skills/mental-health/psych-child/SKILL.md +84 -84
- package/skills/mental-health/psych-grief/LICENSE +21 -21
- package/skills/mental-health/psych-grief/SKILL.md +85 -85
- package/skills/mental-health/psych-mindfulness/LICENSE +21 -21
- package/skills/mental-health/psych-mindfulness/SKILL.md +71 -71
- package/skills/mental-health/psych-org/LICENSE +21 -21
- package/skills/mental-health/psych-org/SKILL.md +115 -115
- package/skills/mental-health/psych-positive/LICENSE +21 -21
- package/skills/mental-health/psych-positive/SKILL.md +86 -86
- package/skills/mental-health/psych-relationships/LICENSE +21 -21
- package/skills/mental-health/psych-relationships/SKILL.md +100 -100
- package/skills/mental-health/psych-trauma/LICENSE +21 -21
- package/skills/mental-health/psych-trauma/SKILL.md +109 -109
- package/skills/model-usage/SKILL.md +75 -75
- package/skills/model-usage/references/codexbar-cli.md +33 -33
- package/skills/model-usage/scripts/model_usage.py +319 -319
- package/skills/model-usage/scripts/test_model_usage.py +40 -40
- package/skills/nano-pdf/SKILL.md +42 -42
- package/skills/node-connect/SKILL.md +147 -147
- package/skills/node-inspect-debugger/SKILL.md +88 -88
- package/skills/notion/SKILL.md +154 -154
- package/skills/obsidian/SKILL.md +123 -123
- package/skills/openai-whisper/SKILL.md +42 -42
- package/skills/openai-whisper-api/SKILL.md +75 -75
- package/skills/openai-whisper-api/scripts/transcribe.sh +154 -154
- package/skills/openhue/SKILL.md +116 -116
- package/skills/oracle/SKILL.md +130 -130
- package/skills/ordercli/SKILL.md +82 -82
- package/skills/peekaboo/SKILL.md +217 -217
- package/skills/pyproject.toml +10 -10
- package/skills/python-debugpy/SKILL.md +76 -76
- package/skills/sag/SKILL.md +91 -91
- package/skills/science/sci-astronomy/LICENSE +21 -21
- package/skills/science/sci-astronomy/SKILL.md +80 -80
- package/skills/science/sci-biology/LICENSE +21 -21
- package/skills/science/sci-biology/SKILL.md +74 -74
- package/skills/science/sci-chemistry/LICENSE +21 -21
- package/skills/science/sci-chemistry/SKILL.md +89 -89
- package/skills/science/sci-climate/LICENSE +21 -21
- package/skills/science/sci-climate/SKILL.md +72 -72
- package/skills/science/sci-data-analysis/LICENSE +21 -21
- package/skills/science/sci-data-analysis/SKILL.md +87 -87
- package/skills/science/sci-environmental-science/LICENSE +21 -21
- package/skills/science/sci-environmental-science/SKILL.md +69 -69
- package/skills/science/sci-geology/LICENSE +21 -21
- package/skills/science/sci-geology/SKILL.md +56 -56
- package/skills/science/sci-method/LICENSE +21 -21
- package/skills/science/sci-method/SKILL.md +77 -77
- package/skills/science/sci-neuroscience/LICENSE +21 -21
- package/skills/science/sci-neuroscience/SKILL.md +79 -79
- package/skills/science/sci-physics/LICENSE +21 -21
- package/skills/science/sci-physics/SKILL.md +78 -78
- package/skills/science/sci-research-methods/LICENSE +21 -21
- package/skills/science/sci-research-methods/SKILL.md +83 -83
- package/skills/science/sci-statistics/LICENSE +21 -21
- package/skills/science/sci-statistics/SKILL.md +249 -249
- package/skills/session-logs/SKILL.md +155 -155
- package/skills/sherpa-onnx-tts/SKILL.md +113 -113
- package/skills/skill-creator/SKILL.md +81 -81
- package/skills/skill-creator/license.txt +202 -202
- package/skills/skill-creator/scripts/init_skill.py +378 -378
- package/skills/skill-creator/scripts/package_skill.py +144 -144
- package/skills/skill-creator/scripts/quick_validate.py +169 -169
- package/skills/skill-creator/scripts/test_init_skill.py +51 -51
- package/skills/skill-creator/scripts/test_package_skill.py +199 -199
- package/skills/skill-creator/scripts/test_quick_validate.py +116 -116
- package/skills/slack/SKILL.md +82 -82
- package/skills/slack-gif-creator/LICENSE +21 -21
- package/skills/slack-gif-creator/SKILL.md +293 -293
- package/skills/slack-gif-creator/requirements.txt +3 -3
- package/skills/social-sciences/social-anthropology/LICENSE +21 -21
- package/skills/social-sciences/social-anthropology/SKILL.md +62 -62
- package/skills/social-sciences/social-economics/LICENSE +21 -21
- package/skills/social-sciences/social-economics/SKILL.md +88 -88
- package/skills/social-sciences/social-geography/LICENSE +21 -21
- package/skills/social-sciences/social-geography/SKILL.md +61 -61
- package/skills/social-sciences/social-international-dev/LICENSE +21 -21
- package/skills/social-sciences/social-international-dev/SKILL.md +76 -76
- package/skills/social-sciences/social-political-science/LICENSE +21 -21
- package/skills/social-sciences/social-political-science/SKILL.md +70 -70
- package/skills/social-sciences/social-public-policy/LICENSE +21 -21
- package/skills/social-sciences/social-public-policy/SKILL.md +73 -73
- package/skills/social-sciences/social-sociology/LICENSE +21 -21
- package/skills/social-sciences/social-sociology/SKILL.md +78 -78
- package/skills/songsee/SKILL.md +53 -53
- package/skills/sonoscli/SKILL.md +69 -69
- package/skills/spike/SKILL.md +55 -55
- package/skills/spotify-player/SKILL.md +68 -68
- package/skills/summarize/SKILL.md +90 -90
- package/skills/taskflow/SKILL.md +153 -153
- package/skills/taskflow/examples/inbox-triage.lobster +33 -33
- package/skills/taskflow/examples/pr-intake.lobster +32 -32
- package/skills/taskflow-inbox-triage/SKILL.md +123 -123
- package/skills/technical/ai-ethics/LICENSE +21 -21
- package/skills/technical/ai-ethics/SKILL.md +92 -92
- package/skills/technical/ai-product-builder/LICENSE +21 -21
- package/skills/technical/ai-product-builder/SKILL.md +180 -180
- package/skills/technical/analytics-setup/LICENSE +21 -21
- package/skills/technical/analytics-setup/SKILL.md +125 -125
- package/skills/technical/api-builder/LICENSE +21 -21
- package/skills/technical/api-builder/SKILL.md +202 -202
- package/skills/technical/architecture-decisions/LICENSE +21 -21
- package/skills/technical/architecture-decisions/SKILL.md +120 -120
- package/skills/technical/auth-security/LICENSE +21 -21
- package/skills/technical/auth-security/SKILL.md +209 -209
- package/skills/technical/blockchain-web3/LICENSE +21 -21
- package/skills/technical/blockchain-web3/SKILL.md +84 -84
- package/skills/technical/cloud-architecture/LICENSE +21 -21
- package/skills/technical/cloud-architecture/SKILL.md +85 -85
- package/skills/technical/content-platform/LICENSE +21 -21
- package/skills/technical/content-platform/SKILL.md +134 -134
- package/skills/technical/cybersecurity-advanced/LICENSE +21 -21
- package/skills/technical/cybersecurity-advanced/SKILL.md +99 -99
- package/skills/technical/data-engineering/LICENSE +21 -21
- package/skills/technical/data-engineering/SKILL.md +117 -117
- package/skills/technical/database-design/LICENSE +21 -21
- package/skills/technical/database-design/SKILL.md +185 -185
- package/skills/technical/devops-cicd/LICENSE +21 -21
- package/skills/technical/devops-cicd/SKILL.md +181 -181
- package/skills/technical/ecommerce-builder/LICENSE +21 -21
- package/skills/technical/ecommerce-builder/SKILL.md +123 -123
- package/skills/technical/email-marketing/LICENSE +21 -21
- package/skills/technical/email-marketing/SKILL.md +128 -128
- package/skills/technical/fintech-builder/LICENSE +21 -21
- package/skills/technical/fintech-builder/SKILL.md +141 -141
- package/skills/technical/full-stack-web/LICENSE +21 -21
- package/skills/technical/full-stack-web/SKILL.md +173 -173
- package/skills/technical/gdpr-basics/LICENSE +21 -21
- package/skills/technical/gdpr-basics/SKILL.md +145 -145
- package/skills/technical/launch-playbook/LICENSE +21 -21
- package/skills/technical/launch-playbook/SKILL.md +95 -95
- package/skills/technical/marketing-copy/LICENSE +21 -21
- package/skills/technical/marketing-copy/SKILL.md +126 -126
- package/skills/technical/marketplace-builder/LICENSE +21 -21
- package/skills/technical/marketplace-builder/SKILL.md +105 -105
- package/skills/technical/mobile-pwa/LICENSE +21 -21
- package/skills/technical/mobile-pwa/SKILL.md +191 -191
- package/skills/technical/no-code-tools/LICENSE +21 -21
- package/skills/technical/no-code-tools/SKILL.md +80 -80
- package/skills/technical/open-source/LICENSE +21 -21
- package/skills/technical/open-source/SKILL.md +71 -71
- package/skills/technical/performance-optimization/LICENSE +21 -21
- package/skills/technical/performance-optimization/SKILL.md +155 -155
- package/skills/technical/pricing-design/LICENSE +21 -21
- package/skills/technical/pricing-design/SKILL.md +87 -87
- package/skills/technical/product-management/LICENSE +21 -21
- package/skills/technical/product-management/SKILL.md +94 -94
- package/skills/technical/saas-builder/LICENSE +21 -21
- package/skills/technical/saas-builder/SKILL.md +138 -138
- package/skills/technical/scope-estimation/LICENSE +21 -21
- package/skills/technical/scope-estimation/SKILL.md +99 -99
- package/skills/technical/secrets-management/LICENSE +21 -21
- package/skills/technical/secrets-management/SKILL.md +135 -135
- package/skills/technical/seo-technical/LICENSE +21 -21
- package/skills/technical/seo-technical/SKILL.md +136 -136
- package/skills/technical/technical-writing/LICENSE +21 -21
- package/skills/technical/technical-writing/SKILL.md +149 -149
- package/skills/technical/ux-research-tools/LICENSE +21 -21
- package/skills/technical/ux-research-tools/SKILL.md +54 -54
- package/skills/theme-factory/LICENSE +21 -21
- package/skills/theme-factory/SKILL.md +65 -65
- package/skills/theme-factory/themes/arctic-frost.md +19 -19
- package/skills/theme-factory/themes/botanical-garden.md +19 -19
- package/skills/theme-factory/themes/desert-rose.md +19 -19
- package/skills/theme-factory/themes/forest-canopy.md +19 -19
- package/skills/theme-factory/themes/golden-hour.md +19 -19
- package/skills/theme-factory/themes/midnight-galaxy.md +19 -19
- package/skills/theme-factory/themes/modern-minimalist.md +19 -19
- package/skills/theme-factory/themes/ocean-depths.md +19 -19
- package/skills/theme-factory/themes/sunset-boulevard.md +19 -19
- package/skills/theme-factory/themes/tech-innovation.md +19 -19
- package/skills/things-mac/SKILL.md +90 -90
- package/skills/tmux/SKILL.md +95 -95
- package/skills/tmux/scripts/find-sessions.sh +112 -112
- package/skills/tmux/scripts/wait-for-text.sh +83 -83
- package/skills/trades/trades-agriculture/LICENSE +21 -21
- package/skills/trades/trades-agriculture/SKILL.md +80 -80
- package/skills/trades/trades-automotive/LICENSE +21 -21
- package/skills/trades/trades-automotive/SKILL.md +84 -84
- package/skills/trades/trades-carpentry/LICENSE +21 -21
- package/skills/trades/trades-carpentry/SKILL.md +71 -71
- package/skills/trades/trades-cooking-pro/LICENSE +21 -21
- package/skills/trades/trades-cooking-pro/SKILL.md +90 -90
- package/skills/trades/trades-electrical/LICENSE +21 -21
- package/skills/trades/trades-electrical/SKILL.md +146 -146
- package/skills/trades/trades-hvac/LICENSE +21 -21
- package/skills/trades/trades-hvac/SKILL.md +80 -80
- package/skills/trades/trades-landscaping/LICENSE +21 -21
- package/skills/trades/trades-landscaping/SKILL.md +60 -60
- package/skills/trades/trades-metalworking/LICENSE +21 -21
- package/skills/trades/trades-metalworking/SKILL.md +64 -64
- package/skills/trades/trades-painting/LICENSE +21 -21
- package/skills/trades/trades-painting/SKILL.md +70 -70
- package/skills/trades/trades-plumbing/LICENSE +21 -21
- package/skills/trades/trades-plumbing/SKILL.md +160 -160
- package/skills/trades/trades-welding/LICENSE +21 -21
- package/skills/trades/trades-welding/SKILL.md +82 -82
- package/skills/trello/SKILL.md +112 -112
- package/skills/uipm-ui-styling/SKILL.md +328 -328
- package/skills/video-frames/SKILL.md +50 -50
- package/skills/video-frames/scripts/frame.sh +81 -81
- package/skills/voice-call/SKILL.md +49 -49
- package/skills/wacli/SKILL.md +76 -76
- package/skills/weather/SKILL.md +91 -91
- package/skills/web-artifacts-builder/LICENSE +21 -21
- package/skills/web-artifacts-builder/SKILL.md +82 -82
- package/skills/web-artifacts-builder/scripts/bundle-artifact.sh +53 -53
- package/skills/web-artifacts-builder/scripts/init-artifact.sh +322 -322
- package/skills/xurl/SKILL.md +124 -124
- package/skills/graphify/SKILL.md +0 -619
- package/skills/graphify/__init__.py +0 -28
- package/skills/graphify/__main__.py +0 -4582
- package/skills/graphify/affected.py +0 -154
- package/skills/graphify/always_on/agents-md.md +0 -12
- package/skills/graphify/always_on/antigravity-rules.md +0 -14
- package/skills/graphify/always_on/claude-md.md +0 -9
- package/skills/graphify/always_on/gemini-md.md +0 -9
- package/skills/graphify/always_on/kiro-steering.md +0 -5
- package/skills/graphify/always_on/vscode-instructions.md +0 -17
- package/skills/graphify/analyze.py +0 -724
- package/skills/graphify/benchmark.py +0 -155
- package/skills/graphify/build.py +0 -487
- package/skills/graphify/cache.py +0 -417
- package/skills/graphify/callflow_html.py +0 -2020
- package/skills/graphify/cluster.py +0 -272
- package/skills/graphify/command-kilo.md +0 -15
- package/skills/graphify/dedup.py +0 -429
- package/skills/graphify/detect.py +0 -1379
- package/skills/graphify/diagnostics.py +0 -390
- package/skills/graphify/export.py +0 -1408
- package/skills/graphify/extract.py +0 -11570
- package/skills/graphify/global_graph.py +0 -159
- package/skills/graphify/google_workspace.py +0 -223
- package/skills/graphify/hooks.py +0 -457
- package/skills/graphify/ingest.py +0 -331
- package/skills/graphify/llm.py +0 -1896
- package/skills/graphify/manifest.py +0 -4
- package/skills/graphify/mcp_ingest.py +0 -392
- package/skills/graphify/multigraph_compat.py +0 -212
- package/skills/graphify/pg_introspect.py +0 -142
- package/skills/graphify/prs.py +0 -748
- package/skills/graphify/querylog.py +0 -70
- package/skills/graphify/report.py +0 -218
- package/skills/graphify/scip_ingest.py +0 -363
- package/skills/graphify/security.py +0 -336
- package/skills/graphify/semantic_cleanup.py +0 -319
- package/skills/graphify/serve.py +0 -1309
- package/skills/graphify/skill-aider.md +0 -1246
- package/skills/graphify/skill-amp.md +0 -613
- package/skills/graphify/skill-claw.md +0 -616
- package/skills/graphify/skill-codex.md +0 -613
- package/skills/graphify/skill-copilot.md +0 -616
- package/skills/graphify/skill-devin.md +0 -1372
- package/skills/graphify/skill-droid.md +0 -613
- package/skills/graphify/skill-kilo.md +0 -625
- package/skills/graphify/skill-kiro.md +0 -615
- package/skills/graphify/skill-opencode.md +0 -608
- package/skills/graphify/skill-pi.md +0 -615
- package/skills/graphify/skill-trae.md +0 -614
- package/skills/graphify/skill-vscode.md +0 -612
- package/skills/graphify/skill-windows.md +0 -651
- package/skills/graphify/skills/amp/references/add-watch.md +0 -56
- package/skills/graphify/skills/amp/references/exports.md +0 -71
- package/skills/graphify/skills/amp/references/extraction-spec.md +0 -68
- package/skills/graphify/skills/amp/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/amp/references/hooks.md +0 -33
- package/skills/graphify/skills/amp/references/query.md +0 -249
- package/skills/graphify/skills/amp/references/transcribe.md +0 -48
- package/skills/graphify/skills/amp/references/update.md +0 -179
- package/skills/graphify/skills/claude/references/add-watch.md +0 -56
- package/skills/graphify/skills/claude/references/exports.md +0 -71
- package/skills/graphify/skills/claude/references/extraction-spec.md +0 -68
- package/skills/graphify/skills/claude/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/claude/references/hooks.md +0 -33
- package/skills/graphify/skills/claude/references/query.md +0 -103
- package/skills/graphify/skills/claude/references/transcribe.md +0 -48
- package/skills/graphify/skills/claude/references/update.md +0 -179
- package/skills/graphify/skills/claw/references/add-watch.md +0 -56
- package/skills/graphify/skills/claw/references/exports.md +0 -71
- package/skills/graphify/skills/claw/references/extraction-spec.md +0 -29
- package/skills/graphify/skills/claw/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/claw/references/hooks.md +0 -33
- package/skills/graphify/skills/claw/references/query.md +0 -249
- package/skills/graphify/skills/claw/references/transcribe.md +0 -48
- package/skills/graphify/skills/claw/references/update.md +0 -179
- package/skills/graphify/skills/codex/references/add-watch.md +0 -56
- package/skills/graphify/skills/codex/references/exports.md +0 -71
- package/skills/graphify/skills/codex/references/extraction-spec.md +0 -29
- package/skills/graphify/skills/codex/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/codex/references/hooks.md +0 -33
- package/skills/graphify/skills/codex/references/query.md +0 -249
- package/skills/graphify/skills/codex/references/transcribe.md +0 -48
- package/skills/graphify/skills/codex/references/update.md +0 -179
- package/skills/graphify/skills/copilot/references/add-watch.md +0 -56
- package/skills/graphify/skills/copilot/references/exports.md +0 -71
- package/skills/graphify/skills/copilot/references/extraction-spec.md +0 -68
- package/skills/graphify/skills/copilot/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/copilot/references/hooks.md +0 -33
- package/skills/graphify/skills/copilot/references/query.md +0 -249
- package/skills/graphify/skills/copilot/references/transcribe.md +0 -48
- package/skills/graphify/skills/copilot/references/update.md +0 -179
- package/skills/graphify/skills/droid/references/add-watch.md +0 -56
- package/skills/graphify/skills/droid/references/exports.md +0 -71
- package/skills/graphify/skills/droid/references/extraction-spec.md +0 -68
- package/skills/graphify/skills/droid/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/droid/references/hooks.md +0 -33
- package/skills/graphify/skills/droid/references/query.md +0 -249
- package/skills/graphify/skills/droid/references/transcribe.md +0 -48
- package/skills/graphify/skills/droid/references/update.md +0 -179
- package/skills/graphify/skills/kilo/references/add-watch.md +0 -56
- package/skills/graphify/skills/kilo/references/exports.md +0 -71
- package/skills/graphify/skills/kilo/references/extraction-spec.md +0 -68
- package/skills/graphify/skills/kilo/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/kilo/references/hooks.md +0 -33
- package/skills/graphify/skills/kilo/references/query.md +0 -249
- package/skills/graphify/skills/kilo/references/transcribe.md +0 -48
- package/skills/graphify/skills/kilo/references/update.md +0 -179
- package/skills/graphify/skills/kiro/references/add-watch.md +0 -56
- package/skills/graphify/skills/kiro/references/exports.md +0 -71
- package/skills/graphify/skills/kiro/references/extraction-spec.md +0 -29
- package/skills/graphify/skills/kiro/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/kiro/references/hooks.md +0 -33
- package/skills/graphify/skills/kiro/references/query.md +0 -249
- package/skills/graphify/skills/kiro/references/transcribe.md +0 -48
- package/skills/graphify/skills/kiro/references/update.md +0 -179
- package/skills/graphify/skills/opencode/references/add-watch.md +0 -56
- package/skills/graphify/skills/opencode/references/exports.md +0 -71
- package/skills/graphify/skills/opencode/references/extraction-spec.md +0 -68
- package/skills/graphify/skills/opencode/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/opencode/references/hooks.md +0 -33
- package/skills/graphify/skills/opencode/references/query.md +0 -249
- package/skills/graphify/skills/opencode/references/transcribe.md +0 -48
- package/skills/graphify/skills/opencode/references/update.md +0 -179
- package/skills/graphify/skills/pi/references/add-watch.md +0 -56
- package/skills/graphify/skills/pi/references/exports.md +0 -71
- package/skills/graphify/skills/pi/references/extraction-spec.md +0 -29
- package/skills/graphify/skills/pi/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/pi/references/hooks.md +0 -33
- package/skills/graphify/skills/pi/references/query.md +0 -249
- package/skills/graphify/skills/pi/references/transcribe.md +0 -48
- package/skills/graphify/skills/pi/references/update.md +0 -179
- package/skills/graphify/skills/trae/references/add-watch.md +0 -56
- package/skills/graphify/skills/trae/references/exports.md +0 -71
- package/skills/graphify/skills/trae/references/extraction-spec.md +0 -68
- package/skills/graphify/skills/trae/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/trae/references/hooks.md +0 -35
- package/skills/graphify/skills/trae/references/query.md +0 -249
- package/skills/graphify/skills/trae/references/transcribe.md +0 -48
- package/skills/graphify/skills/trae/references/update.md +0 -179
- package/skills/graphify/skills/vscode/references/add-watch.md +0 -56
- package/skills/graphify/skills/vscode/references/exports.md +0 -71
- package/skills/graphify/skills/vscode/references/extraction-spec.md +0 -68
- package/skills/graphify/skills/vscode/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/vscode/references/hooks.md +0 -33
- package/skills/graphify/skills/vscode/references/query.md +0 -249
- package/skills/graphify/skills/vscode/references/transcribe.md +0 -48
- package/skills/graphify/skills/vscode/references/update.md +0 -179
- package/skills/graphify/skills/windows/references/add-watch.md +0 -56
- package/skills/graphify/skills/windows/references/exports.md +0 -71
- package/skills/graphify/skills/windows/references/extraction-spec.md +0 -68
- package/skills/graphify/skills/windows/references/github-and-merge.md +0 -46
- package/skills/graphify/skills/windows/references/hooks.md +0 -33
- package/skills/graphify/skills/windows/references/query.md +0 -249
- package/skills/graphify/skills/windows/references/transcribe.md +0 -48
- package/skills/graphify/skills/windows/references/update.md +0 -179
- package/skills/graphify/symbol_resolution.py +0 -538
- package/skills/graphify/transcribe.py +0 -184
- package/skills/graphify/tree_html.py +0 -582
- package/skills/graphify/validate.py +0 -72
- package/skills/graphify/watch.py +0 -898
- package/skills/graphify/wiki.py +0 -282
package/skills/graphify/serve.py
DELETED
|
@@ -1,1309 +0,0 @@
|
|
|
1
|
-
# MCP stdio server - exposes graph query tools to Claude and other agents
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
import json
|
|
4
|
-
import math
|
|
5
|
-
import re
|
|
6
|
-
import sys
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
import networkx as nx
|
|
9
|
-
from networkx.readwrite import json_graph
|
|
10
|
-
from graphify.security import sanitize_label, check_graph_file_size_cap
|
|
11
|
-
from graphify.build import edge_data
|
|
12
|
-
|
|
13
|
-
try:
|
|
14
|
-
import jieba as _jieba # type: ignore[import-untyped]
|
|
15
|
-
except ImportError:
|
|
16
|
-
_jieba = None
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def _load_graph(graph_path: str) -> nx.Graph:
|
|
20
|
-
try:
|
|
21
|
-
resolved = Path(graph_path).resolve()
|
|
22
|
-
if resolved.suffix != ".json":
|
|
23
|
-
raise ValueError(f"Graph path must be a .json file, got: {graph_path!r}")
|
|
24
|
-
if not resolved.exists():
|
|
25
|
-
raise FileNotFoundError(f"Graph file not found: {resolved}")
|
|
26
|
-
check_graph_file_size_cap(resolved)
|
|
27
|
-
safe = resolved
|
|
28
|
-
data = json.loads(safe.read_text(encoding="utf-8"))
|
|
29
|
-
if "links" not in data and "edges" in data:
|
|
30
|
-
data = dict(data, links=data["edges"])
|
|
31
|
-
data = {**data, "directed": True}
|
|
32
|
-
try:
|
|
33
|
-
return json_graph.node_link_graph(data, edges="links")
|
|
34
|
-
except TypeError:
|
|
35
|
-
return json_graph.node_link_graph(data)
|
|
36
|
-
except (ValueError, FileNotFoundError) as exc:
|
|
37
|
-
print(f"error: {exc}", file=sys.stderr)
|
|
38
|
-
sys.exit(1)
|
|
39
|
-
except json.JSONDecodeError as exc:
|
|
40
|
-
print(f"error: graph.json is corrupted ({exc}). Re-run /graphify to rebuild.", file=sys.stderr)
|
|
41
|
-
sys.exit(1)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def _communities_from_graph(G: nx.Graph) -> dict[int, list[str]]:
|
|
45
|
-
"""Reconstruct community dict from community property stored on nodes."""
|
|
46
|
-
communities: dict[int, list[str]] = {}
|
|
47
|
-
for node_id, data in G.nodes(data=True):
|
|
48
|
-
cid = data.get("community")
|
|
49
|
-
if cid is not None:
|
|
50
|
-
communities.setdefault(int(cid), []).append(node_id)
|
|
51
|
-
return communities
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def _strip_diacritics(text: str) -> str:
|
|
55
|
-
import unicodedata
|
|
56
|
-
nfkd = unicodedata.normalize("NFKD", text)
|
|
57
|
-
return "".join(c for c in nfkd if not unicodedata.combining(c))
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def _search_tokens(text: str) -> list[str]:
|
|
61
|
-
"""Split text into word tokens, stripping punctuation and diacritics."""
|
|
62
|
-
return re.findall(r"\w+", _strip_diacritics(str(text)).lower())
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def _has_chinese(text: str) -> bool:
|
|
66
|
-
return any("一" <= ch <= "鿿" for ch in text)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def _segment_chinese(text: str) -> list[str]:
|
|
70
|
-
"""Segment Chinese text and keep the original term for exact matching."""
|
|
71
|
-
if _jieba is not None:
|
|
72
|
-
segments = [w for w in _jieba.cut(text) if len(w.strip()) > 0]
|
|
73
|
-
else:
|
|
74
|
-
segments = [text[i:i + 2] for i in range(len(text) - 1)] or [text]
|
|
75
|
-
if len(text) > 1 and text not in segments:
|
|
76
|
-
segments.append(text)
|
|
77
|
-
return segments
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def _is_searchable(term: str) -> bool:
|
|
81
|
-
"""True if term is Chinese, non-English, or an English word longer than 2 chars."""
|
|
82
|
-
if all("a" <= ch <= "z" for ch in term):
|
|
83
|
-
return len(term) > 2
|
|
84
|
-
return True
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def _query_terms(question: str) -> list[str]:
|
|
88
|
-
"""Split a query into searchable terms, segmenting Chinese text."""
|
|
89
|
-
terms: list[str] = []
|
|
90
|
-
for raw in question.split():
|
|
91
|
-
if _has_chinese(raw):
|
|
92
|
-
for seg in _segment_chinese(raw.lower().strip()):
|
|
93
|
-
seg = seg.strip()
|
|
94
|
-
if seg and _is_searchable(seg):
|
|
95
|
-
terms.append(seg)
|
|
96
|
-
else:
|
|
97
|
-
# Strip punctuation without touching Unicode characters (avoid NFKD mangling non-Latin scripts)
|
|
98
|
-
for tok in re.findall(r"\w+", raw.lower()):
|
|
99
|
-
if _is_searchable(tok):
|
|
100
|
-
terms.append(tok)
|
|
101
|
-
return terms
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
_EXACT_MATCH_BONUS = 1000.0
|
|
105
|
-
_PREFIX_MATCH_BONUS = 100.0
|
|
106
|
-
_SUBSTRING_MATCH_BONUS = 1.0
|
|
107
|
-
_SOURCE_MATCH_BONUS = 0.5
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def _compute_idf(G: nx.Graph, terms: list[str]) -> dict[str, float]:
|
|
111
|
-
"""IDF weights for query terms, cached in G.graph['_idf_cache'].
|
|
112
|
-
|
|
113
|
-
Common terms like 'error' or 'exception' that match hundreds of nodes get
|
|
114
|
-
low weights; rare identifiers like 'FooBarService' get high weights.
|
|
115
|
-
Cache is stored on the graph object itself so it auto-invalidates when
|
|
116
|
-
_maybe_reload() replaces G with a new object.
|
|
117
|
-
"""
|
|
118
|
-
cache: dict[str, float] = G.graph.setdefault("_idf_cache", {})
|
|
119
|
-
N = G.number_of_nodes() or 1
|
|
120
|
-
uncached = [t for t in terms if t not in cache]
|
|
121
|
-
if uncached:
|
|
122
|
-
df: dict[str, int] = {t: 0 for t in uncached}
|
|
123
|
-
for _, data in G.nodes(data=True):
|
|
124
|
-
norm_label = (
|
|
125
|
-
data.get("norm_label") or _strip_diacritics(data.get("label") or "")
|
|
126
|
-
).lower()
|
|
127
|
-
for t in uncached:
|
|
128
|
-
if t in norm_label:
|
|
129
|
-
df[t] += 1
|
|
130
|
-
for t in uncached:
|
|
131
|
-
cache[t] = math.log(1 + N / (1 + df[t]))
|
|
132
|
-
return {t: cache.get(t, math.log(1 + N)) for t in terms}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def _score_nodes(G: nx.Graph, terms: list[str]) -> list[tuple[float, str]]:
|
|
136
|
-
scored = []
|
|
137
|
-
norm_terms = [tok for t in terms for tok in _search_tokens(t)]
|
|
138
|
-
idf = _compute_idf(G, norm_terms)
|
|
139
|
-
# Whole-query string for full-label matching (mirrors _find_node's `term`).
|
|
140
|
-
joined = " ".join(norm_terms)
|
|
141
|
-
# Weight the full-query bonus by the rarest constituent term so a specific
|
|
142
|
-
# multi-word label still outweighs common-token noise; floor at 1.0.
|
|
143
|
-
joined_w = max((idf.get(t, 1.0) for t in norm_terms), default=1.0)
|
|
144
|
-
for nid, data in G.nodes(data=True):
|
|
145
|
-
norm_label = data.get("norm_label") or _strip_diacritics(data.get("label") or "").lower()
|
|
146
|
-
bare_label = norm_label.rstrip("()")
|
|
147
|
-
# Tokenized form of the label (punctuation stripped, same transform as the
|
|
148
|
-
# query). norm_label may still carry punctuation like ':' or '-', which a
|
|
149
|
-
# tokenized query can never equal; comparing token-joined forms on both
|
|
150
|
-
# sides makes "uoce: dehumidifier driver" match query "uoce dehumidifier
|
|
151
|
-
# driver".
|
|
152
|
-
label_tokens = " ".join(_search_tokens(data.get("label") or ""))
|
|
153
|
-
source = (data.get("source_file") or "").lower()
|
|
154
|
-
score = 0.0
|
|
155
|
-
# Full-query tier: a multi-word query that equals (or prefixes) the whole
|
|
156
|
-
# label must dominate the per-token bag-of-words sums below, so `path`/
|
|
157
|
-
# `query` resolve the same node `explain` does (via _find_node). Without
|
|
158
|
-
# this, no single token equals a multi-word label, the per-token exact
|
|
159
|
-
# tier never fires, and every node sharing the token set ties -> arbitrary
|
|
160
|
-
# node-id sort -> wrong/disconnected endpoint -> false "No path found".
|
|
161
|
-
if joined:
|
|
162
|
-
nid_lower = nid.lower()
|
|
163
|
-
if joined in (norm_label, bare_label, label_tokens, nid_lower):
|
|
164
|
-
score += _EXACT_MATCH_BONUS * 10 * joined_w
|
|
165
|
-
elif (
|
|
166
|
-
norm_label.startswith(joined)
|
|
167
|
-
or bare_label.startswith(joined)
|
|
168
|
-
or label_tokens.startswith(joined)
|
|
169
|
-
):
|
|
170
|
-
score += _PREFIX_MATCH_BONUS * 10 * joined_w
|
|
171
|
-
for t in norm_terms:
|
|
172
|
-
w = idf.get(t, 1.0)
|
|
173
|
-
# Three-tier precedence: exact > prefix > substring (take the
|
|
174
|
-
# strongest tier per term so a single term cannot double-count).
|
|
175
|
-
if t == norm_label or t == bare_label:
|
|
176
|
-
score += _EXACT_MATCH_BONUS * w
|
|
177
|
-
elif norm_label.startswith(t) or bare_label.startswith(t):
|
|
178
|
-
score += _PREFIX_MATCH_BONUS * w
|
|
179
|
-
elif t in norm_label:
|
|
180
|
-
score += _SUBSTRING_MATCH_BONUS * w
|
|
181
|
-
if t in source:
|
|
182
|
-
score += _SOURCE_MATCH_BONUS * w
|
|
183
|
-
if score > 0:
|
|
184
|
-
scored.append((score, nid))
|
|
185
|
-
# Sort by score desc; break ties toward the shorter label so a concise exact
|
|
186
|
-
# match beats a longer superset that happens to share the same score.
|
|
187
|
-
scored.sort(key=lambda s: (-s[0], len(G.nodes[s[1]].get("label") or s[1]), s[1]))
|
|
188
|
-
return scored
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def _pick_seeds(scored: list[tuple[float, str]], max_k: int = 3, gap_ratio: float = 0.2) -> list[str]:
|
|
192
|
-
"""Select BFS seed nodes, stopping when score drops too far below the top.
|
|
193
|
-
|
|
194
|
-
Prevents high-frequency noise terms (error, exception) from stealing seed
|
|
195
|
-
slots from a dominant identifier match. When FooBarService scores 1000 and
|
|
196
|
-
error nodes score 1.0, only FooBarService is seeded — the score gap is 99.9%
|
|
197
|
-
which is well above the 20% threshold that would allow additional seeds.
|
|
198
|
-
"""
|
|
199
|
-
if not scored:
|
|
200
|
-
return []
|
|
201
|
-
top_score = scored[0][0]
|
|
202
|
-
seeds = []
|
|
203
|
-
for score, nid in scored[:max_k]:
|
|
204
|
-
if seeds and score < top_score * gap_ratio:
|
|
205
|
-
break
|
|
206
|
-
seeds.append(nid)
|
|
207
|
-
return seeds
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
_CONTEXT_HINTS: tuple[tuple[str, tuple[str, ...]], ...] = (
|
|
211
|
-
("call", ("call", "calls", "called", "invoke", "invokes", "invoked")),
|
|
212
|
-
("import", ("import", "imports", "imported", "module", "modules")),
|
|
213
|
-
("field", ("field", "fields", "member", "members", "property", "properties")),
|
|
214
|
-
("parameter_type", ("parameter", "parameters", "param", "params", "argument", "arguments")),
|
|
215
|
-
("return_type", ("return", "returns", "returned")),
|
|
216
|
-
("generic_arg", ("generic", "generics", "template", "templates")),
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
_CONTEXT_FILTER_ALIASES: dict[str, str] = {
|
|
221
|
-
"param": "parameter_type",
|
|
222
|
-
"params": "parameter_type",
|
|
223
|
-
"parameter": "parameter_type",
|
|
224
|
-
"parameters": "parameter_type",
|
|
225
|
-
"argument": "parameter_type",
|
|
226
|
-
"arguments": "parameter_type",
|
|
227
|
-
"arg": "parameter_type",
|
|
228
|
-
"args": "parameter_type",
|
|
229
|
-
"return": "return_type",
|
|
230
|
-
"returns": "return_type",
|
|
231
|
-
"returned": "return_type",
|
|
232
|
-
"generic": "generic_arg",
|
|
233
|
-
"generics": "generic_arg",
|
|
234
|
-
"template": "generic_arg",
|
|
235
|
-
"templates": "generic_arg",
|
|
236
|
-
"annotation": "attribute",
|
|
237
|
-
"annotations": "attribute",
|
|
238
|
-
"decorator": "attribute",
|
|
239
|
-
"decorators": "attribute",
|
|
240
|
-
"calls": "call",
|
|
241
|
-
"called": "call",
|
|
242
|
-
"invoke": "call",
|
|
243
|
-
"invocation": "call",
|
|
244
|
-
"fields": "field",
|
|
245
|
-
"property": "field",
|
|
246
|
-
"properties": "field",
|
|
247
|
-
"member": "field",
|
|
248
|
-
"members": "field",
|
|
249
|
-
"imports": "import",
|
|
250
|
-
"imported": "import",
|
|
251
|
-
"module": "import",
|
|
252
|
-
"modules": "import",
|
|
253
|
-
"exports": "export",
|
|
254
|
-
"exported": "export",
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
def _normalize_context_filters(filters: list[str] | None) -> list[str]:
|
|
259
|
-
if not filters:
|
|
260
|
-
return []
|
|
261
|
-
normalized: list[str] = []
|
|
262
|
-
seen: set[str] = set()
|
|
263
|
-
for value in filters:
|
|
264
|
-
key = _strip_diacritics(str(value)).strip().lower()
|
|
265
|
-
if not key:
|
|
266
|
-
continue
|
|
267
|
-
key = _CONTEXT_FILTER_ALIASES.get(key, key)
|
|
268
|
-
if key not in seen:
|
|
269
|
-
seen.add(key)
|
|
270
|
-
normalized.append(key)
|
|
271
|
-
return normalized
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
def _infer_context_filters(question: str) -> list[str]:
|
|
275
|
-
lowered = {
|
|
276
|
-
_strip_diacritics(token).lower()
|
|
277
|
-
for token in question.replace("?", " ").replace(",", " ").split()
|
|
278
|
-
}
|
|
279
|
-
inferred: list[str] = []
|
|
280
|
-
for context, hints in _CONTEXT_HINTS:
|
|
281
|
-
if any(hint in lowered for hint in hints):
|
|
282
|
-
inferred.append(context)
|
|
283
|
-
return inferred
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
def _resolve_context_filters(question: str, explicit_filters: list[str] | None = None) -> tuple[list[str], str | None]:
|
|
287
|
-
normalized = _normalize_context_filters(explicit_filters)
|
|
288
|
-
if normalized:
|
|
289
|
-
return normalized, "explicit"
|
|
290
|
-
inferred = _infer_context_filters(question)
|
|
291
|
-
if inferred:
|
|
292
|
-
return inferred, "heuristic"
|
|
293
|
-
return [], None
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
def _filter_graph_by_context(G: nx.Graph, context_filters: list[str] | None) -> nx.Graph:
|
|
297
|
-
filters = set(_normalize_context_filters(context_filters))
|
|
298
|
-
if not filters:
|
|
299
|
-
return G
|
|
300
|
-
H = G.__class__()
|
|
301
|
-
H.add_nodes_from(G.nodes(data=True))
|
|
302
|
-
if isinstance(G, (nx.MultiGraph, nx.MultiDiGraph)):
|
|
303
|
-
for u, v, key, data in G.edges(keys=True, data=True):
|
|
304
|
-
if data.get("context") in filters:
|
|
305
|
-
H.add_edge(u, v, key=key, **data)
|
|
306
|
-
else:
|
|
307
|
-
for u, v, data in G.edges(data=True):
|
|
308
|
-
if data.get("context") in filters:
|
|
309
|
-
H.add_edge(u, v, **data)
|
|
310
|
-
return H
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
def _bfs(G: nx.Graph, start_nodes: list[str], depth: int) -> tuple[set[str], list[tuple]]:
|
|
314
|
-
# Compute hub threshold: nodes above this degree are not expanded as transit.
|
|
315
|
-
# p99 of degree distribution, floored at 50 to avoid over-blocking small graphs.
|
|
316
|
-
degrees = [G.degree(n) for n in G.nodes()]
|
|
317
|
-
if degrees:
|
|
318
|
-
degrees_sorted = sorted(degrees)
|
|
319
|
-
p99_idx = int(len(degrees_sorted) * 0.99)
|
|
320
|
-
hub_threshold = max(50, degrees_sorted[p99_idx])
|
|
321
|
-
else:
|
|
322
|
-
hub_threshold = 50
|
|
323
|
-
seed_set = set(start_nodes)
|
|
324
|
-
visited: set[str] = set(start_nodes)
|
|
325
|
-
frontier = set(start_nodes)
|
|
326
|
-
edges_seen: list[tuple] = []
|
|
327
|
-
for _ in range(depth):
|
|
328
|
-
next_frontier: set[str] = set()
|
|
329
|
-
for n in frontier:
|
|
330
|
-
# Don't expand through high-degree hubs (except seeds - a hub that
|
|
331
|
-
# is the starting node should still be explored).
|
|
332
|
-
if n not in seed_set and G.degree(n) >= hub_threshold:
|
|
333
|
-
continue
|
|
334
|
-
for neighbor in G.neighbors(n):
|
|
335
|
-
if neighbor not in visited:
|
|
336
|
-
next_frontier.add(neighbor)
|
|
337
|
-
edges_seen.append((n, neighbor))
|
|
338
|
-
visited.update(next_frontier)
|
|
339
|
-
frontier = next_frontier
|
|
340
|
-
return visited, edges_seen
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
def _dfs(G: nx.Graph, start_nodes: list[str], depth: int) -> tuple[set[str], list[tuple]]:
|
|
344
|
-
degrees = [G.degree(n) for n in G.nodes()]
|
|
345
|
-
if degrees:
|
|
346
|
-
degrees_sorted = sorted(degrees)
|
|
347
|
-
p99_idx = int(len(degrees_sorted) * 0.99)
|
|
348
|
-
hub_threshold = max(50, degrees_sorted[p99_idx])
|
|
349
|
-
else:
|
|
350
|
-
hub_threshold = 50
|
|
351
|
-
seed_set = set(start_nodes)
|
|
352
|
-
visited: set[str] = set()
|
|
353
|
-
edges_seen: list[tuple] = []
|
|
354
|
-
stack = [(n, 0) for n in reversed(start_nodes)]
|
|
355
|
-
while stack:
|
|
356
|
-
node, d = stack.pop()
|
|
357
|
-
if node in visited or d > depth:
|
|
358
|
-
continue
|
|
359
|
-
visited.add(node)
|
|
360
|
-
if node not in seed_set and G.degree(node) >= hub_threshold:
|
|
361
|
-
continue
|
|
362
|
-
for neighbor in G.neighbors(node):
|
|
363
|
-
if neighbor not in visited:
|
|
364
|
-
stack.append((neighbor, d + 1))
|
|
365
|
-
edges_seen.append((node, neighbor))
|
|
366
|
-
return visited, edges_seen
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
def _subgraph_to_text(G: nx.Graph, nodes: set[str], edges: list[tuple], token_budget: int = 2000, *, seeds: list[str] | None = None) -> str:
|
|
370
|
-
"""Render subgraph as text, cutting at token_budget (approx 3 chars/token).
|
|
371
|
-
|
|
372
|
-
seeds: exact-match nodes rendered first before the degree-sorted expansion,
|
|
373
|
-
so the queried symbol always appears at the top of the output.
|
|
374
|
-
"""
|
|
375
|
-
char_budget = token_budget * 3
|
|
376
|
-
lines = []
|
|
377
|
-
seed_set = set(seeds or [])
|
|
378
|
-
ordered = [n for n in (seeds or []) if n in nodes] + \
|
|
379
|
-
sorted(nodes - seed_set, key=lambda n: G.degree(n), reverse=True)
|
|
380
|
-
for nid in ordered:
|
|
381
|
-
d = G.nodes[nid]
|
|
382
|
-
# Every LLM-derived field passes through sanitize_label before being
|
|
383
|
-
# concatenated into MCP tool output (F-010): an attacker who controls a
|
|
384
|
-
# corpus document can otherwise inject ANSI escapes, fake graphify-out
|
|
385
|
-
# log lines, or prompt-injection markup into the model's context via
|
|
386
|
-
# source_file / source_location / community.
|
|
387
|
-
line = (
|
|
388
|
-
f"NODE {sanitize_label(d.get('label', nid))} "
|
|
389
|
-
f"[src={sanitize_label(str(d.get('source_file', '')))} "
|
|
390
|
-
f"loc={sanitize_label(str(d.get('source_location', '')))} "
|
|
391
|
-
f"community={sanitize_label(str(d.get('community', '')))}]"
|
|
392
|
-
)
|
|
393
|
-
lines.append(line)
|
|
394
|
-
for u, v in edges:
|
|
395
|
-
if u in nodes and v in nodes:
|
|
396
|
-
raw = G[u][v]
|
|
397
|
-
d = next(iter(raw.values()), {}) if isinstance(G, (nx.MultiGraph, nx.MultiDiGraph)) else raw
|
|
398
|
-
context = d.get("context")
|
|
399
|
-
context_suffix = f" context={sanitize_label(str(context))}" if context else ""
|
|
400
|
-
line = (
|
|
401
|
-
f"EDGE {sanitize_label(G.nodes[u].get('label', u))} "
|
|
402
|
-
f"--{sanitize_label(str(d.get('relation', '')))} "
|
|
403
|
-
f"[{sanitize_label(str(d.get('confidence', '')))}{context_suffix}]--> "
|
|
404
|
-
f"{sanitize_label(G.nodes[v].get('label', v))}"
|
|
405
|
-
)
|
|
406
|
-
lines.append(line)
|
|
407
|
-
output = "\n".join(lines)
|
|
408
|
-
if len(output) > char_budget:
|
|
409
|
-
cut_at = output[:char_budget].rfind("\n")
|
|
410
|
-
cut_at = cut_at if cut_at > 0 else char_budget
|
|
411
|
-
total_nodes = sum(1 for l in lines if l.startswith("NODE "))
|
|
412
|
-
shown_nodes = output[:cut_at].count("\nNODE ") + (1 if output.startswith("NODE ") else 0)
|
|
413
|
-
cut_count = total_nodes - shown_nodes
|
|
414
|
-
output = (
|
|
415
|
-
output[:cut_at]
|
|
416
|
-
+ f"\n... (truncated — {cut_count} more nodes cut by ~{token_budget}-token budget."
|
|
417
|
-
f" Narrow with context_filter=['call'] or use get_node for a specific symbol)"
|
|
418
|
-
)
|
|
419
|
-
return output
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
def _query_graph_text(
|
|
423
|
-
G: nx.Graph,
|
|
424
|
-
question: str,
|
|
425
|
-
*,
|
|
426
|
-
mode: str = "bfs",
|
|
427
|
-
depth: int = 3,
|
|
428
|
-
token_budget: int = 2000,
|
|
429
|
-
context_filters: list[str] | None = None,
|
|
430
|
-
) -> str:
|
|
431
|
-
terms = _query_terms(question)
|
|
432
|
-
scored = _score_nodes(G, terms)
|
|
433
|
-
start_nodes = _pick_seeds(scored)
|
|
434
|
-
if not start_nodes:
|
|
435
|
-
return "No matching nodes found."
|
|
436
|
-
resolved_filters, filter_source = _resolve_context_filters(question, context_filters)
|
|
437
|
-
traversal_graph = _filter_graph_by_context(G, resolved_filters)
|
|
438
|
-
nodes, edges = _dfs(traversal_graph, start_nodes, depth) if mode == "dfs" else _bfs(traversal_graph, start_nodes, depth)
|
|
439
|
-
header_parts = [
|
|
440
|
-
f"Traversal: {mode.upper()} depth={depth}",
|
|
441
|
-
f"Start: {[G.nodes[n].get('label', n) for n in start_nodes]}",
|
|
442
|
-
]
|
|
443
|
-
if resolved_filters:
|
|
444
|
-
header_parts.append(f"Context: {', '.join(resolved_filters)} ({filter_source})")
|
|
445
|
-
header_parts.append(f"{len(nodes)} nodes found")
|
|
446
|
-
header = " | ".join(header_parts) + "\n\n"
|
|
447
|
-
return header + _subgraph_to_text(traversal_graph, nodes, edges, token_budget)
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
def _find_node(G: nx.Graph, label: str) -> list[str]:
|
|
451
|
-
"""Return node IDs whose label or ID matches the search term (diacritic-insensitive).
|
|
452
|
-
|
|
453
|
-
Results are ordered by three-tier precedence: exact match, then prefix match,
|
|
454
|
-
then substring match. Node-ID exact matches are grouped with label exact matches.
|
|
455
|
-
"""
|
|
456
|
-
term = " ".join(_search_tokens(label))
|
|
457
|
-
if not term:
|
|
458
|
-
return []
|
|
459
|
-
exact: list[str] = []
|
|
460
|
-
prefix: list[str] = []
|
|
461
|
-
substring: list[str] = []
|
|
462
|
-
for nid, d in G.nodes(data=True):
|
|
463
|
-
norm_label = d.get("norm_label") or _strip_diacritics(d.get("label") or "").lower()
|
|
464
|
-
bare_label = norm_label.rstrip("()")
|
|
465
|
-
nid_lower = nid.lower()
|
|
466
|
-
if term == norm_label or term == bare_label or term == nid_lower:
|
|
467
|
-
exact.append(nid)
|
|
468
|
-
elif norm_label.startswith(term) or bare_label.startswith(term) or nid_lower.startswith(term):
|
|
469
|
-
prefix.append(nid)
|
|
470
|
-
elif term in norm_label:
|
|
471
|
-
substring.append(nid)
|
|
472
|
-
return exact + prefix + substring
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
def _filter_blank_stdin() -> None:
|
|
476
|
-
"""Filter blank lines from stdin before MCP reads it.
|
|
477
|
-
|
|
478
|
-
Some MCP clients (Claude Desktop, etc.) send blank lines between JSON
|
|
479
|
-
messages. The MCP stdio transport tries to parse every line as a
|
|
480
|
-
JSONRPCMessage, so a bare newline triggers a Pydantic ValidationError.
|
|
481
|
-
This installs an OS-level pipe that relays stdin while dropping blanks.
|
|
482
|
-
"""
|
|
483
|
-
import os
|
|
484
|
-
import threading
|
|
485
|
-
|
|
486
|
-
r_fd, w_fd = os.pipe()
|
|
487
|
-
saved_fd = os.dup(sys.stdin.fileno())
|
|
488
|
-
|
|
489
|
-
def _relay() -> None:
|
|
490
|
-
try:
|
|
491
|
-
with open(saved_fd, "rb") as src, open(w_fd, "wb") as dst:
|
|
492
|
-
for line in src:
|
|
493
|
-
if line.strip():
|
|
494
|
-
dst.write(line)
|
|
495
|
-
dst.flush()
|
|
496
|
-
except Exception:
|
|
497
|
-
pass
|
|
498
|
-
|
|
499
|
-
threading.Thread(target=_relay, daemon=True).start()
|
|
500
|
-
os.dup2(r_fd, sys.stdin.fileno())
|
|
501
|
-
os.close(r_fd)
|
|
502
|
-
sys.stdin = open(0, "r", closefd=False)
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
def _build_server(graph_path: str):
|
|
506
|
-
"""Build the configured low-level MCP Server (shared by every transport).
|
|
507
|
-
|
|
508
|
-
All graph query tools and resources are registered here over a single
|
|
509
|
-
``mcp.server.Server`` instance; the caller picks the transport (stdio or
|
|
510
|
-
Streamable HTTP) and runs it. Hot-reload of graph.json works the same way
|
|
511
|
-
regardless of transport, since reloads happen inside the tool handlers.
|
|
512
|
-
"""
|
|
513
|
-
import threading
|
|
514
|
-
|
|
515
|
-
try:
|
|
516
|
-
from mcp.server import Server
|
|
517
|
-
from mcp import types
|
|
518
|
-
from mcp.types import AnyUrl
|
|
519
|
-
except ImportError as e:
|
|
520
|
-
raise ImportError('mcp not installed. Run: pip install "graphifyy[mcp]"') from e
|
|
521
|
-
|
|
522
|
-
G = _load_graph(graph_path)
|
|
523
|
-
communities = _communities_from_graph(G)
|
|
524
|
-
|
|
525
|
-
# Hot-reload state: mtime+size key lets us detect graph.json changes without
|
|
526
|
-
# polling. Initialised from the file stat at startup so the first tool call
|
|
527
|
-
# never triggers a redundant reload.
|
|
528
|
-
_reload_lock = threading.Lock()
|
|
529
|
-
try:
|
|
530
|
-
_s = Path(graph_path).stat()
|
|
531
|
-
_reload_state: dict = {"mtime_ns": _s.st_mtime_ns, "size": _s.st_size}
|
|
532
|
-
except FileNotFoundError:
|
|
533
|
-
_reload_state = {"mtime_ns": 0, "size": -1}
|
|
534
|
-
|
|
535
|
-
def _maybe_reload() -> None:
|
|
536
|
-
nonlocal G, communities
|
|
537
|
-
try:
|
|
538
|
-
s = Path(graph_path).stat()
|
|
539
|
-
key = (s.st_mtime_ns, s.st_size)
|
|
540
|
-
except FileNotFoundError:
|
|
541
|
-
return
|
|
542
|
-
if key == (_reload_state["mtime_ns"], _reload_state["size"]):
|
|
543
|
-
return
|
|
544
|
-
with _reload_lock:
|
|
545
|
-
try:
|
|
546
|
-
s = Path(graph_path).stat()
|
|
547
|
-
key = (s.st_mtime_ns, s.st_size)
|
|
548
|
-
except FileNotFoundError:
|
|
549
|
-
return
|
|
550
|
-
if key == (_reload_state["mtime_ns"], _reload_state["size"]):
|
|
551
|
-
return # another thread already reloaded
|
|
552
|
-
try:
|
|
553
|
-
new_G = _load_graph(graph_path)
|
|
554
|
-
except SystemExit:
|
|
555
|
-
return # keep serving stale graph on transient read error
|
|
556
|
-
G = new_G
|
|
557
|
-
communities = _communities_from_graph(new_G)
|
|
558
|
-
_reload_state["mtime_ns"], _reload_state["size"] = key
|
|
559
|
-
|
|
560
|
-
server = Server("graphify")
|
|
561
|
-
|
|
562
|
-
@server.list_tools()
|
|
563
|
-
async def list_tools() -> list[types.Tool]:
|
|
564
|
-
return [
|
|
565
|
-
types.Tool(
|
|
566
|
-
name="query_graph",
|
|
567
|
-
description="Search the knowledge graph using BFS or DFS. Returns relevant nodes and edges as text context.",
|
|
568
|
-
inputSchema={
|
|
569
|
-
"type": "object",
|
|
570
|
-
"properties": {
|
|
571
|
-
"question": {"type": "string", "description": "Natural language question or keyword search"},
|
|
572
|
-
"mode": {"type": "string", "enum": ["bfs", "dfs"], "default": "bfs",
|
|
573
|
-
"description": "bfs=broad context, dfs=trace a specific path"},
|
|
574
|
-
"depth": {"type": "integer", "default": 3, "description": "Traversal depth (1-6)"},
|
|
575
|
-
"token_budget": {"type": "integer", "default": 2000, "description": "Max output tokens"},
|
|
576
|
-
"context_filter": {
|
|
577
|
-
"type": "array",
|
|
578
|
-
"items": {"type": "string"},
|
|
579
|
-
"description": "Optional explicit edge-context filter, e.g. ['call', 'field']",
|
|
580
|
-
},
|
|
581
|
-
},
|
|
582
|
-
"required": ["question"],
|
|
583
|
-
},
|
|
584
|
-
),
|
|
585
|
-
types.Tool(
|
|
586
|
-
name="get_node",
|
|
587
|
-
description="Get full details for a specific node by label or ID.",
|
|
588
|
-
inputSchema={
|
|
589
|
-
"type": "object",
|
|
590
|
-
"properties": {"label": {"type": "string", "description": "Node label or ID to look up"}},
|
|
591
|
-
"required": ["label"],
|
|
592
|
-
},
|
|
593
|
-
),
|
|
594
|
-
types.Tool(
|
|
595
|
-
name="get_neighbors",
|
|
596
|
-
description="Get all direct neighbors of a node with edge details.",
|
|
597
|
-
inputSchema={
|
|
598
|
-
"type": "object",
|
|
599
|
-
"properties": {
|
|
600
|
-
"label": {"type": "string"},
|
|
601
|
-
"relation_filter": {"type": "string", "description": "Optional: filter by relation type"},
|
|
602
|
-
},
|
|
603
|
-
"required": ["label"],
|
|
604
|
-
},
|
|
605
|
-
),
|
|
606
|
-
types.Tool(
|
|
607
|
-
name="get_community",
|
|
608
|
-
description="Get all nodes in a community by community ID.",
|
|
609
|
-
inputSchema={
|
|
610
|
-
"type": "object",
|
|
611
|
-
"properties": {"community_id": {"type": "integer", "description": "Community ID (0-indexed by size)"}},
|
|
612
|
-
"required": ["community_id"],
|
|
613
|
-
},
|
|
614
|
-
),
|
|
615
|
-
types.Tool(
|
|
616
|
-
name="god_nodes",
|
|
617
|
-
description="Return the most connected nodes - the core abstractions of the knowledge graph.",
|
|
618
|
-
inputSchema={"type": "object", "properties": {"top_n": {"type": "integer", "default": 10}}},
|
|
619
|
-
),
|
|
620
|
-
types.Tool(
|
|
621
|
-
name="graph_stats",
|
|
622
|
-
description="Return summary statistics: node count, edge count, communities, confidence breakdown.",
|
|
623
|
-
inputSchema={"type": "object", "properties": {}},
|
|
624
|
-
),
|
|
625
|
-
types.Tool(
|
|
626
|
-
name="shortest_path",
|
|
627
|
-
description="Find the shortest path between two concepts in the knowledge graph.",
|
|
628
|
-
inputSchema={
|
|
629
|
-
"type": "object",
|
|
630
|
-
"properties": {
|
|
631
|
-
"source": {"type": "string", "description": "Source concept label or keyword"},
|
|
632
|
-
"target": {"type": "string", "description": "Target concept label or keyword"},
|
|
633
|
-
"max_hops": {"type": "integer", "default": 8, "description": "Maximum hops to consider"},
|
|
634
|
-
},
|
|
635
|
-
"required": ["source", "target"],
|
|
636
|
-
},
|
|
637
|
-
),
|
|
638
|
-
types.Tool(
|
|
639
|
-
name="list_prs",
|
|
640
|
-
description=(
|
|
641
|
-
"List open GitHub PRs with CI status, review state, and graph impact "
|
|
642
|
-
"(which communities each PR touches, blast radius). Use this before starting "
|
|
643
|
-
"work to check if a PR already covers the area you're about to change."
|
|
644
|
-
),
|
|
645
|
-
inputSchema={
|
|
646
|
-
"type": "object",
|
|
647
|
-
"properties": {
|
|
648
|
-
"base": {"type": "string", "description": "Base branch to filter PRs by (auto-detected if omitted)"},
|
|
649
|
-
"repo": {"type": "string", "description": "GitHub repo (owner/repo). Defaults to current repo."},
|
|
650
|
-
},
|
|
651
|
-
},
|
|
652
|
-
),
|
|
653
|
-
types.Tool(
|
|
654
|
-
name="get_pr_impact",
|
|
655
|
-
description=(
|
|
656
|
-
"Get detailed graph impact for a specific PR: which files it changes, "
|
|
657
|
-
"which knowledge-graph communities are affected, and how many nodes are touched. "
|
|
658
|
-
"Use this to assess merge risk or check for overlap with your current work."
|
|
659
|
-
),
|
|
660
|
-
inputSchema={
|
|
661
|
-
"type": "object",
|
|
662
|
-
"properties": {
|
|
663
|
-
"pr_number": {"type": "integer", "description": "PR number to analyse"},
|
|
664
|
-
"repo": {"type": "string", "description": "GitHub repo (owner/repo). Defaults to current repo."},
|
|
665
|
-
},
|
|
666
|
-
"required": ["pr_number"],
|
|
667
|
-
},
|
|
668
|
-
),
|
|
669
|
-
types.Tool(
|
|
670
|
-
name="triage_prs",
|
|
671
|
-
description=(
|
|
672
|
-
"Return all actionable open PRs (correct base, not stale) with full graph impact data "
|
|
673
|
-
"so you can reason about review priority, merge order, and conflict risk. "
|
|
674
|
-
"Call this when the user asks 'what PRs should I review?' or 'what's ready to merge?'"
|
|
675
|
-
),
|
|
676
|
-
inputSchema={
|
|
677
|
-
"type": "object",
|
|
678
|
-
"properties": {
|
|
679
|
-
"base": {"type": "string", "description": "Base branch to filter PRs by (auto-detected if omitted)"},
|
|
680
|
-
"repo": {"type": "string", "description": "GitHub repo (owner/repo). Defaults to current repo."},
|
|
681
|
-
},
|
|
682
|
-
},
|
|
683
|
-
),
|
|
684
|
-
]
|
|
685
|
-
|
|
686
|
-
def _tool_query_graph(arguments: dict) -> str:
|
|
687
|
-
import time as _time
|
|
688
|
-
from graphify import querylog
|
|
689
|
-
question = arguments["question"]
|
|
690
|
-
mode = arguments.get("mode", "bfs")
|
|
691
|
-
depth = min(int(arguments.get("depth", 3)), 6)
|
|
692
|
-
budget = int(arguments.get("token_budget", 2000))
|
|
693
|
-
context_filter = arguments.get("context_filter")
|
|
694
|
-
_t0 = _time.perf_counter()
|
|
695
|
-
result = _query_graph_text(
|
|
696
|
-
G,
|
|
697
|
-
question,
|
|
698
|
-
mode=mode,
|
|
699
|
-
depth=depth,
|
|
700
|
-
token_budget=budget,
|
|
701
|
-
context_filters=context_filter,
|
|
702
|
-
)
|
|
703
|
-
querylog.log_query(
|
|
704
|
-
kind="mcp_query",
|
|
705
|
-
question=question,
|
|
706
|
-
corpus=str(graph_path),
|
|
707
|
-
result=result,
|
|
708
|
-
mode=mode,
|
|
709
|
-
depth=depth,
|
|
710
|
-
token_budget=budget,
|
|
711
|
-
duration_ms=(_time.perf_counter() - _t0) * 1000,
|
|
712
|
-
)
|
|
713
|
-
return result
|
|
714
|
-
|
|
715
|
-
def _tool_get_node(arguments: dict) -> str:
|
|
716
|
-
label = arguments["label"].lower()
|
|
717
|
-
matches = [(nid, d) for nid, d in G.nodes(data=True)
|
|
718
|
-
if label in (d.get("label") or "").lower() or label == nid.lower()]
|
|
719
|
-
if not matches:
|
|
720
|
-
return f"No node matching '{label}' found."
|
|
721
|
-
nid, d = matches[0]
|
|
722
|
-
# Sanitise every LLM-derived field before concatenation (F-010).
|
|
723
|
-
return "\n".join([
|
|
724
|
-
f"Node: {sanitize_label(d.get('label', nid))}",
|
|
725
|
-
f" ID: {sanitize_label(nid)}",
|
|
726
|
-
f" Source: {sanitize_label(str(d.get('source_file', '')))} {sanitize_label(str(d.get('source_location', '')))}",
|
|
727
|
-
f" Type: {sanitize_label(str(d.get('file_type', '')))}",
|
|
728
|
-
f" Community: {sanitize_label(str(d.get('community', '')))}",
|
|
729
|
-
f" Degree: {G.degree(nid)}",
|
|
730
|
-
])
|
|
731
|
-
|
|
732
|
-
def _tool_get_neighbors(arguments: dict) -> str:
|
|
733
|
-
label = arguments["label"].lower()
|
|
734
|
-
rel_filter = arguments.get("relation_filter", "").lower()
|
|
735
|
-
matches = _find_node(G, label)
|
|
736
|
-
if not matches:
|
|
737
|
-
return f"No node matching '{label}' found."
|
|
738
|
-
nid = matches[0]
|
|
739
|
-
lines = [f"Neighbors of {sanitize_label(G.nodes[nid].get('label', nid))}:"]
|
|
740
|
-
for nb in G.successors(nid):
|
|
741
|
-
d = edge_data(G, nid, nb)
|
|
742
|
-
rel = d.get("relation", "")
|
|
743
|
-
if rel_filter and rel_filter not in rel.lower():
|
|
744
|
-
continue
|
|
745
|
-
lines.append(
|
|
746
|
-
f" --> {sanitize_label(G.nodes[nb].get('label', nb))} "
|
|
747
|
-
f"[{sanitize_label(str(rel))}] [{sanitize_label(str(d.get('confidence', '')))}]"
|
|
748
|
-
)
|
|
749
|
-
for nb in G.predecessors(nid):
|
|
750
|
-
d = edge_data(G, nb, nid)
|
|
751
|
-
rel = d.get("relation", "")
|
|
752
|
-
if rel_filter and rel_filter not in rel.lower():
|
|
753
|
-
continue
|
|
754
|
-
lines.append(
|
|
755
|
-
f" <-- {sanitize_label(G.nodes[nb].get('label', nb))} "
|
|
756
|
-
f"[{sanitize_label(str(rel))}] [{sanitize_label(str(d.get('confidence', '')))}]"
|
|
757
|
-
)
|
|
758
|
-
return "\n".join(lines)
|
|
759
|
-
|
|
760
|
-
def _tool_get_community(arguments: dict) -> str:
|
|
761
|
-
cid = int(arguments["community_id"])
|
|
762
|
-
nodes = communities.get(cid, [])
|
|
763
|
-
if not nodes:
|
|
764
|
-
return f"Community {cid} not found."
|
|
765
|
-
lines = [f"Community {cid} ({len(nodes)} nodes):"]
|
|
766
|
-
for n in nodes:
|
|
767
|
-
d = G.nodes[n]
|
|
768
|
-
# Sanitise label and source_file (F-010).
|
|
769
|
-
lines.append(
|
|
770
|
-
f" {sanitize_label(d.get('label', n))} "
|
|
771
|
-
f"[{sanitize_label(str(d.get('source_file', '')))}]"
|
|
772
|
-
)
|
|
773
|
-
return "\n".join(lines)
|
|
774
|
-
|
|
775
|
-
def _tool_god_nodes(arguments: dict) -> str:
|
|
776
|
-
from graphify.analyze import god_nodes as _god_nodes
|
|
777
|
-
nodes = _god_nodes(G, top_n=int(arguments.get("top_n", 10)))
|
|
778
|
-
lines = ["God nodes (most connected):"]
|
|
779
|
-
lines += [f" {i}. {n['label']} - {n['degree']} edges" for i, n in enumerate(nodes, 1)]
|
|
780
|
-
return "\n".join(lines)
|
|
781
|
-
|
|
782
|
-
def _tool_graph_stats(_: dict) -> str:
|
|
783
|
-
confs = [d.get("confidence", "EXTRACTED") for _, _, d in G.edges(data=True)]
|
|
784
|
-
total = len(confs) or 1
|
|
785
|
-
return (
|
|
786
|
-
f"Nodes: {G.number_of_nodes()}\n"
|
|
787
|
-
f"Edges: {G.number_of_edges()}\n"
|
|
788
|
-
f"Communities: {len(communities)}\n"
|
|
789
|
-
f"EXTRACTED: {round(confs.count('EXTRACTED')/total*100)}%\n"
|
|
790
|
-
f"INFERRED: {round(confs.count('INFERRED')/total*100)}%\n"
|
|
791
|
-
f"AMBIGUOUS: {round(confs.count('AMBIGUOUS')/total*100)}%\n"
|
|
792
|
-
)
|
|
793
|
-
|
|
794
|
-
def _tool_shortest_path(arguments: dict) -> str:
|
|
795
|
-
src_scored = _score_nodes(G, [t.lower() for t in arguments["source"].split()])
|
|
796
|
-
tgt_scored = _score_nodes(G, [t.lower() for t in arguments["target"].split()])
|
|
797
|
-
if not src_scored:
|
|
798
|
-
return f"No node matching source '{arguments['source']}' found."
|
|
799
|
-
if not tgt_scored:
|
|
800
|
-
return f"No node matching target '{arguments['target']}' found."
|
|
801
|
-
src_nid, tgt_nid = src_scored[0][1], tgt_scored[0][1]
|
|
802
|
-
# Ambiguity guard: when both queries resolve to the same node, the
|
|
803
|
-
# shortest path is trivially zero hops, which is almost never what the
|
|
804
|
-
# caller wanted (see bug #828).
|
|
805
|
-
if src_nid == tgt_nid:
|
|
806
|
-
return (
|
|
807
|
-
f"'{arguments['source']}' and '{arguments['target']}' both resolved to "
|
|
808
|
-
f"the same node '{src_nid}'. Use a more specific label or the exact node ID."
|
|
809
|
-
)
|
|
810
|
-
warnings: list[str] = []
|
|
811
|
-
for name, scored in (("source", src_scored), ("target", tgt_scored)):
|
|
812
|
-
if len(scored) >= 2:
|
|
813
|
-
top, runner = scored[0][0], scored[1][0]
|
|
814
|
-
if top > 0 and (top - runner) / top < 0.10:
|
|
815
|
-
warnings.append(
|
|
816
|
-
f"warning: {name} match was ambiguous "
|
|
817
|
-
f"(top score {top:g}, runner-up {runner:g})"
|
|
818
|
-
)
|
|
819
|
-
max_hops = int(arguments.get("max_hops", 8))
|
|
820
|
-
try:
|
|
821
|
-
# Use undirected view for path-finding (works regardless of query src/tgt order)
|
|
822
|
-
path_nodes = nx.shortest_path(G.to_undirected(as_view=True), src_nid, tgt_nid)
|
|
823
|
-
except (nx.NetworkXNoPath, nx.NodeNotFound):
|
|
824
|
-
return f"No path found between '{G.nodes[src_nid].get('label', src_nid)}' and '{G.nodes[tgt_nid].get('label', tgt_nid)}'."
|
|
825
|
-
hops = len(path_nodes) - 1
|
|
826
|
-
if hops > max_hops:
|
|
827
|
-
return f"Path exceeds max_hops={max_hops} ({hops} hops found)."
|
|
828
|
-
segments = []
|
|
829
|
-
for i in range(len(path_nodes) - 1):
|
|
830
|
-
u, v = path_nodes[i], path_nodes[i + 1]
|
|
831
|
-
if G.has_edge(u, v):
|
|
832
|
-
edata = edge_data(G, u, v)
|
|
833
|
-
forward = True
|
|
834
|
-
else:
|
|
835
|
-
edata = edge_data(G, v, u)
|
|
836
|
-
forward = False
|
|
837
|
-
rel = edata.get("relation", "")
|
|
838
|
-
conf = edata.get("confidence", "")
|
|
839
|
-
conf_str = f" [{conf}]" if conf else ""
|
|
840
|
-
if i == 0:
|
|
841
|
-
segments.append(G.nodes[u].get("label", u))
|
|
842
|
-
if forward:
|
|
843
|
-
segments.append(f"--{rel}{conf_str}--> {G.nodes[v].get('label', v)}")
|
|
844
|
-
else:
|
|
845
|
-
segments.append(f"<--{rel}{conf_str}-- {G.nodes[v].get('label', v)}")
|
|
846
|
-
prefix = ("\n".join(warnings) + "\n") if warnings else ""
|
|
847
|
-
return prefix + f"Shortest path ({hops} hops):\n " + " ".join(segments)
|
|
848
|
-
|
|
849
|
-
def _tool_list_prs(arguments: dict) -> str:
|
|
850
|
-
from graphify.prs import fetch_prs, fetch_worktrees, format_prs_text, _detect_default_branch
|
|
851
|
-
repo = arguments.get("repo") or None
|
|
852
|
-
base = arguments.get("base") or _detect_default_branch(repo)
|
|
853
|
-
try:
|
|
854
|
-
prs = fetch_prs(repo=repo, base=base)
|
|
855
|
-
except RuntimeError as e:
|
|
856
|
-
return f"Error: {e}"
|
|
857
|
-
worktrees = fetch_worktrees()
|
|
858
|
-
for pr in prs:
|
|
859
|
-
pr.worktree_path = worktrees.get(pr.branch)
|
|
860
|
-
return format_prs_text(prs, base)
|
|
861
|
-
|
|
862
|
-
def _tool_get_pr_impact(arguments: dict) -> str:
|
|
863
|
-
from graphify.prs import fetch_pr_files, compute_pr_impact, _gh, _parse_ci
|
|
864
|
-
number = int(arguments["pr_number"])
|
|
865
|
-
repo = arguments.get("repo") or None
|
|
866
|
-
# Use gh pr view directly — works for any base branch, not just the default
|
|
867
|
-
view_args = ["pr", "view", str(number), "--json",
|
|
868
|
-
"title,headRefName,baseRefName,author,isDraft,reviewDecision,statusCheckRollup,updatedAt"]
|
|
869
|
-
if repo:
|
|
870
|
-
view_args += ["--repo", repo]
|
|
871
|
-
pr_data = _gh(*view_args)
|
|
872
|
-
if pr_data is None:
|
|
873
|
-
return f"PR #{number} not found or gh not authenticated."
|
|
874
|
-
files = fetch_pr_files(number, repo)
|
|
875
|
-
if not files:
|
|
876
|
-
return f"PR #{number}: no changed files found (may require gh auth)."
|
|
877
|
-
comms, nodes = compute_pr_impact(files, G)
|
|
878
|
-
ci = _parse_ci(pr_data.get("statusCheckRollup") or [])
|
|
879
|
-
lines = [
|
|
880
|
-
f"PR #{number}: {pr_data['title']}",
|
|
881
|
-
f"CI: {ci} Review: {pr_data.get('reviewDecision') or 'none'}",
|
|
882
|
-
f"Base: {pr_data['baseRefName']} Author: {(pr_data.get('author') or {}).get('login', '?')}",
|
|
883
|
-
f"\nGraph impact: {nodes} nodes across {len(comms)} communities",
|
|
884
|
-
f"Communities touched: {comms}",
|
|
885
|
-
f"Files changed ({len(files)}):",
|
|
886
|
-
]
|
|
887
|
-
lines += [f" {f}" for f in files[:20]]
|
|
888
|
-
if len(files) > 20:
|
|
889
|
-
lines.append(f" … and {len(files) - 20} more")
|
|
890
|
-
return "\n".join(lines)
|
|
891
|
-
|
|
892
|
-
def _tool_triage_prs(arguments: dict) -> str:
|
|
893
|
-
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
894
|
-
from graphify.prs import fetch_prs, fetch_worktrees, fetch_pr_files, compute_pr_impact, _STATUS_ORDER, _detect_default_branch
|
|
895
|
-
repo = arguments.get("repo") or None
|
|
896
|
-
base = arguments.get("base") or _detect_default_branch(repo)
|
|
897
|
-
try:
|
|
898
|
-
prs = fetch_prs(repo=repo, base=base)
|
|
899
|
-
except RuntimeError as e:
|
|
900
|
-
return f"Error: {e}"
|
|
901
|
-
worktrees = fetch_worktrees()
|
|
902
|
-
for pr in prs:
|
|
903
|
-
pr.worktree_path = worktrees.get(pr.branch)
|
|
904
|
-
actionable = [p for p in prs if p.base_branch == base and p.status not in ("WRONG-BASE", "STALE")]
|
|
905
|
-
if not actionable:
|
|
906
|
-
return f"No actionable PRs targeting {base}."
|
|
907
|
-
# Fetch diffs concurrently then compute graph impact using in-memory G
|
|
908
|
-
workers = min(8, len(actionable))
|
|
909
|
-
with ThreadPoolExecutor(max_workers=workers) as pool:
|
|
910
|
-
future_to_pr = {pool.submit(fetch_pr_files, pr.number, repo): pr for pr in actionable}
|
|
911
|
-
for fut in as_completed(future_to_pr):
|
|
912
|
-
pr = future_to_pr[fut]
|
|
913
|
-
try:
|
|
914
|
-
files = fut.result()
|
|
915
|
-
except Exception:
|
|
916
|
-
files = []
|
|
917
|
-
if files:
|
|
918
|
-
pr.files_changed = files
|
|
919
|
-
pr.communities_touched, pr.nodes_affected = compute_pr_impact(files, G)
|
|
920
|
-
header = (
|
|
921
|
-
f"Actionable PRs targeting {base}: {len(actionable)}\n"
|
|
922
|
-
"Rank these by review priority. Higher blast_radius = more graph communities affected = higher merge risk.\n"
|
|
923
|
-
)
|
|
924
|
-
lines = [header]
|
|
925
|
-
for p in sorted(actionable, key=lambda x: (_STATUS_ORDER.index(x.status) if x.status in _STATUS_ORDER else 99)):
|
|
926
|
-
impact = f" blast_radius={p.blast_radius}" if p.blast_radius else ""
|
|
927
|
-
wt = f" worktree={p.worktree_path}" if p.worktree_path else ""
|
|
928
|
-
lines.append(
|
|
929
|
-
f"PR #{p.number} [{p.status}] CI={p.ci_status} review={p.review_decision or 'none'} "
|
|
930
|
-
f"age={p.days_old}d author={p.author}{impact}{wt}\n title: {p.title}"
|
|
931
|
-
)
|
|
932
|
-
return "\n\n".join(lines)
|
|
933
|
-
|
|
934
|
-
_handlers = {
|
|
935
|
-
"query_graph": _tool_query_graph,
|
|
936
|
-
"get_node": _tool_get_node,
|
|
937
|
-
"get_neighbors": _tool_get_neighbors,
|
|
938
|
-
"get_community": _tool_get_community,
|
|
939
|
-
"god_nodes": _tool_god_nodes,
|
|
940
|
-
"graph_stats": _tool_graph_stats,
|
|
941
|
-
"shortest_path": _tool_shortest_path,
|
|
942
|
-
"list_prs": _tool_list_prs,
|
|
943
|
-
"get_pr_impact": _tool_get_pr_impact,
|
|
944
|
-
"triage_prs": _tool_triage_prs,
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
def _load_community_labels() -> dict[int, str]:
|
|
948
|
-
labels_path = Path(graph_path).parent / ".graphify_labels.json"
|
|
949
|
-
if labels_path.exists():
|
|
950
|
-
try:
|
|
951
|
-
return {int(k): v for k, v in json.loads(labels_path.read_text(encoding="utf-8")).items()}
|
|
952
|
-
except Exception:
|
|
953
|
-
pass
|
|
954
|
-
return {cid: f"Community {cid}" for cid in communities}
|
|
955
|
-
|
|
956
|
-
@server.list_resources()
|
|
957
|
-
async def list_resources() -> list[types.Resource]:
|
|
958
|
-
return [
|
|
959
|
-
types.Resource(uri=AnyUrl("graphify://report"), name="Graph Report", description="Full GRAPH_REPORT.md", mimeType="text/markdown"),
|
|
960
|
-
types.Resource(uri=AnyUrl("graphify://stats"), name="Graph Stats", description="Node/edge/community counts and confidence breakdown", mimeType="text/plain"),
|
|
961
|
-
types.Resource(uri=AnyUrl("graphify://god-nodes"), name="God Nodes", description="Top 10 most-connected nodes", mimeType="text/plain"),
|
|
962
|
-
types.Resource(uri=AnyUrl("graphify://surprises"), name="Surprising Connections", description="Cross-community surprising connections", mimeType="text/plain"),
|
|
963
|
-
types.Resource(uri=AnyUrl("graphify://audit"), name="Confidence Audit", description="EXTRACTED/INFERRED/AMBIGUOUS edge breakdown", mimeType="text/plain"),
|
|
964
|
-
types.Resource(uri=AnyUrl("graphify://questions"), name="Suggested Questions", description="Suggested questions for this codebase", mimeType="text/plain"),
|
|
965
|
-
]
|
|
966
|
-
|
|
967
|
-
@server.read_resource()
|
|
968
|
-
async def read_resource(uri: AnyUrl) -> str:
|
|
969
|
-
_maybe_reload()
|
|
970
|
-
uri_str = str(uri)
|
|
971
|
-
if uri_str == "graphify://report":
|
|
972
|
-
report_path = Path(graph_path).parent / "GRAPH_REPORT.md"
|
|
973
|
-
if report_path.exists():
|
|
974
|
-
return report_path.read_text(encoding="utf-8")
|
|
975
|
-
return "GRAPH_REPORT.md not found. Run graphify extract first."
|
|
976
|
-
if uri_str == "graphify://stats":
|
|
977
|
-
return _tool_graph_stats({})
|
|
978
|
-
if uri_str == "graphify://god-nodes":
|
|
979
|
-
return _tool_god_nodes({"top_n": 10})
|
|
980
|
-
if uri_str == "graphify://surprises":
|
|
981
|
-
try:
|
|
982
|
-
from graphify.analyze import surprising_connections
|
|
983
|
-
surprises = surprising_connections(G, communities, top_n=10)
|
|
984
|
-
if not surprises:
|
|
985
|
-
return "No surprising connections found."
|
|
986
|
-
lines = ["Surprising cross-community connections:"]
|
|
987
|
-
for s in surprises:
|
|
988
|
-
lines.append(f" {s.get('source', '')} <-> {s.get('target', '')} [{s.get('relation', '')}]")
|
|
989
|
-
return "\n".join(lines)
|
|
990
|
-
except Exception as exc:
|
|
991
|
-
return f"Could not compute surprising connections: {exc}"
|
|
992
|
-
if uri_str == "graphify://audit":
|
|
993
|
-
confs = [d.get("confidence", "EXTRACTED") for _, _, d in G.edges(data=True)]
|
|
994
|
-
total = len(confs) or 1
|
|
995
|
-
return (
|
|
996
|
-
f"Total edges: {total}\n"
|
|
997
|
-
f"EXTRACTED: {confs.count('EXTRACTED')} ({round(confs.count('EXTRACTED')/total*100)}%)\n"
|
|
998
|
-
f"INFERRED: {confs.count('INFERRED')} ({round(confs.count('INFERRED')/total*100)}%)\n"
|
|
999
|
-
f"AMBIGUOUS: {confs.count('AMBIGUOUS')} ({round(confs.count('AMBIGUOUS')/total*100)}%)\n"
|
|
1000
|
-
)
|
|
1001
|
-
if uri_str == "graphify://questions":
|
|
1002
|
-
try:
|
|
1003
|
-
from graphify.analyze import suggest_questions
|
|
1004
|
-
community_labels = _load_community_labels()
|
|
1005
|
-
questions = suggest_questions(G, communities, community_labels, top_n=10)
|
|
1006
|
-
if not questions:
|
|
1007
|
-
return "No suggested questions available."
|
|
1008
|
-
lines = ["Suggested questions:"]
|
|
1009
|
-
for q in questions:
|
|
1010
|
-
if isinstance(q, dict):
|
|
1011
|
-
lines.append(f" - {q.get('question', '')}")
|
|
1012
|
-
else:
|
|
1013
|
-
lines.append(f" - {q}")
|
|
1014
|
-
return "\n".join(lines)
|
|
1015
|
-
except Exception as exc:
|
|
1016
|
-
return f"Could not generate questions: {exc}"
|
|
1017
|
-
raise ValueError(f"Unknown resource: {uri_str}")
|
|
1018
|
-
|
|
1019
|
-
@server.call_tool()
|
|
1020
|
-
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
1021
|
-
_maybe_reload()
|
|
1022
|
-
handler = _handlers.get(name)
|
|
1023
|
-
if not handler:
|
|
1024
|
-
return [types.TextContent(type="text", text=f"Unknown tool: {name}")]
|
|
1025
|
-
try:
|
|
1026
|
-
return [types.TextContent(type="text", text=handler(arguments))]
|
|
1027
|
-
except Exception as exc:
|
|
1028
|
-
return [types.TextContent(type="text", text=f"Error executing {name}: {exc}")]
|
|
1029
|
-
|
|
1030
|
-
return server
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
def serve(graph_path: str = "graphify-out/graph.json") -> None:
|
|
1034
|
-
"""Start the MCP server over stdio (the default, per-developer transport)."""
|
|
1035
|
-
try:
|
|
1036
|
-
from mcp.server.stdio import stdio_server
|
|
1037
|
-
except ImportError as e:
|
|
1038
|
-
raise ImportError('mcp not installed. Run: pip install "graphifyy[mcp]"') from e
|
|
1039
|
-
import asyncio
|
|
1040
|
-
|
|
1041
|
-
server = _build_server(graph_path)
|
|
1042
|
-
|
|
1043
|
-
async def main() -> None:
|
|
1044
|
-
async with stdio_server() as streams:
|
|
1045
|
-
await server.run(streams[0], streams[1], server.create_initialization_options())
|
|
1046
|
-
|
|
1047
|
-
_filter_blank_stdin()
|
|
1048
|
-
asyncio.run(main())
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
class _MCPASGIApp:
|
|
1052
|
-
"""Raw-ASGI wrapper around the Streamable HTTP session manager.
|
|
1053
|
-
|
|
1054
|
-
Passed to a Starlette ``Route`` as a class instance (not a function) so
|
|
1055
|
-
Starlette treats it as an ASGI app: it serves the exact mount path for all
|
|
1056
|
-
methods (GET/POST/DELETE) with no request/response wrapping and no
|
|
1057
|
-
trailing-slash redirect — mirroring how FastMCP mounts the same manager.
|
|
1058
|
-
"""
|
|
1059
|
-
|
|
1060
|
-
def __init__(self, manager) -> None:
|
|
1061
|
-
self._manager = manager
|
|
1062
|
-
|
|
1063
|
-
async def __call__(self, scope, receive, send) -> None:
|
|
1064
|
-
await self._manager.handle_request(scope, receive, send)
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
class _ApiKeyMiddleware:
|
|
1068
|
-
"""Pure-ASGI API-key gate for the HTTP transport.
|
|
1069
|
-
|
|
1070
|
-
Implemented as raw ASGI (not Starlette's BaseHTTPMiddleware) on purpose:
|
|
1071
|
-
BaseHTTPMiddleware buffers responses and breaks the Streamable HTTP SSE
|
|
1072
|
-
stream. This short-circuits with 401 before the request ever reaches the
|
|
1073
|
-
session manager, leaving the streaming path untouched for authorized calls.
|
|
1074
|
-
"""
|
|
1075
|
-
|
|
1076
|
-
def __init__(self, app, api_key: str) -> None:
|
|
1077
|
-
self.app = app
|
|
1078
|
-
self._expected = api_key.encode("utf-8")
|
|
1079
|
-
|
|
1080
|
-
async def __call__(self, scope, receive, send) -> None:
|
|
1081
|
-
if scope["type"] != "http":
|
|
1082
|
-
await self.app(scope, receive, send)
|
|
1083
|
-
return
|
|
1084
|
-
import hmac
|
|
1085
|
-
headers = dict(scope.get("headers") or [])
|
|
1086
|
-
provided = headers.get(b"x-api-key")
|
|
1087
|
-
if provided is None:
|
|
1088
|
-
# RFC 6750: the auth scheme token is case-insensitive.
|
|
1089
|
-
scheme, _, token = headers.get(b"authorization", b"").partition(b" ")
|
|
1090
|
-
if scheme.lower() == b"bearer" and token:
|
|
1091
|
-
provided = token.strip()
|
|
1092
|
-
# Constant-time compare; reject when no key was supplied at all.
|
|
1093
|
-
if provided is None or not hmac.compare_digest(provided, self._expected):
|
|
1094
|
-
body = b'{"error": "unauthorized"}'
|
|
1095
|
-
await send({
|
|
1096
|
-
"type": "http.response.start",
|
|
1097
|
-
"status": 401,
|
|
1098
|
-
"headers": [
|
|
1099
|
-
(b"content-type", b"application/json"),
|
|
1100
|
-
(b"content-length", str(len(body)).encode("ascii")),
|
|
1101
|
-
],
|
|
1102
|
-
})
|
|
1103
|
-
await send({"type": "http.response.body", "body": body})
|
|
1104
|
-
return
|
|
1105
|
-
await self.app(scope, receive, send)
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
def _build_http_app(
|
|
1109
|
-
graph_path: str,
|
|
1110
|
-
*,
|
|
1111
|
-
host: str = "127.0.0.1",
|
|
1112
|
-
port: int = 8080,
|
|
1113
|
-
api_key: str | None = None,
|
|
1114
|
-
path: str = "/mcp",
|
|
1115
|
-
json_response: bool = False,
|
|
1116
|
-
stateless: bool = False,
|
|
1117
|
-
session_timeout: float | None = 3600.0,
|
|
1118
|
-
):
|
|
1119
|
-
"""Build the Starlette ASGI app for the Streamable HTTP transport.
|
|
1120
|
-
|
|
1121
|
-
Split out from :func:`serve_http` (which blocks on uvicorn) so the wiring
|
|
1122
|
-
can be exercised with an in-process ASGI test client.
|
|
1123
|
-
|
|
1124
|
-
``session_timeout`` reaps stateful sessions idle for that many seconds so a
|
|
1125
|
-
long-running shared server does not leak memory when IDE clients disconnect
|
|
1126
|
-
without sending a DELETE. ``None`` (or <= 0) disables reaping; it is forced
|
|
1127
|
-
to ``None`` in stateless mode, which has no sessions to reap.
|
|
1128
|
-
"""
|
|
1129
|
-
try:
|
|
1130
|
-
import contextlib
|
|
1131
|
-
|
|
1132
|
-
from starlette.applications import Starlette
|
|
1133
|
-
from starlette.middleware import Middleware
|
|
1134
|
-
from starlette.routing import Route
|
|
1135
|
-
|
|
1136
|
-
from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
|
|
1137
|
-
from mcp.server.transport_security import TransportSecuritySettings
|
|
1138
|
-
except ImportError as e:
|
|
1139
|
-
raise ImportError(
|
|
1140
|
-
'HTTP transport needs the mcp extra (mcp + starlette + uvicorn). '
|
|
1141
|
-
'Run: pip install "graphifyy[mcp]"'
|
|
1142
|
-
) from e
|
|
1143
|
-
|
|
1144
|
-
# A blank key (e.g. --api-key "" or an empty GRAPHIFY_API_KEY) must not be
|
|
1145
|
-
# mistaken for "auth on" — normalize it to None so the gate is unambiguous.
|
|
1146
|
-
api_key = (api_key or "").strip() or None
|
|
1147
|
-
|
|
1148
|
-
server = _build_server(graph_path)
|
|
1149
|
-
|
|
1150
|
-
# DNS-rebinding protection. When the operator binds a wildcard address they
|
|
1151
|
-
# are intentionally exposing the server, so accept any Host header; for a
|
|
1152
|
-
# loopback/specific bind, restrict Host to that address (with and without
|
|
1153
|
-
# the port) plus the localhost aliases.
|
|
1154
|
-
if host in ("0.0.0.0", "::", ""):
|
|
1155
|
-
security = TransportSecuritySettings(enable_dns_rebinding_protection=False)
|
|
1156
|
-
else:
|
|
1157
|
-
allowed = {host, "localhost", "127.0.0.1"}
|
|
1158
|
-
allowed |= {f"{h}:{port}" for h in list(allowed)}
|
|
1159
|
-
security = TransportSecuritySettings(allowed_hosts=sorted(allowed))
|
|
1160
|
-
|
|
1161
|
-
# The SDK rejects a non-positive timeout and forbids one in stateless mode.
|
|
1162
|
-
idle_timeout = None if (stateless or not session_timeout or session_timeout <= 0) else session_timeout
|
|
1163
|
-
|
|
1164
|
-
manager = StreamableHTTPSessionManager(
|
|
1165
|
-
app=server,
|
|
1166
|
-
json_response=json_response,
|
|
1167
|
-
stateless=stateless,
|
|
1168
|
-
security_settings=security,
|
|
1169
|
-
session_idle_timeout=idle_timeout,
|
|
1170
|
-
)
|
|
1171
|
-
|
|
1172
|
-
@contextlib.asynccontextmanager
|
|
1173
|
-
async def lifespan(_app):
|
|
1174
|
-
# The session manager owns an anyio task group that must wrap the whole
|
|
1175
|
-
# server lifetime, so enter it here rather than per-request.
|
|
1176
|
-
async with manager.run():
|
|
1177
|
-
yield
|
|
1178
|
-
|
|
1179
|
-
middleware = []
|
|
1180
|
-
if api_key:
|
|
1181
|
-
middleware.append(Middleware(_ApiKeyMiddleware, api_key=api_key))
|
|
1182
|
-
|
|
1183
|
-
return Starlette(
|
|
1184
|
-
routes=[Route(path, endpoint=_MCPASGIApp(manager))],
|
|
1185
|
-
middleware=middleware,
|
|
1186
|
-
lifespan=lifespan,
|
|
1187
|
-
)
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
def serve_http(
|
|
1191
|
-
graph_path: str = "graphify-out/graph.json",
|
|
1192
|
-
*,
|
|
1193
|
-
host: str = "127.0.0.1",
|
|
1194
|
-
port: int = 8080,
|
|
1195
|
-
api_key: str | None = None,
|
|
1196
|
-
path: str = "/mcp",
|
|
1197
|
-
json_response: bool = False,
|
|
1198
|
-
stateless: bool = False,
|
|
1199
|
-
session_timeout: float | None = 3600.0,
|
|
1200
|
-
) -> None:
|
|
1201
|
-
"""Start the MCP server over Streamable HTTP (MCP spec 2025-03-26).
|
|
1202
|
-
|
|
1203
|
-
Serves the same tools/resources as the stdio transport, so a single shared
|
|
1204
|
-
process can host the graph for a whole team. Clients point their IDE MCP
|
|
1205
|
-
config at ``http://<host>:<port><path>`` (default ``/mcp``).
|
|
1206
|
-
|
|
1207
|
-
``api_key`` (or the ``GRAPHIFY_API_KEY`` env var) enables a simple header
|
|
1208
|
-
check (``Authorization: Bearer <key>`` or ``X-API-Key: <key>``). OAuth is a
|
|
1209
|
-
deliberate follow-up. Binding ``0.0.0.0`` exposes the server beyond
|
|
1210
|
-
localhost — set an api_key when you do.
|
|
1211
|
-
"""
|
|
1212
|
-
try:
|
|
1213
|
-
import uvicorn
|
|
1214
|
-
except ImportError as e:
|
|
1215
|
-
raise ImportError(
|
|
1216
|
-
'HTTP transport needs the mcp extra (mcp + starlette + uvicorn). '
|
|
1217
|
-
'Run: pip install "graphifyy[mcp]"'
|
|
1218
|
-
) from e
|
|
1219
|
-
|
|
1220
|
-
api_key = (api_key or "").strip() or None
|
|
1221
|
-
|
|
1222
|
-
app = _build_http_app(
|
|
1223
|
-
graph_path,
|
|
1224
|
-
host=host,
|
|
1225
|
-
port=port,
|
|
1226
|
-
api_key=api_key,
|
|
1227
|
-
path=path,
|
|
1228
|
-
json_response=json_response,
|
|
1229
|
-
stateless=stateless,
|
|
1230
|
-
session_timeout=session_timeout,
|
|
1231
|
-
)
|
|
1232
|
-
|
|
1233
|
-
auth_note = "api-key required" if api_key else "no auth (set --api-key to require one)"
|
|
1234
|
-
print(
|
|
1235
|
-
f"graphify MCP server (streamable-http) on http://{host}:{port}{path} - {auth_note}",
|
|
1236
|
-
file=sys.stderr,
|
|
1237
|
-
)
|
|
1238
|
-
if host in ("0.0.0.0", "::", "") and not api_key:
|
|
1239
|
-
print(
|
|
1240
|
-
f"WARNING: binding {host or '0.0.0.0'} with no api-key exposes the graph "
|
|
1241
|
-
"unauthenticated on the network. Set --api-key (or GRAPHIFY_API_KEY).",
|
|
1242
|
-
file=sys.stderr,
|
|
1243
|
-
)
|
|
1244
|
-
uvicorn.run(app, host=host, port=port)
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
def _main(argv: list[str] | None = None) -> None:
|
|
1248
|
-
import argparse
|
|
1249
|
-
import os
|
|
1250
|
-
|
|
1251
|
-
parser = argparse.ArgumentParser(
|
|
1252
|
-
prog="python -m graphify.serve",
|
|
1253
|
-
description="Serve a graphify knowledge graph over MCP (stdio or Streamable HTTP).",
|
|
1254
|
-
)
|
|
1255
|
-
parser.add_argument(
|
|
1256
|
-
"graph_path",
|
|
1257
|
-
nargs="?",
|
|
1258
|
-
default="graphify-out/graph.json",
|
|
1259
|
-
help="Path to graph.json (default: graphify-out/graph.json)",
|
|
1260
|
-
)
|
|
1261
|
-
parser.add_argument(
|
|
1262
|
-
"--transport",
|
|
1263
|
-
choices=["stdio", "http"],
|
|
1264
|
-
default="stdio",
|
|
1265
|
-
help="Transport to serve on (default: stdio)",
|
|
1266
|
-
)
|
|
1267
|
-
parser.add_argument("--host", default="127.0.0.1", help="HTTP bind host (default: 127.0.0.1)")
|
|
1268
|
-
parser.add_argument("--port", type=int, default=8080, help="HTTP bind port (default: 8080)")
|
|
1269
|
-
parser.add_argument(
|
|
1270
|
-
"--api-key",
|
|
1271
|
-
default=os.environ.get("GRAPHIFY_API_KEY"),
|
|
1272
|
-
help="Require this key on the HTTP transport (env: GRAPHIFY_API_KEY)",
|
|
1273
|
-
)
|
|
1274
|
-
parser.add_argument("--path", default="/mcp", help="HTTP mount path (default: /mcp)")
|
|
1275
|
-
parser.add_argument(
|
|
1276
|
-
"--json-response",
|
|
1277
|
-
action="store_true",
|
|
1278
|
-
help="Return plain JSON responses instead of SSE streams",
|
|
1279
|
-
)
|
|
1280
|
-
parser.add_argument(
|
|
1281
|
-
"--stateless",
|
|
1282
|
-
action="store_true",
|
|
1283
|
-
help="Run without per-session state (for load-balanced / CI deployments)",
|
|
1284
|
-
)
|
|
1285
|
-
parser.add_argument(
|
|
1286
|
-
"--session-timeout",
|
|
1287
|
-
type=float,
|
|
1288
|
-
default=3600.0,
|
|
1289
|
-
help="Reap stateful sessions idle this many seconds (default: 3600; 0 disables)",
|
|
1290
|
-
)
|
|
1291
|
-
args = parser.parse_args(argv)
|
|
1292
|
-
|
|
1293
|
-
if args.transport == "http":
|
|
1294
|
-
serve_http(
|
|
1295
|
-
args.graph_path,
|
|
1296
|
-
host=args.host,
|
|
1297
|
-
port=args.port,
|
|
1298
|
-
api_key=args.api_key,
|
|
1299
|
-
path=args.path,
|
|
1300
|
-
json_response=args.json_response,
|
|
1301
|
-
stateless=args.stateless,
|
|
1302
|
-
session_timeout=args.session_timeout,
|
|
1303
|
-
)
|
|
1304
|
-
else:
|
|
1305
|
-
serve(args.graph_path)
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
if __name__ == "__main__":
|
|
1309
|
-
_main()
|