codeply-cli 0.5.6 → 0.6.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/LICENSE +21 -21
- package/THIRD_PARTY_NOTICES.md +65 -65
- package/bin/codeply.js +8 -3
- package/lib/agent.mjs +2596 -2268
- package/lib/ai.js +135 -27
- 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/autopilot.js +84 -0
- package/lib/bot-mail.js +46 -0
- package/lib/bots.js +142 -15
- package/lib/brain.js +914 -0
- package/lib/call-assist.js +120 -0
- package/lib/chatgpt.js +282 -282
- package/lib/cloud-browser.mjs +143 -143
- package/lib/cloud.mjs +1396 -1320
- package/lib/commands.js +103 -103
- package/lib/computer.js +136 -0
- 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/design-tools.mjs +173 -0
- package/lib/diagnostics.js +192 -192
- package/lib/dsh-acp.mjs +444 -0
- package/lib/edit-engine.js +364 -364
- package/lib/github-agent.mjs +326 -326
- package/lib/handoff.mjs +245 -0
- package/lib/history.js +78 -75
- package/lib/life-sources.js +319 -0
- package/lib/life-store.js +356 -0
- package/lib/life-triggers.js +286 -0
- package/lib/life.js +487 -0
- package/lib/mail-watch.js +3 -3
- package/lib/mcp.js +258 -258
- package/lib/native-tools.mjs +17 -5
- package/lib/oauth-connectors.js +76 -21
- package/lib/permissions.js +109 -109
- package/lib/plugins.js +356 -353
- package/lib/reach.js +67 -67
- package/lib/render-md.mjs +647 -617
- package/lib/screen.js +77 -0
- package/lib/server.mjs +458 -457
- package/lib/session-db.js +220 -220
- package/lib/share.js +208 -168
- package/lib/skills.js +4 -1
- package/lib/snapshot.js +146 -146
- package/lib/subagents.js +4 -2
- package/lib/telemetry.js +105 -105
- package/lib/terminal-hints.js +154 -154
- package/lib/textarea.mjs +264 -258
- package/lib/tools.mjs +326 -40
- package/lib/tui.mjs +1459 -1086
- package/lib/typecheck-worker.js +147 -147
- package/lib/web-tools.js +209 -209
- package/package.json +1 -1
- 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/codeply-taste/LICENSE +21 -0
- package/skills/codeply-taste/SKILL.md +100 -0
- package/skills/codeply-taste/SOURCE.md +10 -0
- package/skills/codeply-taste/assets/base.css +100 -0
- package/skills/codeply-taste/assets/base.js +37 -0
- package/skills/codeply-taste/library/directions.json +1078 -0
- package/skills/codeply-taste/library/heroes.json +894 -0
- package/skills/codeply-taste/library/motions.json +57 -0
- package/skills/codeply-taste/library/palettes.json +1485 -0
- package/skills/codeply-taste/library/photos.json +7240 -0
- package/skills/codeply-taste/library/sections.json +4136 -0
- package/skills/codeply-taste/library/sites.json +7274 -0
- package/skills/codeply-taste/library/type.json +2024 -0
- package/skills/codeply-taste/references/colour.md +141 -0
- package/skills/codeply-taste/references/copy.md +177 -0
- package/skills/codeply-taste/references/critique.md +171 -0
- package/skills/codeply-taste/references/imagery.md +377 -0
- package/skills/codeply-taste/references/layout.md +178 -0
- package/skills/codeply-taste/references/motion.md +292 -0
- package/skills/codeply-taste/references/research.md +306 -0
- package/skills/codeply-taste/references/tells.md +115 -0
- package/skills/codeply-taste/references/type.md +170 -0
- package/skills/codeply-taste/scripts/assets.mjs +865 -0
- package/skills/codeply-taste/scripts/draw.mjs +525 -0
- package/skills/codeply-taste/scripts/inspect.mjs +205 -0
- package/skills/codeply-taste/scripts/lib/cdp.mjs +205 -0
- package/skills/codeply-taste/scripts/lib/probe.mjs +569 -0
- package/skills/codeply-taste/scripts/lib/rules.mjs +137 -0
- package/skills/codeply-taste/scripts/lint.mjs +108 -0
- 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
package/lib/commands.js
CHANGED
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Custom slash commands: a markdown file per command, same layout opencode
|
|
3
|
-
* and Claude Code use, so existing ones can be copied over.
|
|
4
|
-
*
|
|
5
|
-
* ~/.codeply/commands/<name>.md (every project)
|
|
6
|
-
* <project>/.codeply/commands/<name>.md (this project; same name wins)
|
|
7
|
-
*
|
|
8
|
-
* ---
|
|
9
|
-
* description: Review the changed files for bugs
|
|
10
|
-
* mode: Plan # optional: Build | Plan | Ask
|
|
11
|
-
* ---
|
|
12
|
-
* Review $ARGUMENTS for correctness bugs. Cite file:line.
|
|
13
|
-
*
|
|
14
|
-
* In the body, $ARGUMENTS is everything typed after the command, $1 $2 ...
|
|
15
|
-
* are single words (the highest one takes the rest), and if the body has no
|
|
16
|
-
* placeholder at all the arguments are appended on their own line.
|
|
17
|
-
* Sub-folders become part of the name: commands/git/pr.md is /git/pr.
|
|
18
|
-
* Installed plugins add theirs as /<plugin>:<name> (see plugins.js).
|
|
19
|
-
*/
|
|
20
|
-
const fs = require('fs');
|
|
21
|
-
const os = require('os');
|
|
22
|
-
const path = require('path');
|
|
23
|
-
const plugins = require('./plugins.js');
|
|
24
|
-
|
|
25
|
-
const MAX_BODY = 20000;
|
|
26
|
-
const RESERVED = new Set(['goal', 'g', 'skills', 'skill', 'skill-list']);
|
|
27
|
-
|
|
28
|
-
function parseFrontmatter(text) {
|
|
29
|
-
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
|
|
30
|
-
if (!m) return { meta: {}, body: text };
|
|
31
|
-
const meta = {};
|
|
32
|
-
for (const line of m[1].split(/\r?\n/)) {
|
|
33
|
-
const kv = /^([A-Za-z_-]+)\s*:\s*(.*)$/.exec(line);
|
|
34
|
-
if (kv) meta[kv[1].toLowerCase()] = kv[2].trim().replace(/^["']|["']$/g, '');
|
|
35
|
-
}
|
|
36
|
-
return { meta, body: text.slice(m[0].length) };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function scan(dir, prefix, out) {
|
|
40
|
-
let entries;
|
|
41
|
-
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
42
|
-
for (const e of entries) {
|
|
43
|
-
const full = path.join(dir, e.name);
|
|
44
|
-
if (e.isDirectory()) scan(full, `${prefix}${e.name}/`, out);
|
|
45
|
-
else if (e.isFile() && e.name.toLowerCase().endsWith('.md')) {
|
|
46
|
-
const name = `${prefix}${e.name.slice(0, -3)}`.toLowerCase().replace(/\s+/g, '-');
|
|
47
|
-
if (RESERVED.has(name)) continue;
|
|
48
|
-
try {
|
|
49
|
-
const { meta, body } = parseFrontmatter(fs.readFileSync(full, 'utf8').slice(0, MAX_BODY));
|
|
50
|
-
const mode = ['Build', 'Plan', 'Ask'].find((x) => x.toLowerCase() === String(meta.mode || '').toLowerCase());
|
|
51
|
-
out.set(name, {
|
|
52
|
-
name,
|
|
53
|
-
description: meta.description || body.trim().split('\n')[0].slice(0, 100),
|
|
54
|
-
mode: mode || null,
|
|
55
|
-
body: body.trim(),
|
|
56
|
-
file: full,
|
|
57
|
-
});
|
|
58
|
-
} catch {}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** @returns {Map<string, {name, description, mode, body, file}>} */
|
|
64
|
-
function loadCommands(cwd) {
|
|
65
|
-
const out = new Map();
|
|
66
|
-
for (const { plugin, dir } of plugins.commandDirs(cwd)) scan(dir, `${plugin}:`, out);
|
|
67
|
-
scan(path.join(os.homedir(), '.codeply', 'commands'), '', out);
|
|
68
|
-
if (cwd) scan(path.join(cwd, '.codeply', 'commands'), '', out);
|
|
69
|
-
return out;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Fill a command's template with what was typed after it. */
|
|
73
|
-
function expand(cmd, argText) {
|
|
74
|
-
const args = String(argText || '').trim();
|
|
75
|
-
const words = args ? args.split(/\s+/) : [];
|
|
76
|
-
let body = cmd.body;
|
|
77
|
-
const nums = [...body.matchAll(/\$(\d+)/g)].map((m) => Number(m[1]));
|
|
78
|
-
const max = nums.length ? Math.max(...nums) : 0;
|
|
79
|
-
const used = /\$ARGUMENTS|\$\d+/.test(body);
|
|
80
|
-
body = body.replace(/\$(\d+)/g, (_, n) => {
|
|
81
|
-
const i = Number(n) - 1;
|
|
82
|
-
return Number(n) === max ? words.slice(i).join(' ') : (words[i] || '');
|
|
83
|
-
});
|
|
84
|
-
body = body.replace(/\$ARGUMENTS/g, args);
|
|
85
|
-
if (!used && args) body = `${body}\n\n${args}`;
|
|
86
|
-
return body.trim();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* If `text` starts with a known custom command, the expanded prompt and the
|
|
91
|
-
* command; otherwise null. `/goal` and the app's built-ins are never matched.
|
|
92
|
-
*/
|
|
93
|
-
function resolve(text, cwd) {
|
|
94
|
-
const m = /^\/([A-Za-z0-9_./:-]+)(?:\s+([\s\S]*))?$/.exec(String(text || '').trim());
|
|
95
|
-
if (!m) return null;
|
|
96
|
-
const name = m[1].toLowerCase();
|
|
97
|
-
if (RESERVED.has(name)) return null;
|
|
98
|
-
const cmd = loadCommands(cwd).get(name);
|
|
99
|
-
if (!cmd) return null;
|
|
100
|
-
return { command: cmd, prompt: expand(cmd, m[2] || '') };
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
module.exports = { loadCommands, expand, resolve, parseFrontmatter };
|
|
1
|
+
/**
|
|
2
|
+
* Custom slash commands: a markdown file per command, same layout opencode
|
|
3
|
+
* and Claude Code use, so existing ones can be copied over.
|
|
4
|
+
*
|
|
5
|
+
* ~/.codeply/commands/<name>.md (every project)
|
|
6
|
+
* <project>/.codeply/commands/<name>.md (this project; same name wins)
|
|
7
|
+
*
|
|
8
|
+
* ---
|
|
9
|
+
* description: Review the changed files for bugs
|
|
10
|
+
* mode: Plan # optional: Build | Plan | Ask
|
|
11
|
+
* ---
|
|
12
|
+
* Review $ARGUMENTS for correctness bugs. Cite file:line.
|
|
13
|
+
*
|
|
14
|
+
* In the body, $ARGUMENTS is everything typed after the command, $1 $2 ...
|
|
15
|
+
* are single words (the highest one takes the rest), and if the body has no
|
|
16
|
+
* placeholder at all the arguments are appended on their own line.
|
|
17
|
+
* Sub-folders become part of the name: commands/git/pr.md is /git/pr.
|
|
18
|
+
* Installed plugins add theirs as /<plugin>:<name> (see plugins.js).
|
|
19
|
+
*/
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const os = require('os');
|
|
22
|
+
const path = require('path');
|
|
23
|
+
const plugins = require('./plugins.js');
|
|
24
|
+
|
|
25
|
+
const MAX_BODY = 20000;
|
|
26
|
+
const RESERVED = new Set(['goal', 'g', 'skills', 'skill', 'skill-list', 'plugins', 'plugin']);
|
|
27
|
+
|
|
28
|
+
function parseFrontmatter(text) {
|
|
29
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
|
|
30
|
+
if (!m) return { meta: {}, body: text };
|
|
31
|
+
const meta = {};
|
|
32
|
+
for (const line of m[1].split(/\r?\n/)) {
|
|
33
|
+
const kv = /^([A-Za-z_-]+)\s*:\s*(.*)$/.exec(line);
|
|
34
|
+
if (kv) meta[kv[1].toLowerCase()] = kv[2].trim().replace(/^["']|["']$/g, '');
|
|
35
|
+
}
|
|
36
|
+
return { meta, body: text.slice(m[0].length) };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function scan(dir, prefix, out) {
|
|
40
|
+
let entries;
|
|
41
|
+
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
42
|
+
for (const e of entries) {
|
|
43
|
+
const full = path.join(dir, e.name);
|
|
44
|
+
if (e.isDirectory()) scan(full, `${prefix}${e.name}/`, out);
|
|
45
|
+
else if (e.isFile() && e.name.toLowerCase().endsWith('.md')) {
|
|
46
|
+
const name = `${prefix}${e.name.slice(0, -3)}`.toLowerCase().replace(/\s+/g, '-');
|
|
47
|
+
if (RESERVED.has(name)) continue;
|
|
48
|
+
try {
|
|
49
|
+
const { meta, body } = parseFrontmatter(fs.readFileSync(full, 'utf8').slice(0, MAX_BODY));
|
|
50
|
+
const mode = ['Build', 'Plan', 'Ask'].find((x) => x.toLowerCase() === String(meta.mode || '').toLowerCase());
|
|
51
|
+
out.set(name, {
|
|
52
|
+
name,
|
|
53
|
+
description: meta.description || body.trim().split('\n')[0].slice(0, 100),
|
|
54
|
+
mode: mode || null,
|
|
55
|
+
body: body.trim(),
|
|
56
|
+
file: full,
|
|
57
|
+
});
|
|
58
|
+
} catch {}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** @returns {Map<string, {name, description, mode, body, file}>} */
|
|
64
|
+
function loadCommands(cwd) {
|
|
65
|
+
const out = new Map();
|
|
66
|
+
for (const { plugin, dir } of plugins.commandDirs(cwd)) scan(dir, `${plugin}:`, out);
|
|
67
|
+
scan(path.join(os.homedir(), '.codeply', 'commands'), '', out);
|
|
68
|
+
if (cwd) scan(path.join(cwd, '.codeply', 'commands'), '', out);
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Fill a command's template with what was typed after it. */
|
|
73
|
+
function expand(cmd, argText) {
|
|
74
|
+
const args = String(argText || '').trim();
|
|
75
|
+
const words = args ? args.split(/\s+/) : [];
|
|
76
|
+
let body = cmd.body;
|
|
77
|
+
const nums = [...body.matchAll(/\$(\d+)/g)].map((m) => Number(m[1]));
|
|
78
|
+
const max = nums.length ? Math.max(...nums) : 0;
|
|
79
|
+
const used = /\$ARGUMENTS|\$\d+/.test(body);
|
|
80
|
+
body = body.replace(/\$(\d+)/g, (_, n) => {
|
|
81
|
+
const i = Number(n) - 1;
|
|
82
|
+
return Number(n) === max ? words.slice(i).join(' ') : (words[i] || '');
|
|
83
|
+
});
|
|
84
|
+
body = body.replace(/\$ARGUMENTS/g, args);
|
|
85
|
+
if (!used && args) body = `${body}\n\n${args}`;
|
|
86
|
+
return body.trim();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* If `text` starts with a known custom command, the expanded prompt and the
|
|
91
|
+
* command; otherwise null. `/goal` and the app's built-ins are never matched.
|
|
92
|
+
*/
|
|
93
|
+
function resolve(text, cwd) {
|
|
94
|
+
const m = /^\/([A-Za-z0-9_./:-]+)(?:\s+([\s\S]*))?$/.exec(String(text || '').trim());
|
|
95
|
+
if (!m) return null;
|
|
96
|
+
const name = m[1].toLowerCase();
|
|
97
|
+
if (RESERVED.has(name)) return null;
|
|
98
|
+
const cmd = loadCommands(cwd).get(name);
|
|
99
|
+
if (!cmd) return null;
|
|
100
|
+
return { command: cmd, prompt: expand(cmd, m[2] || '') };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = { loadCommands, expand, resolve, parseFrontmatter };
|
package/lib/computer.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// use_computer: the agent drives other apps on this PC with the mouse and
|
|
2
|
+
// keyboard (the same hands voice mode uses, voice/act.js), and sees the result.
|
|
3
|
+
//
|
|
4
|
+
// Every action that changes something first makes sure the window it is meant
|
|
5
|
+
// for is really in front. If it is not, nothing is typed or clicked: a stray
|
|
6
|
+
// keystroke in the wrong window (the chat the user is reading, a terminal) is
|
|
7
|
+
// the worst thing this tool could do.
|
|
8
|
+
//
|
|
9
|
+
// Only the desktop app has hands, so it attaches a host (computer-desktop.js):
|
|
10
|
+
// host.front() -> { app, title, bounds, front } | null
|
|
11
|
+
// host.focus(want) -> the same for the window it brought forward | null
|
|
12
|
+
// host.capture(win) -> { image, w, h, text? } of the screen that window is on
|
|
13
|
+
// host.point(x, y) -> screen point for a spot on the last capture | null
|
|
14
|
+
// host.click(pt, opts), host.type(text), host.keys(combo), host.scroll(pt, clicks)
|
|
15
|
+
// host.isOwn(win) -> true for Codeply's own windows
|
|
16
|
+
let host = null;
|
|
17
|
+
|
|
18
|
+
function attach(h) { host = h && typeof h === 'object' ? h : null; }
|
|
19
|
+
function available() { return !!host; }
|
|
20
|
+
|
|
21
|
+
const ACTIONS = new Set(['look', 'focus', 'click', 'double_click', 'right_click', 'type', 'keys', 'scroll', 'wait']);
|
|
22
|
+
const CHANGES = new Set(['click', 'double_click', 'right_click', 'type', 'keys', 'scroll']);
|
|
23
|
+
const ALIASES = { open: 'focus', activate: 'focus', switch: 'focus', screenshot: 'look', see: 'look', press: 'keys', key: 'keys', hotkey: 'keys', write: 'type', doubleclick: 'double_click', rightclick: 'right_click', sleep: 'wait' };
|
|
24
|
+
|
|
25
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
26
|
+
const clip = (s, n) => { s = String(s || '').replace(/\s+/g, ' ').trim(); return s.length > n ? `${s.slice(0, n - 1)}…` : s; };
|
|
27
|
+
const matches = (win, want) => !!win && `${win.app} ${win.title}`.toLowerCase().includes(String(want).toLowerCase());
|
|
28
|
+
const named = (win) => (win ? clip(win.title || win.app || 'a window', 60) : 'nothing');
|
|
29
|
+
|
|
30
|
+
/** A fresh picture of the screen the window is on, as the tool's result. */
|
|
31
|
+
async function seeing(win, said, label = '') {
|
|
32
|
+
let shot = null;
|
|
33
|
+
try { shot = await host.capture(win); } catch (e) { return { ok: true, output: `${said} (No screenshot: ${e.message}.)` }; }
|
|
34
|
+
if (!shot || !shot.image) return { ok: true, output: `${said} (The screen could not be captured.)` };
|
|
35
|
+
const lines = [
|
|
36
|
+
said,
|
|
37
|
+
`Screenshot attached, ${shot.w} x ${shot.h} pixels, window in front: ${named(win)}. Spots for click and scroll are x and y in this picture's pixels, measured from its top left.`,
|
|
38
|
+
shot.text ? `Text on the screen (OCR, one row per line, may have small mistakes):\n${String(shot.text).slice(0, 4000)}` : '',
|
|
39
|
+
].filter(Boolean);
|
|
40
|
+
return { ok: true, output: lines.join('\n\n'), meta: { imageDataUrls: [shot.image], ...(label ? { label } : {}) } };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* <action> look | focus | click | double_click | right_click | type | keys | scroll | wait
|
|
45
|
+
* <window> words from the app name or window title it is for (required to act)
|
|
46
|
+
* <x> <y> a spot on the latest screenshot (click, scroll); <text> to type; <keys> "ctrl+n", "enter";
|
|
47
|
+
* <amount> scroll clicks (negative is up); <seconds> to wait.
|
|
48
|
+
*/
|
|
49
|
+
async function tool(args = {}, ctx = {}) {
|
|
50
|
+
if (!host) return { ok: false, output: 'use_computer only works in the Codeply desktop app on Windows or macOS.' };
|
|
51
|
+
let action = String(args.action || '').trim().toLowerCase().replace(/[\s-]+/g, '_');
|
|
52
|
+
action = ALIASES[action.replace(/_/g, '')] || ALIASES[action] || action;
|
|
53
|
+
if (!ACTIONS.has(action)) return { ok: false, output: `use_computer needs <action>: one of ${[...ACTIONS].join(', ')}.` };
|
|
54
|
+
const want = String(args.window || args.app || '').trim();
|
|
55
|
+
|
|
56
|
+
if (action === 'wait') {
|
|
57
|
+
const secs = Math.max(1, Math.min(30, Number(args.seconds) || 3));
|
|
58
|
+
if (ctx.signal && ctx.signal.aborted) return { ok: false, output: 'Stopped.' };
|
|
59
|
+
await sleep(secs * 1000);
|
|
60
|
+
let win = null; try { win = await host.front(); } catch {}
|
|
61
|
+
return seeing(win, `Waited ${secs} s.`, `Waited ${secs} s and looked`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (action === 'look' && !want) {
|
|
65
|
+
let win = null; try { win = await host.front(); } catch {}
|
|
66
|
+
return seeing(win, 'Looked at the screen.', 'Looked at the screen');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!want) return { ok: false, output: `use_computer ${action} needs <window>: a few words of the app name or window title it is for, so it never lands in the wrong window.` };
|
|
70
|
+
|
|
71
|
+
// Bring it forward unless it already is.
|
|
72
|
+
let win = null;
|
|
73
|
+
try { win = await host.front(); } catch {}
|
|
74
|
+
if (!matches(win, want) || (host.isOwn && host.isOwn(win))) {
|
|
75
|
+
try { win = await host.focus(want); } catch (e) { return { ok: false, output: `Could not switch to "${want}": ${e.message}` }; }
|
|
76
|
+
if (!win) return { ok: false, output: `No open window matches "${want}". Open the app first (on Windows: <codeply:run> start "" "shell:AppsFolder\\..." or the app's name; on a Mac: open -a "App"), then use_computer focus it.` };
|
|
77
|
+
await sleep(250);
|
|
78
|
+
// What is really in front now decides; the window it tried keeps its name for the messages below.
|
|
79
|
+
try { const now = await host.front(); win = now && matches(now, want) ? { ...now, front: true } : { ...win, front: false }; } catch {}
|
|
80
|
+
}
|
|
81
|
+
if (host.isOwn && host.isOwn(win)) return { ok: false, output: `"${want}" is Codeply's own window. use_computer is for other apps; nothing was done.` };
|
|
82
|
+
if (!win || !win.front || !matches(win, want)) {
|
|
83
|
+
let front = null; try { front = await host.front(); } catch {}
|
|
84
|
+
return { ok: false, output: `Could not bring "${want}" to the front (the window in front is ${named(front)}), so nothing was ${action === 'type' ? 'typed' : action === 'keys' ? 'pressed' : 'clicked'}. Try use_computer focus again, or a more exact <window>.` };
|
|
85
|
+
}
|
|
86
|
+
if (action === 'focus' || action === 'look') return seeing(win, `${named(win)} is in front.`, `Brought ${named(win)} to the front`);
|
|
87
|
+
|
|
88
|
+
// What it will do, checked before asking.
|
|
89
|
+
let pt = null;
|
|
90
|
+
let what = '';
|
|
91
|
+
if (action === 'type') {
|
|
92
|
+
const text = String(args.text == null ? '' : args.text);
|
|
93
|
+
if (!text) return { ok: false, output: 'use_computer type needs <text>.' };
|
|
94
|
+
if (text.length > 2000) return { ok: false, output: 'use_computer type takes up to 2000 characters at a time.' };
|
|
95
|
+
what = `Type "${clip(text, 120)}" into ${named(win)}`;
|
|
96
|
+
} else if (action === 'keys') {
|
|
97
|
+
const combo = String(args.keys || args.key || args.text || '').trim().toLowerCase();
|
|
98
|
+
if (!combo) return { ok: false, output: 'use_computer keys needs <keys>, like enter, ctrl+n or cmd+shift+t.' };
|
|
99
|
+
what = `Press ${combo} in ${named(win)}`;
|
|
100
|
+
} else {
|
|
101
|
+
const x = Number(args.x); const y = Number(args.y);
|
|
102
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) return { ok: false, output: `use_computer ${action} needs <x> and <y>: a spot on the latest screenshot (use_computer look shows one).` };
|
|
103
|
+
pt = host.point(x, y);
|
|
104
|
+
if (!pt) return { ok: false, output: 'There is no screenshot to measure that spot on yet, or it is outside it. Call use_computer look (or focus) first, then give x and y on that picture.' };
|
|
105
|
+
what = action === 'scroll' ? `Scroll ${Number(args.amount) < 0 ? 'up' : 'down'} in ${named(win)}` : `${action === 'double_click' ? 'Double-click' : action === 'right_click' ? 'Right-click' : 'Click'}${args.target ? ` "${clip(args.target, 60)}"` : ''} in ${named(win)}`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (CHANGES.has(action) && typeof ctx.approve === 'function') {
|
|
109
|
+
const v = await ctx.approve({ tool: 'use_computer', title: what, detail: `Codeply will use your mouse and keyboard in ${named(win)}.`, danger: false });
|
|
110
|
+
const verdict = v && typeof v === 'object' ? v.verdict : v;
|
|
111
|
+
if (verdict === 'reject') return { ok: false, output: `The user said no to: ${what}.`, meta: { rejected: true } };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Focus can drift while the user was asked: check once more right before acting.
|
|
115
|
+
try {
|
|
116
|
+
const now = await host.front();
|
|
117
|
+
if (!matches(now, want)) {
|
|
118
|
+
const again = await host.focus(want);
|
|
119
|
+
if (!again || !again.front) return { ok: false, output: `${named(now)} came to the front before Codeply could act, so nothing was done. Try again.` };
|
|
120
|
+
}
|
|
121
|
+
} catch {}
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
if (action === 'type') await host.type(String(args.text));
|
|
125
|
+
else if (action === 'keys') await host.keys(String(args.keys || args.key || args.text).trim().toLowerCase());
|
|
126
|
+
else if (action === 'scroll') await host.scroll(pt, Number(args.amount) || 3);
|
|
127
|
+
else await host.click(pt, { button: action === 'right_click' ? 'right' : 'left', count: action === 'double_click' ? 2 : 1 });
|
|
128
|
+
} catch (e) {
|
|
129
|
+
return { ok: false, output: `${what} failed: ${e.message}` };
|
|
130
|
+
}
|
|
131
|
+
await sleep(action === 'type' || action === 'keys' ? 500 : 700);
|
|
132
|
+
const r = await seeing(win, `Done: ${what}.`);
|
|
133
|
+
return { ...r, meta: { ...(r.meta || {}), label: clip(what, 100) } };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = { attach, available, tool, ACTIONS };
|
|
@@ -1,21 +1,21 @@
|
|
|
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 template = readFileSync(path.join(__dirname, 'artifact-template.html'), 'utf8');
|
|
7
|
-
const data = JSON.parse(readFileSync(path.join(__dirname, 'table-data.json'), 'utf8'));
|
|
8
|
-
|
|
9
|
-
const totalApps = data.rows.length;
|
|
10
|
-
const totalShots = data.rows.reduce((s, r) => s + r.s, 0);
|
|
11
|
-
const generatedAt = new Date(data.generatedAt).toISOString().slice(0, 16).replace('T', ' ') + ' UTC';
|
|
12
|
-
|
|
13
|
-
const out = template
|
|
14
|
-
.replace('__DATA_JSON__', JSON.stringify(data).replace(/</g, '\\u003c'))
|
|
15
|
-
.replace('__GENERATED_AT__', generatedAt)
|
|
16
|
-
.replace('__TOTAL_APPS__', String(totalApps))
|
|
17
|
-
.replace('__TOTAL_SHOTS__', String(totalShots));
|
|
18
|
-
|
|
19
|
-
const outPath = process.argv[2];
|
|
20
|
-
writeFileSync(outPath, out);
|
|
21
|
-
console.log('wrote', outPath, '(' + (out.length / 1024).toFixed(0) + ' KB)');
|
|
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 template = readFileSync(path.join(__dirname, 'artifact-template.html'), 'utf8');
|
|
7
|
+
const data = JSON.parse(readFileSync(path.join(__dirname, 'table-data.json'), 'utf8'));
|
|
8
|
+
|
|
9
|
+
const totalApps = data.rows.length;
|
|
10
|
+
const totalShots = data.rows.reduce((s, r) => s + r.s, 0);
|
|
11
|
+
const generatedAt = new Date(data.generatedAt).toISOString().slice(0, 16).replace('T', ' ') + ' UTC';
|
|
12
|
+
|
|
13
|
+
const out = template
|
|
14
|
+
.replace('__DATA_JSON__', JSON.stringify(data).replace(/</g, '\\u003c'))
|
|
15
|
+
.replace('__GENERATED_AT__', generatedAt)
|
|
16
|
+
.replace('__TOTAL_APPS__', String(totalApps))
|
|
17
|
+
.replace('__TOTAL_SHOTS__', String(totalShots));
|
|
18
|
+
|
|
19
|
+
const outPath = process.argv[2];
|
|
20
|
+
writeFileSync(outPath, out);
|
|
21
|
+
console.log('wrote', outPath, '(' + (out.length / 1024).toFixed(0) + ' KB)');
|
|
@@ -1,45 +1,45 @@
|
|
|
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 OUT_PATH = path.join(__dirname, 'index.json');
|
|
7
|
-
|
|
8
|
-
// [category, appId] pairs confirmed as wrong-category mismatches on manual review.
|
|
9
|
-
// Same app can be a correct match in one category and a mismatch in another
|
|
10
|
-
// (e.g. "BetterHelp" is a real health_fitness app but wrongly matched a
|
|
11
|
-
// real_estate search term), so removal is scoped per (category, id), not global.
|
|
12
|
-
const REMOVE = [
|
|
13
|
-
['productivity', 6470821480], // "Zapia" matched from "Zapier" search - unrelated app
|
|
14
|
-
['productivity', 1038369065], // "Flo Cycle & Period Tracker" matched from "Glo" - wrong app (correct in health_fitness)
|
|
15
|
-
['productivity', 1573566111], // "Complices" matched from "Complice" - unrelated French dating app
|
|
16
|
-
['shopping', 6748155184], // "Courtyard: TCG, Watches, Cards" - unrelated marketplace
|
|
17
|
-
['food_delivery', 1416720539], // "Tango Reserve by AgilQuest" matched from generic "Reserve" search - enterprise workspace booking, not food
|
|
18
|
-
['food_delivery', 6748155184], // "Courtyard" again - unrelated
|
|
19
|
-
['real_estate', 995252384], // "BetterHelp - Therapy" matched from "Better.com" - wrong app (correct in health_fitness)
|
|
20
|
-
['real_estate', 1264782561], // "Co-Star Personalized Astrology" matched from "CoStar" - astrology app, not commercial real estate data
|
|
21
|
-
['real_estate', 1457119021], // "Rainbow - Ethereum Wallet" - unrelated crypto wallet
|
|
22
|
-
['real_estate', 407108860], // "Cozi Family Organizer" - unrelated family calendar app
|
|
23
|
-
['real_estate', 880735556], // "Gods of Olympus" matched from "Zeus Living" - unrelated mobile game
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
const idx = JSON.parse(readFileSync(OUT_PATH, 'utf8'));
|
|
27
|
-
let removed = 0;
|
|
28
|
-
for (const [cat, id] of REMOVE) {
|
|
29
|
-
const before = idx.categories[cat].length;
|
|
30
|
-
idx.categories[cat] = idx.categories[cat].filter((a) => a.id !== id);
|
|
31
|
-
removed += before - idx.categories[cat].length;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
idx.cleanedAt = new Date().toISOString();
|
|
35
|
-
writeFileSync(OUT_PATH, JSON.stringify(idx, null, 2));
|
|
36
|
-
console.log(`Removed ${removed} confirmed-mismatch entries.`);
|
|
37
|
-
|
|
38
|
-
let totalApps = 0, totalShots = 0;
|
|
39
|
-
for (const [cat, apps] of Object.entries(idx.categories)) {
|
|
40
|
-
const shots = apps.reduce((s, a) => s + a.screenshots.length, 0);
|
|
41
|
-
totalApps += apps.length;
|
|
42
|
-
totalShots += shots;
|
|
43
|
-
console.log(`${cat}: ${apps.length} apps, ${shots} screenshots`);
|
|
44
|
-
}
|
|
45
|
-
console.log(`\nFinal: ${totalApps} apps, ${totalShots} screenshots`);
|
|
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 OUT_PATH = path.join(__dirname, 'index.json');
|
|
7
|
+
|
|
8
|
+
// [category, appId] pairs confirmed as wrong-category mismatches on manual review.
|
|
9
|
+
// Same app can be a correct match in one category and a mismatch in another
|
|
10
|
+
// (e.g. "BetterHelp" is a real health_fitness app but wrongly matched a
|
|
11
|
+
// real_estate search term), so removal is scoped per (category, id), not global.
|
|
12
|
+
const REMOVE = [
|
|
13
|
+
['productivity', 6470821480], // "Zapia" matched from "Zapier" search - unrelated app
|
|
14
|
+
['productivity', 1038369065], // "Flo Cycle & Period Tracker" matched from "Glo" - wrong app (correct in health_fitness)
|
|
15
|
+
['productivity', 1573566111], // "Complices" matched from "Complice" - unrelated French dating app
|
|
16
|
+
['shopping', 6748155184], // "Courtyard: TCG, Watches, Cards" - unrelated marketplace
|
|
17
|
+
['food_delivery', 1416720539], // "Tango Reserve by AgilQuest" matched from generic "Reserve" search - enterprise workspace booking, not food
|
|
18
|
+
['food_delivery', 6748155184], // "Courtyard" again - unrelated
|
|
19
|
+
['real_estate', 995252384], // "BetterHelp - Therapy" matched from "Better.com" - wrong app (correct in health_fitness)
|
|
20
|
+
['real_estate', 1264782561], // "Co-Star Personalized Astrology" matched from "CoStar" - astrology app, not commercial real estate data
|
|
21
|
+
['real_estate', 1457119021], // "Rainbow - Ethereum Wallet" - unrelated crypto wallet
|
|
22
|
+
['real_estate', 407108860], // "Cozi Family Organizer" - unrelated family calendar app
|
|
23
|
+
['real_estate', 880735556], // "Gods of Olympus" matched from "Zeus Living" - unrelated mobile game
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const idx = JSON.parse(readFileSync(OUT_PATH, 'utf8'));
|
|
27
|
+
let removed = 0;
|
|
28
|
+
for (const [cat, id] of REMOVE) {
|
|
29
|
+
const before = idx.categories[cat].length;
|
|
30
|
+
idx.categories[cat] = idx.categories[cat].filter((a) => a.id !== id);
|
|
31
|
+
removed += before - idx.categories[cat].length;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
idx.cleanedAt = new Date().toISOString();
|
|
35
|
+
writeFileSync(OUT_PATH, JSON.stringify(idx, null, 2));
|
|
36
|
+
console.log(`Removed ${removed} confirmed-mismatch entries.`);
|
|
37
|
+
|
|
38
|
+
let totalApps = 0, totalShots = 0;
|
|
39
|
+
for (const [cat, apps] of Object.entries(idx.categories)) {
|
|
40
|
+
const shots = apps.reduce((s, a) => s + a.screenshots.length, 0);
|
|
41
|
+
totalApps += apps.length;
|
|
42
|
+
totalShots += shots;
|
|
43
|
+
console.log(`${cat}: ${apps.length} apps, ${shots} screenshots`);
|
|
44
|
+
}
|
|
45
|
+
console.log(`\nFinal: ${totalApps} apps, ${totalShots} screenshots`);
|