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/handoff.mjs
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local <-> cloud handoff: a run on the PC carries on in Craft Cloud when the
|
|
3
|
+
* PC goes away (power cut, crash, lost connection), and comes back to the PC
|
|
4
|
+
* when it returns. Only one side edits at a time.
|
|
5
|
+
*
|
|
6
|
+
* lease A row in Supabase (run_leases, see supabase/handoff.sql). The PC
|
|
7
|
+
* renews it every 15 s with the server's clock. A watchdog on the
|
|
8
|
+
* server starts a cloud run once it is 60 s stale. The PC stops
|
|
9
|
+
* its own run after 40 s without a renewal, so the two never
|
|
10
|
+
* overlap (self-fencing).
|
|
11
|
+
* WIP The working tree plus the run's state (.craft-handoff.json),
|
|
12
|
+
* committed together through Craft's own git folder (never the
|
|
13
|
+
* project's .git) and pushed to craft/wip-<chat>. Pushed a moment
|
|
14
|
+
* after every step that can change files, and on a timer.
|
|
15
|
+
* resume The new side gets the chat so far, the steps already done and
|
|
16
|
+
* the todo list, and continues from the first unfinished item.
|
|
17
|
+
* hand-back The PC asks for the chat back (handback/<chat>/want.json on
|
|
18
|
+
* craft-sessions). The runner stops between steps, pushes, and
|
|
19
|
+
* answers with handback/<chat>/done.json. The PC applies the
|
|
20
|
+
* cloud's changes with a 3-way merge and carries on.
|
|
21
|
+
*/
|
|
22
|
+
import fs from 'fs';
|
|
23
|
+
import path from 'path';
|
|
24
|
+
import os from 'os';
|
|
25
|
+
import { git } from './github-agent.mjs';
|
|
26
|
+
import { stageWorkingTree, initMirrorGit, WORKFLOW_PATH, BOT, authFor } from './cloud.mjs';
|
|
27
|
+
|
|
28
|
+
export const STATE_FILE = '.craft-handoff.json';
|
|
29
|
+
export const wipBranch = (sid) => `craft/wip-${String(sid).replace(/[^A-Za-z0-9_-]/g, '')}`;
|
|
30
|
+
export const HANDBACK = {
|
|
31
|
+
want: (sid) => `handback/${sid}/want.json`,
|
|
32
|
+
done: (sid) => `handback/${sid}/done.json`,
|
|
33
|
+
};
|
|
34
|
+
export const BEAT_MS = 15000; // the PC renews its lease this often
|
|
35
|
+
export const FENCE_MS = 40000; // and stops its run after this long without a renewal
|
|
36
|
+
export const STALE_MS = 60000; // the watchdog takes over after this long (server clock)
|
|
37
|
+
export const WIP_DEBOUNCE_MS = 2000;
|
|
38
|
+
export const WIP_EVERY_MS = 20000;
|
|
39
|
+
|
|
40
|
+
const MAX_STEPS = 80;
|
|
41
|
+
const MAX_NOTES = 3;
|
|
42
|
+
// Tools whose step can change files: a WIP push follows each of them.
|
|
43
|
+
export const MUTATING = new Set(['write_file', 'edit_file', 'apply_patch', 'run', 'fetch_image', 'supabase_sql', 'github_create_repo']);
|
|
44
|
+
|
|
45
|
+
const VERBS = {
|
|
46
|
+
write_file: 'wrote', edit_file: 'edited', apply_patch: 'patched', run: 'ran', fetch_image: 'downloaded',
|
|
47
|
+
read_file: 'read', list_dir: 'listed', search: 'searched', web_fetch: 'fetched', web_search: 'searched the web for',
|
|
48
|
+
browser_check: 'checked in the browser', todo: 'updated the todo list',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** One line per finished step, for the side that carries on. */
|
|
52
|
+
export function stepLine(ev) {
|
|
53
|
+
if (!ev || !ev.name) return null;
|
|
54
|
+
const label = String(ev.summary || (ev.args && (ev.args.path || ev.args.command || ev.args.pattern || ev.args.url || ev.args.query)) || '').slice(0, 160);
|
|
55
|
+
const exit = ev.meta && typeof ev.meta.exitCode === 'number' ? ` (exit ${ev.meta.exitCode})` : '';
|
|
56
|
+
const verb = VERBS[ev.name] || ev.name;
|
|
57
|
+
if (ev.name === 'todo') return null; // the list itself travels as todos
|
|
58
|
+
return `${verb} ${label}${exit}${ev.ok === false ? ' - FAILED' : ''}`.trim();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** The model-facing chat before this turn, without pasted images (they stay on the PC). */
|
|
62
|
+
export function cleanHistory(history) {
|
|
63
|
+
return (Array.isArray(history) ? history : []).slice(-40).map((t) => ({ role: t.role, content: typeof t.content === 'string' ? t.content : String(t.content || '') }));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** A run's state at the start of a turn. */
|
|
67
|
+
export function newRunState({ sessionId, mode = 'Build', userMessage, history, roleId = null, startedAt = Date.now() }) {
|
|
68
|
+
return { v: 1, sessionId, mode, userMessage: String(userMessage || ''), history: cleanHistory(history), roleId, startedAt, steps: [], todos: [], notes: [], side: 'pc', legs: [] };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Fold one agent event into the state. Returns true when the step may have changed files. */
|
|
72
|
+
export function recordEvent(state, ev) {
|
|
73
|
+
if (!state || !ev) return false;
|
|
74
|
+
if (ev.type === 'tool_end') {
|
|
75
|
+
if (ev.meta && Array.isArray(ev.meta.todos)) state.todos = ev.meta.todos.map((t) => ({ text: String(t.text || ''), status: t.status || 'pending' }));
|
|
76
|
+
const line = stepLine(ev);
|
|
77
|
+
if (line) { state.steps.push(line); if (state.steps.length > MAX_STEPS) state.steps.splice(0, state.steps.length - MAX_STEPS); }
|
|
78
|
+
return MUTATING.has(ev.name);
|
|
79
|
+
}
|
|
80
|
+
if (ev.type === 'text' && ev.interim && ev.text) {
|
|
81
|
+
state.notes.push(String(ev.text).slice(0, 600));
|
|
82
|
+
if (state.notes.length > MAX_NOTES) state.notes.shift();
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const TODO_MARK = { done: '[x]', in_progress: '[~]', dropped: '[-]', pending: '[ ]' };
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The message the side that carries on is given: the original request, what is
|
|
91
|
+
* already done, and the todo list. `to`: 'cloud' (the PC went away), 'pc'
|
|
92
|
+
* (back from the cloud) or 'self' (the PC carries on after its own pause or crash).
|
|
93
|
+
*/
|
|
94
|
+
export function continuationPrompt(state, to = 'cloud') {
|
|
95
|
+
const why = to === 'cloud'
|
|
96
|
+
? "This task was already running on the user's PC, which went offline (power cut, crash or lost connection). You are carrying on from where it stopped."
|
|
97
|
+
: to === 'pc'
|
|
98
|
+
? 'This task carried on in Craft Cloud while the PC was offline. The PC is back and you are carrying on from where the cloud stopped.'
|
|
99
|
+
: 'This task was cut off on this PC (lost connection, or Craft closed). You are carrying on from the last save.';
|
|
100
|
+
const lines = [state.userMessage, '', '---', `[Handoff] ${why}`, 'The files on disk already include every change from the steps below.'];
|
|
101
|
+
if (state.steps.length) lines.push('', 'Steps already done (do not redo them):', ...state.steps.map((s, i) => `${i + 1}. ${s}`));
|
|
102
|
+
else lines.push('', 'No steps had finished yet.');
|
|
103
|
+
if (state.todos.length) lines.push('', 'Todo list (keep it up to date with the todo tool):', ...state.todos.map((t) => `${TODO_MARK[t.status] || '[ ]'} ${t.text}`));
|
|
104
|
+
if (state.notes.length) lines.push('', 'Your last notes before the switch:', ...state.notes.map((n) => `- ${n}`));
|
|
105
|
+
lines.push('', 'Continue from the first unfinished item. The last step may have been cut off part way, so check its result before relying on it.');
|
|
106
|
+
return lines.join('\n');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ─── WIP commits ─────────────────────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Commit the working tree and the state together, on top of `parent` (the
|
|
113
|
+
* last WIP commit, or none), and push it to craft/wip-<chat>. `force` only on
|
|
114
|
+
* the first push of a run, when this side holds the lease. Returns the sha,
|
|
115
|
+
* or the parent when nothing changed.
|
|
116
|
+
*/
|
|
117
|
+
export async function pushWip({ cwd, home, token, repo, sessionId, state, parent = null, force = false, serverUrl = 'https://github.com', remoteUrl }) {
|
|
118
|
+
const s = await stageWorkingTree(cwd, home);
|
|
119
|
+
const blob = await git(cwd, ['--git-dir', s.gitDir, 'hash-object', '-w', '--stdin'], { input: JSON.stringify({ ...state, savedAt: Date.now() }) });
|
|
120
|
+
await s.G(['update-index', '--add', '--cacheinfo', `100644,${blob},${STATE_FILE}`]);
|
|
121
|
+
const tree = await s.G(['write-tree']);
|
|
122
|
+
if (parent && !force) {
|
|
123
|
+
const prevTree = await s.G(['rev-parse', `${parent}^{tree}`]).catch(() => null);
|
|
124
|
+
// Only the state's savedAt differs: compare without it.
|
|
125
|
+
if (prevTree && (await sameButState(s, parent, tree))) return { sha: parent, pushed: false };
|
|
126
|
+
}
|
|
127
|
+
const sha = await git(cwd, ['--git-dir', s.gitDir, ...BOT, 'commit-tree', tree, ...(parent ? ['-p', parent] : []), '-m', `Craft WIP ${sessionId} (${state.steps.length} steps)`]);
|
|
128
|
+
await s.G(['update-ref', `refs/craft/wip/${sessionId}`, sha]);
|
|
129
|
+
const url = remoteUrl || `${serverUrl.replace(/\/$/, '')}/${repo}.git`;
|
|
130
|
+
await git(cwd, ['--git-dir', s.gitDir, 'push', '-q', ...(force ? ['--force'] : []), url, `${sha}:refs/heads/${wipBranch(sessionId)}`], { auth: token ? authFor(token, serverUrl) : undefined });
|
|
131
|
+
return { sha, pushed: true };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** True when `tree` matches `parent`'s tree apart from the state file's savedAt. */
|
|
135
|
+
async function sameButState(s, parent, tree) {
|
|
136
|
+
const diff = await s.G(['diff', '--name-only', parent, tree]).catch(() => 'x');
|
|
137
|
+
const names = diff.split('\n').filter(Boolean);
|
|
138
|
+
if (!names.length) return true;
|
|
139
|
+
if (names.length !== 1 || names[0] !== STATE_FILE) return false;
|
|
140
|
+
try {
|
|
141
|
+
const a = JSON.parse(await s.G(['show', `${parent}:${STATE_FILE}`]));
|
|
142
|
+
const b = JSON.parse(await s.G(['show', `${tree}:${STATE_FILE}`]));
|
|
143
|
+
delete a.savedAt; delete b.savedAt;
|
|
144
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
145
|
+
} catch { return false; }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Bring the cloud's WIP back: the change from `fromSha` (where the cloud
|
|
150
|
+
* started) to the branch head, applied onto the working tree with a 3-way
|
|
151
|
+
* merge, so edits made here after the last push survive. Returns the files,
|
|
152
|
+
* any conflicts, the new head and the state the cloud left.
|
|
153
|
+
*/
|
|
154
|
+
export async function applyWip({ cwd, home, token, repo, sessionId, fromSha, serverUrl = 'https://github.com', remoteUrl }) {
|
|
155
|
+
const m = await initMirrorGit(cwd, home);
|
|
156
|
+
const url = remoteUrl || `${serverUrl.replace(/\/$/, '')}/${repo}.git`;
|
|
157
|
+
const ref = `refs/craft/wip-remote/${sessionId}`;
|
|
158
|
+
await git(cwd, ['--git-dir', m.gitDir, 'fetch', '-q', '--no-tags', url, `+refs/heads/${wipBranch(sessionId)}:${ref}`], { auth: token ? authFor(token, serverUrl) : undefined });
|
|
159
|
+
const toSha = await m.G(['rev-parse', ref]);
|
|
160
|
+
let state = null;
|
|
161
|
+
try { state = JSON.parse(await m.G(['show', `${toSha}:${STATE_FILE}`])); } catch {}
|
|
162
|
+
const spec = ['--', '.', `:(exclude)${WORKFLOW_PATH}`, ':(exclude).codeply', `:(exclude)${STATE_FILE}`];
|
|
163
|
+
if (!fromSha || fromSha === toSha) return { files: [], conflicts: [], toSha, state, applied: false };
|
|
164
|
+
const patch = await git(cwd, ['--git-dir', m.gitDir, 'diff', '--binary', '--full-index', fromSha, toSha, ...spec]);
|
|
165
|
+
const files = (await git(cwd, ['--git-dir', m.gitDir, 'diff', '--name-only', fromSha, toSha, ...spec])).split('\n').filter(Boolean);
|
|
166
|
+
if (!patch.trim()) return { files: [], conflicts: [], toSha, state, applied: false };
|
|
167
|
+
await stageWorkingTree(cwd, home);
|
|
168
|
+
let conflicts = [];
|
|
169
|
+
try {
|
|
170
|
+
await m.G(['apply', '--3way', '--whitespace=nowarn', '-'], { input: `${patch}\n` });
|
|
171
|
+
} catch (e) {
|
|
172
|
+
const unmerged = await m.G(['diff', '--name-only', '--diff-filter=U']).catch(() => '');
|
|
173
|
+
conflicts = unmerged.split('\n').filter(Boolean);
|
|
174
|
+
if (!conflicts.length) throw new Error(`Could not apply the cloud's changes: ${e.message}`);
|
|
175
|
+
}
|
|
176
|
+
await m.G(['update-ref', `refs/craft/wip/${sessionId}`, toSha]);
|
|
177
|
+
return { files, conflicts, toSha, state, applied: true };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** The state inside a checked-out WIP tree (the runner), removed from disk so the agent never sees it. */
|
|
181
|
+
export function takeStateFile(cwd) {
|
|
182
|
+
const file = path.join(cwd, STATE_FILE);
|
|
183
|
+
try {
|
|
184
|
+
const state = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
185
|
+
fs.unlinkSync(file);
|
|
186
|
+
return state;
|
|
187
|
+
} catch { return null; }
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ─── The PC's side of the lease ──────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Keeps the lease for one run. `store` talks to run_leases (Supabase RPCs in
|
|
194
|
+
* the app, an in-memory table in tests):
|
|
195
|
+
* begin(row) -> { epoch } | { error } beat({ sessionId, epoch, wipSha }) -> { ok, row } end({ sessionId, epoch, state })
|
|
196
|
+
* onFence(reason) is called once when this side must stop editing: 'offline'
|
|
197
|
+
* (no renewal for FENCE_MS) or 'taken' (the cloud holds the lease now).
|
|
198
|
+
* With keepGoingOffline (a local model that works without internet) an
|
|
199
|
+
* offline spell only calls onOffline(true/false), and the run keeps going.
|
|
200
|
+
*/
|
|
201
|
+
export function makeLease({ store, sessionId, now = Date.now, beatMs = BEAT_MS, fenceMs = FENCE_MS, onFence = () => {}, onOffline = () => {}, keepGoingOffline = false, setTimer = setInterval, clearTimer = clearInterval }) {
|
|
202
|
+
let epoch = null; let lastOk = now(); let timer = null; let fenced = null; let offline = false; let wipSha = null; let beating = false;
|
|
203
|
+
const fence = (why) => { if (fenced) return; fenced = why; stopTimer(); onFence(why); };
|
|
204
|
+
const stopTimer = () => { if (timer) { clearTimer(timer); timer = null; } };
|
|
205
|
+
const beat = async () => {
|
|
206
|
+
if (fenced || epoch == null || beating) return;
|
|
207
|
+
beating = true;
|
|
208
|
+
try {
|
|
209
|
+
const r = await store.beat({ sessionId, epoch, wipSha });
|
|
210
|
+
if (r && r.ok) {
|
|
211
|
+
lastOk = now();
|
|
212
|
+
if (offline) { offline = false; onOffline(false); }
|
|
213
|
+
} else if (r && r.row) {
|
|
214
|
+
fence('taken');
|
|
215
|
+
}
|
|
216
|
+
} catch {
|
|
217
|
+
if (!offline) { offline = true; onOffline(true); }
|
|
218
|
+
if (!keepGoingOffline && now() - lastOk > fenceMs) fence('offline');
|
|
219
|
+
} finally { beating = false; }
|
|
220
|
+
if (!fenced && !keepGoingOffline && now() - lastOk > fenceMs) fence('offline');
|
|
221
|
+
};
|
|
222
|
+
return {
|
|
223
|
+
async start(row) {
|
|
224
|
+
const r = await store.begin({ ...row, sessionId });
|
|
225
|
+
if (!r || r.error) throw new Error((r && r.error) || 'Could not start the cloud backup.');
|
|
226
|
+
epoch = r.epoch; lastOk = now(); wipSha = row.wipSha || null;
|
|
227
|
+
timer = setTimer(beat, beatMs);
|
|
228
|
+
return epoch;
|
|
229
|
+
},
|
|
230
|
+
beat,
|
|
231
|
+
saved(sha) { wipSha = sha; },
|
|
232
|
+
get epoch() { return epoch; },
|
|
233
|
+
get fenced() { return fenced; },
|
|
234
|
+
get offline() { return offline; },
|
|
235
|
+
get lastOk() { return lastOk; },
|
|
236
|
+
async end(state = 'done') {
|
|
237
|
+
stopTimer();
|
|
238
|
+
if (fenced || epoch == null) return;
|
|
239
|
+
try { await store.end({ sessionId, epoch, state }); } catch {}
|
|
240
|
+
},
|
|
241
|
+
stop: stopTimer,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export const hostname = () => os.hostname();
|
package/lib/history.js
CHANGED
|
@@ -1,75 +1,78 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Model-facing history built from a stored session (shared by the desktop app
|
|
3
|
-
* and `codeply serve`): alternating prose turns. Each assistant turn carries a
|
|
4
|
-
* short, factual list of the actions it really performed, so on a follow-up the
|
|
5
|
-
* model knows what it changed last time instead of reconstructing it from its own
|
|
6
|
-
* (possibly wrong) summary. Also carries forward a bounded number of the most
|
|
7
|
-
* recent pasted images.
|
|
8
|
-
*/
|
|
9
|
-
const MAX_HISTORY_IMAGES = 4;
|
|
10
|
-
|
|
11
|
-
const ACTION_VERBS = {
|
|
12
|
-
write_file: 'wrote', edit_file: 'edited', apply_patch: 'patched', web_fetch: 'fetched', web_search: 'searched the web for', image_search: 'searched images for', reach_me: 'reached the phone:', watch_email: 'set an email alert for',
|
|
13
|
-
run: 'ran', fetch_image: 'downloaded', browser_check: 'checked in browser', vercel_deploy: 'deployed', supabase_sql: 'ran SQL',
|
|
14
|
-
supabase_api: 'called Supabase API', vercel_api: 'called Vercel API', github_create_repo: 'pushed to GitHub',
|
|
15
|
-
supabase_create_project: 'created Supabase project', gmail_send: 'emailed', slack_post_message: 'posted to Slack',
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
} else if (m.kind === '
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
t.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Model-facing history built from a stored session (shared by the desktop app
|
|
3
|
+
* and `codeply serve`): alternating prose turns. Each assistant turn carries a
|
|
4
|
+
* short, factual list of the actions it really performed, so on a follow-up the
|
|
5
|
+
* model knows what it changed last time instead of reconstructing it from its own
|
|
6
|
+
* (possibly wrong) summary. Also carries forward a bounded number of the most
|
|
7
|
+
* recent pasted images.
|
|
8
|
+
*/
|
|
9
|
+
const MAX_HISTORY_IMAGES = 4;
|
|
10
|
+
|
|
11
|
+
const ACTION_VERBS = {
|
|
12
|
+
write_file: 'wrote', edit_file: 'edited', apply_patch: 'patched', web_fetch: 'fetched', web_search: 'searched the web for', image_search: 'searched images for', reach_me: 'reached the phone:', watch_email: 'set an email alert for',
|
|
13
|
+
run: 'ran', fetch_image: 'downloaded', browser_check: 'checked in browser', vercel_deploy: 'deployed', supabase_sql: 'ran SQL',
|
|
14
|
+
supabase_api: 'called Supabase API', vercel_api: 'called Vercel API', github_create_repo: 'pushed to GitHub',
|
|
15
|
+
supabase_create_project: 'created Supabase project', gmail_send: 'emailed', slack_post_message: 'posted to Slack',
|
|
16
|
+
use_computer: 'on the computer:', look_at_screen: 'looked at the screen', life_context: 'looked up', calendar_add: 'added to the calendar',
|
|
17
|
+
calendar_update: 'changed the calendar:', gmail_search: 'searched email for', gmail_read: 'read the email', remember: 'remembered', hand_off: 'handed off',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** One line per tool call the agent really made, for grounding later turns. */
|
|
21
|
+
function describeAction(m) {
|
|
22
|
+
const verb = ACTION_VERBS[m.name];
|
|
23
|
+
if (!verb) return null;
|
|
24
|
+
const exit = typeof m.exitCode === 'number' ? ` (exit ${m.exitCode})` : '';
|
|
25
|
+
const what = m.name === 'run' && m.command ? String(m.command).slice(0, 600) : (m.label || '');
|
|
26
|
+
return `${verb} ${what}${exit}${m.ok === false ? ' - FAILED' : ''}`.trim();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function buildHistory(session) {
|
|
30
|
+
const turns = [];
|
|
31
|
+
let pendingActions = [];
|
|
32
|
+
const flushActions = () => {
|
|
33
|
+
if (!pendingActions.length) return;
|
|
34
|
+
const last = turns[turns.length - 1];
|
|
35
|
+
const note = `[Actions actually performed: ${pendingActions.slice(0, 12).join('; ')}${pendingActions.length > 12 ? `; +${pendingActions.length - 12} more` : ''}]`;
|
|
36
|
+
if (last && last.role === 'assistant') last.content += `\n\n${note}`;
|
|
37
|
+
else turns.push({ role: 'assistant', content: note });
|
|
38
|
+
pendingActions = [];
|
|
39
|
+
};
|
|
40
|
+
for (const m of session.messages) {
|
|
41
|
+
if (m.kind === 'user') {
|
|
42
|
+
flushActions();
|
|
43
|
+
turns.push({ role: 'user', content: m.expanded || m.text, images: m.images || null });
|
|
44
|
+
} else if (m.kind === 'assistant' && m.text) {
|
|
45
|
+
const last = turns[turns.length - 1];
|
|
46
|
+
if (last && last.role === 'assistant') last.content += '\n\n' + m.text;
|
|
47
|
+
else turns.push({ role: 'assistant', content: m.text });
|
|
48
|
+
} else if (m.kind === 'tool') {
|
|
49
|
+
const line = describeAction(m);
|
|
50
|
+
if (line) pendingActions.push(line);
|
|
51
|
+
} else if (m.kind === 'question') {
|
|
52
|
+
pendingActions.push(m.answer
|
|
53
|
+
? `asked the user "${String(m.question).slice(0, 160)}" and they answered "${String(m.answer).slice(0, 200)}"`
|
|
54
|
+
: `asked the user "${String(m.question).slice(0, 160)}" but they left it to you`);
|
|
55
|
+
} else if (m.kind === 'checkpoint' && m.undone) {
|
|
56
|
+
// Otherwise the model believes its earlier edits are still on disk.
|
|
57
|
+
pendingActions.push(`LATER UNDONE BY THE USER: every file change from this message was reverted (${m.files.slice(0, 6).map((f) => f.file).join(', ')}${m.total > 6 ? ', ...' : ''}); those files are back to how they were before it`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
flushActions();
|
|
61
|
+
const kept = turns.slice(-20);
|
|
62
|
+
// A history must start with a user turn for most providers.
|
|
63
|
+
while (kept.length && kept[0].role !== 'user') kept.shift();
|
|
64
|
+
|
|
65
|
+
let imageBudget = MAX_HISTORY_IMAGES;
|
|
66
|
+
for (let i = kept.length - 1; i >= 0; i--) {
|
|
67
|
+
const t = kept[i];
|
|
68
|
+
if (t.role !== 'user' || !t.images || !t.images.length || imageBudget <= 0) { delete t.images; continue; }
|
|
69
|
+
const take = t.images.slice(0, imageBudget);
|
|
70
|
+
imageBudget -= take.length;
|
|
71
|
+
t.content = [{ type: 'text', text: t.content }, ...take.map((dataUrl) => ({ type: 'image_url', image_url: { url: dataUrl } }))];
|
|
72
|
+
delete t.images;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return kept;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = { buildHistory, describeAction };
|