codeply-cli 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +63 -63
- package/bin/codeply.js +129 -6
- package/lib/agent.mjs +2139 -2139
- package/lib/ai.mjs +6 -6
- package/lib/apply-patch.js +217 -217
- package/lib/arity-table.json +138 -138
- package/lib/arity.js +70 -70
- package/lib/auth.mjs +6 -6
- package/lib/cloud.mjs +708 -0
- package/lib/commands.js +103 -103
- package/lib/design-library/assemble-artifact.mjs +21 -21
- package/lib/design-library/cleanup.mjs +45 -45
- package/lib/design-library/index.json +22379 -22379
- package/lib/design-library/make-table-data.mjs +39 -39
- package/lib/diagnostics.js +192 -192
- package/lib/edit-engine.js +364 -364
- package/lib/github-agent.mjs +311 -290
- package/lib/history.js +75 -75
- package/lib/mcp.js +258 -258
- package/lib/native-tools.mjs +189 -189
- package/lib/oauth-connectors.js +2 -1
- package/lib/permissions.js +109 -109
- package/lib/plugins.js +353 -353
- package/lib/server.mjs +457 -457
- package/lib/session-db.js +220 -220
- package/lib/share.js +168 -168
- package/lib/skills.js +416 -416
- package/lib/snapshot.js +146 -146
- package/lib/terminal-hints.js +154 -154
- package/lib/tools.mjs +2012 -2012
- package/lib/typecheck-worker.js +147 -147
- package/lib/web-tools.js +158 -158
- package/package.json +49 -47
- package/skills/SOURCE.md +58 -58
- package/skills/accessibility/SKILL.md +147 -147
- package/skills/agent-architecture-audit/SKILL.md +257 -257
- package/skills/agent-eval/SKILL.md +147 -147
- package/skills/agent-harness-construction/SKILL.md +74 -74
- package/skills/agent-introspection-debugging/SKILL.md +154 -154
- package/skills/agent-payment-x402/SKILL.md +225 -225
- package/skills/agent-self-evaluation/SKILL.md +182 -182
- package/skills/agent-self-evaluation/references/evaluation-criteria.md +71 -71
- package/skills/agent-self-evaluation/references/hook-integration.md +64 -64
- package/skills/agent-sort/SKILL.md +216 -216
- package/skills/agentic-engineering/SKILL.md +64 -64
- package/skills/agentic-os/SKILL.md +388 -388
- package/skills/ai-first-engineering/SKILL.md +52 -52
- package/skills/ai-regression-testing/SKILL.md +386 -386
- package/skills/android-clean-architecture/SKILL.md +340 -340
- package/skills/angular-developer/SKILL.md +155 -155
- package/skills/angular-developer/references/angular-animations.md +160 -160
- package/skills/angular-developer/references/angular-aria.md +410 -410
- package/skills/angular-developer/references/cli.md +86 -86
- package/skills/angular-developer/references/component-harnesses.md +59 -59
- package/skills/angular-developer/references/component-styling.md +91 -91
- package/skills/angular-developer/references/components.md +117 -117
- package/skills/angular-developer/references/creating-services.md +97 -97
- package/skills/angular-developer/references/data-resolvers.md +69 -69
- package/skills/angular-developer/references/define-routes.md +67 -67
- package/skills/angular-developer/references/defining-providers.md +72 -72
- package/skills/angular-developer/references/di-fundamentals.md +120 -120
- package/skills/angular-developer/references/e2e-testing.md +56 -56
- package/skills/angular-developer/references/effects.md +83 -83
- package/skills/angular-developer/references/hierarchical-injectors.md +43 -43
- package/skills/angular-developer/references/host-elements.md +80 -80
- package/skills/angular-developer/references/injection-context.md +63 -63
- package/skills/angular-developer/references/inputs.md +101 -101
- package/skills/angular-developer/references/linked-signal.md +59 -59
- package/skills/angular-developer/references/loading-strategies.md +61 -61
- package/skills/angular-developer/references/mcp.md +108 -108
- package/skills/angular-developer/references/navigate-to-routes.md +69 -69
- package/skills/angular-developer/references/outputs.md +86 -86
- package/skills/angular-developer/references/reactive-forms.md +122 -122
- package/skills/angular-developer/references/rendering-strategies.md +44 -44
- package/skills/angular-developer/references/resource.md +77 -77
- package/skills/angular-developer/references/route-animations.md +56 -56
- package/skills/angular-developer/references/route-guards.md +52 -52
- package/skills/angular-developer/references/router-lifecycle.md +45 -45
- package/skills/angular-developer/references/router-testing.md +87 -87
- package/skills/angular-developer/references/show-routes-with-outlets.md +68 -68
- package/skills/angular-developer/references/signal-forms.md +795 -795
- package/skills/angular-developer/references/signals-overview.md +94 -94
- package/skills/angular-developer/references/tailwind-css.md +69 -69
- package/skills/angular-developer/references/template-driven-forms.md +114 -114
- package/skills/angular-developer/references/testing-fundamentals.md +65 -65
- package/skills/api-connector-builder/SKILL.md +121 -121
- package/skills/api-design/SKILL.md +524 -524
- package/skills/architecture-decision-records/SKILL.md +180 -180
- package/skills/article-writing/SKILL.md +80 -80
- package/skills/automation-audit-ops/SKILL.md +143 -143
- package/skills/autonomous-agent-harness/SKILL.md +274 -274
- package/skills/autonomous-loops/SKILL.md +611 -611
- package/skills/backend-patterns/SKILL.md +562 -562
- package/skills/benchmark/SKILL.md +95 -95
- package/skills/benchmark-methodology/SKILL.md +191 -191
- package/skills/benchmark-optimization-loop/SKILL.md +71 -71
- package/skills/blender-motion-state-inspection/SKILL.md +165 -165
- package/skills/blueprint/SKILL.md +106 -106
- package/skills/brand-discovery/SKILL.md +145 -145
- package/skills/brand-discovery/references/10_purpose-why.md +40 -40
- package/skills/brand-discovery/references/20_positioning.md +44 -44
- package/skills/brand-discovery/references/30_audience-niche.md +52 -52
- package/skills/brand-discovery/references/40_personality-archetype.md +57 -57
- package/skills/brand-discovery/references/50_voice-tone.md +59 -59
- package/skills/brand-discovery/references/60_narrative-story.md +50 -50
- package/skills/brand-discovery/references/70_founder-tension.md +49 -49
- package/skills/brand-discovery/references/90_SYNTHESIS.md +133 -133
- package/skills/brand-voice/SKILL.md +98 -98
- package/skills/brand-voice/references/voice-profile-schema.md +55 -55
- package/skills/browser-qa/SKILL.md +105 -105
- package/skills/bun-runtime/SKILL.md +85 -85
- package/skills/canary-watch/SKILL.md +108 -108
- package/skills/carrier-relationship-management/SKILL.md +212 -212
- package/skills/cisco-ios-patterns/SKILL.md +164 -164
- package/skills/ck/SKILL.md +148 -148
- package/skills/claude-devfleet/SKILL.md +112 -112
- package/skills/click-path-audit/SKILL.md +245 -245
- package/skills/clickhouse-io/SKILL.md +445 -445
- package/skills/code-tour/SKILL.md +254 -254
- package/skills/codebase-onboarding/SKILL.md +234 -234
- package/skills/codehealth-mcp/SKILL.md +167 -167
- package/skills/coding-standards/SKILL.md +551 -551
- package/skills/competitive-platform-analysis/SKILL.md +214 -214
- package/skills/competitive-report-structure/SKILL.md +162 -162
- package/skills/compose-multiplatform-patterns/SKILL.md +300 -300
- package/skills/config-gc/SKILL.md +120 -120
- package/skills/configure-ecc/SKILL.md +385 -385
- package/skills/connections-optimizer/SKILL.md +190 -190
- package/skills/content-engine/SKILL.md +132 -132
- package/skills/content-hash-cache-pattern/SKILL.md +162 -162
- package/skills/context-budget/SKILL.md +136 -136
- package/skills/continuous-agent-loop/SKILL.md +46 -46
- package/skills/continuous-learning/SKILL.md +132 -132
- package/skills/continuous-learning-v2/SKILL.md +361 -361
- package/skills/contract-first/SKILL.md +287 -287
- package/skills/cost-aware-llm-pipeline/SKILL.md +184 -184
- package/skills/cost-tracking/SKILL.md +97 -97
- package/skills/council/SKILL.md +204 -204
- package/skills/cpp-coding-standards/SKILL.md +724 -724
- package/skills/cpp-testing/SKILL.md +325 -325
- package/skills/crosspost/SKILL.md +112 -112
- package/skills/csharp-testing/SKILL.md +322 -322
- package/skills/customer-billing-ops/SKILL.md +141 -141
- package/skills/customs-trade-compliance/SKILL.md +263 -263
- package/skills/dart-flutter-patterns/SKILL.md +564 -564
- package/skills/dashboard-builder/SKILL.md +109 -109
- package/skills/data-scraper-agent/SKILL.md +765 -765
- package/skills/data-throughput-accelerator/SKILL.md +74 -74
- package/skills/database-migrations/SKILL.md +430 -430
- package/skills/deep-research/SKILL.md +160 -160
- package/skills/defi-amm-security/SKILL.md +167 -167
- package/skills/delivery-gate/SKILL.md +126 -126
- package/skills/deployment-patterns/SKILL.md +428 -428
- package/skills/design-system/SKILL.md +83 -83
- package/skills/django-celery/SKILL.md +458 -458
- package/skills/django-patterns/SKILL.md +735 -735
- package/skills/django-security/SKILL.md +644 -644
- package/skills/django-tdd/SKILL.md +730 -730
- package/skills/django-verification/SKILL.md +470 -470
- package/skills/dmux-workflows/SKILL.md +192 -192
- package/skills/docker-patterns/SKILL.md +365 -365
- package/skills/documentation-lookup/SKILL.md +91 -91
- package/skills/dotnet-patterns/SKILL.md +322 -322
- package/skills/dynamic-workflow-mode/SKILL.md +124 -124
- package/skills/e2e-testing/SKILL.md +327 -327
- package/skills/ecc-guide/SKILL.md +190 -190
- package/skills/ecc-recipes/SKILL.md +149 -149
- package/skills/ecc-tools-cost-audit/SKILL.md +161 -161
- package/skills/email-ops/SKILL.md +122 -122
- package/skills/energy-procurement/SKILL.md +228 -228
- package/skills/enterprise-agent-ops/SKILL.md +51 -51
- package/skills/error-handling/SKILL.md +377 -377
- package/skills/eval-harness/SKILL.md +271 -271
- package/skills/evm-token-decimals/SKILL.md +131 -131
- package/skills/exa-search/SKILL.md +108 -108
- package/skills/fal-ai-media/SKILL.md +289 -289
- package/skills/fastapi-patterns/SKILL.md +514 -514
- package/skills/finance-billing-ops/SKILL.md +128 -128
- package/skills/flox-environments/SKILL.md +497 -497
- package/skills/flutter-dart-code-review/SKILL.md +436 -436
- package/skills/foundation-models-on-device/SKILL.md +243 -243
- package/skills/frontend-a11y/SKILL.md +446 -446
- package/skills/frontend-design-direction/SKILL.md +93 -93
- package/skills/frontend-patterns/SKILL.md +657 -657
- package/skills/frontend-slides/SKILL.md +185 -185
- package/skills/fsharp-testing/SKILL.md +281 -281
- package/skills/gan-style-harness/SKILL.md +279 -279
- package/skills/gateguard/SKILL.md +133 -133
- package/skills/generating-python-installer/SKILL.md +820 -820
- package/skills/git-workflow/SKILL.md +716 -716
- package/skills/github-ops/SKILL.md +145 -145
- package/skills/golang-patterns/SKILL.md +676 -676
- package/skills/golang-testing/SKILL.md +721 -721
- package/skills/google-workspace-ops/SKILL.md +96 -96
- package/skills/growth-log/SKILL.md +128 -128
- package/skills/healthcare-cdss-patterns/SKILL.md +246 -246
- package/skills/healthcare-emr-patterns/SKILL.md +160 -160
- package/skills/healthcare-eval-harness/SKILL.md +208 -208
- package/skills/healthcare-phi-compliance/SKILL.md +146 -146
- package/skills/hermes-imports/SKILL.md +89 -89
- package/skills/hexagonal-architecture/SKILL.md +277 -277
- package/skills/hipaa-compliance/SKILL.md +79 -79
- package/skills/homelab-network-readiness/SKILL.md +170 -170
- package/skills/homelab-network-setup/SKILL.md +130 -130
- package/skills/homelab-pihole-dns/SKILL.md +275 -275
- package/skills/homelab-vlan-segmentation/SKILL.md +312 -312
- package/skills/homelab-wireguard-vpn/SKILL.md +306 -306
- package/skills/hookify-rules/SKILL.md +128 -128
- package/skills/inherit-legacy-style/SKILL.md +157 -157
- package/skills/intent-driven-development/SKILL.md +360 -360
- package/skills/inventory-demand-planning/SKILL.md +247 -247
- package/skills/investor-materials/SKILL.md +97 -97
- package/skills/investor-outreach/SKILL.md +92 -92
- package/skills/ios-icon-gen/SKILL.md +158 -158
- package/skills/iterative-retrieval/SKILL.md +212 -212
- package/skills/ito-basket-compare/SKILL.md +64 -64
- package/skills/ito-compute/SKILL.md +129 -129
- package/skills/ito-data-atlas-agent/SKILL.md +64 -64
- package/skills/ito-market-intelligence/SKILL.md +61 -61
- package/skills/ito-trade-planner/SKILL.md +68 -68
- package/skills/java-coding-standards/SKILL.md +384 -384
- package/skills/jira-integration/SKILL.md +303 -303
- package/skills/jpa-patterns/SKILL.md +152 -152
- package/skills/knowledge-ops/SKILL.md +155 -155
- package/skills/kotlin-coroutines-flows/SKILL.md +285 -285
- package/skills/kotlin-exposed-patterns/SKILL.md +720 -720
- package/skills/kotlin-ktor-patterns/SKILL.md +690 -690
- package/skills/kotlin-patterns/SKILL.md +712 -712
- package/skills/kotlin-testing/SKILL.md +825 -825
- package/skills/kubernetes-patterns/SKILL.md +756 -756
- package/skills/laravel-patterns/SKILL.md +416 -416
- package/skills/laravel-plugin-discovery/SKILL.md +230 -230
- package/skills/laravel-security/SKILL.md +948 -948
- package/skills/laravel-tdd/SKILL.md +675 -675
- package/skills/laravel-verification/SKILL.md +180 -180
- package/skills/latency-critical-systems/SKILL.md +75 -75
- package/skills/lead-intelligence/SKILL.md +322 -322
- package/skills/liquid-glass-design/SKILL.md +279 -279
- package/skills/llm-trading-agent-security/SKILL.md +147 -147
- package/skills/logistics-exception-management/SKILL.md +222 -222
- package/skills/loop-design-check/SKILL.md +143 -143
- package/skills/mailtrap-email-integration/SKILL.md +77 -77
- package/skills/make-interfaces-feel-better/SKILL.md +152 -152
- package/skills/manim-video/SKILL.md +90 -90
- package/skills/market-research/SKILL.md +76 -76
- package/skills/marketing-campaign/SKILL.md +114 -114
- package/skills/mcp-server-patterns/SKILL.md +70 -70
- package/skills/messages-ops/SKILL.md +105 -105
- package/skills/ml-adoption-playbook/SKILL.md +57 -57
- package/skills/mle-workflow/SKILL.md +348 -348
- package/skills/motion-advanced/SKILL.md +596 -596
- package/skills/motion-foundations/SKILL.md +299 -299
- package/skills/motion-patterns/SKILL.md +434 -434
- package/skills/motion-ui/SKILL.md +576 -576
- package/skills/mysql-patterns/SKILL.md +413 -413
- package/skills/nanoclaw-repl/SKILL.md +34 -34
- package/skills/nestjs-patterns/SKILL.md +231 -231
- package/skills/netmiko-ssh-automation/SKILL.md +174 -174
- package/skills/network-bgp-diagnostics/SKILL.md +168 -168
- package/skills/network-config-validation/SKILL.md +211 -211
- package/skills/network-interface-health/SKILL.md +153 -153
- package/skills/nextjs-turbopack/SKILL.md +58 -58
- package/skills/nodejs-keccak256/SKILL.md +103 -103
- package/skills/nutrient-document-processing/SKILL.md +168 -168
- package/skills/nuxt4-patterns/SKILL.md +101 -101
- package/skills/openclaw-persona-forge/SKILL.md +289 -289
- package/skills/openclaw-persona-forge/references/avatar-style.md +124 -124
- package/skills/openclaw-persona-forge/references/boundary-rules.md +53 -53
- package/skills/openclaw-persona-forge/references/error-handling.md +53 -53
- package/skills/openclaw-persona-forge/references/identity-tension.md +48 -48
- package/skills/openclaw-persona-forge/references/naming-system.md +39 -39
- package/skills/openclaw-persona-forge/references/output-template.md +166 -166
- package/skills/opensource-pipeline/SKILL.md +256 -256
- package/skills/orch-add-feature/SKILL.md +45 -45
- package/skills/orch-build-mvp/SKILL.md +49 -49
- package/skills/orch-change-feature/SKILL.md +43 -43
- package/skills/orch-fix-defect/SKILL.md +43 -43
- package/skills/orch-pipeline/SKILL.md +121 -121
- package/skills/orch-refine-code/SKILL.md +44 -44
- package/skills/parallel-execution-optimizer/SKILL.md +74 -74
- package/skills/perl-patterns/SKILL.md +505 -505
- package/skills/perl-security/SKILL.md +504 -504
- package/skills/perl-testing/SKILL.md +476 -476
- package/skills/plan-canvas/SKILL.md +153 -153
- package/skills/plan-orchestrate/SKILL.md +263 -263
- package/skills/plankton-code-quality/SKILL.md +237 -237
- package/skills/postgres-patterns/SKILL.md +148 -148
- package/skills/prediction-market-oracle-research/SKILL.md +64 -64
- package/skills/prediction-market-risk-review/SKILL.md +61 -61
- package/skills/premium-web-design/SKILL.md +154 -154
- package/skills/prisma-patterns/SKILL.md +401 -401
- package/skills/product-capability/SKILL.md +142 -142
- package/skills/product-lens/SKILL.md +93 -93
- package/skills/production-audit/SKILL.md +207 -207
- package/skills/production-scheduling/SKILL.md +238 -238
- package/skills/project-flow-ops/SKILL.md +112 -112
- package/skills/prompt-optimizer/SKILL.md +398 -398
- package/skills/python-patterns/SKILL.md +751 -751
- package/skills/python-testing/SKILL.md +817 -817
- package/skills/pytorch-patterns/SKILL.md +397 -397
- package/skills/quality-nonconformance/SKILL.md +260 -260
- package/skills/quarkus-patterns/SKILL.md +723 -723
- package/skills/quarkus-security/SKILL.md +468 -468
- package/skills/quarkus-tdd/SKILL.md +812 -812
- package/skills/quarkus-verification/SKILL.md +480 -480
- package/skills/ralphinho-rfc-pipeline/SKILL.md +68 -68
- package/skills/react-native-patterns/SKILL.md +326 -326
- package/skills/react-patterns/SKILL.md +342 -342
- package/skills/react-performance/SKILL.md +575 -575
- package/skills/react-testing/SKILL.md +424 -424
- package/skills/recsys-pipeline-architect/SKILL.md +115 -115
- package/skills/recursive-decision-ledger/SKILL.md +81 -81
- package/skills/redis-patterns/SKILL.md +404 -404
- package/skills/regex-vs-llm-structured-text/SKILL.md +221 -221
- package/skills/remotion-video-creation/SKILL.md +43 -43
- package/skills/repo-scan/SKILL.md +79 -79
- package/skills/research-ops/SKILL.md +113 -113
- package/skills/returns-reverse-logistics/SKILL.md +240 -240
- package/skills/rules-distill/SKILL.md +265 -265
- package/skills/rust-patterns/SKILL.md +500 -500
- package/skills/rust-testing/SKILL.md +501 -501
- package/skills/safety-guard/SKILL.md +76 -76
- package/skills/santa-method/SKILL.md +307 -307
- package/skills/scientific-db-pubmed-database/SKILL.md +176 -176
- package/skills/scientific-db-uspto-database/SKILL.md +178 -178
- package/skills/scientific-pkg-gget/SKILL.md +167 -167
- package/skills/scientific-thinking-literature-review/SKILL.md +193 -193
- package/skills/scientific-thinking-scholar-evaluation/SKILL.md +161 -161
- package/skills/search-first/SKILL.md +183 -183
- package/skills/security-bounty-hunter/SKILL.md +100 -100
- package/skills/security-review/SKILL.md +504 -504
- package/skills/security-scan/SKILL.md +166 -166
- package/skills/seo/SKILL.md +155 -155
- package/skills/skill-comply/SKILL.md +59 -59
- package/skills/skill-scout/SKILL.md +141 -141
- package/skills/skill-stocktake/SKILL.md +195 -195
- package/skills/social-graph-ranker/SKILL.md +155 -155
- package/skills/social-publisher/SKILL.md +130 -130
- package/skills/springboot-patterns/SKILL.md +315 -315
- package/skills/springboot-security/SKILL.md +273 -273
- package/skills/springboot-tdd/SKILL.md +159 -159
- package/skills/springboot-verification/SKILL.md +232 -232
- package/skills/strategic-compact/SKILL.md +142 -142
- package/skills/swift-actor-persistence/SKILL.md +144 -144
- package/skills/swift-concurrency-6-2/SKILL.md +216 -216
- package/skills/swift-protocol-di-testing/SKILL.md +191 -191
- package/skills/swiftui-patterns/SKILL.md +259 -259
- package/skills/taste/SKILL.md +264 -264
- package/skills/taste/references/genre-taxonomy.md +87 -87
- package/skills/tdd-workflow/SKILL.md +583 -583
- package/skills/team-agent-orchestration/SKILL.md +111 -111
- package/skills/team-builder/SKILL.md +169 -169
- package/skills/terminal-ops/SKILL.md +110 -110
- package/skills/tinystruct-patterns/SKILL.md +279 -279
- package/skills/tinystruct-patterns/references/architecture.md +90 -90
- package/skills/tinystruct-patterns/references/data-handling.md +60 -60
- package/skills/tinystruct-patterns/references/database.md +99 -99
- package/skills/tinystruct-patterns/references/routing.md +64 -64
- package/skills/tinystruct-patterns/references/system-usage.md +97 -97
- package/skills/tinystruct-patterns/references/testing.md +72 -72
- package/skills/token-budget-advisor/SKILL.md +134 -134
- package/skills/ui-demo/SKILL.md +466 -466
- package/skills/ui-to-vue/SKILL.md +135 -135
- package/skills/uncloud/SKILL.md +344 -344
- package/skills/unified-memory/SKILL.md +170 -170
- package/skills/unified-notifications-ops/SKILL.md +188 -188
- package/skills/verification-loop/SKILL.md +129 -129
- package/skills/video-editing/SKILL.md +311 -311
- package/skills/videodb/SKILL.md +375 -375
- package/skills/visa-doc-translate/SKILL.md +117 -117
- package/skills/vite-patterns/SKILL.md +450 -450
- package/skills/vue-patterns/SKILL.md +471 -471
- package/skills/windows-desktop-e2e/SKILL.md +888 -888
- package/skills/workspace-surface-audit/SKILL.md +126 -126
- package/skills/x-api/SKILL.md +235 -235
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
|
|
5
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
const idx = JSON.parse(readFileSync(path.join(__dirname, 'index.json'), 'utf8'));
|
|
7
|
-
|
|
8
|
-
const CATEGORY_LABELS = {
|
|
9
|
-
productivity: 'Productivity',
|
|
10
|
-
finance: 'Finance',
|
|
11
|
-
shopping: 'Shopping',
|
|
12
|
-
social: 'Social',
|
|
13
|
-
travel: 'Travel',
|
|
14
|
-
food_delivery: 'Food Delivery',
|
|
15
|
-
health_fitness: 'Health & Fitness',
|
|
16
|
-
education: 'Education',
|
|
17
|
-
entertainment: 'Entertainment',
|
|
18
|
-
real_estate: 'Real Estate',
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const rows = [];
|
|
22
|
-
for (const [cat, apps] of Object.entries(idx.categories)) {
|
|
23
|
-
for (const a of apps) {
|
|
24
|
-
rows.push({
|
|
25
|
-
n: a.name,
|
|
26
|
-
c: cat,
|
|
27
|
-
r: a.rating ? Math.round(a.rating * 10) / 10 : null,
|
|
28
|
-
rc: a.ratingCount || 0,
|
|
29
|
-
s: a.screenshots.length,
|
|
30
|
-
u: a.appStoreUrl,
|
|
31
|
-
i: a.icon,
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
rows.sort((x, y) => y.s - x.s);
|
|
36
|
-
|
|
37
|
-
const out = { generatedAt: new Date().toISOString(), labels: CATEGORY_LABELS, rows };
|
|
38
|
-
writeFileSync(path.join(__dirname, 'table-data.json'), JSON.stringify(out));
|
|
39
|
-
console.log('rows:', rows.length);
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const idx = JSON.parse(readFileSync(path.join(__dirname, 'index.json'), 'utf8'));
|
|
7
|
+
|
|
8
|
+
const CATEGORY_LABELS = {
|
|
9
|
+
productivity: 'Productivity',
|
|
10
|
+
finance: 'Finance',
|
|
11
|
+
shopping: 'Shopping',
|
|
12
|
+
social: 'Social',
|
|
13
|
+
travel: 'Travel',
|
|
14
|
+
food_delivery: 'Food Delivery',
|
|
15
|
+
health_fitness: 'Health & Fitness',
|
|
16
|
+
education: 'Education',
|
|
17
|
+
entertainment: 'Entertainment',
|
|
18
|
+
real_estate: 'Real Estate',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const rows = [];
|
|
22
|
+
for (const [cat, apps] of Object.entries(idx.categories)) {
|
|
23
|
+
for (const a of apps) {
|
|
24
|
+
rows.push({
|
|
25
|
+
n: a.name,
|
|
26
|
+
c: cat,
|
|
27
|
+
r: a.rating ? Math.round(a.rating * 10) / 10 : null,
|
|
28
|
+
rc: a.ratingCount || 0,
|
|
29
|
+
s: a.screenshots.length,
|
|
30
|
+
u: a.appStoreUrl,
|
|
31
|
+
i: a.icon,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
rows.sort((x, y) => y.s - x.s);
|
|
36
|
+
|
|
37
|
+
const out = { generatedAt: new Date().toISOString(), labels: CATEGORY_LABELS, rows };
|
|
38
|
+
writeFileSync(path.join(__dirname, 'table-data.json'), JSON.stringify(out));
|
|
39
|
+
console.log('rows:', rows.length);
|
package/lib/diagnostics.js
CHANGED
|
@@ -1,192 +1,192 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Quick syntax checks on a file the agent just wrote or edited, so a broken
|
|
3
|
-
* change is reported in the same step instead of surfacing three steps later
|
|
4
|
-
* (or never). Syntax only, and fast: nothing here type-checks a whole project
|
|
5
|
-
* or needs a language server. Idea from opencode, which appends LSP errors to
|
|
6
|
-
* edit results.
|
|
7
|
-
*
|
|
8
|
-
* checkFile() never throws; when a checker is missing or unsure it stays quiet.
|
|
9
|
-
*/
|
|
10
|
-
const fs = require('fs');
|
|
11
|
-
const path = require('path');
|
|
12
|
-
const { execFile } = require('child_process');
|
|
13
|
-
|
|
14
|
-
const TIMEOUT_MS = 8000;
|
|
15
|
-
const MAX_PROBLEMS = 10;
|
|
16
|
-
|
|
17
|
-
function run(cmd, args, opts = {}) {
|
|
18
|
-
return new Promise((resolve) => {
|
|
19
|
-
execFile(cmd, args, { timeout: TIMEOUT_MS, windowsHide: true, maxBuffer: 1024 * 1024, ...opts }, (err, stdout, stderr) => {
|
|
20
|
-
resolve({ code: err ? (typeof err.code === 'number' ? err.code : 1) : 0, out: `${stdout || ''}${stderr || ''}`, missing: err && err.code === 'ENOENT' });
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// ── JavaScript ──
|
|
26
|
-
async function checkJs(file) {
|
|
27
|
-
const r = await run(process.execPath, ['--check', file], { env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' } });
|
|
28
|
-
if (r.code === 0) return [];
|
|
29
|
-
const text = r.out.trim();
|
|
30
|
-
// JSX in a .js file (common in React projects) is not plain JS; node can't judge it.
|
|
31
|
-
if (/Unexpected token '<'|Unexpected token <|JSX/.test(text)) return [];
|
|
32
|
-
const loc = text.match(/:(\d+)\r?\n/);
|
|
33
|
-
const msg = (text.match(/^(SyntaxError: .+)$/m) || [null, text.split('\n').find((l) => l.trim()) || 'syntax error'])[1];
|
|
34
|
-
return [`${loc ? `line ${loc[1]}: ` : ''}${msg}`];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// ── JSON ──
|
|
38
|
-
const JSONC_NAMES = /^(tsconfig.*|jsconfig.*|\.eslintrc|devcontainer|settings|launch|tasks|extensions)\.json$/i;
|
|
39
|
-
function checkJson(file, text) {
|
|
40
|
-
if (JSONC_NAMES.test(path.basename(file)) || /[\\/]\.vscode[\\/]/.test(file)) return [];
|
|
41
|
-
try { JSON.parse(text.replace(/^\uFEFF/, '')); return []; }
|
|
42
|
-
catch (e) {
|
|
43
|
-
const pos = Number((e.message.match(/position (\d+)/) || [])[1]);
|
|
44
|
-
const line = Number.isFinite(pos) ? text.slice(0, pos).split('\n').length : null;
|
|
45
|
-
return [`${line ? `line ${line}: ` : ''}invalid JSON (${e.message.replace(/ in JSON at position \d+.*$/, '')})`];
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ── TypeScript / TSX, through the project's own compiler, syntax only ──
|
|
50
|
-
function findUp(start, rel, stop) {
|
|
51
|
-
let dir = start;
|
|
52
|
-
while (true) {
|
|
53
|
-
const p = path.join(dir, rel);
|
|
54
|
-
if (fs.existsSync(p)) return p;
|
|
55
|
-
const up = path.dirname(dir);
|
|
56
|
-
if (up === dir || (stop && dir === stop)) return null;
|
|
57
|
-
dir = up;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
// ── Real type checking (semantic), in a warm worker per project ──
|
|
61
|
-
const { fork } = require('child_process');
|
|
62
|
-
const workers = new Map(); // project root -> { proc, pending, nextId, ready }
|
|
63
|
-
const FIRST_CHECK_MS = 25000; // a big project's first build can take a while
|
|
64
|
-
const CHECK_MS = 10000;
|
|
65
|
-
|
|
66
|
-
function typeWorker(projectRoot, tsDir) {
|
|
67
|
-
let w = workers.get(projectRoot);
|
|
68
|
-
if (w && !w.dead) return w;
|
|
69
|
-
const proc = fork(path.join(__dirname, 'typecheck-worker.js'), [projectRoot, tsDir], {
|
|
70
|
-
env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' },
|
|
71
|
-
stdio: ['ignore', 'ignore', 'ignore', 'ipc'],
|
|
72
|
-
windowsHide: true,
|
|
73
|
-
});
|
|
74
|
-
w = { proc, pending: new Map(), nextId: 1, checks: 0, dead: false };
|
|
75
|
-
proc.on('message', (m) => {
|
|
76
|
-
const p = m && m.id != null && w.pending.get(m.id);
|
|
77
|
-
if (p) { w.pending.delete(m.id); p(m); }
|
|
78
|
-
});
|
|
79
|
-
proc.on('exit', () => { w.dead = true; for (const [, p] of w.pending) p({ error: 'worker exited' }); w.pending.clear(); });
|
|
80
|
-
proc.unref();
|
|
81
|
-
workers.set(projectRoot, w);
|
|
82
|
-
return w;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function typeCheck(file, projectRoot, tsDir) {
|
|
86
|
-
const w = typeWorker(projectRoot, tsDir);
|
|
87
|
-
const timeout = w.checks++ === 0 ? FIRST_CHECK_MS : CHECK_MS;
|
|
88
|
-
return new Promise((resolve) => {
|
|
89
|
-
const id = w.nextId++;
|
|
90
|
-
const timer = setTimeout(() => { w.pending.delete(id); resolve(null); }, timeout);
|
|
91
|
-
w.pending.set(id, (m) => { clearTimeout(timer); resolve(m.error ? null : m.problems); });
|
|
92
|
-
try { w.proc.send({ id, file }); } catch { clearTimeout(timer); resolve(null); }
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
process.on('exit', () => { for (const [, w] of workers) try { w.proc.kill(); } catch {} });
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Code navigation through the project's own TypeScript (works for .ts, .tsx, .js, .jsx).
|
|
99
|
-
* @param {{op:'definition'|'references'|'implementation'|'hover'|'documentSymbol'|'workspaceSymbol', file?:string, line?:number, character?:number, symbol?:string, query?:string}} req
|
|
100
|
-
* @returns {Promise<{ok:boolean, text:string}>}
|
|
101
|
-
*/
|
|
102
|
-
async function navigate(req, cwd) {
|
|
103
|
-
const start = req.file ? path.dirname(req.file) : cwd;
|
|
104
|
-
const tsDir = findUp(start, path.join('node_modules', 'typescript'), path.parse(cwd).root);
|
|
105
|
-
if (!tsDir) return { ok: false, text: 'Code navigation needs TypeScript installed in the project (run npm install typescript). Use search instead.' };
|
|
106
|
-
const cfg = findUp(start, 'tsconfig.json', path.parse(cwd).root) || findUp(start, 'jsconfig.json', path.parse(cwd).root);
|
|
107
|
-
const projectRoot = cfg ? path.dirname(cfg) : cwd;
|
|
108
|
-
const w = typeWorker(projectRoot, tsDir);
|
|
109
|
-
const timeout = w.checks++ === 0 ? FIRST_CHECK_MS : CHECK_MS;
|
|
110
|
-
return new Promise((resolve) => {
|
|
111
|
-
const id = w.nextId++;
|
|
112
|
-
const timer = setTimeout(() => { w.pending.delete(id); resolve({ ok: false, text: 'Code navigation timed out (the project is still loading). Try again, or use search.' }); }, timeout + 10000);
|
|
113
|
-
w.pending.set(id, (m) => { clearTimeout(timer); resolve(m.error ? { ok: false, text: `Code navigation failed: ${m.error}` } : { ok: true, text: m.text }); });
|
|
114
|
-
try { w.proc.send({ id, ...req }); } catch { clearTimeout(timer); resolve({ ok: false, text: 'Code navigation is unavailable.' }); }
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async function checkTs(file, text, cwd) {
|
|
119
|
-
const tsDir = findUp(path.dirname(file), path.join('node_modules', 'typescript'), path.parse(cwd).root);
|
|
120
|
-
if (!tsDir) return [];
|
|
121
|
-
// With a tsconfig/jsconfig the project is set up for type checking: ask
|
|
122
|
-
// the worker for real (semantic) errors. It falls back to the syntax-only
|
|
123
|
-
// pass below when it's slow or unavailable.
|
|
124
|
-
const cfg = findUp(path.dirname(file), 'tsconfig.json', path.parse(cwd).root) || findUp(path.dirname(file), 'jsconfig.json', path.parse(cwd).root);
|
|
125
|
-
if (cfg) {
|
|
126
|
-
const problems = await typeCheck(file, path.dirname(cfg), tsDir);
|
|
127
|
-
if (problems) return problems;
|
|
128
|
-
}
|
|
129
|
-
let ts;
|
|
130
|
-
try { ts = require(tsDir); } catch { return []; }
|
|
131
|
-
const out = ts.transpileModule(text, {
|
|
132
|
-
fileName: file,
|
|
133
|
-
reportDiagnostics: true,
|
|
134
|
-
compilerOptions: { jsx: file.endsWith('x') ? ts.JsxEmit.Preserve : undefined, target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.ESNext },
|
|
135
|
-
});
|
|
136
|
-
return (out.diagnostics || []).filter((d) => d.category === ts.DiagnosticCategory.Error).map((d) => {
|
|
137
|
-
const line = d.file && d.start != null ? d.file.getLineAndCharacterOfPosition(d.start).line + 1 : null;
|
|
138
|
-
return `${line ? `line ${line}: ` : ''}${ts.flattenDiagnosticMessageText(d.messageText, ' ')}`;
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// ── CSS: unbalanced braces are the classic broken-edit symptom ──
|
|
143
|
-
function checkCss(text) {
|
|
144
|
-
const clean = text.replace(/\/\*[\s\S]*?\*\//g, '').replace(/"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'/g, '""');
|
|
145
|
-
let depth = 0, line = 1;
|
|
146
|
-
for (const ch of clean) {
|
|
147
|
-
if (ch === '\n') line++;
|
|
148
|
-
else if (ch === '{') depth++;
|
|
149
|
-
else if (ch === '}' && --depth < 0) return [`line ${line}: a "}" with no matching "{"`];
|
|
150
|
-
}
|
|
151
|
-
return depth > 0 ? [`${depth} "{" never closed (end of file)`] : [];
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// ── Python ──
|
|
155
|
-
let pythonCmd; // undefined = not probed yet, null = none found
|
|
156
|
-
async function checkPy(file) {
|
|
157
|
-
if (pythonCmd === undefined) {
|
|
158
|
-
pythonCmd = null;
|
|
159
|
-
for (const c of process.platform === 'win32' ? ['py', 'python', 'python3'] : ['python3', 'python']) {
|
|
160
|
-
const r = await run(c, ['--version']);
|
|
161
|
-
if (r.code === 0 && /Python 3/.test(r.out)) { pythonCmd = c; break; }
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
if (!pythonCmd) return [];
|
|
165
|
-
const code = 'import sys,ast\nsrc=open(sys.argv[1],encoding="utf-8").read()\ntry:\n ast.parse(src)\nexcept SyntaxError as e:\n print(f"line {e.lineno}: SyntaxError: {e.msg}");sys.exit(1)';
|
|
166
|
-
const r = await run(pythonCmd, ['-c', code, file]);
|
|
167
|
-
return r.code === 0 ? [] : [r.out.trim().split('\n').pop()];
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* @param {string} abs absolute path of the file that just changed
|
|
172
|
-
* @param {string} cwd project root
|
|
173
|
-
* @returns {Promise<string[]>} problems, empty when clean or not checkable
|
|
174
|
-
*/
|
|
175
|
-
async function checkFile(abs, cwd) {
|
|
176
|
-
try {
|
|
177
|
-
const ext = path.extname(abs).toLowerCase();
|
|
178
|
-
if (!['.js', '.cjs', '.mjs', '.json', '.ts', '.tsx', '.mts', '.cts', '.jsx', '.css', '.py'].includes(ext)) return [];
|
|
179
|
-
const stat = fs.statSync(abs);
|
|
180
|
-
if (stat.size > 2_000_000) return [];
|
|
181
|
-
const text = fs.readFileSync(abs, 'utf8');
|
|
182
|
-
let problems = [];
|
|
183
|
-
if (ext === '.js' || ext === '.cjs' || ext === '.mjs') problems = await checkJs(abs);
|
|
184
|
-
else if (ext === '.json') problems = checkJson(abs, text);
|
|
185
|
-
else if (ext === '.jsx' || ext.startsWith('.ts') || ext === '.mts' || ext === '.cts') problems = await checkTs(abs, text, cwd);
|
|
186
|
-
else if (ext === '.css') problems = checkCss(text);
|
|
187
|
-
else if (ext === '.py') problems = await checkPy(abs);
|
|
188
|
-
return problems.filter(Boolean).slice(0, MAX_PROBLEMS);
|
|
189
|
-
} catch { return []; }
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
module.exports = { checkFile, navigate };
|
|
1
|
+
/**
|
|
2
|
+
* Quick syntax checks on a file the agent just wrote or edited, so a broken
|
|
3
|
+
* change is reported in the same step instead of surfacing three steps later
|
|
4
|
+
* (or never). Syntax only, and fast: nothing here type-checks a whole project
|
|
5
|
+
* or needs a language server. Idea from opencode, which appends LSP errors to
|
|
6
|
+
* edit results.
|
|
7
|
+
*
|
|
8
|
+
* checkFile() never throws; when a checker is missing or unsure it stays quiet.
|
|
9
|
+
*/
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const { execFile } = require('child_process');
|
|
13
|
+
|
|
14
|
+
const TIMEOUT_MS = 8000;
|
|
15
|
+
const MAX_PROBLEMS = 10;
|
|
16
|
+
|
|
17
|
+
function run(cmd, args, opts = {}) {
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
execFile(cmd, args, { timeout: TIMEOUT_MS, windowsHide: true, maxBuffer: 1024 * 1024, ...opts }, (err, stdout, stderr) => {
|
|
20
|
+
resolve({ code: err ? (typeof err.code === 'number' ? err.code : 1) : 0, out: `${stdout || ''}${stderr || ''}`, missing: err && err.code === 'ENOENT' });
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ── JavaScript ──
|
|
26
|
+
async function checkJs(file) {
|
|
27
|
+
const r = await run(process.execPath, ['--check', file], { env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' } });
|
|
28
|
+
if (r.code === 0) return [];
|
|
29
|
+
const text = r.out.trim();
|
|
30
|
+
// JSX in a .js file (common in React projects) is not plain JS; node can't judge it.
|
|
31
|
+
if (/Unexpected token '<'|Unexpected token <|JSX/.test(text)) return [];
|
|
32
|
+
const loc = text.match(/:(\d+)\r?\n/);
|
|
33
|
+
const msg = (text.match(/^(SyntaxError: .+)$/m) || [null, text.split('\n').find((l) => l.trim()) || 'syntax error'])[1];
|
|
34
|
+
return [`${loc ? `line ${loc[1]}: ` : ''}${msg}`];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ── JSON ──
|
|
38
|
+
const JSONC_NAMES = /^(tsconfig.*|jsconfig.*|\.eslintrc|devcontainer|settings|launch|tasks|extensions)\.json$/i;
|
|
39
|
+
function checkJson(file, text) {
|
|
40
|
+
if (JSONC_NAMES.test(path.basename(file)) || /[\\/]\.vscode[\\/]/.test(file)) return [];
|
|
41
|
+
try { JSON.parse(text.replace(/^\uFEFF/, '')); return []; }
|
|
42
|
+
catch (e) {
|
|
43
|
+
const pos = Number((e.message.match(/position (\d+)/) || [])[1]);
|
|
44
|
+
const line = Number.isFinite(pos) ? text.slice(0, pos).split('\n').length : null;
|
|
45
|
+
return [`${line ? `line ${line}: ` : ''}invalid JSON (${e.message.replace(/ in JSON at position \d+.*$/, '')})`];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── TypeScript / TSX, through the project's own compiler, syntax only ──
|
|
50
|
+
function findUp(start, rel, stop) {
|
|
51
|
+
let dir = start;
|
|
52
|
+
while (true) {
|
|
53
|
+
const p = path.join(dir, rel);
|
|
54
|
+
if (fs.existsSync(p)) return p;
|
|
55
|
+
const up = path.dirname(dir);
|
|
56
|
+
if (up === dir || (stop && dir === stop)) return null;
|
|
57
|
+
dir = up;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// ── Real type checking (semantic), in a warm worker per project ──
|
|
61
|
+
const { fork } = require('child_process');
|
|
62
|
+
const workers = new Map(); // project root -> { proc, pending, nextId, ready }
|
|
63
|
+
const FIRST_CHECK_MS = 25000; // a big project's first build can take a while
|
|
64
|
+
const CHECK_MS = 10000;
|
|
65
|
+
|
|
66
|
+
function typeWorker(projectRoot, tsDir) {
|
|
67
|
+
let w = workers.get(projectRoot);
|
|
68
|
+
if (w && !w.dead) return w;
|
|
69
|
+
const proc = fork(path.join(__dirname, 'typecheck-worker.js'), [projectRoot, tsDir], {
|
|
70
|
+
env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' },
|
|
71
|
+
stdio: ['ignore', 'ignore', 'ignore', 'ipc'],
|
|
72
|
+
windowsHide: true,
|
|
73
|
+
});
|
|
74
|
+
w = { proc, pending: new Map(), nextId: 1, checks: 0, dead: false };
|
|
75
|
+
proc.on('message', (m) => {
|
|
76
|
+
const p = m && m.id != null && w.pending.get(m.id);
|
|
77
|
+
if (p) { w.pending.delete(m.id); p(m); }
|
|
78
|
+
});
|
|
79
|
+
proc.on('exit', () => { w.dead = true; for (const [, p] of w.pending) p({ error: 'worker exited' }); w.pending.clear(); });
|
|
80
|
+
proc.unref();
|
|
81
|
+
workers.set(projectRoot, w);
|
|
82
|
+
return w;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function typeCheck(file, projectRoot, tsDir) {
|
|
86
|
+
const w = typeWorker(projectRoot, tsDir);
|
|
87
|
+
const timeout = w.checks++ === 0 ? FIRST_CHECK_MS : CHECK_MS;
|
|
88
|
+
return new Promise((resolve) => {
|
|
89
|
+
const id = w.nextId++;
|
|
90
|
+
const timer = setTimeout(() => { w.pending.delete(id); resolve(null); }, timeout);
|
|
91
|
+
w.pending.set(id, (m) => { clearTimeout(timer); resolve(m.error ? null : m.problems); });
|
|
92
|
+
try { w.proc.send({ id, file }); } catch { clearTimeout(timer); resolve(null); }
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
process.on('exit', () => { for (const [, w] of workers) try { w.proc.kill(); } catch {} });
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Code navigation through the project's own TypeScript (works for .ts, .tsx, .js, .jsx).
|
|
99
|
+
* @param {{op:'definition'|'references'|'implementation'|'hover'|'documentSymbol'|'workspaceSymbol', file?:string, line?:number, character?:number, symbol?:string, query?:string}} req
|
|
100
|
+
* @returns {Promise<{ok:boolean, text:string}>}
|
|
101
|
+
*/
|
|
102
|
+
async function navigate(req, cwd) {
|
|
103
|
+
const start = req.file ? path.dirname(req.file) : cwd;
|
|
104
|
+
const tsDir = findUp(start, path.join('node_modules', 'typescript'), path.parse(cwd).root);
|
|
105
|
+
if (!tsDir) return { ok: false, text: 'Code navigation needs TypeScript installed in the project (run npm install typescript). Use search instead.' };
|
|
106
|
+
const cfg = findUp(start, 'tsconfig.json', path.parse(cwd).root) || findUp(start, 'jsconfig.json', path.parse(cwd).root);
|
|
107
|
+
const projectRoot = cfg ? path.dirname(cfg) : cwd;
|
|
108
|
+
const w = typeWorker(projectRoot, tsDir);
|
|
109
|
+
const timeout = w.checks++ === 0 ? FIRST_CHECK_MS : CHECK_MS;
|
|
110
|
+
return new Promise((resolve) => {
|
|
111
|
+
const id = w.nextId++;
|
|
112
|
+
const timer = setTimeout(() => { w.pending.delete(id); resolve({ ok: false, text: 'Code navigation timed out (the project is still loading). Try again, or use search.' }); }, timeout + 10000);
|
|
113
|
+
w.pending.set(id, (m) => { clearTimeout(timer); resolve(m.error ? { ok: false, text: `Code navigation failed: ${m.error}` } : { ok: true, text: m.text }); });
|
|
114
|
+
try { w.proc.send({ id, ...req }); } catch { clearTimeout(timer); resolve({ ok: false, text: 'Code navigation is unavailable.' }); }
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function checkTs(file, text, cwd) {
|
|
119
|
+
const tsDir = findUp(path.dirname(file), path.join('node_modules', 'typescript'), path.parse(cwd).root);
|
|
120
|
+
if (!tsDir) return [];
|
|
121
|
+
// With a tsconfig/jsconfig the project is set up for type checking: ask
|
|
122
|
+
// the worker for real (semantic) errors. It falls back to the syntax-only
|
|
123
|
+
// pass below when it's slow or unavailable.
|
|
124
|
+
const cfg = findUp(path.dirname(file), 'tsconfig.json', path.parse(cwd).root) || findUp(path.dirname(file), 'jsconfig.json', path.parse(cwd).root);
|
|
125
|
+
if (cfg) {
|
|
126
|
+
const problems = await typeCheck(file, path.dirname(cfg), tsDir);
|
|
127
|
+
if (problems) return problems;
|
|
128
|
+
}
|
|
129
|
+
let ts;
|
|
130
|
+
try { ts = require(tsDir); } catch { return []; }
|
|
131
|
+
const out = ts.transpileModule(text, {
|
|
132
|
+
fileName: file,
|
|
133
|
+
reportDiagnostics: true,
|
|
134
|
+
compilerOptions: { jsx: file.endsWith('x') ? ts.JsxEmit.Preserve : undefined, target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.ESNext },
|
|
135
|
+
});
|
|
136
|
+
return (out.diagnostics || []).filter((d) => d.category === ts.DiagnosticCategory.Error).map((d) => {
|
|
137
|
+
const line = d.file && d.start != null ? d.file.getLineAndCharacterOfPosition(d.start).line + 1 : null;
|
|
138
|
+
return `${line ? `line ${line}: ` : ''}${ts.flattenDiagnosticMessageText(d.messageText, ' ')}`;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ── CSS: unbalanced braces are the classic broken-edit symptom ──
|
|
143
|
+
function checkCss(text) {
|
|
144
|
+
const clean = text.replace(/\/\*[\s\S]*?\*\//g, '').replace(/"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'/g, '""');
|
|
145
|
+
let depth = 0, line = 1;
|
|
146
|
+
for (const ch of clean) {
|
|
147
|
+
if (ch === '\n') line++;
|
|
148
|
+
else if (ch === '{') depth++;
|
|
149
|
+
else if (ch === '}' && --depth < 0) return [`line ${line}: a "}" with no matching "{"`];
|
|
150
|
+
}
|
|
151
|
+
return depth > 0 ? [`${depth} "{" never closed (end of file)`] : [];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ── Python ──
|
|
155
|
+
let pythonCmd; // undefined = not probed yet, null = none found
|
|
156
|
+
async function checkPy(file) {
|
|
157
|
+
if (pythonCmd === undefined) {
|
|
158
|
+
pythonCmd = null;
|
|
159
|
+
for (const c of process.platform === 'win32' ? ['py', 'python', 'python3'] : ['python3', 'python']) {
|
|
160
|
+
const r = await run(c, ['--version']);
|
|
161
|
+
if (r.code === 0 && /Python 3/.test(r.out)) { pythonCmd = c; break; }
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (!pythonCmd) return [];
|
|
165
|
+
const code = 'import sys,ast\nsrc=open(sys.argv[1],encoding="utf-8").read()\ntry:\n ast.parse(src)\nexcept SyntaxError as e:\n print(f"line {e.lineno}: SyntaxError: {e.msg}");sys.exit(1)';
|
|
166
|
+
const r = await run(pythonCmd, ['-c', code, file]);
|
|
167
|
+
return r.code === 0 ? [] : [r.out.trim().split('\n').pop()];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @param {string} abs absolute path of the file that just changed
|
|
172
|
+
* @param {string} cwd project root
|
|
173
|
+
* @returns {Promise<string[]>} problems, empty when clean or not checkable
|
|
174
|
+
*/
|
|
175
|
+
async function checkFile(abs, cwd) {
|
|
176
|
+
try {
|
|
177
|
+
const ext = path.extname(abs).toLowerCase();
|
|
178
|
+
if (!['.js', '.cjs', '.mjs', '.json', '.ts', '.tsx', '.mts', '.cts', '.jsx', '.css', '.py'].includes(ext)) return [];
|
|
179
|
+
const stat = fs.statSync(abs);
|
|
180
|
+
if (stat.size > 2_000_000) return [];
|
|
181
|
+
const text = fs.readFileSync(abs, 'utf8');
|
|
182
|
+
let problems = [];
|
|
183
|
+
if (ext === '.js' || ext === '.cjs' || ext === '.mjs') problems = await checkJs(abs);
|
|
184
|
+
else if (ext === '.json') problems = checkJson(abs, text);
|
|
185
|
+
else if (ext === '.jsx' || ext.startsWith('.ts') || ext === '.mts' || ext === '.cts') problems = await checkTs(abs, text, cwd);
|
|
186
|
+
else if (ext === '.css') problems = checkCss(text);
|
|
187
|
+
else if (ext === '.py') problems = await checkPy(abs);
|
|
188
|
+
return problems.filter(Boolean).slice(0, MAX_PROBLEMS);
|
|
189
|
+
} catch { return []; }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = { checkFile, navigate };
|