bonecode 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +64 -50
- package/bin/bonecode +47 -42
- package/bone/output/agent/.dockerignore +7 -7
- package/bone/output/agent/.env.example +36 -36
- package/bone/output/agent/.github/workflows/ci.yaml +58 -58
- package/bone/output/agent/AgentDomain.bone.map +349 -349
- package/bone/output/agent/AgentDomain.postman_collection.json +957 -957
- package/bone/output/agent/Dockerfile +22 -22
- package/bone/output/agent/README.md +47 -47
- package/bone/output/agent/admin/index.html +739 -739
- package/bone/output/agent/docker-compose.yaml +22 -22
- package/bone/output/agent/k8s/deployment.yaml +75 -75
- package/bone/output/agent/migrations/agent.sql +36 -36
- package/bone/output/agent/migrations/agent_instance.sql +36 -36
- package/bone/output/agent/migrations/audit_log.sql +18 -18
- package/bone/output/agent/migrations/build_step.sql +34 -34
- package/bone/output/agent/migrations/event_outbox.sql +31 -31
- package/bone/output/agent/migrations/plan.sql +30 -30
- package/bone/output/agent/migrations/task.sql +30 -30
- package/bone/output/agent/migrations/tool_call.sql +33 -33
- package/bone/output/agent/openapi.yaml +1116 -1116
- package/bone/output/agent/package.json +35 -35
- package/bone/output/agent/schema.graphql +233 -233
- package/bone/output/agent/sdk/client.ts +231 -231
- package/bone/output/agent/src/algorithms.ts +2 -2
- package/bone/output/agent/src/audit.ts +44 -44
- package/bone/output/agent/src/auth.ts +57 -57
- package/bone/output/agent/src/cron.ts +12 -12
- package/bone/output/agent/src/db.ts +31 -31
- package/bone/output/agent/src/debug.ts +66 -66
- package/bone/output/agent/src/events.ts +243 -243
- package/bone/output/agent/src/extensions.ts +54 -54
- package/bone/output/agent/src/failure_rules.ts +322 -322
- package/bone/output/agent/src/flows.ts +168 -168
- package/bone/output/agent/src/health.ts +43 -43
- package/bone/output/agent/src/index.ts +99 -99
- package/bone/output/agent/src/logger.ts +69 -66
- package/bone/output/agent/src/metrics.ts +75 -75
- package/bone/output/agent/src/migrate.ts +351 -351
- package/bone/output/agent/src/migration_diff.ts +108 -108
- package/bone/output/agent/src/notify.ts +125 -125
- package/bone/output/agent/src/routes/plan.ts +91 -91
- package/bone/output/agent/src/routes/task.ts +105 -105
- package/bone/output/agent/src/routes/tool_call.ts +166 -166
- package/bone/output/agent/src/schemas.ts +384 -384
- package/bone/output/agent/src/state_machines/agent_instance.ts +24 -24
- package/bone/output/agent/src/state_machines/build_step.ts +22 -22
- package/bone/output/agent/src/state_machines/plan.ts +22 -22
- package/bone/output/agent/src/state_machines/task.ts +22 -22
- package/bone/output/agent/src/state_machines/tool_call.ts +22 -22
- package/bone/output/agent/src/tests.ts +361 -361
- package/bone/output/agent/src/websocket.ts +200 -200
- package/bone/output/agent/tsconfig.json +24 -24
- package/bone/output/rag/.dockerignore +7 -7
- package/bone/output/rag/.env.example +36 -36
- package/bone/output/rag/.github/workflows/ci.yaml +58 -58
- package/bone/output/rag/Dockerfile +22 -22
- package/bone/output/rag/RAGDomain.bone.map +286 -286
- package/bone/output/rag/RAGDomain.postman_collection.json +922 -922
- package/bone/output/rag/README.md +47 -47
- package/bone/output/rag/admin/index.html +817 -817
- package/bone/output/rag/docker-compose.yaml +22 -22
- package/bone/output/rag/k8s/deployment.yaml +75 -75
- package/bone/output/rag/migrations/audit_log.sql +18 -18
- package/bone/output/rag/migrations/code_chunk.sql +34 -34
- package/bone/output/rag/migrations/code_file.sql +33 -33
- package/bone/output/rag/migrations/event_outbox.sql +31 -31
- package/bone/output/rag/migrations/indexing_job.sql +33 -33
- package/bone/output/rag/migrations/knowledge_base.sql +35 -35
- package/bone/output/rag/migrations/memory_entry.sql +34 -34
- package/bone/output/rag/openapi.yaml +1097 -1097
- package/bone/output/rag/package.json +35 -35
- package/bone/output/rag/schema.graphql +245 -245
- package/bone/output/rag/sdk/client.ts +234 -234
- package/bone/output/rag/src/algorithms.ts +2 -2
- package/bone/output/rag/src/audit.ts +37 -37
- package/bone/output/rag/src/auth.ts +57 -57
- package/bone/output/rag/src/cron.ts +12 -12
- package/bone/output/rag/src/db.ts +31 -31
- package/bone/output/rag/src/debug.ts +66 -66
- package/bone/output/rag/src/events.ts +243 -243
- package/bone/output/rag/src/extensions.ts +350 -350
- package/bone/output/rag/src/failure_rules.ts +314 -314
- package/bone/output/rag/src/flows.ts +239 -239
- package/bone/output/rag/src/health.ts +43 -43
- package/bone/output/rag/src/index.ts +94 -94
- package/bone/output/rag/src/logger.ts +69 -66
- package/bone/output/rag/src/metrics.ts +75 -75
- package/bone/output/rag/src/migrate.ts +363 -363
- package/bone/output/rag/src/migration_diff.ts +108 -108
- package/bone/output/rag/src/notify.ts +99 -99
- package/bone/output/rag/src/routes/code_chunk.ts +75 -75
- package/bone/output/rag/src/routes/code_file.ts +101 -101
- package/bone/output/rag/src/routes/indexing_job.ts +87 -87
- package/bone/output/rag/src/routes/knowledge_base.ts +230 -230
- package/bone/output/rag/src/routes/memory_entry.ts +87 -87
- package/bone/output/rag/src/schemas.ts +394 -394
- package/bone/output/rag/src/state_machines/code_file.ts +23 -23
- package/bone/output/rag/src/state_machines/indexing_job.ts +22 -22
- package/bone/output/rag/src/state_machines/knowledge_base.ts +23 -23
- package/bone/output/rag/src/state_machines/memory_entry.ts +20 -20
- package/bone/output/rag/src/tests.ts +339 -339
- package/bone/output/rag/tsconfig.json +24 -24
- package/bone/output/session/.dockerignore +7 -7
- package/bone/output/session/.env.example +36 -36
- package/bone/output/session/.github/workflows/ci.yaml +58 -58
- package/bone/output/session/Dockerfile +22 -22
- package/bone/output/session/README.md +47 -47
- package/bone/output/session/SessionDomain.bone.map +349 -349
- package/bone/output/session/SessionDomain.postman_collection.json +957 -957
- package/bone/output/session/admin/index.html +666 -666
- package/bone/output/session/docker-compose.yaml +22 -22
- package/bone/output/session/k8s/deployment.yaml +75 -75
- package/bone/output/session/migrations/audit_log.sql +18 -18
- package/bone/output/session/migrations/event_outbox.sql +31 -31
- package/bone/output/session/migrations/message.sql +31 -31
- package/bone/output/session/migrations/part.sql +28 -28
- package/bone/output/session/migrations/permission.sql +28 -28
- package/bone/output/session/migrations/project.sql +28 -28
- package/bone/output/session/migrations/session.sql +38 -38
- package/bone/output/session/openapi.yaml +1101 -1101
- package/bone/output/session/package.json +35 -35
- package/bone/output/session/schema.graphql +222 -222
- package/bone/output/session/sdk/client.ts +225 -225
- package/bone/output/session/src/algorithms.ts +2 -2
- package/bone/output/session/src/audit.ts +44 -44
- package/bone/output/session/src/auth.ts +57 -57
- package/bone/output/session/src/cron.ts +12 -12
- package/bone/output/session/src/db.ts +31 -31
- package/bone/output/session/src/debug.ts +66 -66
- package/bone/output/session/src/events.ts +270 -270
- package/bone/output/session/src/extensions.ts +215 -215
- package/bone/output/session/src/failure_rules.ts +283 -283
- package/bone/output/session/src/flows.ts +168 -168
- package/bone/output/session/src/health.ts +43 -43
- package/bone/output/session/src/index.ts +99 -99
- package/bone/output/session/src/logger.ts +67 -66
- package/bone/output/session/src/metrics.ts +75 -75
- package/bone/output/session/src/migrate.ts +331 -331
- package/bone/output/session/src/migration_diff.ts +108 -108
- package/bone/output/session/src/notify.ts +112 -112
- package/bone/output/session/src/routes/message.ts +93 -93
- package/bone/output/session/src/routes/part.ts +79 -79
- package/bone/output/session/src/routes/permission.ts +79 -79
- package/bone/output/session/src/routes/project.ts +79 -79
- package/bone/output/session/src/routes/session.ts +294 -294
- package/bone/output/session/src/schemas.ts +357 -357
- package/bone/output/session/src/state_machines/session.ts +23 -23
- package/bone/output/session/src/tests.ts +325 -325
- package/bone/output/session/src/websocket.ts +223 -200
- package/bone/output/session/tsconfig.json +24 -24
- package/bone/output/workspace/.dockerignore +7 -7
- package/bone/output/workspace/.env.example +36 -36
- package/bone/output/workspace/.github/workflows/ci.yaml +58 -58
- package/bone/output/workspace/Dockerfile +22 -22
- package/bone/output/workspace/README.md +45 -45
- package/bone/output/workspace/WorkspaceDomain.bone.map +188 -188
- package/bone/output/workspace/WorkspaceDomain.postman_collection.json +620 -620
- package/bone/output/workspace/admin/index.html +484 -484
- package/bone/output/workspace/docker-compose.yaml +22 -22
- package/bone/output/workspace/k8s/deployment.yaml +75 -75
- package/bone/output/workspace/migrations/audit_log.sql +18 -18
- package/bone/output/workspace/migrations/codebase.sql +34 -34
- package/bone/output/workspace/migrations/event_outbox.sql +31 -31
- package/bone/output/workspace/migrations/snapshot.sql +32 -32
- package/bone/output/workspace/migrations/workspace.sql +33 -33
- package/bone/output/workspace/openapi.yaml +721 -721
- package/bone/output/workspace/package.json +35 -35
- package/bone/output/workspace/schema.graphql +153 -153
- package/bone/output/workspace/sdk/client.ts +155 -155
- package/bone/output/workspace/src/algorithms.ts +2 -2
- package/bone/output/workspace/src/audit.ts +37 -37
- package/bone/output/workspace/src/auth.ts +57 -57
- package/bone/output/workspace/src/cron.ts +12 -12
- package/bone/output/workspace/src/db.ts +31 -31
- package/bone/output/workspace/src/debug.ts +66 -66
- package/bone/output/workspace/src/events.ts +243 -243
- package/bone/output/workspace/src/extensions.ts +44 -44
- package/bone/output/workspace/src/failure_rules.ts +152 -152
- package/bone/output/workspace/src/health.ts +43 -43
- package/bone/output/workspace/src/index.ts +88 -88
- package/bone/output/workspace/src/logger.ts +69 -66
- package/bone/output/workspace/src/metrics.ts +75 -75
- package/bone/output/workspace/src/migrate.ts +219 -219
- package/bone/output/workspace/src/migration_diff.ts +108 -108
- package/bone/output/workspace/src/notify.ts +73 -73
- package/bone/output/workspace/src/routes/codebase.ts +87 -87
- package/bone/output/workspace/src/routes/snapshot.ts +127 -127
- package/bone/output/workspace/src/routes/workspace.ts +190 -190
- package/bone/output/workspace/src/schemas.ts +231 -231
- package/bone/output/workspace/src/state_machines/codebase.ts +21 -21
- package/bone/output/workspace/src/state_machines/snapshot.ts +20 -20
- package/bone/output/workspace/src/state_machines/workspace.ts +21 -21
- package/bone/output/workspace/src/tests.ts +248 -248
- package/bone/output/workspace/tsconfig.json +24 -24
- package/compat/opencode_adapter.ts +282 -34
- package/dist/bone/output/agent/src/algorithms.d.ts +1 -0
- package/dist/bone/output/agent/src/algorithms.js +3 -0
- package/dist/bone/output/agent/src/algorithms.js.map +1 -0
- package/dist/bone/output/agent/src/audit.d.ts +3 -0
- package/dist/bone/output/agent/src/audit.js +40 -0
- package/dist/bone/output/agent/src/audit.js.map +1 -0
- package/dist/bone/output/agent/src/auth.d.ts +8 -0
- package/dist/bone/output/agent/src/auth.js +56 -0
- package/dist/bone/output/agent/src/auth.js.map +1 -0
- package/dist/bone/output/agent/src/db.d.ts +6 -0
- package/dist/bone/output/agent/src/db.js +63 -0
- package/dist/bone/output/agent/src/db.js.map +1 -0
- package/dist/bone/output/agent/src/events.d.ts +25 -0
- package/dist/bone/output/agent/src/events.js +184 -0
- package/dist/bone/output/agent/src/events.js.map +1 -0
- package/dist/bone/output/agent/src/logger.d.ts +28 -0
- package/dist/bone/output/agent/src/logger.js +45 -0
- package/dist/bone/output/agent/src/logger.js.map +1 -0
- package/dist/bone/output/agent/src/metrics.d.ts +5 -0
- package/dist/bone/output/agent/src/metrics.js +60 -0
- package/dist/bone/output/agent/src/metrics.js.map +1 -0
- package/dist/bone/output/agent/src/routes/agent_instance.d.ts +1 -0
- package/dist/bone/output/agent/src/routes/agent_instance.js +253 -0
- package/dist/bone/output/agent/src/routes/agent_instance.js.map +1 -0
- package/dist/bone/output/agent/src/routes/build_step.d.ts +1 -0
- package/dist/bone/output/agent/src/routes/build_step.js +133 -0
- package/dist/bone/output/agent/src/routes/build_step.js.map +1 -0
- package/dist/bone/output/agent/src/routes/plan.d.ts +1 -0
- package/dist/bone/output/agent/src/routes/plan.js +119 -0
- package/dist/bone/output/agent/src/routes/plan.js.map +1 -0
- package/dist/bone/output/agent/src/routes/task.d.ts +1 -0
- package/dist/bone/output/agent/src/routes/task.js +133 -0
- package/dist/bone/output/agent/src/routes/task.js.map +1 -0
- package/dist/bone/output/agent/src/routes/tool_call.d.ts +1 -0
- package/dist/bone/output/agent/src/routes/tool_call.js +190 -0
- package/dist/bone/output/agent/src/routes/tool_call.js.map +1 -0
- package/dist/bone/output/agent/src/state_machines/agent_instance.d.ts +9 -0
- package/dist/bone/output/agent/src/state_machines/agent_instance.js +22 -0
- package/dist/bone/output/agent/src/state_machines/agent_instance.js.map +1 -0
- package/dist/bone/output/agent/src/state_machines/build_step.d.ts +9 -0
- package/dist/bone/output/agent/src/state_machines/build_step.js +20 -0
- package/dist/bone/output/agent/src/state_machines/build_step.js.map +1 -0
- package/dist/bone/output/agent/src/state_machines/plan.d.ts +9 -0
- package/dist/bone/output/agent/src/state_machines/plan.js +20 -0
- package/dist/bone/output/agent/src/state_machines/plan.js.map +1 -0
- package/dist/bone/output/agent/src/state_machines/task.d.ts +9 -0
- package/dist/bone/output/agent/src/state_machines/task.js +20 -0
- package/dist/bone/output/agent/src/state_machines/task.js.map +1 -0
- package/dist/bone/output/agent/src/state_machines/tool_call.d.ts +9 -0
- package/dist/bone/output/agent/src/state_machines/tool_call.js +20 -0
- package/dist/bone/output/agent/src/state_machines/tool_call.js.map +1 -0
- package/dist/bone/output/rag/src/algorithms.d.ts +1 -0
- package/dist/bone/output/rag/src/algorithms.js +3 -0
- package/dist/bone/output/rag/src/algorithms.js.map +1 -0
- package/dist/bone/output/rag/src/auth.d.ts +8 -0
- package/dist/bone/output/rag/src/auth.js +56 -0
- package/dist/bone/output/rag/src/auth.js.map +1 -0
- package/dist/bone/output/rag/src/db.d.ts +6 -0
- package/dist/bone/output/rag/src/db.js +63 -0
- package/dist/bone/output/rag/src/db.js.map +1 -0
- package/dist/bone/output/rag/src/events.d.ts +25 -0
- package/dist/bone/output/rag/src/events.js +184 -0
- package/dist/bone/output/rag/src/events.js.map +1 -0
- package/dist/bone/output/rag/src/extensions.d.ts +83 -0
- package/dist/bone/output/rag/src/extensions.js +329 -0
- package/dist/bone/output/rag/src/extensions.js.map +1 -0
- package/dist/bone/output/rag/src/flows.d.ts +24 -0
- package/dist/bone/output/rag/src/flows.js +236 -0
- package/dist/bone/output/rag/src/flows.js.map +1 -0
- package/dist/bone/output/rag/src/logger.d.ts +28 -0
- package/dist/bone/output/rag/src/logger.js +45 -0
- package/dist/bone/output/rag/src/logger.js.map +1 -0
- package/dist/bone/output/rag/src/metrics.d.ts +5 -0
- package/dist/bone/output/rag/src/metrics.js +60 -0
- package/dist/bone/output/rag/src/metrics.js.map +1 -0
- package/dist/bone/output/rag/src/routes/code_chunk.d.ts +1 -0
- package/dist/bone/output/rag/src/routes/code_chunk.js +100 -0
- package/dist/bone/output/rag/src/routes/code_chunk.js.map +1 -0
- package/dist/bone/output/rag/src/routes/code_file.d.ts +1 -0
- package/dist/bone/output/rag/src/routes/code_file.js +127 -0
- package/dist/bone/output/rag/src/routes/code_file.js.map +1 -0
- package/dist/bone/output/rag/src/routes/indexing_job.d.ts +1 -0
- package/dist/bone/output/rag/src/routes/indexing_job.js +113 -0
- package/dist/bone/output/rag/src/routes/indexing_job.js.map +1 -0
- package/dist/bone/output/rag/src/routes/knowledge_base.d.ts +1 -0
- package/dist/bone/output/rag/src/routes/knowledge_base.js +242 -0
- package/dist/bone/output/rag/src/routes/knowledge_base.js.map +1 -0
- package/dist/bone/output/rag/src/routes/memory_entry.d.ts +1 -0
- package/dist/bone/output/rag/src/routes/memory_entry.js +113 -0
- package/dist/bone/output/rag/src/routes/memory_entry.js.map +1 -0
- package/dist/bone/output/rag/src/state_machines/code_file.d.ts +9 -0
- package/dist/bone/output/rag/src/state_machines/code_file.js +21 -0
- package/dist/bone/output/rag/src/state_machines/code_file.js.map +1 -0
- package/dist/bone/output/rag/src/state_machines/indexing_job.d.ts +9 -0
- package/dist/bone/output/rag/src/state_machines/indexing_job.js +20 -0
- package/dist/bone/output/rag/src/state_machines/indexing_job.js.map +1 -0
- package/dist/bone/output/rag/src/state_machines/knowledge_base.d.ts +9 -0
- package/dist/bone/output/rag/src/state_machines/knowledge_base.js +21 -0
- package/dist/bone/output/rag/src/state_machines/knowledge_base.js.map +1 -0
- package/dist/bone/output/rag/src/state_machines/memory_entry.d.ts +9 -0
- package/dist/bone/output/rag/src/state_machines/memory_entry.js +18 -0
- package/dist/bone/output/rag/src/state_machines/memory_entry.js.map +1 -0
- package/dist/bone/output/session/src/algorithms.d.ts +1 -0
- package/dist/bone/output/session/src/algorithms.js +3 -0
- package/dist/bone/output/session/src/algorithms.js.map +1 -0
- package/dist/bone/output/session/src/audit.d.ts +3 -0
- package/dist/bone/output/session/src/audit.js +40 -0
- package/dist/bone/output/session/src/audit.js.map +1 -0
- package/dist/bone/output/session/src/auth.d.ts +8 -0
- package/dist/bone/output/session/src/auth.js +56 -0
- package/dist/bone/output/session/src/auth.js.map +1 -0
- package/dist/bone/output/session/src/db.d.ts +6 -0
- package/dist/bone/output/session/src/db.js +63 -0
- package/dist/bone/output/session/src/db.js.map +1 -0
- package/dist/bone/output/session/src/events.d.ts +26 -0
- package/dist/bone/output/session/src/events.js +212 -0
- package/dist/bone/output/session/src/events.js.map +1 -0
- package/dist/bone/output/session/src/extensions.d.ts +41 -0
- package/dist/bone/output/session/src/extensions.js +217 -0
- package/dist/bone/output/session/src/extensions.js.map +1 -0
- package/dist/bone/output/session/src/logger.d.ts +28 -0
- package/dist/bone/output/session/src/logger.js +44 -0
- package/dist/bone/output/session/src/logger.js.map +1 -0
- package/dist/bone/output/session/src/metrics.d.ts +5 -0
- package/dist/bone/output/session/src/metrics.js +60 -0
- package/dist/bone/output/session/src/metrics.js.map +1 -0
- package/dist/bone/output/session/src/routes/message.d.ts +1 -0
- package/dist/bone/output/session/src/routes/message.js +120 -0
- package/dist/bone/output/session/src/routes/message.js.map +1 -0
- package/dist/bone/output/session/src/routes/part.d.ts +1 -0
- package/dist/bone/output/session/src/routes/part.js +106 -0
- package/dist/bone/output/session/src/routes/part.js.map +1 -0
- package/dist/bone/output/session/src/routes/permission.d.ts +1 -0
- package/dist/bone/output/session/src/routes/permission.js +106 -0
- package/dist/bone/output/session/src/routes/permission.js.map +1 -0
- package/dist/bone/output/session/src/routes/project.d.ts +1 -0
- package/dist/bone/output/session/src/routes/project.js +106 -0
- package/dist/bone/output/session/src/routes/project.js.map +1 -0
- package/dist/bone/output/session/src/routes/session.d.ts +1 -0
- package/dist/bone/output/session/src/routes/session.js +308 -0
- package/dist/bone/output/session/src/routes/session.js.map +1 -0
- package/dist/bone/output/session/src/state_machines/session.d.ts +9 -0
- package/dist/bone/output/session/src/state_machines/session.js +21 -0
- package/dist/bone/output/session/src/state_machines/session.js.map +1 -0
- package/dist/bone/output/session/src/websocket.d.ts +15 -0
- package/dist/bone/output/session/src/websocket.js +215 -0
- package/dist/bone/output/session/src/websocket.js.map +1 -0
- package/dist/bone/output/workspace/src/algorithms.d.ts +1 -0
- package/dist/bone/output/workspace/src/algorithms.js +3 -0
- package/dist/bone/output/workspace/src/algorithms.js.map +1 -0
- package/dist/bone/output/workspace/src/auth.d.ts +8 -0
- package/dist/bone/output/workspace/src/auth.js +56 -0
- package/dist/bone/output/workspace/src/auth.js.map +1 -0
- package/dist/bone/output/workspace/src/db.d.ts +6 -0
- package/dist/bone/output/workspace/src/db.js +63 -0
- package/dist/bone/output/workspace/src/db.js.map +1 -0
- package/dist/bone/output/workspace/src/events.d.ts +25 -0
- package/dist/bone/output/workspace/src/events.js +184 -0
- package/dist/bone/output/workspace/src/events.js.map +1 -0
- package/dist/bone/output/workspace/src/logger.d.ts +28 -0
- package/dist/bone/output/workspace/src/logger.js +45 -0
- package/dist/bone/output/workspace/src/logger.js.map +1 -0
- package/dist/bone/output/workspace/src/metrics.d.ts +5 -0
- package/dist/bone/output/workspace/src/metrics.js +60 -0
- package/dist/bone/output/workspace/src/metrics.js.map +1 -0
- package/dist/bone/output/workspace/src/routes/codebase.d.ts +1 -0
- package/dist/bone/output/workspace/src/routes/codebase.js +113 -0
- package/dist/bone/output/workspace/src/routes/codebase.js.map +1 -0
- package/dist/bone/output/workspace/src/routes/snapshot.d.ts +1 -0
- package/dist/bone/output/workspace/src/routes/snapshot.js +151 -0
- package/dist/bone/output/workspace/src/routes/snapshot.js.map +1 -0
- package/dist/bone/output/workspace/src/routes/workspace.d.ts +1 -0
- package/dist/bone/output/workspace/src/routes/workspace.js +209 -0
- package/dist/bone/output/workspace/src/routes/workspace.js.map +1 -0
- package/dist/bone/output/workspace/src/state_machines/codebase.d.ts +9 -0
- package/dist/bone/output/workspace/src/state_machines/codebase.js +19 -0
- package/dist/bone/output/workspace/src/state_machines/codebase.js.map +1 -0
- package/dist/bone/output/workspace/src/state_machines/snapshot.d.ts +9 -0
- package/dist/bone/output/workspace/src/state_machines/snapshot.js +18 -0
- package/dist/bone/output/workspace/src/state_machines/snapshot.js.map +1 -0
- package/dist/bone/output/workspace/src/state_machines/workspace.d.ts +9 -0
- package/dist/bone/output/workspace/src/state_machines/workspace.js +19 -0
- package/dist/bone/output/workspace/src/state_machines/workspace.js.map +1 -0
- package/dist/compat/opencode_adapter.d.ts +25 -0
- package/dist/compat/opencode_adapter.js +599 -0
- package/dist/compat/opencode_adapter.js.map +1 -0
- package/dist/extensions/chunker.d.ts +24 -0
- package/dist/extensions/chunker.js +360 -0
- package/dist/extensions/chunker.js.map +1 -0
- package/dist/extensions/embedding_provider.d.ts +18 -0
- package/dist/extensions/embedding_provider.js +150 -0
- package/dist/extensions/embedding_provider.js.map +1 -0
- package/dist/extensions/llm_provider.d.ts +33 -0
- package/dist/extensions/llm_provider.js +338 -0
- package/dist/extensions/llm_provider.js.map +1 -0
- package/dist/extensions/mcp_bridge.d.ts +44 -0
- package/dist/extensions/mcp_bridge.js +151 -0
- package/dist/extensions/mcp_bridge.js.map +1 -0
- package/dist/extensions/rag_search.d.ts +38 -0
- package/dist/extensions/rag_search.js +242 -0
- package/dist/extensions/rag_search.js.map +1 -0
- package/dist/extensions/snapshot.d.ts +14 -0
- package/dist/extensions/snapshot.js +158 -0
- package/dist/extensions/snapshot.js.map +1 -0
- package/dist/extensions/tool_executor.d.ts +28 -0
- package/dist/extensions/tool_executor.js +268 -0
- package/dist/extensions/tool_executor.js.map +1 -0
- package/dist/src/cli.d.ts +15 -0
- package/dist/src/cli.js +687 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.d.ts +44 -0
- package/dist/src/config.js +165 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/context_builder.d.ts +51 -0
- package/dist/src/context_builder.js +558 -0
- package/dist/src/context_builder.js.map +1 -0
- package/dist/src/db_adapter.d.ts +24 -0
- package/dist/src/db_adapter.js +341 -0
- package/dist/src/db_adapter.js.map +1 -0
- package/dist/src/engine/session/compaction_logic.d.ts +11 -0
- package/dist/src/engine/session/compaction_logic.js +113 -0
- package/dist/src/engine/session/compaction_logic.js.map +1 -0
- package/dist/src/engine/session/instruction_loader.d.ts +5 -0
- package/dist/src/engine/session/instruction_loader.js +78 -0
- package/dist/src/engine/session/instruction_loader.js.map +1 -0
- package/dist/src/engine/session/overflow_check.d.ts +14 -0
- package/dist/src/engine/session/overflow_check.js +45 -0
- package/dist/src/engine/session/overflow_check.js.map +1 -0
- package/dist/src/engine/session/prompt.d.ts +45 -0
- package/dist/src/engine/session/prompt.js +584 -0
- package/dist/src/engine/session/prompt.js.map +1 -0
- package/dist/src/engine/session/provider_transform.d.ts +59 -0
- package/dist/src/engine/session/provider_transform.js +193 -0
- package/dist/src/engine/session/provider_transform.js.map +1 -0
- package/dist/src/engine/session/retry_logic.d.ts +12 -0
- package/dist/src/engine/session/retry_logic.js +72 -0
- package/dist/src/engine/session/retry_logic.js.map +1 -0
- package/dist/src/engine/session/system_prompt.d.ts +9 -0
- package/dist/src/engine/session/system_prompt.js +96 -0
- package/dist/src/engine/session/system_prompt.js.map +1 -0
- package/dist/src/engine/session/tool_registry.d.ts +5 -0
- package/dist/src/engine/session/tool_registry.js +117 -0
- package/dist/src/engine/session/tool_registry.js.map +1 -0
- package/dist/src/export.d.ts +13 -0
- package/dist/src/export.js +103 -0
- package/dist/src/export.js.map +1 -0
- package/dist/src/mdns.d.ts +7 -0
- package/dist/src/mdns.js +60 -0
- package/dist/src/mdns.js.map +1 -0
- package/dist/src/rag_worker.d.ts +38 -0
- package/dist/src/rag_worker.js +435 -0
- package/dist/src/rag_worker.js.map +1 -0
- package/dist/src/server.d.ts +11 -0
- package/dist/src/server.js +214 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/stats.d.ts +45 -0
- package/dist/src/stats.js +233 -0
- package/dist/src/stats.js.map +1 -0
- package/dist/src/tui.d.ts +29 -0
- package/dist/src/tui.js +1053 -0
- package/dist/src/tui.js.map +1 -0
- package/package.json +21 -5
- package/src/cli.ts +314 -113
- package/src/db_adapter.ts +354 -0
- package/src/engine/account/account.sql.ts +39 -39
- package/src/engine/account/account.ts +456 -456
- package/src/engine/account/repo.ts +166 -166
- package/src/engine/account/schema.ts +99 -99
- package/src/engine/account/url.ts +8 -8
- package/src/engine/acp/README.md +174 -174
- package/src/engine/acp/agent.ts +1968 -1968
- package/src/engine/acp/runtime.ts +22 -22
- package/src/engine/acp/session.ts +122 -122
- package/src/engine/acp/types.ts +24 -24
- package/src/engine/agent/agent.ts +463 -463
- package/src/engine/agent/generate.txt +75 -75
- package/src/engine/agent/prompt/compaction.txt +9 -9
- package/src/engine/agent/prompt/explore.txt +18 -18
- package/src/engine/agent/prompt/scout.txt +36 -36
- package/src/engine/agent/prompt/summary.txt +11 -11
- package/src/engine/agent/prompt/title.txt +44 -44
- package/src/engine/agent/subagent-permissions.ts +34 -34
- package/src/engine/auth/index.ts +96 -96
- package/src/engine/background/background/job.ts +200 -200
- package/src/engine/background/job.ts +200 -200
- package/src/engine/bus/bus-event.ts +45 -45
- package/src/engine/bus/global.ts +22 -22
- package/src/engine/bus/index.ts +203 -203
- package/src/engine/command/command/index.ts +181 -181
- package/src/engine/command/command/template/initialize.txt +66 -66
- package/src/engine/command/command/template/review.txt +101 -101
- package/src/engine/command/index.ts +181 -181
- package/src/engine/command/template/initialize.txt +66 -66
- package/src/engine/command/template/review.txt +101 -101
- package/src/engine/config/agent.ts +172 -172
- package/src/engine/config/attachment.ts +25 -25
- package/src/engine/config/command.ts +62 -62
- package/src/engine/config/config.ts +833 -833
- package/src/engine/config/console-state.ts +14 -14
- package/src/engine/config/entry-name.ts +16 -16
- package/src/engine/config/error.ts +23 -23
- package/src/engine/config/formatter.ts +13 -13
- package/src/engine/config/layout.ts +6 -6
- package/src/engine/config/lsp.ts +43 -43
- package/src/engine/config/managed.ts +71 -71
- package/src/engine/config/markdown.ts +96 -96
- package/src/engine/config/mcp.ts +56 -56
- package/src/engine/config/model-id.ts +5 -5
- package/src/engine/config/parse.ts +79 -79
- package/src/engine/config/paths.ts +45 -45
- package/src/engine/config/permission.ts +58 -58
- package/src/engine/config/plugin.ts +84 -84
- package/src/engine/config/provider.ts +111 -111
- package/src/engine/config/reference.ts +23 -23
- package/src/engine/config/server.ts +19 -19
- package/src/engine/config/skills.ts +14 -14
- package/src/engine/config/variable.ts +90 -90
- package/src/engine/control-plane/adapters/index.ts +41 -41
- package/src/engine/control-plane/adapters/worktree.ts +96 -96
- package/src/engine/control-plane/dev/README.md +19 -19
- package/src/engine/control-plane/dev/debug-workspace-plugin.ts +73 -73
- package/src/engine/control-plane/schema.ts +14 -14
- package/src/engine/control-plane/types.ts +59 -59
- package/src/engine/control-plane/util.ts +39 -39
- package/src/engine/control-plane/workspace-adapter-runtime.ts +51 -51
- package/src/engine/control-plane/workspace-context.ts +26 -26
- package/src/engine/control-plane/workspace.sql.ts +20 -20
- package/src/engine/control-plane/workspace.ts +1072 -1072
- package/src/engine/data-migration.ts +161 -161
- package/src/engine/effect/app-runtime.ts +143 -143
- package/src/engine/effect/bootstrap-runtime.ts +29 -29
- package/src/engine/effect/bridge.ts +84 -84
- package/src/engine/effect/config-service.ts +67 -67
- package/src/engine/effect/instance-ref.ts +11 -11
- package/src/engine/effect/instance-registry.ts +12 -12
- package/src/engine/effect/instance-state.ts +72 -72
- package/src/engine/effect/promise.ts +17 -17
- package/src/engine/effect/run-service.ts +47 -47
- package/src/engine/effect/runner.ts +217 -217
- package/src/engine/effect/runtime-flags.ts +74 -74
- package/src/engine/effect/service-use.ts +38 -38
- package/src/engine/env/index.ts +37 -37
- package/src/engine/event-v2-bridge.ts +89 -89
- package/src/engine/file/file/ignore.ts +81 -81
- package/src/engine/file/file/index.ts +651 -651
- package/src/engine/file/file/protected.ts +59 -59
- package/src/engine/file/file/ripgrep.ts +481 -481
- package/src/engine/file/file/watcher.ts +167 -167
- package/src/engine/file/ignore.ts +81 -81
- package/src/engine/file/index.ts +651 -651
- package/src/engine/file/protected.ts +59 -59
- package/src/engine/file/ripgrep.ts +481 -481
- package/src/engine/file/watcher.ts +167 -167
- package/src/engine/format/format/formatter.ts +404 -404
- package/src/engine/format/format/index.ts +209 -209
- package/src/engine/format/formatter.ts +404 -404
- package/src/engine/format/index.ts +209 -209
- package/src/engine/git/git/index.ts +347 -347
- package/src/engine/git/index.ts +347 -347
- package/src/engine/id/id.ts +80 -80
- package/src/engine/ide/index.ts +70 -70
- package/src/engine/image/image/image.ts +176 -176
- package/src/engine/image/image.ts +176 -176
- package/src/engine/index.ts +251 -251
- package/src/engine/installation/index.ts +327 -327
- package/src/engine/lsp/client.ts +707 -707
- package/src/engine/lsp/diagnostic.ts +29 -29
- package/src/engine/lsp/language.ts +121 -121
- package/src/engine/lsp/launch.ts +21 -21
- package/src/engine/lsp/lsp/client.ts +707 -707
- package/src/engine/lsp/lsp/diagnostic.ts +29 -29
- package/src/engine/lsp/lsp/language.ts +121 -121
- package/src/engine/lsp/lsp/launch.ts +21 -21
- package/src/engine/lsp/lsp/lsp.ts +507 -507
- package/src/engine/lsp/lsp/server.ts +2064 -2064
- package/src/engine/lsp/lsp.ts +507 -507
- package/src/engine/lsp/server.ts +2064 -2064
- package/src/engine/mcp/auth.ts +146 -146
- package/src/engine/mcp/index.ts +958 -958
- package/src/engine/mcp/mcp/auth.ts +146 -146
- package/src/engine/mcp/mcp/index.ts +958 -958
- package/src/engine/mcp/mcp/oauth-callback.ts +232 -232
- package/src/engine/mcp/mcp/oauth-provider.ts +214 -214
- package/src/engine/mcp/oauth-callback.ts +232 -232
- package/src/engine/mcp/oauth-provider.ts +214 -214
- package/src/engine/node.ts +6 -6
- package/src/engine/patch/index.ts +689 -689
- package/src/engine/patch/patch/index.ts +689 -689
- package/src/engine/permission/arity.ts +163 -163
- package/src/engine/permission/evaluate.ts +15 -15
- package/src/engine/permission/index.ts +306 -306
- package/src/engine/permission/permission/arity.ts +163 -163
- package/src/engine/permission/permission/evaluate.ts +15 -15
- package/src/engine/permission/permission/index.ts +306 -306
- package/src/engine/permission/permission/schema.ts +13 -13
- package/src/engine/permission/schema.ts +13 -13
- package/src/engine/plugin/azure.ts +26 -26
- package/src/engine/plugin/cloudflare.ts +76 -76
- package/src/engine/plugin/codex.ts +622 -622
- package/src/engine/plugin/digitalocean.ts +411 -411
- package/src/engine/plugin/github-copilot/copilot.ts +394 -394
- package/src/engine/plugin/github-copilot/models.ts +196 -196
- package/src/engine/plugin/index.ts +295 -295
- package/src/engine/plugin/install.ts +439 -439
- package/src/engine/plugin/loader.ts +216 -216
- package/src/engine/plugin/meta.ts +188 -188
- package/src/engine/plugin/shared.ts +323 -323
- package/src/engine/project/bootstrap-service.ts +9 -9
- package/src/engine/project/bootstrap.ts +75 -75
- package/src/engine/project/instance-context.ts +24 -24
- package/src/engine/project/instance-layer.ts +11 -11
- package/src/engine/project/instance-runtime.ts +16 -16
- package/src/engine/project/instance-store.ts +193 -193
- package/src/engine/project/project.sql.ts +17 -17
- package/src/engine/project/project.ts +537 -537
- package/src/engine/project/schema.ts +13 -13
- package/src/engine/project/vcs.ts +405 -405
- package/src/engine/provider/auth.ts +225 -225
- package/src/engine/provider/error.ts +204 -204
- package/src/engine/provider/model-status.ts +8 -8
- package/src/engine/provider/provider.ts +1843 -1843
- package/src/engine/provider/schema.ts +30 -30
- package/src/engine/provider/transform.ts +1376 -1376
- package/src/engine/pty/index.ts +365 -365
- package/src/engine/pty/input.ts +24 -24
- package/src/engine/pty/pty/index.ts +365 -365
- package/src/engine/pty/pty/input.ts +24 -24
- package/src/engine/pty/pty/pty.bun.ts +26 -26
- package/src/engine/pty/pty/pty.node.ts +27 -27
- package/src/engine/pty/pty/pty.ts +25 -25
- package/src/engine/pty/pty/schema.ts +14 -14
- package/src/engine/pty/pty/ticket.ts +68 -68
- package/src/engine/pty/pty.bun.ts +26 -26
- package/src/engine/pty/pty.node.ts +27 -27
- package/src/engine/pty/pty.ts +25 -25
- package/src/engine/pty/schema.ts +14 -14
- package/src/engine/pty/ticket.ts +68 -68
- package/src/engine/question/index.ts +213 -213
- package/src/engine/question/question/index.ts +213 -213
- package/src/engine/question/question/schema.ts +10 -10
- package/src/engine/question/schema.ts +10 -10
- package/src/engine/reference/reference/reference.ts +241 -241
- package/src/engine/reference/reference/repository-cache.ts +147 -147
- package/src/engine/reference/reference.ts +241 -241
- package/src/engine/reference/repository-cache.ts +147 -147
- package/src/engine/session/compaction.ts +651 -651
- package/src/engine/session/instruction.ts +238 -238
- package/src/engine/session/llm.ts +459 -459
- package/src/engine/session/message-error.ts +14 -14
- package/src/engine/session/message-v2.ts +1202 -1202
- package/src/engine/session/message.ts +146 -146
- package/src/engine/session/overflow.ts +32 -32
- package/src/engine/session/processor.ts +823 -823
- package/src/engine/session/prompt/anthropic.txt +105 -105
- package/src/engine/session/prompt/beast.txt +147 -147
- package/src/engine/session/prompt/build-switch.txt +5 -5
- package/src/engine/session/prompt/codex.txt +79 -79
- package/src/engine/session/prompt/copilot-gpt-5.txt +143 -143
- package/src/engine/session/prompt/default.txt +105 -105
- package/src/engine/session/prompt/gemini.txt +155 -155
- package/src/engine/session/prompt/gpt.txt +107 -107
- package/src/engine/session/prompt/kimi.txt +95 -95
- package/src/engine/session/prompt/max-steps.txt +15 -15
- package/src/engine/session/prompt/plan-reminder-anthropic.txt +67 -67
- package/src/engine/session/prompt/plan.txt +26 -26
- package/src/engine/session/prompt/trinity.txt +97 -97
- package/src/engine/session/prompt.ts +66 -9
- package/src/engine/session/retry.ts +200 -200
- package/src/engine/session/revert.ts +162 -162
- package/src/engine/session/run-state.ts +153 -153
- package/src/engine/session/schema.ts +26 -26
- package/src/engine/session/session.sql.ts +137 -137
- package/src/engine/session/session.ts +1011 -1011
- package/src/engine/session/status.ts +94 -94
- package/src/engine/session/summary.ts +164 -164
- package/src/engine/session/system.ts +84 -84
- package/src/engine/session/todo.ts +81 -81
- package/src/engine/share/session.ts +61 -61
- package/src/engine/share/share-next.ts +376 -376
- package/src/engine/share/share.sql.ts +13 -13
- package/src/engine/shell/shell/shell.ts +215 -215
- package/src/engine/shell/shell.ts +215 -215
- package/src/engine/skill/discovery.ts +116 -116
- package/src/engine/skill/index.ts +336 -336
- package/src/engine/skill/prompt/customize-opencode.md +377 -377
- package/src/engine/skill/skill/discovery.ts +116 -116
- package/src/engine/skill/skill/index.ts +336 -336
- package/src/engine/skill/skill/prompt/customize-opencode.md +377 -377
- package/src/engine/snapshot/index.ts +762 -762
- package/src/engine/snapshot/snapshot/index.ts +762 -762
- package/src/engine/sync/README.md +179 -179
- package/src/engine/sync/event.sql.ts +17 -17
- package/src/engine/sync/index.ts +410 -410
- package/src/engine/sync/schema.ts +11 -11
- package/src/engine/temporary.ts +33 -33
- package/src/engine/tool/apply_patch.ts +313 -313
- package/src/engine/tool/apply_patch.txt +33 -33
- package/src/engine/tool/edit.ts +711 -711
- package/src/engine/tool/edit.txt +10 -10
- package/src/engine/tool/external-directory.ts +49 -49
- package/src/engine/tool/glob.ts +103 -103
- package/src/engine/tool/glob.txt +6 -6
- package/src/engine/tool/grep.ts +156 -156
- package/src/engine/tool/grep.txt +8 -8
- package/src/engine/tool/invalid.ts +21 -21
- package/src/engine/tool/json-schema.ts +164 -164
- package/src/engine/tool/lsp.ts +113 -113
- package/src/engine/tool/lsp.txt +24 -24
- package/src/engine/tool/mcp-websearch.ts +96 -96
- package/src/engine/tool/plan-enter.txt +14 -14
- package/src/engine/tool/plan-exit.txt +13 -13
- package/src/engine/tool/plan.ts +78 -78
- package/src/engine/tool/question.ts +44 -44
- package/src/engine/tool/question.txt +10 -10
- package/src/engine/tool/read.ts +337 -337
- package/src/engine/tool/read.txt +14 -14
- package/src/engine/tool/registry.ts +472 -472
- package/src/engine/tool/repo_clone.ts +80 -80
- package/src/engine/tool/repo_clone.txt +5 -5
- package/src/engine/tool/repo_overview.ts +279 -279
- package/src/engine/tool/repo_overview.txt +4 -4
- package/src/engine/tool/schema.ts +14 -14
- package/src/engine/tool/shell/id.ts +19 -19
- package/src/engine/tool/shell/prompt.ts +295 -295
- package/src/engine/tool/shell/shell.txt +77 -77
- package/src/engine/tool/shell.ts +647 -647
- package/src/engine/tool/skill.ts +75 -75
- package/src/engine/tool/skill.txt +5 -5
- package/src/engine/tool/task.ts +337 -337
- package/src/engine/tool/task.txt +58 -58
- package/src/engine/tool/task_status.ts +179 -179
- package/src/engine/tool/task_status.txt +13 -13
- package/src/engine/tool/todo.ts +57 -57
- package/src/engine/tool/todowrite.txt +167 -167
- package/src/engine/tool/tool/apply_patch.ts +313 -313
- package/src/engine/tool/tool/apply_patch.txt +33 -33
- package/src/engine/tool/tool/edit.ts +711 -711
- package/src/engine/tool/tool/edit.txt +10 -10
- package/src/engine/tool/tool/external-directory.ts +49 -49
- package/src/engine/tool/tool/glob.ts +103 -103
- package/src/engine/tool/tool/glob.txt +6 -6
- package/src/engine/tool/tool/grep.ts +156 -156
- package/src/engine/tool/tool/grep.txt +8 -8
- package/src/engine/tool/tool/invalid.ts +21 -21
- package/src/engine/tool/tool/json-schema.ts +164 -164
- package/src/engine/tool/tool/lsp.ts +113 -113
- package/src/engine/tool/tool/lsp.txt +24 -24
- package/src/engine/tool/tool/mcp-websearch.ts +96 -96
- package/src/engine/tool/tool/plan-enter.txt +14 -14
- package/src/engine/tool/tool/plan-exit.txt +13 -13
- package/src/engine/tool/tool/plan.ts +78 -78
- package/src/engine/tool/tool/question.ts +44 -44
- package/src/engine/tool/tool/question.txt +10 -10
- package/src/engine/tool/tool/read.ts +337 -337
- package/src/engine/tool/tool/read.txt +14 -14
- package/src/engine/tool/tool/registry.ts +472 -472
- package/src/engine/tool/tool/repo_clone.ts +80 -80
- package/src/engine/tool/tool/repo_clone.txt +5 -5
- package/src/engine/tool/tool/repo_overview.ts +279 -279
- package/src/engine/tool/tool/repo_overview.txt +4 -4
- package/src/engine/tool/tool/schema.ts +14 -14
- package/src/engine/tool/tool/shell/id.ts +19 -19
- package/src/engine/tool/tool/shell/prompt.ts +295 -295
- package/src/engine/tool/tool/shell/shell.txt +77 -77
- package/src/engine/tool/tool/shell.ts +647 -647
- package/src/engine/tool/tool/skill.ts +75 -75
- package/src/engine/tool/tool/skill.txt +5 -5
- package/src/engine/tool/tool/task.ts +337 -337
- package/src/engine/tool/tool/task.txt +58 -58
- package/src/engine/tool/tool/task_status.ts +179 -179
- package/src/engine/tool/tool/task_status.txt +13 -13
- package/src/engine/tool/tool/todo.ts +57 -57
- package/src/engine/tool/tool/todowrite.txt +167 -167
- package/src/engine/tool/tool/tool.ts +164 -164
- package/src/engine/tool/tool/truncate.ts +160 -160
- package/src/engine/tool/tool/truncation-dir.ts +4 -4
- package/src/engine/tool/tool/webfetch.ts +192 -192
- package/src/engine/tool/tool/webfetch.txt +13 -13
- package/src/engine/tool/tool/websearch.ts +143 -143
- package/src/engine/tool/tool/websearch.txt +14 -14
- package/src/engine/tool/tool/write.ts +104 -104
- package/src/engine/tool/tool/write.txt +8 -8
- package/src/engine/tool/tool.ts +164 -164
- package/src/engine/tool/truncate.ts +160 -160
- package/src/engine/tool/truncation-dir.ts +4 -4
- package/src/engine/tool/webfetch.ts +192 -192
- package/src/engine/tool/webfetch.txt +13 -13
- package/src/engine/tool/websearch.ts +143 -143
- package/src/engine/tool/websearch.txt +14 -14
- package/src/engine/tool/write.ts +104 -104
- package/src/engine/tool/write.txt +8 -8
- package/src/engine/util/archive.ts +17 -17
- package/src/engine/util/bom.ts +31 -31
- package/src/engine/util/data-url.ts +9 -9
- package/src/engine/util/defer.ts +10 -10
- package/src/engine/util/effect-http-client.ts +11 -11
- package/src/engine/util/error.ts +88 -88
- package/src/engine/util/filesystem.ts +252 -252
- package/src/engine/util/format.ts +20 -20
- package/src/engine/util/iife.ts +3 -3
- package/src/engine/util/lazy.ts +20 -20
- package/src/engine/util/local-context.ts +25 -25
- package/src/engine/util/locale.ts +86 -86
- package/src/engine/util/media.ts +26 -26
- package/src/engine/util/process.ts +176 -176
- package/src/engine/util/queue.ts +32 -32
- package/src/engine/util/record.ts +3 -3
- package/src/engine/util/repository.ts +158 -158
- package/src/engine/util/rpc.ts +66 -66
- package/src/engine/util/signal.ts +12 -12
- package/src/engine/util/timeout.ts +13 -13
- package/src/engine/util/token.ts +7 -7
- package/src/engine/util/util/archive.ts +17 -17
- package/src/engine/util/util/bom.ts +31 -31
- package/src/engine/util/util/data-url.ts +9 -9
- package/src/engine/util/util/defer.ts +10 -10
- package/src/engine/util/util/effect-http-client.ts +11 -11
- package/src/engine/util/util/error.ts +88 -88
- package/src/engine/util/util/filesystem.ts +252 -252
- package/src/engine/util/util/format.ts +20 -20
- package/src/engine/util/util/iife.ts +3 -3
- package/src/engine/util/util/lazy.ts +20 -20
- package/src/engine/util/util/local-context.ts +25 -25
- package/src/engine/util/util/locale.ts +86 -86
- package/src/engine/util/util/media.ts +26 -26
- package/src/engine/util/util/process.ts +176 -176
- package/src/engine/util/util/queue.ts +32 -32
- package/src/engine/util/util/record.ts +3 -3
- package/src/engine/util/util/repository.ts +158 -158
- package/src/engine/util/util/rpc.ts +66 -66
- package/src/engine/util/util/signal.ts +12 -12
- package/src/engine/util/util/timeout.ts +13 -13
- package/src/engine/util/util/token.ts +7 -7
- package/src/engine/util/util/which.ts +14 -14
- package/src/engine/util/util/wildcard.ts +59 -59
- package/src/engine/util/which.ts +14 -14
- package/src/engine/util/wildcard.ts +59 -59
- package/src/engine/worktree/index.ts +621 -621
- package/src/export.ts +122 -0
- package/src/mdns.ts +53 -0
- package/src/server.ts +151 -156
- package/src/stats.ts +290 -0
- package/src/tui.ts +964 -480
|
@@ -1,689 +1,689 @@
|
|
|
1
|
-
import { Effect, Schema } from "effect"
|
|
2
|
-
import * as path from "path"
|
|
3
|
-
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
|
4
|
-
import * as Log from "@opencode-ai/core/util/log"
|
|
5
|
-
import * as Bom from "../util/bom"
|
|
6
|
-
|
|
7
|
-
const log = Log.create({ service: "patch" })
|
|
8
|
-
|
|
9
|
-
export const PatchSchema = Schema.Struct({
|
|
10
|
-
patchText: Schema.String.annotate({ description: "The full patch text that describes all changes to be made" }),
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
export type PatchParams = Schema.Schema.Type<typeof PatchSchema>
|
|
14
|
-
|
|
15
|
-
// Core types matching the Rust implementation
|
|
16
|
-
export interface ApplyPatchArgs {
|
|
17
|
-
patch: string
|
|
18
|
-
hunks: Hunk[]
|
|
19
|
-
workdir?: string
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type Hunk =
|
|
23
|
-
| { type: "add"; path: string; contents: string }
|
|
24
|
-
| { type: "delete"; path: string }
|
|
25
|
-
| { type: "update"; path: string; move_path?: string; chunks: UpdateFileChunk[] }
|
|
26
|
-
|
|
27
|
-
export interface UpdateFileChunk {
|
|
28
|
-
old_lines: string[]
|
|
29
|
-
new_lines: string[]
|
|
30
|
-
change_context?: string
|
|
31
|
-
is_end_of_file?: boolean
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface ApplyPatchAction {
|
|
35
|
-
changes: Map<string, ApplyPatchFileChange>
|
|
36
|
-
patch: string
|
|
37
|
-
cwd: string
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export type ApplyPatchFileChange =
|
|
41
|
-
| { type: "add"; content: string }
|
|
42
|
-
| { type: "delete"; content: string }
|
|
43
|
-
| { type: "update"; unified_diff: string; move_path?: string; new_content: string }
|
|
44
|
-
|
|
45
|
-
export interface AffectedPaths {
|
|
46
|
-
added: string[]
|
|
47
|
-
modified: string[]
|
|
48
|
-
deleted: string[]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export enum ApplyPatchError {
|
|
52
|
-
ParseError = "ParseError",
|
|
53
|
-
IoError = "IoError",
|
|
54
|
-
ComputeReplacements = "ComputeReplacements",
|
|
55
|
-
ImplicitInvocation = "ImplicitInvocation",
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export enum MaybeApplyPatch {
|
|
59
|
-
Body = "Body",
|
|
60
|
-
ShellParseError = "ShellParseError",
|
|
61
|
-
PatchParseError = "PatchParseError",
|
|
62
|
-
NotApplyPatch = "NotApplyPatch",
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export enum MaybeApplyPatchVerified {
|
|
66
|
-
Body = "Body",
|
|
67
|
-
ShellParseError = "ShellParseError",
|
|
68
|
-
CorrectnessError = "CorrectnessError",
|
|
69
|
-
NotApplyPatch = "NotApplyPatch",
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Parser implementation
|
|
73
|
-
function parsePatchHeader(
|
|
74
|
-
lines: string[],
|
|
75
|
-
startIdx: number,
|
|
76
|
-
): { filePath: string; movePath?: string; nextIdx: number } | null {
|
|
77
|
-
const line = lines[startIdx]
|
|
78
|
-
|
|
79
|
-
if (line.startsWith("*** Add File:")) {
|
|
80
|
-
const filePath = line.slice("*** Add File:".length).trim()
|
|
81
|
-
return filePath ? { filePath, nextIdx: startIdx + 1 } : null
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (line.startsWith("*** Delete File:")) {
|
|
85
|
-
const filePath = line.slice("*** Delete File:".length).trim()
|
|
86
|
-
return filePath ? { filePath, nextIdx: startIdx + 1 } : null
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (line.startsWith("*** Update File:")) {
|
|
90
|
-
const filePath = line.slice("*** Update File:".length).trim()
|
|
91
|
-
let movePath: string | undefined
|
|
92
|
-
let nextIdx = startIdx + 1
|
|
93
|
-
|
|
94
|
-
// Check for move directive
|
|
95
|
-
if (nextIdx < lines.length && lines[nextIdx].startsWith("*** Move to:")) {
|
|
96
|
-
movePath = lines[nextIdx].slice("*** Move to:".length).trim()
|
|
97
|
-
nextIdx++
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return filePath ? { filePath, movePath, nextIdx } : null
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return null
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function parseUpdateFileChunks(lines: string[], startIdx: number): { chunks: UpdateFileChunk[]; nextIdx: number } {
|
|
107
|
-
const chunks: UpdateFileChunk[] = []
|
|
108
|
-
let i = startIdx
|
|
109
|
-
|
|
110
|
-
while (i < lines.length && !lines[i].startsWith("***")) {
|
|
111
|
-
if (lines[i].startsWith("@@")) {
|
|
112
|
-
// Parse context line
|
|
113
|
-
const contextLine = lines[i].substring(2).trim()
|
|
114
|
-
i++
|
|
115
|
-
|
|
116
|
-
const oldLines: string[] = []
|
|
117
|
-
const newLines: string[] = []
|
|
118
|
-
let isEndOfFile = false
|
|
119
|
-
|
|
120
|
-
// Parse change lines
|
|
121
|
-
while (i < lines.length && !lines[i].startsWith("@@") && !lines[i].startsWith("***")) {
|
|
122
|
-
const changeLine = lines[i]
|
|
123
|
-
|
|
124
|
-
if (changeLine === "*** End of File") {
|
|
125
|
-
isEndOfFile = true
|
|
126
|
-
i++
|
|
127
|
-
break
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (changeLine.startsWith(" ")) {
|
|
131
|
-
// Keep line - appears in both old and new
|
|
132
|
-
const content = changeLine.substring(1)
|
|
133
|
-
oldLines.push(content)
|
|
134
|
-
newLines.push(content)
|
|
135
|
-
} else if (changeLine.startsWith("-")) {
|
|
136
|
-
// Remove line - only in old
|
|
137
|
-
oldLines.push(changeLine.substring(1))
|
|
138
|
-
} else if (changeLine.startsWith("+")) {
|
|
139
|
-
// Add line - only in new
|
|
140
|
-
newLines.push(changeLine.substring(1))
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
i++
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
chunks.push({
|
|
147
|
-
old_lines: oldLines,
|
|
148
|
-
new_lines: newLines,
|
|
149
|
-
change_context: contextLine || undefined,
|
|
150
|
-
is_end_of_file: isEndOfFile || undefined,
|
|
151
|
-
})
|
|
152
|
-
} else {
|
|
153
|
-
i++
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return { chunks, nextIdx: i }
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function parseAddFileContent(lines: string[], startIdx: number): { content: string; nextIdx: number } {
|
|
161
|
-
let content = ""
|
|
162
|
-
let i = startIdx
|
|
163
|
-
|
|
164
|
-
while (i < lines.length && !lines[i].startsWith("***")) {
|
|
165
|
-
if (lines[i].startsWith("+")) {
|
|
166
|
-
content += lines[i].substring(1) + "\n"
|
|
167
|
-
}
|
|
168
|
-
i++
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Remove trailing newline
|
|
172
|
-
if (content.endsWith("\n")) {
|
|
173
|
-
content = content.slice(0, -1)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return { content, nextIdx: i }
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function stripHeredoc(input: string): string {
|
|
180
|
-
// Match heredoc patterns like: cat <<'EOF'\n...\nEOF or <<EOF\n...\nEOF
|
|
181
|
-
const heredocMatch = input.match(/^(?:cat\s+)?<<['"]?(\w+)['"]?\s*\n([\s\S]*?)\n\1\s*$/)
|
|
182
|
-
if (heredocMatch) {
|
|
183
|
-
return heredocMatch[2]
|
|
184
|
-
}
|
|
185
|
-
return input
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export function parsePatch(patchText: string): { hunks: Hunk[] } {
|
|
189
|
-
const cleaned = stripHeredoc(patchText.trim())
|
|
190
|
-
const lines = cleaned.split("\n")
|
|
191
|
-
const hunks: Hunk[] = []
|
|
192
|
-
let i = 0
|
|
193
|
-
|
|
194
|
-
// Look for Begin/End patch markers
|
|
195
|
-
const beginMarker = "*** Begin Patch"
|
|
196
|
-
const endMarker = "*** End Patch"
|
|
197
|
-
|
|
198
|
-
const beginIdx = lines.findIndex((line) => line.trim() === beginMarker)
|
|
199
|
-
const endIdx = lines.findIndex((line) => line.trim() === endMarker)
|
|
200
|
-
|
|
201
|
-
if (beginIdx === -1 || endIdx === -1 || beginIdx >= endIdx) {
|
|
202
|
-
throw new Error("Invalid patch format: missing Begin/End markers")
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Parse content between markers
|
|
206
|
-
i = beginIdx + 1
|
|
207
|
-
|
|
208
|
-
while (i < endIdx) {
|
|
209
|
-
const header = parsePatchHeader(lines, i)
|
|
210
|
-
if (!header) {
|
|
211
|
-
i++
|
|
212
|
-
continue
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (lines[i].startsWith("*** Add File:")) {
|
|
216
|
-
const { content, nextIdx } = parseAddFileContent(lines, header.nextIdx)
|
|
217
|
-
hunks.push({
|
|
218
|
-
type: "add",
|
|
219
|
-
path: header.filePath,
|
|
220
|
-
contents: content,
|
|
221
|
-
})
|
|
222
|
-
i = nextIdx
|
|
223
|
-
} else if (lines[i].startsWith("*** Delete File:")) {
|
|
224
|
-
hunks.push({
|
|
225
|
-
type: "delete",
|
|
226
|
-
path: header.filePath,
|
|
227
|
-
})
|
|
228
|
-
i = header.nextIdx
|
|
229
|
-
} else if (lines[i].startsWith("*** Update File:")) {
|
|
230
|
-
const { chunks, nextIdx } = parseUpdateFileChunks(lines, header.nextIdx)
|
|
231
|
-
hunks.push({
|
|
232
|
-
type: "update",
|
|
233
|
-
path: header.filePath,
|
|
234
|
-
move_path: header.movePath,
|
|
235
|
-
chunks,
|
|
236
|
-
})
|
|
237
|
-
i = nextIdx
|
|
238
|
-
} else {
|
|
239
|
-
i++
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return { hunks }
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Apply patch functionality
|
|
247
|
-
export function maybeParseApplyPatch(
|
|
248
|
-
argv: string[],
|
|
249
|
-
):
|
|
250
|
-
| { type: MaybeApplyPatch.Body; args: ApplyPatchArgs }
|
|
251
|
-
| { type: MaybeApplyPatch.PatchParseError; error: Error }
|
|
252
|
-
| { type: MaybeApplyPatch.NotApplyPatch } {
|
|
253
|
-
const APPLY_PATCH_COMMANDS = ["apply_patch", "applypatch"]
|
|
254
|
-
|
|
255
|
-
// Direct invocation: apply_patch <patch>
|
|
256
|
-
if (argv.length === 2 && APPLY_PATCH_COMMANDS.includes(argv[0])) {
|
|
257
|
-
try {
|
|
258
|
-
const { hunks } = parsePatch(argv[1])
|
|
259
|
-
return {
|
|
260
|
-
type: MaybeApplyPatch.Body,
|
|
261
|
-
args: {
|
|
262
|
-
patch: argv[1],
|
|
263
|
-
hunks,
|
|
264
|
-
},
|
|
265
|
-
}
|
|
266
|
-
} catch (error) {
|
|
267
|
-
return {
|
|
268
|
-
type: MaybeApplyPatch.PatchParseError,
|
|
269
|
-
error: error as Error,
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Bash heredoc form: bash -lc 'apply_patch <<"EOF" ...'
|
|
275
|
-
if (argv.length === 3 && argv[0] === "bash" && argv[1] === "-lc") {
|
|
276
|
-
// Simple extraction - in real implementation would need proper bash parsing
|
|
277
|
-
const script = argv[2]
|
|
278
|
-
const heredocMatch = script.match(/apply_patch\s*<<['"](\w+)['"]\s*\n([\s\S]*?)\n\1/)
|
|
279
|
-
|
|
280
|
-
if (heredocMatch) {
|
|
281
|
-
const patchContent = heredocMatch[2]
|
|
282
|
-
try {
|
|
283
|
-
const { hunks } = parsePatch(patchContent)
|
|
284
|
-
return {
|
|
285
|
-
type: MaybeApplyPatch.Body,
|
|
286
|
-
args: {
|
|
287
|
-
patch: patchContent,
|
|
288
|
-
hunks,
|
|
289
|
-
},
|
|
290
|
-
}
|
|
291
|
-
} catch (error) {
|
|
292
|
-
return {
|
|
293
|
-
type: MaybeApplyPatch.PatchParseError,
|
|
294
|
-
error: error as Error,
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return { type: MaybeApplyPatch.NotApplyPatch }
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// File content manipulation
|
|
304
|
-
interface ApplyPatchFileUpdate {
|
|
305
|
-
unified_diff: string
|
|
306
|
-
content: string
|
|
307
|
-
bom: boolean
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
export function deriveNewContentsFromChunks(
|
|
311
|
-
filePath: string,
|
|
312
|
-
chunks: UpdateFileChunk[],
|
|
313
|
-
originalText: string,
|
|
314
|
-
): ApplyPatchFileUpdate {
|
|
315
|
-
const originalContent = Bom.split(originalText)
|
|
316
|
-
|
|
317
|
-
let originalLines = originalContent.text.split("\n")
|
|
318
|
-
|
|
319
|
-
// Drop trailing empty element for consistent line counting
|
|
320
|
-
if (originalLines.length > 0 && originalLines[originalLines.length - 1] === "") {
|
|
321
|
-
originalLines.pop()
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
const replacements = computeReplacements(originalLines, filePath, chunks)
|
|
325
|
-
let newLines = applyReplacements(originalLines, replacements)
|
|
326
|
-
|
|
327
|
-
// Ensure trailing newline
|
|
328
|
-
if (newLines.length === 0 || newLines[newLines.length - 1] !== "") {
|
|
329
|
-
newLines.push("")
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const next = Bom.split(newLines.join("\n"))
|
|
333
|
-
const newContent = next.text
|
|
334
|
-
|
|
335
|
-
// Generate unified diff
|
|
336
|
-
const unifiedDiff = generateUnifiedDiff(originalContent.text, newContent)
|
|
337
|
-
|
|
338
|
-
return {
|
|
339
|
-
unified_diff: unifiedDiff,
|
|
340
|
-
content: newContent,
|
|
341
|
-
bom: originalContent.bom || next.bom,
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
function computeReplacements(
|
|
346
|
-
originalLines: string[],
|
|
347
|
-
filePath: string,
|
|
348
|
-
chunks: UpdateFileChunk[],
|
|
349
|
-
): Array<[number, number, string[]]> {
|
|
350
|
-
const replacements: Array<[number, number, string[]]> = []
|
|
351
|
-
let lineIndex = 0
|
|
352
|
-
|
|
353
|
-
for (const chunk of chunks) {
|
|
354
|
-
// Handle context-based seeking
|
|
355
|
-
if (chunk.change_context) {
|
|
356
|
-
const contextIdx = seekSequence(originalLines, [chunk.change_context], lineIndex)
|
|
357
|
-
if (contextIdx === -1) {
|
|
358
|
-
throw new Error(`Failed to find context '${chunk.change_context}' in ${filePath}`)
|
|
359
|
-
}
|
|
360
|
-
lineIndex = contextIdx + 1
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// Handle pure addition (no old lines)
|
|
364
|
-
if (chunk.old_lines.length === 0) {
|
|
365
|
-
const insertionIdx =
|
|
366
|
-
originalLines.length > 0 && originalLines[originalLines.length - 1] === ""
|
|
367
|
-
? originalLines.length - 1
|
|
368
|
-
: originalLines.length
|
|
369
|
-
replacements.push([insertionIdx, 0, chunk.new_lines])
|
|
370
|
-
continue
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// Try to match old lines in the file
|
|
374
|
-
let pattern = chunk.old_lines
|
|
375
|
-
let newSlice = chunk.new_lines
|
|
376
|
-
let found = seekSequence(originalLines, pattern, lineIndex, chunk.is_end_of_file)
|
|
377
|
-
|
|
378
|
-
// Retry without trailing empty line if not found
|
|
379
|
-
if (found === -1 && pattern.length > 0 && pattern[pattern.length - 1] === "") {
|
|
380
|
-
pattern = pattern.slice(0, -1)
|
|
381
|
-
if (newSlice.length > 0 && newSlice[newSlice.length - 1] === "") {
|
|
382
|
-
newSlice = newSlice.slice(0, -1)
|
|
383
|
-
}
|
|
384
|
-
found = seekSequence(originalLines, pattern, lineIndex, chunk.is_end_of_file)
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if (found !== -1) {
|
|
388
|
-
replacements.push([found, pattern.length, newSlice])
|
|
389
|
-
lineIndex = found + pattern.length
|
|
390
|
-
} else {
|
|
391
|
-
throw new Error(`Failed to find expected lines in ${filePath}:\n${chunk.old_lines.join("\n")}`)
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// Sort replacements by index to apply in order
|
|
396
|
-
replacements.sort((a, b) => a[0] - b[0])
|
|
397
|
-
|
|
398
|
-
return replacements
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function applyReplacements(lines: string[], replacements: Array<[number, number, string[]]>): string[] {
|
|
402
|
-
// Apply replacements in reverse order to avoid index shifting
|
|
403
|
-
const result = [...lines]
|
|
404
|
-
|
|
405
|
-
for (let i = replacements.length - 1; i >= 0; i--) {
|
|
406
|
-
const [startIdx, oldLen, newSegment] = replacements[i]
|
|
407
|
-
|
|
408
|
-
// Remove old lines
|
|
409
|
-
result.splice(startIdx, oldLen)
|
|
410
|
-
|
|
411
|
-
// Insert new lines
|
|
412
|
-
for (let j = 0; j < newSegment.length; j++) {
|
|
413
|
-
result.splice(startIdx + j, 0, newSegment[j])
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
return result
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Normalize Unicode punctuation to ASCII equivalents (like Rust's normalize_unicode)
|
|
421
|
-
function normalizeUnicode(str: string): string {
|
|
422
|
-
return str
|
|
423
|
-
.replace(/[‘’‚‛]/g, "'") // single quotes
|
|
424
|
-
.replace(/[“”„‟]/g, '"') // double quotes
|
|
425
|
-
.replace(/[‐‑‒–—―]/g, "-") // dashes
|
|
426
|
-
.replace(/…/g, "...") // ellipsis
|
|
427
|
-
.replace(/ /g, " ") // non-breaking space
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
type Comparator = (a: string, b: string) => boolean
|
|
431
|
-
|
|
432
|
-
function tryMatch(lines: string[], pattern: string[], startIndex: number, compare: Comparator, eof: boolean): number {
|
|
433
|
-
// If EOF anchor, try matching from end of file first
|
|
434
|
-
if (eof) {
|
|
435
|
-
const fromEnd = lines.length - pattern.length
|
|
436
|
-
if (fromEnd >= startIndex) {
|
|
437
|
-
let matches = true
|
|
438
|
-
for (let j = 0; j < pattern.length; j++) {
|
|
439
|
-
if (!compare(lines[fromEnd + j], pattern[j])) {
|
|
440
|
-
matches = false
|
|
441
|
-
break
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
if (matches) return fromEnd
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// Forward search from startIndex
|
|
449
|
-
for (let i = startIndex; i <= lines.length - pattern.length; i++) {
|
|
450
|
-
let matches = true
|
|
451
|
-
for (let j = 0; j < pattern.length; j++) {
|
|
452
|
-
if (!compare(lines[i + j], pattern[j])) {
|
|
453
|
-
matches = false
|
|
454
|
-
break
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
if (matches) return i
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
return -1
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
function seekSequence(lines: string[], pattern: string[], startIndex: number, eof = false): number {
|
|
464
|
-
if (pattern.length === 0) return -1
|
|
465
|
-
|
|
466
|
-
// Pass 1: exact match
|
|
467
|
-
const exact = tryMatch(lines, pattern, startIndex, (a, b) => a === b, eof)
|
|
468
|
-
if (exact !== -1) return exact
|
|
469
|
-
|
|
470
|
-
// Pass 2: rstrip (trim trailing whitespace)
|
|
471
|
-
const rstrip = tryMatch(lines, pattern, startIndex, (a, b) => a.trimEnd() === b.trimEnd(), eof)
|
|
472
|
-
if (rstrip !== -1) return rstrip
|
|
473
|
-
|
|
474
|
-
// Pass 3: trim (both ends)
|
|
475
|
-
const trim = tryMatch(lines, pattern, startIndex, (a, b) => a.trim() === b.trim(), eof)
|
|
476
|
-
if (trim !== -1) return trim
|
|
477
|
-
|
|
478
|
-
// Pass 4: normalized (Unicode punctuation to ASCII)
|
|
479
|
-
const normalized = tryMatch(
|
|
480
|
-
lines,
|
|
481
|
-
pattern,
|
|
482
|
-
startIndex,
|
|
483
|
-
(a, b) => normalizeUnicode(a.trim()) === normalizeUnicode(b.trim()),
|
|
484
|
-
eof,
|
|
485
|
-
)
|
|
486
|
-
return normalized
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
function generateUnifiedDiff(oldContent: string, newContent: string): string {
|
|
490
|
-
const oldLines = oldContent.split("\n")
|
|
491
|
-
const newLines = newContent.split("\n")
|
|
492
|
-
|
|
493
|
-
// Simple diff generation - in a real implementation you'd use a proper diff algorithm
|
|
494
|
-
let diff = "@@ -1 +1 @@\n"
|
|
495
|
-
|
|
496
|
-
// Find changes (simplified approach)
|
|
497
|
-
const maxLen = Math.max(oldLines.length, newLines.length)
|
|
498
|
-
let hasChanges = false
|
|
499
|
-
|
|
500
|
-
for (let i = 0; i < maxLen; i++) {
|
|
501
|
-
const oldLine = oldLines[i] || ""
|
|
502
|
-
const newLine = newLines[i] || ""
|
|
503
|
-
|
|
504
|
-
if (oldLine !== newLine) {
|
|
505
|
-
if (oldLine) diff += `-${oldLine}\n`
|
|
506
|
-
if (newLine) diff += `+${newLine}\n`
|
|
507
|
-
hasChanges = true
|
|
508
|
-
} else if (oldLine) {
|
|
509
|
-
diff += ` ${oldLine}\n`
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
return hasChanges ? diff : ""
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// Apply hunks to filesystem
|
|
517
|
-
export const applyHunksToFiles = Effect.fn("Patch.applyHunksToFiles")(function* (hunks: Hunk[]) {
|
|
518
|
-
if (hunks.length === 0) {
|
|
519
|
-
return yield* Effect.fail(new Error("No files were modified."))
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
const fs = yield* AppFileSystem.Service
|
|
523
|
-
|
|
524
|
-
const added: string[] = []
|
|
525
|
-
const modified: string[] = []
|
|
526
|
-
const deleted: string[] = []
|
|
527
|
-
|
|
528
|
-
for (const hunk of hunks) {
|
|
529
|
-
switch (hunk.type) {
|
|
530
|
-
case "add": {
|
|
531
|
-
yield* fs.writeWithDirs(hunk.path, hunk.contents)
|
|
532
|
-
added.push(hunk.path)
|
|
533
|
-
log.info(`Added file: ${hunk.path}`)
|
|
534
|
-
break
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
case "delete": {
|
|
538
|
-
yield* fs.remove(hunk.path)
|
|
539
|
-
deleted.push(hunk.path)
|
|
540
|
-
log.info(`Deleted file: ${hunk.path}`)
|
|
541
|
-
break
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
case "update": {
|
|
545
|
-
const originalText = yield* fs.readFileString(hunk.path)
|
|
546
|
-
const fileUpdate = deriveNewContentsFromChunks(hunk.path, hunk.chunks, originalText)
|
|
547
|
-
|
|
548
|
-
if (hunk.move_path) {
|
|
549
|
-
yield* fs.writeWithDirs(hunk.move_path, Bom.join(fileUpdate.content, fileUpdate.bom))
|
|
550
|
-
yield* fs.remove(hunk.path)
|
|
551
|
-
modified.push(hunk.move_path)
|
|
552
|
-
log.info(`Moved file: ${hunk.path} -> ${hunk.move_path}`)
|
|
553
|
-
} else {
|
|
554
|
-
yield* fs.writeWithDirs(hunk.path, Bom.join(fileUpdate.content, fileUpdate.bom))
|
|
555
|
-
modified.push(hunk.path)
|
|
556
|
-
log.info(`Updated file: ${hunk.path}`)
|
|
557
|
-
}
|
|
558
|
-
break
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
return { added, modified, deleted } satisfies AffectedPaths
|
|
564
|
-
})
|
|
565
|
-
|
|
566
|
-
// Main patch application function
|
|
567
|
-
export const applyPatch = Effect.fn("Patch.applyPatch")(function* (patchText: string) {
|
|
568
|
-
const { hunks } = parsePatch(patchText)
|
|
569
|
-
return yield* applyHunksToFiles(hunks)
|
|
570
|
-
})
|
|
571
|
-
|
|
572
|
-
type MaybeApplyPatchVerifiedResult =
|
|
573
|
-
| { type: MaybeApplyPatchVerified.Body; action: ApplyPatchAction }
|
|
574
|
-
| { type: MaybeApplyPatchVerified.CorrectnessError; error: Error }
|
|
575
|
-
| { type: MaybeApplyPatchVerified.NotApplyPatch }
|
|
576
|
-
|
|
577
|
-
// Effectful verified-parse: needs AppFileSystem.Service to read existing files
|
|
578
|
-
export const maybeParseApplyPatchVerified = Effect.fn("Patch.maybeParseApplyPatchVerified")(function* (
|
|
579
|
-
argv: string[],
|
|
580
|
-
cwd: string,
|
|
581
|
-
) {
|
|
582
|
-
// Detect implicit patch invocation (raw patch without apply_patch command)
|
|
583
|
-
if (argv.length === 1) {
|
|
584
|
-
try {
|
|
585
|
-
parsePatch(argv[0])
|
|
586
|
-
return {
|
|
587
|
-
type: MaybeApplyPatchVerified.CorrectnessError,
|
|
588
|
-
error: new Error(ApplyPatchError.ImplicitInvocation),
|
|
589
|
-
} satisfies MaybeApplyPatchVerifiedResult
|
|
590
|
-
} catch {
|
|
591
|
-
// Not a patch, continue
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
const result = maybeParseApplyPatch(argv)
|
|
596
|
-
|
|
597
|
-
switch (result.type) {
|
|
598
|
-
case MaybeApplyPatch.Body: {
|
|
599
|
-
const fs = yield* AppFileSystem.Service
|
|
600
|
-
const args = result.args
|
|
601
|
-
const effectiveCwd = args.workdir ? path.resolve(cwd, args.workdir) : cwd
|
|
602
|
-
const changes = new Map<string, ApplyPatchFileChange>()
|
|
603
|
-
|
|
604
|
-
for (const hunk of args.hunks) {
|
|
605
|
-
const resolvedPath = path.resolve(
|
|
606
|
-
effectiveCwd,
|
|
607
|
-
hunk.type === "update" && hunk.move_path ? hunk.move_path : hunk.path,
|
|
608
|
-
)
|
|
609
|
-
|
|
610
|
-
switch (hunk.type) {
|
|
611
|
-
case "add":
|
|
612
|
-
changes.set(resolvedPath, {
|
|
613
|
-
type: "add",
|
|
614
|
-
content: hunk.contents,
|
|
615
|
-
})
|
|
616
|
-
break
|
|
617
|
-
|
|
618
|
-
case "delete": {
|
|
619
|
-
const deletePath = path.resolve(effectiveCwd, hunk.path)
|
|
620
|
-
const content = yield* fs.readFileString(deletePath).pipe(Effect.catch(() => Effect.succeed(undefined)))
|
|
621
|
-
if (content === undefined) {
|
|
622
|
-
return {
|
|
623
|
-
type: MaybeApplyPatchVerified.CorrectnessError,
|
|
624
|
-
error: new Error(`Failed to read file for deletion: ${deletePath}`),
|
|
625
|
-
} satisfies MaybeApplyPatchVerifiedResult
|
|
626
|
-
}
|
|
627
|
-
changes.set(resolvedPath, {
|
|
628
|
-
type: "delete",
|
|
629
|
-
content,
|
|
630
|
-
})
|
|
631
|
-
break
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
case "update": {
|
|
635
|
-
const updatePath = path.resolve(effectiveCwd, hunk.path)
|
|
636
|
-
const originalText = yield* fs
|
|
637
|
-
.readFileString(updatePath)
|
|
638
|
-
.pipe(
|
|
639
|
-
Effect.catch((cause) =>
|
|
640
|
-
Effect.succeed(new Error(`Failed to read file ${updatePath}: ${cause}`, { cause })),
|
|
641
|
-
),
|
|
642
|
-
)
|
|
643
|
-
if (originalText instanceof Error) {
|
|
644
|
-
return {
|
|
645
|
-
type: MaybeApplyPatchVerified.CorrectnessError,
|
|
646
|
-
error: originalText,
|
|
647
|
-
} satisfies MaybeApplyPatchVerifiedResult
|
|
648
|
-
}
|
|
649
|
-
try {
|
|
650
|
-
const fileUpdate = deriveNewContentsFromChunks(updatePath, hunk.chunks, originalText)
|
|
651
|
-
changes.set(resolvedPath, {
|
|
652
|
-
type: "update",
|
|
653
|
-
unified_diff: fileUpdate.unified_diff,
|
|
654
|
-
move_path: hunk.move_path ? path.resolve(effectiveCwd, hunk.move_path) : undefined,
|
|
655
|
-
new_content: fileUpdate.content,
|
|
656
|
-
})
|
|
657
|
-
} catch (error) {
|
|
658
|
-
return {
|
|
659
|
-
type: MaybeApplyPatchVerified.CorrectnessError,
|
|
660
|
-
error: error as Error,
|
|
661
|
-
} satisfies MaybeApplyPatchVerifiedResult
|
|
662
|
-
}
|
|
663
|
-
break
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
return {
|
|
669
|
-
type: MaybeApplyPatchVerified.Body,
|
|
670
|
-
action: {
|
|
671
|
-
changes,
|
|
672
|
-
patch: args.patch,
|
|
673
|
-
cwd: effectiveCwd,
|
|
674
|
-
},
|
|
675
|
-
} satisfies MaybeApplyPatchVerifiedResult
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
case MaybeApplyPatch.PatchParseError:
|
|
679
|
-
return {
|
|
680
|
-
type: MaybeApplyPatchVerified.CorrectnessError,
|
|
681
|
-
error: result.error,
|
|
682
|
-
} satisfies MaybeApplyPatchVerifiedResult
|
|
683
|
-
|
|
684
|
-
case MaybeApplyPatch.NotApplyPatch:
|
|
685
|
-
return { type: MaybeApplyPatchVerified.NotApplyPatch } satisfies MaybeApplyPatchVerifiedResult
|
|
686
|
-
}
|
|
687
|
-
})
|
|
688
|
-
|
|
689
|
-
export * as Patch from "."
|
|
1
|
+
import { Effect, Schema } from "effect"
|
|
2
|
+
import * as path from "path"
|
|
3
|
+
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
|
4
|
+
import * as Log from "@opencode-ai/core/util/log"
|
|
5
|
+
import * as Bom from "../util/bom"
|
|
6
|
+
|
|
7
|
+
const log = Log.create({ service: "patch" })
|
|
8
|
+
|
|
9
|
+
export const PatchSchema = Schema.Struct({
|
|
10
|
+
patchText: Schema.String.annotate({ description: "The full patch text that describes all changes to be made" }),
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
export type PatchParams = Schema.Schema.Type<typeof PatchSchema>
|
|
14
|
+
|
|
15
|
+
// Core types matching the Rust implementation
|
|
16
|
+
export interface ApplyPatchArgs {
|
|
17
|
+
patch: string
|
|
18
|
+
hunks: Hunk[]
|
|
19
|
+
workdir?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type Hunk =
|
|
23
|
+
| { type: "add"; path: string; contents: string }
|
|
24
|
+
| { type: "delete"; path: string }
|
|
25
|
+
| { type: "update"; path: string; move_path?: string; chunks: UpdateFileChunk[] }
|
|
26
|
+
|
|
27
|
+
export interface UpdateFileChunk {
|
|
28
|
+
old_lines: string[]
|
|
29
|
+
new_lines: string[]
|
|
30
|
+
change_context?: string
|
|
31
|
+
is_end_of_file?: boolean
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ApplyPatchAction {
|
|
35
|
+
changes: Map<string, ApplyPatchFileChange>
|
|
36
|
+
patch: string
|
|
37
|
+
cwd: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type ApplyPatchFileChange =
|
|
41
|
+
| { type: "add"; content: string }
|
|
42
|
+
| { type: "delete"; content: string }
|
|
43
|
+
| { type: "update"; unified_diff: string; move_path?: string; new_content: string }
|
|
44
|
+
|
|
45
|
+
export interface AffectedPaths {
|
|
46
|
+
added: string[]
|
|
47
|
+
modified: string[]
|
|
48
|
+
deleted: string[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export enum ApplyPatchError {
|
|
52
|
+
ParseError = "ParseError",
|
|
53
|
+
IoError = "IoError",
|
|
54
|
+
ComputeReplacements = "ComputeReplacements",
|
|
55
|
+
ImplicitInvocation = "ImplicitInvocation",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export enum MaybeApplyPatch {
|
|
59
|
+
Body = "Body",
|
|
60
|
+
ShellParseError = "ShellParseError",
|
|
61
|
+
PatchParseError = "PatchParseError",
|
|
62
|
+
NotApplyPatch = "NotApplyPatch",
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export enum MaybeApplyPatchVerified {
|
|
66
|
+
Body = "Body",
|
|
67
|
+
ShellParseError = "ShellParseError",
|
|
68
|
+
CorrectnessError = "CorrectnessError",
|
|
69
|
+
NotApplyPatch = "NotApplyPatch",
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Parser implementation
|
|
73
|
+
function parsePatchHeader(
|
|
74
|
+
lines: string[],
|
|
75
|
+
startIdx: number,
|
|
76
|
+
): { filePath: string; movePath?: string; nextIdx: number } | null {
|
|
77
|
+
const line = lines[startIdx]
|
|
78
|
+
|
|
79
|
+
if (line.startsWith("*** Add File:")) {
|
|
80
|
+
const filePath = line.slice("*** Add File:".length).trim()
|
|
81
|
+
return filePath ? { filePath, nextIdx: startIdx + 1 } : null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (line.startsWith("*** Delete File:")) {
|
|
85
|
+
const filePath = line.slice("*** Delete File:".length).trim()
|
|
86
|
+
return filePath ? { filePath, nextIdx: startIdx + 1 } : null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (line.startsWith("*** Update File:")) {
|
|
90
|
+
const filePath = line.slice("*** Update File:".length).trim()
|
|
91
|
+
let movePath: string | undefined
|
|
92
|
+
let nextIdx = startIdx + 1
|
|
93
|
+
|
|
94
|
+
// Check for move directive
|
|
95
|
+
if (nextIdx < lines.length && lines[nextIdx].startsWith("*** Move to:")) {
|
|
96
|
+
movePath = lines[nextIdx].slice("*** Move to:".length).trim()
|
|
97
|
+
nextIdx++
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return filePath ? { filePath, movePath, nextIdx } : null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return null
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function parseUpdateFileChunks(lines: string[], startIdx: number): { chunks: UpdateFileChunk[]; nextIdx: number } {
|
|
107
|
+
const chunks: UpdateFileChunk[] = []
|
|
108
|
+
let i = startIdx
|
|
109
|
+
|
|
110
|
+
while (i < lines.length && !lines[i].startsWith("***")) {
|
|
111
|
+
if (lines[i].startsWith("@@")) {
|
|
112
|
+
// Parse context line
|
|
113
|
+
const contextLine = lines[i].substring(2).trim()
|
|
114
|
+
i++
|
|
115
|
+
|
|
116
|
+
const oldLines: string[] = []
|
|
117
|
+
const newLines: string[] = []
|
|
118
|
+
let isEndOfFile = false
|
|
119
|
+
|
|
120
|
+
// Parse change lines
|
|
121
|
+
while (i < lines.length && !lines[i].startsWith("@@") && !lines[i].startsWith("***")) {
|
|
122
|
+
const changeLine = lines[i]
|
|
123
|
+
|
|
124
|
+
if (changeLine === "*** End of File") {
|
|
125
|
+
isEndOfFile = true
|
|
126
|
+
i++
|
|
127
|
+
break
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (changeLine.startsWith(" ")) {
|
|
131
|
+
// Keep line - appears in both old and new
|
|
132
|
+
const content = changeLine.substring(1)
|
|
133
|
+
oldLines.push(content)
|
|
134
|
+
newLines.push(content)
|
|
135
|
+
} else if (changeLine.startsWith("-")) {
|
|
136
|
+
// Remove line - only in old
|
|
137
|
+
oldLines.push(changeLine.substring(1))
|
|
138
|
+
} else if (changeLine.startsWith("+")) {
|
|
139
|
+
// Add line - only in new
|
|
140
|
+
newLines.push(changeLine.substring(1))
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
i++
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
chunks.push({
|
|
147
|
+
old_lines: oldLines,
|
|
148
|
+
new_lines: newLines,
|
|
149
|
+
change_context: contextLine || undefined,
|
|
150
|
+
is_end_of_file: isEndOfFile || undefined,
|
|
151
|
+
})
|
|
152
|
+
} else {
|
|
153
|
+
i++
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return { chunks, nextIdx: i }
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function parseAddFileContent(lines: string[], startIdx: number): { content: string; nextIdx: number } {
|
|
161
|
+
let content = ""
|
|
162
|
+
let i = startIdx
|
|
163
|
+
|
|
164
|
+
while (i < lines.length && !lines[i].startsWith("***")) {
|
|
165
|
+
if (lines[i].startsWith("+")) {
|
|
166
|
+
content += lines[i].substring(1) + "\n"
|
|
167
|
+
}
|
|
168
|
+
i++
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Remove trailing newline
|
|
172
|
+
if (content.endsWith("\n")) {
|
|
173
|
+
content = content.slice(0, -1)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return { content, nextIdx: i }
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function stripHeredoc(input: string): string {
|
|
180
|
+
// Match heredoc patterns like: cat <<'EOF'\n...\nEOF or <<EOF\n...\nEOF
|
|
181
|
+
const heredocMatch = input.match(/^(?:cat\s+)?<<['"]?(\w+)['"]?\s*\n([\s\S]*?)\n\1\s*$/)
|
|
182
|
+
if (heredocMatch) {
|
|
183
|
+
return heredocMatch[2]
|
|
184
|
+
}
|
|
185
|
+
return input
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function parsePatch(patchText: string): { hunks: Hunk[] } {
|
|
189
|
+
const cleaned = stripHeredoc(patchText.trim())
|
|
190
|
+
const lines = cleaned.split("\n")
|
|
191
|
+
const hunks: Hunk[] = []
|
|
192
|
+
let i = 0
|
|
193
|
+
|
|
194
|
+
// Look for Begin/End patch markers
|
|
195
|
+
const beginMarker = "*** Begin Patch"
|
|
196
|
+
const endMarker = "*** End Patch"
|
|
197
|
+
|
|
198
|
+
const beginIdx = lines.findIndex((line) => line.trim() === beginMarker)
|
|
199
|
+
const endIdx = lines.findIndex((line) => line.trim() === endMarker)
|
|
200
|
+
|
|
201
|
+
if (beginIdx === -1 || endIdx === -1 || beginIdx >= endIdx) {
|
|
202
|
+
throw new Error("Invalid patch format: missing Begin/End markers")
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Parse content between markers
|
|
206
|
+
i = beginIdx + 1
|
|
207
|
+
|
|
208
|
+
while (i < endIdx) {
|
|
209
|
+
const header = parsePatchHeader(lines, i)
|
|
210
|
+
if (!header) {
|
|
211
|
+
i++
|
|
212
|
+
continue
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (lines[i].startsWith("*** Add File:")) {
|
|
216
|
+
const { content, nextIdx } = parseAddFileContent(lines, header.nextIdx)
|
|
217
|
+
hunks.push({
|
|
218
|
+
type: "add",
|
|
219
|
+
path: header.filePath,
|
|
220
|
+
contents: content,
|
|
221
|
+
})
|
|
222
|
+
i = nextIdx
|
|
223
|
+
} else if (lines[i].startsWith("*** Delete File:")) {
|
|
224
|
+
hunks.push({
|
|
225
|
+
type: "delete",
|
|
226
|
+
path: header.filePath,
|
|
227
|
+
})
|
|
228
|
+
i = header.nextIdx
|
|
229
|
+
} else if (lines[i].startsWith("*** Update File:")) {
|
|
230
|
+
const { chunks, nextIdx } = parseUpdateFileChunks(lines, header.nextIdx)
|
|
231
|
+
hunks.push({
|
|
232
|
+
type: "update",
|
|
233
|
+
path: header.filePath,
|
|
234
|
+
move_path: header.movePath,
|
|
235
|
+
chunks,
|
|
236
|
+
})
|
|
237
|
+
i = nextIdx
|
|
238
|
+
} else {
|
|
239
|
+
i++
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return { hunks }
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Apply patch functionality
|
|
247
|
+
export function maybeParseApplyPatch(
|
|
248
|
+
argv: string[],
|
|
249
|
+
):
|
|
250
|
+
| { type: MaybeApplyPatch.Body; args: ApplyPatchArgs }
|
|
251
|
+
| { type: MaybeApplyPatch.PatchParseError; error: Error }
|
|
252
|
+
| { type: MaybeApplyPatch.NotApplyPatch } {
|
|
253
|
+
const APPLY_PATCH_COMMANDS = ["apply_patch", "applypatch"]
|
|
254
|
+
|
|
255
|
+
// Direct invocation: apply_patch <patch>
|
|
256
|
+
if (argv.length === 2 && APPLY_PATCH_COMMANDS.includes(argv[0])) {
|
|
257
|
+
try {
|
|
258
|
+
const { hunks } = parsePatch(argv[1])
|
|
259
|
+
return {
|
|
260
|
+
type: MaybeApplyPatch.Body,
|
|
261
|
+
args: {
|
|
262
|
+
patch: argv[1],
|
|
263
|
+
hunks,
|
|
264
|
+
},
|
|
265
|
+
}
|
|
266
|
+
} catch (error) {
|
|
267
|
+
return {
|
|
268
|
+
type: MaybeApplyPatch.PatchParseError,
|
|
269
|
+
error: error as Error,
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Bash heredoc form: bash -lc 'apply_patch <<"EOF" ...'
|
|
275
|
+
if (argv.length === 3 && argv[0] === "bash" && argv[1] === "-lc") {
|
|
276
|
+
// Simple extraction - in real implementation would need proper bash parsing
|
|
277
|
+
const script = argv[2]
|
|
278
|
+
const heredocMatch = script.match(/apply_patch\s*<<['"](\w+)['"]\s*\n([\s\S]*?)\n\1/)
|
|
279
|
+
|
|
280
|
+
if (heredocMatch) {
|
|
281
|
+
const patchContent = heredocMatch[2]
|
|
282
|
+
try {
|
|
283
|
+
const { hunks } = parsePatch(patchContent)
|
|
284
|
+
return {
|
|
285
|
+
type: MaybeApplyPatch.Body,
|
|
286
|
+
args: {
|
|
287
|
+
patch: patchContent,
|
|
288
|
+
hunks,
|
|
289
|
+
},
|
|
290
|
+
}
|
|
291
|
+
} catch (error) {
|
|
292
|
+
return {
|
|
293
|
+
type: MaybeApplyPatch.PatchParseError,
|
|
294
|
+
error: error as Error,
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return { type: MaybeApplyPatch.NotApplyPatch }
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// File content manipulation
|
|
304
|
+
interface ApplyPatchFileUpdate {
|
|
305
|
+
unified_diff: string
|
|
306
|
+
content: string
|
|
307
|
+
bom: boolean
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function deriveNewContentsFromChunks(
|
|
311
|
+
filePath: string,
|
|
312
|
+
chunks: UpdateFileChunk[],
|
|
313
|
+
originalText: string,
|
|
314
|
+
): ApplyPatchFileUpdate {
|
|
315
|
+
const originalContent = Bom.split(originalText)
|
|
316
|
+
|
|
317
|
+
let originalLines = originalContent.text.split("\n")
|
|
318
|
+
|
|
319
|
+
// Drop trailing empty element for consistent line counting
|
|
320
|
+
if (originalLines.length > 0 && originalLines[originalLines.length - 1] === "") {
|
|
321
|
+
originalLines.pop()
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const replacements = computeReplacements(originalLines, filePath, chunks)
|
|
325
|
+
let newLines = applyReplacements(originalLines, replacements)
|
|
326
|
+
|
|
327
|
+
// Ensure trailing newline
|
|
328
|
+
if (newLines.length === 0 || newLines[newLines.length - 1] !== "") {
|
|
329
|
+
newLines.push("")
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const next = Bom.split(newLines.join("\n"))
|
|
333
|
+
const newContent = next.text
|
|
334
|
+
|
|
335
|
+
// Generate unified diff
|
|
336
|
+
const unifiedDiff = generateUnifiedDiff(originalContent.text, newContent)
|
|
337
|
+
|
|
338
|
+
return {
|
|
339
|
+
unified_diff: unifiedDiff,
|
|
340
|
+
content: newContent,
|
|
341
|
+
bom: originalContent.bom || next.bom,
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function computeReplacements(
|
|
346
|
+
originalLines: string[],
|
|
347
|
+
filePath: string,
|
|
348
|
+
chunks: UpdateFileChunk[],
|
|
349
|
+
): Array<[number, number, string[]]> {
|
|
350
|
+
const replacements: Array<[number, number, string[]]> = []
|
|
351
|
+
let lineIndex = 0
|
|
352
|
+
|
|
353
|
+
for (const chunk of chunks) {
|
|
354
|
+
// Handle context-based seeking
|
|
355
|
+
if (chunk.change_context) {
|
|
356
|
+
const contextIdx = seekSequence(originalLines, [chunk.change_context], lineIndex)
|
|
357
|
+
if (contextIdx === -1) {
|
|
358
|
+
throw new Error(`Failed to find context '${chunk.change_context}' in ${filePath}`)
|
|
359
|
+
}
|
|
360
|
+
lineIndex = contextIdx + 1
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Handle pure addition (no old lines)
|
|
364
|
+
if (chunk.old_lines.length === 0) {
|
|
365
|
+
const insertionIdx =
|
|
366
|
+
originalLines.length > 0 && originalLines[originalLines.length - 1] === ""
|
|
367
|
+
? originalLines.length - 1
|
|
368
|
+
: originalLines.length
|
|
369
|
+
replacements.push([insertionIdx, 0, chunk.new_lines])
|
|
370
|
+
continue
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Try to match old lines in the file
|
|
374
|
+
let pattern = chunk.old_lines
|
|
375
|
+
let newSlice = chunk.new_lines
|
|
376
|
+
let found = seekSequence(originalLines, pattern, lineIndex, chunk.is_end_of_file)
|
|
377
|
+
|
|
378
|
+
// Retry without trailing empty line if not found
|
|
379
|
+
if (found === -1 && pattern.length > 0 && pattern[pattern.length - 1] === "") {
|
|
380
|
+
pattern = pattern.slice(0, -1)
|
|
381
|
+
if (newSlice.length > 0 && newSlice[newSlice.length - 1] === "") {
|
|
382
|
+
newSlice = newSlice.slice(0, -1)
|
|
383
|
+
}
|
|
384
|
+
found = seekSequence(originalLines, pattern, lineIndex, chunk.is_end_of_file)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (found !== -1) {
|
|
388
|
+
replacements.push([found, pattern.length, newSlice])
|
|
389
|
+
lineIndex = found + pattern.length
|
|
390
|
+
} else {
|
|
391
|
+
throw new Error(`Failed to find expected lines in ${filePath}:\n${chunk.old_lines.join("\n")}`)
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Sort replacements by index to apply in order
|
|
396
|
+
replacements.sort((a, b) => a[0] - b[0])
|
|
397
|
+
|
|
398
|
+
return replacements
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function applyReplacements(lines: string[], replacements: Array<[number, number, string[]]>): string[] {
|
|
402
|
+
// Apply replacements in reverse order to avoid index shifting
|
|
403
|
+
const result = [...lines]
|
|
404
|
+
|
|
405
|
+
for (let i = replacements.length - 1; i >= 0; i--) {
|
|
406
|
+
const [startIdx, oldLen, newSegment] = replacements[i]
|
|
407
|
+
|
|
408
|
+
// Remove old lines
|
|
409
|
+
result.splice(startIdx, oldLen)
|
|
410
|
+
|
|
411
|
+
// Insert new lines
|
|
412
|
+
for (let j = 0; j < newSegment.length; j++) {
|
|
413
|
+
result.splice(startIdx + j, 0, newSegment[j])
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return result
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Normalize Unicode punctuation to ASCII equivalents (like Rust's normalize_unicode)
|
|
421
|
+
function normalizeUnicode(str: string): string {
|
|
422
|
+
return str
|
|
423
|
+
.replace(/[‘’‚‛]/g, "'") // single quotes
|
|
424
|
+
.replace(/[“”„‟]/g, '"') // double quotes
|
|
425
|
+
.replace(/[‐‑‒–—―]/g, "-") // dashes
|
|
426
|
+
.replace(/…/g, "...") // ellipsis
|
|
427
|
+
.replace(/ /g, " ") // non-breaking space
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
type Comparator = (a: string, b: string) => boolean
|
|
431
|
+
|
|
432
|
+
function tryMatch(lines: string[], pattern: string[], startIndex: number, compare: Comparator, eof: boolean): number {
|
|
433
|
+
// If EOF anchor, try matching from end of file first
|
|
434
|
+
if (eof) {
|
|
435
|
+
const fromEnd = lines.length - pattern.length
|
|
436
|
+
if (fromEnd >= startIndex) {
|
|
437
|
+
let matches = true
|
|
438
|
+
for (let j = 0; j < pattern.length; j++) {
|
|
439
|
+
if (!compare(lines[fromEnd + j], pattern[j])) {
|
|
440
|
+
matches = false
|
|
441
|
+
break
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
if (matches) return fromEnd
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Forward search from startIndex
|
|
449
|
+
for (let i = startIndex; i <= lines.length - pattern.length; i++) {
|
|
450
|
+
let matches = true
|
|
451
|
+
for (let j = 0; j < pattern.length; j++) {
|
|
452
|
+
if (!compare(lines[i + j], pattern[j])) {
|
|
453
|
+
matches = false
|
|
454
|
+
break
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if (matches) return i
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return -1
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function seekSequence(lines: string[], pattern: string[], startIndex: number, eof = false): number {
|
|
464
|
+
if (pattern.length === 0) return -1
|
|
465
|
+
|
|
466
|
+
// Pass 1: exact match
|
|
467
|
+
const exact = tryMatch(lines, pattern, startIndex, (a, b) => a === b, eof)
|
|
468
|
+
if (exact !== -1) return exact
|
|
469
|
+
|
|
470
|
+
// Pass 2: rstrip (trim trailing whitespace)
|
|
471
|
+
const rstrip = tryMatch(lines, pattern, startIndex, (a, b) => a.trimEnd() === b.trimEnd(), eof)
|
|
472
|
+
if (rstrip !== -1) return rstrip
|
|
473
|
+
|
|
474
|
+
// Pass 3: trim (both ends)
|
|
475
|
+
const trim = tryMatch(lines, pattern, startIndex, (a, b) => a.trim() === b.trim(), eof)
|
|
476
|
+
if (trim !== -1) return trim
|
|
477
|
+
|
|
478
|
+
// Pass 4: normalized (Unicode punctuation to ASCII)
|
|
479
|
+
const normalized = tryMatch(
|
|
480
|
+
lines,
|
|
481
|
+
pattern,
|
|
482
|
+
startIndex,
|
|
483
|
+
(a, b) => normalizeUnicode(a.trim()) === normalizeUnicode(b.trim()),
|
|
484
|
+
eof,
|
|
485
|
+
)
|
|
486
|
+
return normalized
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function generateUnifiedDiff(oldContent: string, newContent: string): string {
|
|
490
|
+
const oldLines = oldContent.split("\n")
|
|
491
|
+
const newLines = newContent.split("\n")
|
|
492
|
+
|
|
493
|
+
// Simple diff generation - in a real implementation you'd use a proper diff algorithm
|
|
494
|
+
let diff = "@@ -1 +1 @@\n"
|
|
495
|
+
|
|
496
|
+
// Find changes (simplified approach)
|
|
497
|
+
const maxLen = Math.max(oldLines.length, newLines.length)
|
|
498
|
+
let hasChanges = false
|
|
499
|
+
|
|
500
|
+
for (let i = 0; i < maxLen; i++) {
|
|
501
|
+
const oldLine = oldLines[i] || ""
|
|
502
|
+
const newLine = newLines[i] || ""
|
|
503
|
+
|
|
504
|
+
if (oldLine !== newLine) {
|
|
505
|
+
if (oldLine) diff += `-${oldLine}\n`
|
|
506
|
+
if (newLine) diff += `+${newLine}\n`
|
|
507
|
+
hasChanges = true
|
|
508
|
+
} else if (oldLine) {
|
|
509
|
+
diff += ` ${oldLine}\n`
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return hasChanges ? diff : ""
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Apply hunks to filesystem
|
|
517
|
+
export const applyHunksToFiles = Effect.fn("Patch.applyHunksToFiles")(function* (hunks: Hunk[]) {
|
|
518
|
+
if (hunks.length === 0) {
|
|
519
|
+
return yield* Effect.fail(new Error("No files were modified."))
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const fs = yield* AppFileSystem.Service
|
|
523
|
+
|
|
524
|
+
const added: string[] = []
|
|
525
|
+
const modified: string[] = []
|
|
526
|
+
const deleted: string[] = []
|
|
527
|
+
|
|
528
|
+
for (const hunk of hunks) {
|
|
529
|
+
switch (hunk.type) {
|
|
530
|
+
case "add": {
|
|
531
|
+
yield* fs.writeWithDirs(hunk.path, hunk.contents)
|
|
532
|
+
added.push(hunk.path)
|
|
533
|
+
log.info(`Added file: ${hunk.path}`)
|
|
534
|
+
break
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
case "delete": {
|
|
538
|
+
yield* fs.remove(hunk.path)
|
|
539
|
+
deleted.push(hunk.path)
|
|
540
|
+
log.info(`Deleted file: ${hunk.path}`)
|
|
541
|
+
break
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
case "update": {
|
|
545
|
+
const originalText = yield* fs.readFileString(hunk.path)
|
|
546
|
+
const fileUpdate = deriveNewContentsFromChunks(hunk.path, hunk.chunks, originalText)
|
|
547
|
+
|
|
548
|
+
if (hunk.move_path) {
|
|
549
|
+
yield* fs.writeWithDirs(hunk.move_path, Bom.join(fileUpdate.content, fileUpdate.bom))
|
|
550
|
+
yield* fs.remove(hunk.path)
|
|
551
|
+
modified.push(hunk.move_path)
|
|
552
|
+
log.info(`Moved file: ${hunk.path} -> ${hunk.move_path}`)
|
|
553
|
+
} else {
|
|
554
|
+
yield* fs.writeWithDirs(hunk.path, Bom.join(fileUpdate.content, fileUpdate.bom))
|
|
555
|
+
modified.push(hunk.path)
|
|
556
|
+
log.info(`Updated file: ${hunk.path}`)
|
|
557
|
+
}
|
|
558
|
+
break
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
return { added, modified, deleted } satisfies AffectedPaths
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
// Main patch application function
|
|
567
|
+
export const applyPatch = Effect.fn("Patch.applyPatch")(function* (patchText: string) {
|
|
568
|
+
const { hunks } = parsePatch(patchText)
|
|
569
|
+
return yield* applyHunksToFiles(hunks)
|
|
570
|
+
})
|
|
571
|
+
|
|
572
|
+
type MaybeApplyPatchVerifiedResult =
|
|
573
|
+
| { type: MaybeApplyPatchVerified.Body; action: ApplyPatchAction }
|
|
574
|
+
| { type: MaybeApplyPatchVerified.CorrectnessError; error: Error }
|
|
575
|
+
| { type: MaybeApplyPatchVerified.NotApplyPatch }
|
|
576
|
+
|
|
577
|
+
// Effectful verified-parse: needs AppFileSystem.Service to read existing files
|
|
578
|
+
export const maybeParseApplyPatchVerified = Effect.fn("Patch.maybeParseApplyPatchVerified")(function* (
|
|
579
|
+
argv: string[],
|
|
580
|
+
cwd: string,
|
|
581
|
+
) {
|
|
582
|
+
// Detect implicit patch invocation (raw patch without apply_patch command)
|
|
583
|
+
if (argv.length === 1) {
|
|
584
|
+
try {
|
|
585
|
+
parsePatch(argv[0])
|
|
586
|
+
return {
|
|
587
|
+
type: MaybeApplyPatchVerified.CorrectnessError,
|
|
588
|
+
error: new Error(ApplyPatchError.ImplicitInvocation),
|
|
589
|
+
} satisfies MaybeApplyPatchVerifiedResult
|
|
590
|
+
} catch {
|
|
591
|
+
// Not a patch, continue
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const result = maybeParseApplyPatch(argv)
|
|
596
|
+
|
|
597
|
+
switch (result.type) {
|
|
598
|
+
case MaybeApplyPatch.Body: {
|
|
599
|
+
const fs = yield* AppFileSystem.Service
|
|
600
|
+
const args = result.args
|
|
601
|
+
const effectiveCwd = args.workdir ? path.resolve(cwd, args.workdir) : cwd
|
|
602
|
+
const changes = new Map<string, ApplyPatchFileChange>()
|
|
603
|
+
|
|
604
|
+
for (const hunk of args.hunks) {
|
|
605
|
+
const resolvedPath = path.resolve(
|
|
606
|
+
effectiveCwd,
|
|
607
|
+
hunk.type === "update" && hunk.move_path ? hunk.move_path : hunk.path,
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
switch (hunk.type) {
|
|
611
|
+
case "add":
|
|
612
|
+
changes.set(resolvedPath, {
|
|
613
|
+
type: "add",
|
|
614
|
+
content: hunk.contents,
|
|
615
|
+
})
|
|
616
|
+
break
|
|
617
|
+
|
|
618
|
+
case "delete": {
|
|
619
|
+
const deletePath = path.resolve(effectiveCwd, hunk.path)
|
|
620
|
+
const content = yield* fs.readFileString(deletePath).pipe(Effect.catch(() => Effect.succeed(undefined)))
|
|
621
|
+
if (content === undefined) {
|
|
622
|
+
return {
|
|
623
|
+
type: MaybeApplyPatchVerified.CorrectnessError,
|
|
624
|
+
error: new Error(`Failed to read file for deletion: ${deletePath}`),
|
|
625
|
+
} satisfies MaybeApplyPatchVerifiedResult
|
|
626
|
+
}
|
|
627
|
+
changes.set(resolvedPath, {
|
|
628
|
+
type: "delete",
|
|
629
|
+
content,
|
|
630
|
+
})
|
|
631
|
+
break
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
case "update": {
|
|
635
|
+
const updatePath = path.resolve(effectiveCwd, hunk.path)
|
|
636
|
+
const originalText = yield* fs
|
|
637
|
+
.readFileString(updatePath)
|
|
638
|
+
.pipe(
|
|
639
|
+
Effect.catch((cause) =>
|
|
640
|
+
Effect.succeed(new Error(`Failed to read file ${updatePath}: ${cause}`, { cause })),
|
|
641
|
+
),
|
|
642
|
+
)
|
|
643
|
+
if (originalText instanceof Error) {
|
|
644
|
+
return {
|
|
645
|
+
type: MaybeApplyPatchVerified.CorrectnessError,
|
|
646
|
+
error: originalText,
|
|
647
|
+
} satisfies MaybeApplyPatchVerifiedResult
|
|
648
|
+
}
|
|
649
|
+
try {
|
|
650
|
+
const fileUpdate = deriveNewContentsFromChunks(updatePath, hunk.chunks, originalText)
|
|
651
|
+
changes.set(resolvedPath, {
|
|
652
|
+
type: "update",
|
|
653
|
+
unified_diff: fileUpdate.unified_diff,
|
|
654
|
+
move_path: hunk.move_path ? path.resolve(effectiveCwd, hunk.move_path) : undefined,
|
|
655
|
+
new_content: fileUpdate.content,
|
|
656
|
+
})
|
|
657
|
+
} catch (error) {
|
|
658
|
+
return {
|
|
659
|
+
type: MaybeApplyPatchVerified.CorrectnessError,
|
|
660
|
+
error: error as Error,
|
|
661
|
+
} satisfies MaybeApplyPatchVerifiedResult
|
|
662
|
+
}
|
|
663
|
+
break
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return {
|
|
669
|
+
type: MaybeApplyPatchVerified.Body,
|
|
670
|
+
action: {
|
|
671
|
+
changes,
|
|
672
|
+
patch: args.patch,
|
|
673
|
+
cwd: effectiveCwd,
|
|
674
|
+
},
|
|
675
|
+
} satisfies MaybeApplyPatchVerifiedResult
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
case MaybeApplyPatch.PatchParseError:
|
|
679
|
+
return {
|
|
680
|
+
type: MaybeApplyPatchVerified.CorrectnessError,
|
|
681
|
+
error: result.error,
|
|
682
|
+
} satisfies MaybeApplyPatchVerifiedResult
|
|
683
|
+
|
|
684
|
+
case MaybeApplyPatch.NotApplyPatch:
|
|
685
|
+
return { type: MaybeApplyPatchVerified.NotApplyPatch } satisfies MaybeApplyPatchVerifiedResult
|
|
686
|
+
}
|
|
687
|
+
})
|
|
688
|
+
|
|
689
|
+
export * as Patch from "."
|