@desplega.ai/agent-swarm 1.158.0 → 1.160.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/README.md +1 -1
- package/dist/{acp-adapter-xaq4n6pc.js → acp-adapter-2mjwcsfh.js} +124 -27
- package/dist/{actions-p9hz5yat.js → actions-e43rxskr.js} +35 -30
- package/dist/{anthropic-messages-51pz26qe.js → anthropic-messages-5qx80j9k.js} +106 -16
- package/dist/{app-g26wdcz6.js → app-mc7xfagn.js} +12 -10
- package/dist/{assistant-wydfqkb3.js → assistant-sedkzv3b.js} +42 -31
- package/dist/{azure-openai-responses-8gksqtmz.js → azure-openai-responses-nfb21z9a.js} +13 -14
- package/dist/{boot-reembed-se8zmdcp.js → boot-reembed-cqz9swn5.js} +13 -12
- package/dist/{boot-reembed-g5ckg9yb.js → boot-reembed-m3656j2n.js} +14 -13
- package/dist/{boot-scrub-logs-wfxqan61.js → boot-scrub-logs-xbxf5d7w.js} +11 -9
- package/dist/boot-seeds-gsetbs5y.js +28 -0
- package/dist/{claude-adapter-tv2x4f36.js → claude-adapter-dc6289mc.js} +28 -23
- package/dist/{claude-managed-adapter-41b2s7fd.js → claude-managed-adapter-naaw51me.js} +4 -3
- package/dist/{claude-managed-setup-60g8aazx.js → claude-managed-setup-eacvchx0.js} +12 -3
- package/dist/claude-sdk-session-bqp2xvym.js +29722 -0
- package/dist/{cli-987hg0aa.js → cli-0jwe9034.js} +2 -2
- package/dist/{cli-vj6h9kc2.js → cli-0m7wct0d.js} +59 -1
- package/dist/{cli-c07r9a2m.js → cli-0q3avq3s.js} +12 -11
- package/dist/{cli-19jenss3.js → cli-0wgxmwf6.js} +31 -10
- package/dist/cli-0x01kwrd.js +491 -0
- package/dist/cli-0xqde53b.js +176 -0
- package/dist/cli-10nhj6xq.js +8355 -0
- package/dist/{cli-tt9k8r35.js → cli-12tszpk9.js} +479 -910
- package/dist/{cli-5b6b62tz.js → cli-13hw4z91.js} +1 -1
- package/dist/{cli-cqt19wg6.js → cli-1a2j50m0.js} +11 -2
- package/dist/{cli-xberxa1r.js → cli-25fcq4b4.js} +2 -2
- package/dist/{cli-npssxgaz.js → cli-2pdaysab.js} +52 -2
- package/dist/cli-3qhyh31j.js +166 -0
- package/dist/cli-447dt1h3.js +3828 -0
- package/dist/cli-4derpgyk.js +115 -0
- package/dist/{cli-00w2c66p.js → cli-523679eh.js} +13 -2
- package/dist/{cli-y95wp3tg.js → cli-58e8yr0d.js} +1 -1
- package/dist/{cli-24k806sc.js → cli-5nbmpy8w.js} +3 -3
- package/dist/{cli-53sz8gkz.js → cli-6cs6wzxt.js} +1 -1
- package/dist/cli-741yb0xx.js +1027 -0
- package/dist/cli-74h9hscv.js +69 -0
- package/dist/cli-7cxw8b60.js +14910 -0
- package/dist/{cli-xhaeg2nc.js → cli-7e398j1h.js} +1 -1
- package/dist/cli-7kyk9jr3.js +22 -0
- package/dist/cli-89s4ngw3.js +183 -0
- package/dist/{cli-9b13ggd1.js → cli-89v6kyq7.js} +1 -0
- package/dist/{cli-ftfvggzx.js → cli-9hsgwz4w.js} +1045 -581
- package/dist/{cli-rqz8qbw7.js → cli-a8dvhzrt.js} +59 -20
- package/dist/{cli-j57qkrpq.js → cli-azhgzetg.js} +395 -56
- package/dist/cli-br0qdrnp.js +2150 -0
- package/dist/{cli-rj19hc34.js → cli-btfv8y88.js} +1 -1
- package/dist/{cli-8qmme6vd.js → cli-c8a36vcc.js} +2 -2
- package/dist/cli-cpvsaqsw.js +333 -0
- package/dist/cli-d5czme6m.js +17805 -0
- package/dist/{cli-h38x0qhg.js → cli-et8m9xsv.js} +4 -3
- package/dist/{cli-x24pshtq.js → cli-evvtk35y.js} +6 -6
- package/dist/{cli-7s3syk22.js → cli-f8gy6r2r.js} +5 -5
- package/dist/{cli-zt1227k1.js → cli-fkqhbg8g.js} +5 -3
- package/dist/{cli-9httdpyq.js → cli-g2whhdrf.js} +1 -1
- package/dist/cli-gt4hxb8p.js +99 -0
- package/dist/{cli-s8eet254.js → cli-jajnsm8q.js} +37184 -53838
- package/dist/{cli-7gtvvpbh.js → cli-jayjpjmb.js} +21 -12
- package/dist/{cli-68w09sjw.js → cli-jyk0ynw2.js} +27 -89
- package/dist/{cli-aehm1rbq.js → cli-jz4w45qt.js} +1152 -61
- package/dist/cli-kmcpfwn2.js +333856 -0
- package/dist/{cli-4198qc9v.js → cli-ktmyrtpn.js} +19 -3
- package/dist/{cli-j55n64b6.js → cli-mfe5btp9.js} +505 -189
- package/dist/{cli-q67y4wzm.js → cli-phsaj4xq.js} +24 -2
- package/dist/{cli-1hkrch3k.js → cli-pm1rst0h.js} +46 -7
- package/dist/{cli-pw9rj5t9.js → cli-pqetb83f.js} +1 -176
- package/dist/{cli-ggm92wcn.js → cli-ptr8h7kp.js} +20 -1
- package/dist/{cli-s8s499xy.js → cli-qbksc292.js} +3 -2
- package/dist/{cli-47m6dkd3.js → cli-qydf22qq.js} +597 -346
- package/dist/{cli-3gmcwfyx.js → cli-r1mxd1xh.js} +13 -6
- package/dist/cli-rb9m6rpe.js +4980 -0
- package/dist/cli-rykfmgwg.js +102 -0
- package/dist/{cli-5d10vd2m.js → cli-shkxm1vn.js} +6 -5
- package/dist/{cli-eetrvv91.js → cli-t3p77qk1.js} +1 -1
- package/dist/cli-tfky2838.js +756 -0
- package/dist/{cli-g8djp6qe.js → cli-tmqt7dpj.js} +40 -0
- package/dist/{cli-fgqxwrpv.js → cli-tpq83z89.js} +1631 -127
- package/dist/cli-trc24wk2.js +143 -0
- package/dist/{cli-aky8tctm.js → cli-tzx2ke1v.js} +3 -3
- package/dist/cli-v7fn5gms.js +1425 -0
- package/dist/{cli-wscdvcqz.js → cli-vctdqs5h.js} +1 -1
- package/dist/{cli-cw9zck8j.js → cli-xjcywfsf.js} +8 -4
- package/dist/{cli-k0g1sjzm.js → cli-ybgv4kw2.js} +18 -11
- package/dist/{cli-rjehvrts.js → cli-ydmcgve1.js} +8 -8
- package/dist/{cli-vhjwh6cz.js → cli-ygwm91nt.js} +1 -1
- package/dist/{cli-mcnhgnn1.js → cli-ykk5jaax.js} +184 -26
- package/dist/{cli-de1396j2.js → cli-ywybs5as.js} +7 -1
- package/dist/cli-zpep9q5e.js +491 -0
- package/dist/cli.js +41 -32
- package/dist/cloudflare-workers-ai-system-one-k6fbxw9d.js +46 -0
- package/dist/{codex-adapter-cnm8wk11.js → codex-adapter-nmxcatww.js} +26 -17
- package/dist/{codex-hook-9hptmdhj.js → codex-hook-20me6byw.js} +2 -2
- package/dist/{codex-login-x3jk4etn.js → codex-login-w6fz4xbz.js} +50 -5
- package/dist/{codex-session-runner-gfg547zj.js → codex-session-runner-90aa80ev.js} +24 -17
- package/dist/{commands-e3bn0p75.js → commands-8wcq1kn7.js} +11 -9
- package/dist/{db-03v9kzr2.js → db-j40kc4se.js} +25 -11
- package/dist/{devin-adapter-8vgkwh29.js → devin-adapter-dpsv6hd9.js} +1 -1
- package/dist/{dispatcher-nrmg8yht.js → dispatcher-4zqy768d.js} +34 -29
- package/dist/{dsh-adapter-k03nfqa6.js → dsh-adapter-mpnzgztj.js} +3 -3
- package/dist/{e2b-93x1k0j5.js → e2b-ez07znam.js} +4 -3
- package/dist/execute-6e7qeyk4.js +1017 -0
- package/dist/{google-generative-ai-bxmv50nc.js → google-generative-ai-k6n5nbpp.js} +6 -5
- package/dist/{google-vertex-809af514.js → google-vertex-44xxtcvp.js} +6 -5
- package/dist/{handlers-aqcedbyb.js → handlers-kjdce1w5.js} +37 -32
- package/dist/{hook-ybvmrmhq.js → hook-czx13n12.js} +19 -15
- package/dist/{hook-7vkskkre.js → hook-r2t4bqfg.js} +18 -14
- package/dist/{http-2eqa8t24.js → http-3bbb19be.js} +900 -145
- package/dist/{index-f6cryxwe.js → index-4a5njnm1.js} +2 -59
- package/dist/{index-x71bvq0p.js → index-668me3f0.js} +35 -30
- package/dist/{index-c6zsv1bd.js → index-7aj368tw.js} +13 -12
- package/dist/{index-1yks3qcr.js → index-fg0dsp6c.js} +34 -29
- package/dist/{index-chgdkq36.js → index-kkv84jq9.js} +34 -29
- package/dist/{index-a3vn96n8.js → index-zg7vp46x.js} +198 -54
- package/dist/{keepalive-vtkf5n99.js → keepalive-yra8dy57.js} +13 -11
- package/dist/{lead-h3sp357x.js → lead-va0pad2c.js} +54 -49
- package/dist/llama-cpp-classify-tgj35k8d.js +335 -0
- package/dist/{maintenance-jzeqtk3q.js → maintenance-hqewtmyg.js} +14 -13
- package/dist/{mistral-conversations-zx0kn554.js → mistral-conversations-pc3ntnxt.js} +14 -17
- package/dist/{oauth-refresh-sweep-qp3dzmdp.js → oauth-refresh-sweep-7rdt1m9n.js} +12 -10
- package/dist/{onboard-tmsp0qbz.js → onboard-j6ms6d0x.js} +6 -5
- package/dist/{openai-codex-responses-4vjqzvjp.js → openai-codex-responses-bbancrr0.js} +21 -8
- package/dist/{openai-completions-9hjrqbw8.js → openai-completions-jpaj5g2b.js} +9 -12
- package/dist/{openai-responses-7b1pn0xt.js → openai-responses-200k1wx4.js} +23 -18
- package/dist/{opencode-adapter-x6x2da1z.js → opencode-adapter-89rabkw2.js} +8 -7
- package/dist/{openrouter-images-9f9ek4rw.js → openrouter-images-8yx3487g.js} +5 -7
- package/dist/{otel-impl-9mz73q65.js → otel-impl-a792rjz0.js} +1 -1
- package/dist/{pi-messages-txpjj39q.js → pi-messages-vxdt8v7j.js} +2 -1
- package/dist/{pi-mono-adapter-m6dvv0dz.js → pi-mono-adapter-g7qzvr3v.js} +295 -70
- package/dist/pricing-refresh-wx0tp7cb.js +39 -0
- package/dist/quickjs-r1pq2107.wasm +0 -0
- package/dist/{rbac-roles-c9wqz83x.js → rbac-roles-8tzawacv.js} +12 -10
- package/dist/{render-v2-gryrh9h8.js → render-v2-mm7zswb8.js} +12 -10
- package/dist/runtime-zyssgse0.js +24 -0
- package/dist/{setup-q9720bt6.js → setup-8y70ys6t.js} +6 -5
- package/dist/typesafe-system-one-2ef30pec.js +27 -0
- package/dist/{virtual-modules-3htpgn8x.js → virtual-modules-6nmk7h3n.js} +22 -13
- package/dist/{work-objects-b76x7deb.js → work-objects-fg6xkb0n.js} +37 -32
- package/dist/{worker-6vrxbv41.js → worker-wmwhxsph.js} +54 -49
- package/openapi.json +1314 -91
- package/package.json +12 -11
- package/src/be/db/agents.ts +20 -0
- package/src/be/db/api-keys.ts +70 -0
- package/src/be/db/tasks/human-free.ts +442 -0
- package/src/be/db/tasks/read.ts +56 -1
- package/src/be/db/tasks/write.ts +107 -11
- package/src/be/db.ts +274 -188
- package/src/be/harness-model-support.ts +182 -0
- package/src/be/human-free-drain.ts +67 -0
- package/src/be/memory/providers/sqlite-store.ts +51 -15
- package/src/be/migrations/182_task_human_free_flag.sql +63 -0
- package/src/be/migrations/183_human_free_reclassify_queue.sql +25 -0
- package/src/be/migrations/184_model_catalog.sql +120 -0
- package/src/be/migrations/185_api_key_auth_failures.sql +6 -0
- package/src/be/migrations/186_api_key_seat_mismatch.sql +8 -0
- package/src/be/model-catalog-store.ts +644 -0
- package/src/be/model-tier-keys.ts +46 -0
- package/src/be/model-tier-resolution.ts +534 -0
- package/src/be/model-validation.ts +188 -0
- package/src/be/models-catalog.ts +61 -7
- package/src/be/modelsdev-cache.json +82 -0
- package/src/be/modelsdev-cache.ts +2 -0
- package/src/be/pricing-refresh.ts +154 -12
- package/src/be/scripts/typecheck.ts +15 -0
- package/src/be/seed/runner.ts +18 -12
- package/src/be/seed/types.ts +1 -0
- package/src/be/seed-scripts/catalog/task-failure-audit.ts +61 -9
- package/src/be/swarm-config-guard.ts +8 -0
- package/src/cli.tsx +10 -0
- package/src/commands/claude-managed-setup.ts +3 -1
- package/src/commands/codex-login.ts +67 -0
- package/src/commands/credential-outcome-report.ts +191 -0
- package/src/commands/rate-limit-outcome.ts +34 -4
- package/src/commands/runner.ts +357 -186
- package/src/commands/seat-mismatch-report.ts +46 -0
- package/src/extensions/apply-task-create.ts +27 -1
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/heartbeat/heartbeat.ts +79 -17
- package/src/heartbeat/templates.ts +2 -2
- package/src/http/agents.ts +62 -1
- package/src/http/api-keys.ts +140 -2
- package/src/http/codex-oauth-keep-warm.ts +3 -5
- package/src/http/index.ts +8 -0
- package/src/http/memory.ts +12 -5
- package/src/http/models-catalog.ts +357 -8
- package/src/http/poll.ts +54 -3
- package/src/http/schedules.ts +51 -6
- package/src/http/script-runs.ts +12 -0
- package/src/http/session-data.ts +2 -5
- package/src/http/stats.ts +6 -8
- package/src/http/status.ts +15 -1
- package/src/http/tasks.ts +90 -7
- package/src/http/usage-cache.ts +56 -15
- package/src/http/workflows.ts +46 -8
- package/src/mcp-client/http-client.ts +5 -0
- package/src/memory/recall-query.ts +74 -0
- package/src/prompts/base-prompt.ts +15 -4
- package/src/prompts/session-templates.ts +23 -1
- package/src/providers/acp-adapter.ts +1 -0
- package/src/providers/claude-adapter.ts +14 -5
- package/src/providers/claude-managed-adapter.ts +1 -0
- package/src/providers/claude-managed-models.ts +47 -161
- package/src/providers/claude-sdk-session.ts +3 -1
- package/src/providers/codex-adapter.ts +14 -14
- package/src/providers/codex-models.ts +65 -198
- package/src/providers/devin-adapter.ts +1 -0
- package/src/providers/dsh-adapter.ts +2 -1
- package/src/providers/harness-version.ts +83 -7
- package/src/providers/opencode-adapter.ts +53 -1
- package/src/providers/pi-binary-root/src/extensions/codemode/worker.ts +11 -0
- package/src/providers/pi-codemode-runtime.ts +17 -0
- package/src/providers/pi-mono-adapter.ts +361 -83
- package/src/providers/pi-mono-extension.ts +16 -1
- package/src/providers/reasoning-effort.ts +44 -140
- package/src/providers/types.ts +8 -0
- package/src/rbac/legacy-policy.ts +43 -0
- package/src/rbac/permissions.ts +15 -0
- package/src/scripts-runtime/sdk-allowlist.ts +4 -0
- package/src/scripts-runtime/types/stdlib.d.ts +15 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
- package/src/server.ts +6 -0
- package/src/slack/assistant.ts +13 -0
- package/src/slack/message-text.ts +56 -2
- package/src/slack/render-v2.ts +87 -37
- package/src/slack/session-status.ts +541 -0
- package/src/slack/thread-buffer.ts +10 -2
- package/src/tasks/sibling-awareness.ts +3 -2
- package/src/telemetry.ts +5 -4
- package/src/templates.d.ts +6 -0
- package/src/tests/agents-list-model-display.test.ts +4 -6
- package/src/tests/api-key-auth-failure-route.test.ts +142 -0
- package/src/tests/api-key-tracking.test.ts +368 -1
- package/src/tests/base-prompt.test.ts +43 -2
- package/src/tests/claude-adapter.test.ts +68 -0
- package/src/tests/claude-managed-adapter.test.ts +12 -18
- package/src/tests/codex-adapter.test.ts +2 -1
- package/src/tests/codex-auth-failure.test.ts +52 -0
- package/src/tests/codex-gpt6-release.test.ts +66 -5
- package/src/tests/codex-login.test.ts +116 -0
- package/src/tests/context-window.test.ts +7 -5
- package/src/tests/credential-exhaustion-policy.test.ts +118 -3
- package/src/tests/credential-outcome-report.test.ts +171 -0
- package/src/tests/credential-status-api.test.ts +103 -2
- package/src/tests/db-extraction-contract.test.ts +1 -0
- package/src/tests/db-task-read-contract.test.ts +10 -1
- package/src/tests/db-task-write-contract.test.ts +535 -2
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/dokploy-deploy.test.ts +315 -0
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/explicit-model-validation.test.ts +583 -0
- package/src/tests/extensions-pre-task.test.ts +73 -0
- package/src/tests/fetch-resolved-env.test.ts +46 -0
- package/src/tests/hang-watchdog-worker.ts +47 -0
- package/src/tests/hang-watchdog.test.ts +45 -0
- package/src/tests/hang-watchdog.ts +30 -0
- package/src/tests/harness-model-guard.test.ts +123 -0
- package/src/tests/harness-model-support.test.ts +374 -0
- package/src/tests/harness-version.test.ts +70 -3
- package/src/tests/heartbeat-checklist-config.test.ts +71 -0
- package/src/tests/heartbeat-checklist.test.ts +4 -2
- package/src/tests/heartbeat-orphan-resume.test.ts +48 -0
- package/src/tests/http-task-write-ownership.test.ts +172 -0
- package/src/tests/human-free-flag.test.ts +279 -0
- package/src/tests/human-free-oracle.ts +57 -0
- package/src/tests/human-free-reclassify.test.ts +669 -0
- package/src/tests/memory-fts-populate.test.ts +139 -0
- package/src/tests/memory-http-recall-gating.test.ts +125 -1
- package/src/tests/migration-046-budgets.test.ts +3 -3
- package/src/tests/model-catalog-migration.test.ts +134 -0
- package/src/tests/model-catalog-table.test.ts +249 -0
- package/src/tests/model-catalog-write-access.test.ts +387 -0
- package/src/tests/model-rate-limit-windows.test.ts +19 -0
- package/src/tests/model-tier-resolution.test.ts +611 -0
- package/src/tests/models-catalog.test.ts +1 -1
- package/src/tests/multi-runtime-enabled-stats.test.ts +65 -1
- package/src/tests/opencode-adapter.test.ts +157 -2
- package/src/tests/package-publish.test.ts +137 -36
- package/src/tests/pi-codemode.test.ts +246 -0
- package/src/tests/pi-mono-adapter.test.ts +3 -0
- package/src/tests/pi-native-mcp.test.ts +193 -0
- package/src/tests/pi-tool-exposure.test.ts +374 -0
- package/src/tests/preload.ts +3 -0
- package/src/tests/pricing-routes.test.ts +2 -2
- package/src/tests/prompt-template-session.test.ts +5 -3
- package/src/tests/rate-limit-event.test.ts +65 -0
- package/src/tests/rate-limit-outcome.test.ts +90 -0
- package/src/tests/rbac-engine.test.ts +77 -3
- package/src/tests/reasoning-effort.test.ts +109 -0
- package/src/tests/refresh-modelsdev-carryforward.test.ts +5 -5
- package/src/tests/runner-key-completion-outcome.test.ts +112 -0
- package/src/tests/runner-key-outcome-late-reset.test.ts +224 -0
- package/src/tests/runner-registration-retry.test.ts +149 -0
- package/src/tests/runtime-model-catalog.test.ts +86 -0
- package/src/tests/script-connections.test.ts +9 -0
- package/src/tests/seat-mismatch-report.test.ts +85 -0
- package/src/tests/seed-scripts.test.ts +138 -0
- package/src/tests/seed.test.ts +25 -0
- package/src/tests/session-costs.test.ts +14 -11
- package/src/tests/slack-message-text.test.ts +101 -0
- package/src/tests/slack-render-v2.test.ts +96 -0
- package/src/tests/slack-session-status.test.ts +626 -0
- package/src/tests/slack-thread-buffer-context.test.ts +93 -0
- package/src/tests/status.test.ts +29 -0
- package/src/tests/steering-promotion.test.ts +51 -0
- package/src/tests/store-progress-ownership.test.ts +136 -0
- package/src/tests/subscription-plans.test.ts +28 -0
- package/src/tests/task-cascade-fail.test.ts +148 -2
- package/src/tests/task-citations.test.ts +3 -2
- package/src/tests/tool-annotations.test.ts +1 -1
- package/src/tests/usage-cache.test.ts +166 -0
- package/src/tests/workflow-agent-task.test.ts +30 -0
- package/src/tests/workflow-executors.test.ts +5 -2
- package/src/tests/workflow-system-one-decision-review.test.ts +1021 -0
- package/src/tests/workflow-system-one-decision-save-warnings.test.ts +365 -0
- package/src/tests/workflow-system-one-decision.test.ts +2063 -0
- package/src/tests/workflow-triggers-v2.test.ts +320 -0
- package/src/tools/model-catalog/index.ts +137 -0
- package/src/tools/schedules/create-schedule.ts +17 -2
- package/src/tools/schedules/patch-schedule.ts +31 -1
- package/src/tools/schedules/update-schedule.ts +31 -1
- package/src/tools/send-task.ts +18 -1
- package/src/tools/store-progress.ts +49 -4
- package/src/tools/task-action.ts +14 -1
- package/src/tools/tool-config.ts +3 -1
- package/src/tools/workflows/create-workflow.ts +17 -4
- package/src/tools/workflows/patch-workflow-node.ts +17 -7
- package/src/tools/workflows/patch-workflow.ts +9 -2
- package/src/tools/workflows/update-workflow.ts +17 -4
- package/src/types.ts +41 -1
- package/src/utils/codex-auth-failure.ts +34 -0
- package/src/utils/context-window.ts +47 -53
- package/src/utils/credentials.ts +72 -30
- package/src/utils/error-tracker.ts +80 -0
- package/src/utils/harness-cli-version.ts +115 -0
- package/src/utils/harness-model-error.ts +33 -0
- package/src/utils/model-rate-limit-windows.ts +12 -0
- package/src/utils/runtime-model-catalog.ts +152 -0
- package/src/utils/spawn-model-guard.ts +43 -0
- package/src/utils/subscription-plans.ts +22 -0
- package/src/workflows/approval-resolution.ts +39 -0
- package/src/workflows/definition.ts +7 -0
- package/src/workflows/engine.ts +69 -1
- package/src/workflows/executors/agent-task.ts +16 -6
- package/src/workflows/executors/base.ts +53 -0
- package/src/workflows/executors/human-in-the-loop.ts +8 -8
- package/src/workflows/executors/index.ts +1 -0
- package/src/workflows/executors/registry.ts +2 -0
- package/src/workflows/executors/system-one-decision.ts +1232 -0
- package/src/workflows/executors/system-one-providers.ts +301 -0
- package/src/workflows/executors/workflow-llm.ts +13 -1
- package/src/workflows/model-validation.ts +45 -0
- package/src/workflows/patch-definition.ts +5 -0
- package/src/workflows/readiness.ts +86 -0
- package/src/workflows/recovery.ts +12 -12
- package/src/workflows/resume.ts +23 -9
- package/src/workflows/triggers.ts +85 -0
- package/templates/schedules/daily-blocker-digest/content.md +4 -5
- package/templates/skills/agent-browser/SKILL.md +6 -5
- package/templates/skills/agent-browser/content.md +6 -5
- package/templates/skills/heartbeat-runbook/config.json +1 -1
- package/templates/skills/heartbeat-runbook/content.md +2 -2
- package/templates/skills/swarm-scripts/SKILL.md +1 -1
- package/templates/skills/swarm-scripts/content.md +1 -1
- package/templates/skills/workflow-iterate/content.md +82 -1
- package/templates/workflows/claude-code-changelog-watch/content.md +2 -0
- package/templates/workflows/pr-review-status-sweep/content.md +2 -0
- package/dist/boot-seeds-s3q01xj3.js +0 -26
- package/dist/claude-sdk-session-t442qz6f.js +0 -39108
- package/dist/cli-0xjkj1j7.js +0 -61
- package/dist/cli-20cj37vt.js +0 -335561
- package/dist/cli-2djtr51b.js +0 -48
- package/dist/cli-65hjmev5.js +0 -1141
- package/dist/cli-aw1jwp1r.js +0 -14075
- package/dist/cli-h967nb6r.js +0 -6603
- package/dist/cli-vapyk8sw.js +0 -20
- package/dist/cli-ws6rqycm.js +0 -247
- package/dist/pricing-refresh-v1cbr9te.js +0 -27
- package/src/providers/modelsdev-reasoning.json +0 -6453
- package/dist/{index-f24115ge.js → index-2wsdsnmm.js} +3 -3
|
@@ -0,0 +1,3828 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Container,
|
|
3
|
+
Spacer,
|
|
4
|
+
Text,
|
|
5
|
+
VisualLinePreview,
|
|
6
|
+
formatToolCallWithArgs,
|
|
7
|
+
getAgentDir,
|
|
8
|
+
getFileRevision,
|
|
9
|
+
getShellConfig,
|
|
10
|
+
getTextOutput,
|
|
11
|
+
keyHint,
|
|
12
|
+
normalizePath,
|
|
13
|
+
replaceTabs,
|
|
14
|
+
stripBom
|
|
15
|
+
} from "./cli-d5czme6m.js";
|
|
16
|
+
import {
|
|
17
|
+
require_cross_spawn
|
|
18
|
+
} from "./cli-5bfdm1ah.js";
|
|
19
|
+
import {
|
|
20
|
+
require_signal_exit
|
|
21
|
+
} from "./cli-0xqde53b.js";
|
|
22
|
+
import {
|
|
23
|
+
__commonJS,
|
|
24
|
+
__require,
|
|
25
|
+
__toESM
|
|
26
|
+
} from "./cli-bc05qbss.js";
|
|
27
|
+
|
|
28
|
+
// node_modules/graceful-fs/polyfills.js
|
|
29
|
+
var require_polyfills = __commonJS(function(exports, module) {
|
|
30
|
+
var constants = __require("constants");
|
|
31
|
+
var origCwd = process.cwd;
|
|
32
|
+
var cwd = null;
|
|
33
|
+
var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform;
|
|
34
|
+
process.cwd = function() {
|
|
35
|
+
if (!cwd)
|
|
36
|
+
cwd = origCwd.call(process);
|
|
37
|
+
return cwd;
|
|
38
|
+
};
|
|
39
|
+
try {
|
|
40
|
+
process.cwd();
|
|
41
|
+
} catch (er) {}
|
|
42
|
+
if (typeof process.chdir === "function") {
|
|
43
|
+
chdir = process.chdir;
|
|
44
|
+
process.chdir = function(d) {
|
|
45
|
+
cwd = null;
|
|
46
|
+
chdir.call(process, d);
|
|
47
|
+
};
|
|
48
|
+
if (Object.setPrototypeOf)
|
|
49
|
+
Object.setPrototypeOf(process.chdir, chdir);
|
|
50
|
+
}
|
|
51
|
+
var chdir;
|
|
52
|
+
module.exports = patch;
|
|
53
|
+
function patch(fs) {
|
|
54
|
+
if (constants.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
|
55
|
+
patchLchmod(fs);
|
|
56
|
+
}
|
|
57
|
+
if (!fs.lutimes) {
|
|
58
|
+
patchLutimes(fs);
|
|
59
|
+
}
|
|
60
|
+
fs.chown = chownFix(fs.chown);
|
|
61
|
+
fs.fchown = chownFix(fs.fchown);
|
|
62
|
+
fs.lchown = chownFix(fs.lchown);
|
|
63
|
+
fs.chmod = chmodFix(fs.chmod);
|
|
64
|
+
fs.fchmod = chmodFix(fs.fchmod);
|
|
65
|
+
fs.lchmod = chmodFix(fs.lchmod);
|
|
66
|
+
fs.chownSync = chownFixSync(fs.chownSync);
|
|
67
|
+
fs.fchownSync = chownFixSync(fs.fchownSync);
|
|
68
|
+
fs.lchownSync = chownFixSync(fs.lchownSync);
|
|
69
|
+
fs.chmodSync = chmodFixSync(fs.chmodSync);
|
|
70
|
+
fs.fchmodSync = chmodFixSync(fs.fchmodSync);
|
|
71
|
+
fs.lchmodSync = chmodFixSync(fs.lchmodSync);
|
|
72
|
+
fs.stat = statFix(fs.stat);
|
|
73
|
+
fs.fstat = statFix(fs.fstat);
|
|
74
|
+
fs.lstat = statFix(fs.lstat);
|
|
75
|
+
fs.statSync = statFixSync(fs.statSync);
|
|
76
|
+
fs.fstatSync = statFixSync(fs.fstatSync);
|
|
77
|
+
fs.lstatSync = statFixSync(fs.lstatSync);
|
|
78
|
+
if (fs.chmod && !fs.lchmod) {
|
|
79
|
+
fs.lchmod = function(path, mode, cb) {
|
|
80
|
+
if (cb)
|
|
81
|
+
process.nextTick(cb);
|
|
82
|
+
};
|
|
83
|
+
fs.lchmodSync = function() {};
|
|
84
|
+
}
|
|
85
|
+
if (fs.chown && !fs.lchown) {
|
|
86
|
+
fs.lchown = function(path, uid, gid, cb) {
|
|
87
|
+
if (cb)
|
|
88
|
+
process.nextTick(cb);
|
|
89
|
+
};
|
|
90
|
+
fs.lchownSync = function() {};
|
|
91
|
+
}
|
|
92
|
+
if (platform === "win32") {
|
|
93
|
+
fs.rename = typeof fs.rename !== "function" ? fs.rename : function(fs$rename) {
|
|
94
|
+
function rename(from, to, cb) {
|
|
95
|
+
var start = Date.now();
|
|
96
|
+
var backoff = 0;
|
|
97
|
+
fs$rename(from, to, function CB(er) {
|
|
98
|
+
if (er && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY") && Date.now() - start < 60000) {
|
|
99
|
+
setTimeout(function() {
|
|
100
|
+
fs.stat(to, function(stater, st) {
|
|
101
|
+
if (stater && stater.code === "ENOENT")
|
|
102
|
+
fs$rename(from, to, CB);
|
|
103
|
+
else
|
|
104
|
+
cb(er);
|
|
105
|
+
});
|
|
106
|
+
}, backoff);
|
|
107
|
+
if (backoff < 100)
|
|
108
|
+
backoff += 10;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (cb)
|
|
112
|
+
cb(er);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (Object.setPrototypeOf)
|
|
116
|
+
Object.setPrototypeOf(rename, fs$rename);
|
|
117
|
+
return rename;
|
|
118
|
+
}(fs.rename);
|
|
119
|
+
}
|
|
120
|
+
fs.read = typeof fs.read !== "function" ? fs.read : function(fs$read) {
|
|
121
|
+
function read(fd, buffer, offset, length, position, callback_) {
|
|
122
|
+
var callback;
|
|
123
|
+
if (callback_ && typeof callback_ === "function") {
|
|
124
|
+
var eagCounter = 0;
|
|
125
|
+
callback = function(er, _, __) {
|
|
126
|
+
if (er && er.code === "EAGAIN" && eagCounter < 10) {
|
|
127
|
+
eagCounter++;
|
|
128
|
+
return fs$read.call(fs, fd, buffer, offset, length, position, callback);
|
|
129
|
+
}
|
|
130
|
+
callback_.apply(this, arguments);
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return fs$read.call(fs, fd, buffer, offset, length, position, callback);
|
|
134
|
+
}
|
|
135
|
+
if (Object.setPrototypeOf)
|
|
136
|
+
Object.setPrototypeOf(read, fs$read);
|
|
137
|
+
return read;
|
|
138
|
+
}(fs.read);
|
|
139
|
+
fs.readSync = typeof fs.readSync !== "function" ? fs.readSync : function(fs$readSync) {
|
|
140
|
+
return function(fd, buffer, offset, length, position) {
|
|
141
|
+
var eagCounter = 0;
|
|
142
|
+
while (true) {
|
|
143
|
+
try {
|
|
144
|
+
return fs$readSync.call(fs, fd, buffer, offset, length, position);
|
|
145
|
+
} catch (er) {
|
|
146
|
+
if (er.code === "EAGAIN" && eagCounter < 10) {
|
|
147
|
+
eagCounter++;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
throw er;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}(fs.readSync);
|
|
155
|
+
function patchLchmod(fs2) {
|
|
156
|
+
fs2.lchmod = function(path, mode, callback) {
|
|
157
|
+
fs2.open(path, constants.O_WRONLY | constants.O_SYMLINK, mode, function(err, fd) {
|
|
158
|
+
if (err) {
|
|
159
|
+
if (callback)
|
|
160
|
+
callback(err);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
fs2.fchmod(fd, mode, function(err2) {
|
|
164
|
+
fs2.close(fd, function(err22) {
|
|
165
|
+
if (callback)
|
|
166
|
+
callback(err2 || err22);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
fs2.lchmodSync = function(path, mode) {
|
|
172
|
+
var fd = fs2.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode);
|
|
173
|
+
var threw = true;
|
|
174
|
+
var ret;
|
|
175
|
+
try {
|
|
176
|
+
ret = fs2.fchmodSync(fd, mode);
|
|
177
|
+
threw = false;
|
|
178
|
+
} finally {
|
|
179
|
+
if (threw) {
|
|
180
|
+
try {
|
|
181
|
+
fs2.closeSync(fd);
|
|
182
|
+
} catch (er) {}
|
|
183
|
+
} else {
|
|
184
|
+
fs2.closeSync(fd);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return ret;
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function patchLutimes(fs2) {
|
|
191
|
+
if (constants.hasOwnProperty("O_SYMLINK") && fs2.futimes) {
|
|
192
|
+
fs2.lutimes = function(path, at, mt, cb) {
|
|
193
|
+
fs2.open(path, constants.O_SYMLINK, function(er, fd) {
|
|
194
|
+
if (er) {
|
|
195
|
+
if (cb)
|
|
196
|
+
cb(er);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
fs2.futimes(fd, at, mt, function(er2) {
|
|
200
|
+
fs2.close(fd, function(er22) {
|
|
201
|
+
if (cb)
|
|
202
|
+
cb(er2 || er22);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
fs2.lutimesSync = function(path, at, mt) {
|
|
208
|
+
var fd = fs2.openSync(path, constants.O_SYMLINK);
|
|
209
|
+
var ret;
|
|
210
|
+
var threw = true;
|
|
211
|
+
try {
|
|
212
|
+
ret = fs2.futimesSync(fd, at, mt);
|
|
213
|
+
threw = false;
|
|
214
|
+
} finally {
|
|
215
|
+
if (threw) {
|
|
216
|
+
try {
|
|
217
|
+
fs2.closeSync(fd);
|
|
218
|
+
} catch (er) {}
|
|
219
|
+
} else {
|
|
220
|
+
fs2.closeSync(fd);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return ret;
|
|
224
|
+
};
|
|
225
|
+
} else if (fs2.futimes) {
|
|
226
|
+
fs2.lutimes = function(_a, _b, _c, cb) {
|
|
227
|
+
if (cb)
|
|
228
|
+
process.nextTick(cb);
|
|
229
|
+
};
|
|
230
|
+
fs2.lutimesSync = function() {};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
function chmodFix(orig) {
|
|
234
|
+
if (!orig)
|
|
235
|
+
return orig;
|
|
236
|
+
return function(target, mode, cb) {
|
|
237
|
+
return orig.call(fs, target, mode, function(er) {
|
|
238
|
+
if (chownErOk(er))
|
|
239
|
+
er = null;
|
|
240
|
+
if (cb)
|
|
241
|
+
cb.apply(this, arguments);
|
|
242
|
+
});
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function chmodFixSync(orig) {
|
|
246
|
+
if (!orig)
|
|
247
|
+
return orig;
|
|
248
|
+
return function(target, mode) {
|
|
249
|
+
try {
|
|
250
|
+
return orig.call(fs, target, mode);
|
|
251
|
+
} catch (er) {
|
|
252
|
+
if (!chownErOk(er))
|
|
253
|
+
throw er;
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function chownFix(orig) {
|
|
258
|
+
if (!orig)
|
|
259
|
+
return orig;
|
|
260
|
+
return function(target, uid, gid, cb) {
|
|
261
|
+
return orig.call(fs, target, uid, gid, function(er) {
|
|
262
|
+
if (chownErOk(er))
|
|
263
|
+
er = null;
|
|
264
|
+
if (cb)
|
|
265
|
+
cb.apply(this, arguments);
|
|
266
|
+
});
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function chownFixSync(orig) {
|
|
270
|
+
if (!orig)
|
|
271
|
+
return orig;
|
|
272
|
+
return function(target, uid, gid) {
|
|
273
|
+
try {
|
|
274
|
+
return orig.call(fs, target, uid, gid);
|
|
275
|
+
} catch (er) {
|
|
276
|
+
if (!chownErOk(er))
|
|
277
|
+
throw er;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function statFix(orig) {
|
|
282
|
+
if (!orig)
|
|
283
|
+
return orig;
|
|
284
|
+
return function(target, options, cb) {
|
|
285
|
+
if (typeof options === "function") {
|
|
286
|
+
cb = options;
|
|
287
|
+
options = null;
|
|
288
|
+
}
|
|
289
|
+
function callback(er, stats) {
|
|
290
|
+
if (stats) {
|
|
291
|
+
if (stats.uid < 0)
|
|
292
|
+
stats.uid += 4294967296;
|
|
293
|
+
if (stats.gid < 0)
|
|
294
|
+
stats.gid += 4294967296;
|
|
295
|
+
}
|
|
296
|
+
if (cb)
|
|
297
|
+
cb.apply(this, arguments);
|
|
298
|
+
}
|
|
299
|
+
return options ? orig.call(fs, target, options, callback) : orig.call(fs, target, callback);
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
function statFixSync(orig) {
|
|
303
|
+
if (!orig)
|
|
304
|
+
return orig;
|
|
305
|
+
return function(target, options) {
|
|
306
|
+
var stats = options ? orig.call(fs, target, options) : orig.call(fs, target);
|
|
307
|
+
if (stats) {
|
|
308
|
+
if (stats.uid < 0)
|
|
309
|
+
stats.uid += 4294967296;
|
|
310
|
+
if (stats.gid < 0)
|
|
311
|
+
stats.gid += 4294967296;
|
|
312
|
+
}
|
|
313
|
+
return stats;
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function chownErOk(er) {
|
|
317
|
+
if (!er)
|
|
318
|
+
return true;
|
|
319
|
+
if (er.code === "ENOSYS")
|
|
320
|
+
return true;
|
|
321
|
+
var nonroot = !process.getuid || process.getuid() !== 0;
|
|
322
|
+
if (nonroot) {
|
|
323
|
+
if (er.code === "EINVAL" || er.code === "EPERM")
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// node_modules/graceful-fs/legacy-streams.js
|
|
332
|
+
var require_legacy_streams = __commonJS(function(exports, module) {
|
|
333
|
+
var Stream = __require("stream").Stream;
|
|
334
|
+
module.exports = legacy;
|
|
335
|
+
function legacy(fs) {
|
|
336
|
+
return {
|
|
337
|
+
ReadStream,
|
|
338
|
+
WriteStream
|
|
339
|
+
};
|
|
340
|
+
function ReadStream(path, options) {
|
|
341
|
+
if (!(this instanceof ReadStream))
|
|
342
|
+
return new ReadStream(path, options);
|
|
343
|
+
Stream.call(this);
|
|
344
|
+
var self = this;
|
|
345
|
+
this.path = path;
|
|
346
|
+
this.fd = null;
|
|
347
|
+
this.readable = true;
|
|
348
|
+
this.paused = false;
|
|
349
|
+
this.flags = "r";
|
|
350
|
+
this.mode = 438;
|
|
351
|
+
this.bufferSize = 64 * 1024;
|
|
352
|
+
options = options || {};
|
|
353
|
+
var keys = Object.keys(options);
|
|
354
|
+
for (var index = 0, length = keys.length;index < length; index++) {
|
|
355
|
+
var key = keys[index];
|
|
356
|
+
this[key] = options[key];
|
|
357
|
+
}
|
|
358
|
+
if (this.encoding)
|
|
359
|
+
this.setEncoding(this.encoding);
|
|
360
|
+
if (this.start !== undefined) {
|
|
361
|
+
if (typeof this.start !== "number") {
|
|
362
|
+
throw TypeError("start must be a Number");
|
|
363
|
+
}
|
|
364
|
+
if (this.end === undefined) {
|
|
365
|
+
this.end = Infinity;
|
|
366
|
+
} else if (typeof this.end !== "number") {
|
|
367
|
+
throw TypeError("end must be a Number");
|
|
368
|
+
}
|
|
369
|
+
if (this.start > this.end) {
|
|
370
|
+
throw new Error("start must be <= end");
|
|
371
|
+
}
|
|
372
|
+
this.pos = this.start;
|
|
373
|
+
}
|
|
374
|
+
if (this.fd !== null) {
|
|
375
|
+
process.nextTick(function() {
|
|
376
|
+
self._read();
|
|
377
|
+
});
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
fs.open(this.path, this.flags, this.mode, function(err, fd) {
|
|
381
|
+
if (err) {
|
|
382
|
+
self.emit("error", err);
|
|
383
|
+
self.readable = false;
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
self.fd = fd;
|
|
387
|
+
self.emit("open", fd);
|
|
388
|
+
self._read();
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
function WriteStream(path, options) {
|
|
392
|
+
if (!(this instanceof WriteStream))
|
|
393
|
+
return new WriteStream(path, options);
|
|
394
|
+
Stream.call(this);
|
|
395
|
+
this.path = path;
|
|
396
|
+
this.fd = null;
|
|
397
|
+
this.writable = true;
|
|
398
|
+
this.flags = "w";
|
|
399
|
+
this.encoding = "binary";
|
|
400
|
+
this.mode = 438;
|
|
401
|
+
this.bytesWritten = 0;
|
|
402
|
+
options = options || {};
|
|
403
|
+
var keys = Object.keys(options);
|
|
404
|
+
for (var index = 0, length = keys.length;index < length; index++) {
|
|
405
|
+
var key = keys[index];
|
|
406
|
+
this[key] = options[key];
|
|
407
|
+
}
|
|
408
|
+
if (this.start !== undefined) {
|
|
409
|
+
if (typeof this.start !== "number") {
|
|
410
|
+
throw TypeError("start must be a Number");
|
|
411
|
+
}
|
|
412
|
+
if (this.start < 0) {
|
|
413
|
+
throw new Error("start must be >= zero");
|
|
414
|
+
}
|
|
415
|
+
this.pos = this.start;
|
|
416
|
+
}
|
|
417
|
+
this.busy = false;
|
|
418
|
+
this._queue = [];
|
|
419
|
+
if (this.fd === null) {
|
|
420
|
+
this._open = fs.open;
|
|
421
|
+
this._queue.push([this._open, this.path, this.flags, this.mode, undefined]);
|
|
422
|
+
this.flush();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
// node_modules/graceful-fs/clone.js
|
|
429
|
+
var require_clone = __commonJS(function(exports, module) {
|
|
430
|
+
module.exports = clone;
|
|
431
|
+
var getPrototypeOf = Object.getPrototypeOf || function(obj) {
|
|
432
|
+
return obj.__proto__;
|
|
433
|
+
};
|
|
434
|
+
function clone(obj) {
|
|
435
|
+
if (obj === null || typeof obj !== "object")
|
|
436
|
+
return obj;
|
|
437
|
+
if (obj instanceof Object)
|
|
438
|
+
var copy = { __proto__: getPrototypeOf(obj) };
|
|
439
|
+
else
|
|
440
|
+
var copy = Object.create(null);
|
|
441
|
+
Object.getOwnPropertyNames(obj).forEach(function(key) {
|
|
442
|
+
Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key));
|
|
443
|
+
});
|
|
444
|
+
return copy;
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// node_modules/graceful-fs/graceful-fs.js
|
|
449
|
+
var require_graceful_fs = __commonJS(function(exports, module) {
|
|
450
|
+
var fs = __require("fs");
|
|
451
|
+
var polyfills = require_polyfills();
|
|
452
|
+
var legacy = require_legacy_streams();
|
|
453
|
+
var clone = require_clone();
|
|
454
|
+
var util = __require("util");
|
|
455
|
+
var gracefulQueue;
|
|
456
|
+
var previousSymbol;
|
|
457
|
+
if (typeof Symbol === "function" && typeof Symbol.for === "function") {
|
|
458
|
+
gracefulQueue = Symbol.for("graceful-fs.queue");
|
|
459
|
+
previousSymbol = Symbol.for("graceful-fs.previous");
|
|
460
|
+
} else {
|
|
461
|
+
gracefulQueue = "___graceful-fs.queue";
|
|
462
|
+
previousSymbol = "___graceful-fs.previous";
|
|
463
|
+
}
|
|
464
|
+
function noop() {}
|
|
465
|
+
function publishQueue(context, queue2) {
|
|
466
|
+
Object.defineProperty(context, gracefulQueue, {
|
|
467
|
+
get: function() {
|
|
468
|
+
return queue2;
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
var debug = noop;
|
|
473
|
+
if (util.debuglog)
|
|
474
|
+
debug = util.debuglog("gfs4");
|
|
475
|
+
else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || ""))
|
|
476
|
+
debug = function() {
|
|
477
|
+
var m = util.format.apply(util, arguments);
|
|
478
|
+
m = "GFS4: " + m.split(/\n/).join(`
|
|
479
|
+
GFS4: `);
|
|
480
|
+
console.error(m);
|
|
481
|
+
};
|
|
482
|
+
if (!fs[gracefulQueue]) {
|
|
483
|
+
queue = global[gracefulQueue] || [];
|
|
484
|
+
publishQueue(fs, queue);
|
|
485
|
+
fs.close = function(fs$close) {
|
|
486
|
+
function close(fd, cb) {
|
|
487
|
+
return fs$close.call(fs, fd, function(err) {
|
|
488
|
+
if (!err) {
|
|
489
|
+
resetQueue();
|
|
490
|
+
}
|
|
491
|
+
if (typeof cb === "function")
|
|
492
|
+
cb.apply(this, arguments);
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
Object.defineProperty(close, previousSymbol, {
|
|
496
|
+
value: fs$close
|
|
497
|
+
});
|
|
498
|
+
return close;
|
|
499
|
+
}(fs.close);
|
|
500
|
+
fs.closeSync = function(fs$closeSync) {
|
|
501
|
+
function closeSync(fd) {
|
|
502
|
+
fs$closeSync.apply(fs, arguments);
|
|
503
|
+
resetQueue();
|
|
504
|
+
}
|
|
505
|
+
Object.defineProperty(closeSync, previousSymbol, {
|
|
506
|
+
value: fs$closeSync
|
|
507
|
+
});
|
|
508
|
+
return closeSync;
|
|
509
|
+
}(fs.closeSync);
|
|
510
|
+
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
|
|
511
|
+
process.on("exit", function() {
|
|
512
|
+
debug(fs[gracefulQueue]);
|
|
513
|
+
__require("assert").equal(fs[gracefulQueue].length, 0);
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
var queue;
|
|
518
|
+
if (!global[gracefulQueue]) {
|
|
519
|
+
publishQueue(global, fs[gracefulQueue]);
|
|
520
|
+
}
|
|
521
|
+
module.exports = patch(clone(fs));
|
|
522
|
+
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
|
|
523
|
+
module.exports = patch(fs);
|
|
524
|
+
fs.__patched = true;
|
|
525
|
+
}
|
|
526
|
+
function patch(fs2) {
|
|
527
|
+
polyfills(fs2);
|
|
528
|
+
fs2.gracefulify = patch;
|
|
529
|
+
fs2.createReadStream = createReadStream;
|
|
530
|
+
fs2.createWriteStream = createWriteStream;
|
|
531
|
+
var fs$readFile = fs2.readFile;
|
|
532
|
+
fs2.readFile = readFile;
|
|
533
|
+
function readFile(path, options, cb) {
|
|
534
|
+
if (typeof options === "function")
|
|
535
|
+
cb = options, options = null;
|
|
536
|
+
return go$readFile(path, options, cb);
|
|
537
|
+
function go$readFile(path2, options2, cb2, startTime) {
|
|
538
|
+
return fs$readFile(path2, options2, function(err) {
|
|
539
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
540
|
+
enqueue([go$readFile, [path2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
541
|
+
else {
|
|
542
|
+
if (typeof cb2 === "function")
|
|
543
|
+
cb2.apply(this, arguments);
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
var fs$writeFile = fs2.writeFile;
|
|
549
|
+
fs2.writeFile = writeFile2;
|
|
550
|
+
function writeFile2(path, data, options, cb) {
|
|
551
|
+
if (typeof options === "function")
|
|
552
|
+
cb = options, options = null;
|
|
553
|
+
return go$writeFile(path, data, options, cb);
|
|
554
|
+
function go$writeFile(path2, data2, options2, cb2, startTime) {
|
|
555
|
+
return fs$writeFile(path2, data2, options2, function(err) {
|
|
556
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
557
|
+
enqueue([go$writeFile, [path2, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
558
|
+
else {
|
|
559
|
+
if (typeof cb2 === "function")
|
|
560
|
+
cb2.apply(this, arguments);
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
var fs$appendFile = fs2.appendFile;
|
|
566
|
+
if (fs$appendFile)
|
|
567
|
+
fs2.appendFile = appendFile;
|
|
568
|
+
function appendFile(path, data, options, cb) {
|
|
569
|
+
if (typeof options === "function")
|
|
570
|
+
cb = options, options = null;
|
|
571
|
+
return go$appendFile(path, data, options, cb);
|
|
572
|
+
function go$appendFile(path2, data2, options2, cb2, startTime) {
|
|
573
|
+
return fs$appendFile(path2, data2, options2, function(err) {
|
|
574
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
575
|
+
enqueue([go$appendFile, [path2, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
576
|
+
else {
|
|
577
|
+
if (typeof cb2 === "function")
|
|
578
|
+
cb2.apply(this, arguments);
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
var fs$copyFile = fs2.copyFile;
|
|
584
|
+
if (fs$copyFile)
|
|
585
|
+
fs2.copyFile = copyFile;
|
|
586
|
+
function copyFile(src, dest, flags, cb) {
|
|
587
|
+
if (typeof flags === "function") {
|
|
588
|
+
cb = flags;
|
|
589
|
+
flags = 0;
|
|
590
|
+
}
|
|
591
|
+
return go$copyFile(src, dest, flags, cb);
|
|
592
|
+
function go$copyFile(src2, dest2, flags2, cb2, startTime) {
|
|
593
|
+
return fs$copyFile(src2, dest2, flags2, function(err) {
|
|
594
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
595
|
+
enqueue([go$copyFile, [src2, dest2, flags2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
596
|
+
else {
|
|
597
|
+
if (typeof cb2 === "function")
|
|
598
|
+
cb2.apply(this, arguments);
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
var fs$readdir = fs2.readdir;
|
|
604
|
+
fs2.readdir = readdir;
|
|
605
|
+
var noReaddirOptionVersions = /^v[0-5]\./;
|
|
606
|
+
function readdir(path, options, cb) {
|
|
607
|
+
if (typeof options === "function")
|
|
608
|
+
cb = options, options = null;
|
|
609
|
+
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path2, options2, cb2, startTime) {
|
|
610
|
+
return fs$readdir(path2, fs$readdirCallback(path2, options2, cb2, startTime));
|
|
611
|
+
} : function go$readdir2(path2, options2, cb2, startTime) {
|
|
612
|
+
return fs$readdir(path2, options2, fs$readdirCallback(path2, options2, cb2, startTime));
|
|
613
|
+
};
|
|
614
|
+
return go$readdir(path, options, cb);
|
|
615
|
+
function fs$readdirCallback(path2, options2, cb2, startTime) {
|
|
616
|
+
return function(err, files) {
|
|
617
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
618
|
+
enqueue([
|
|
619
|
+
go$readdir,
|
|
620
|
+
[path2, options2, cb2],
|
|
621
|
+
err,
|
|
622
|
+
startTime || Date.now(),
|
|
623
|
+
Date.now()
|
|
624
|
+
]);
|
|
625
|
+
else {
|
|
626
|
+
if (files && files.sort)
|
|
627
|
+
files.sort();
|
|
628
|
+
if (typeof cb2 === "function")
|
|
629
|
+
cb2.call(this, err, files);
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (process.version.substr(0, 4) === "v0.8") {
|
|
635
|
+
var legStreams = legacy(fs2);
|
|
636
|
+
ReadStream = legStreams.ReadStream;
|
|
637
|
+
WriteStream = legStreams.WriteStream;
|
|
638
|
+
}
|
|
639
|
+
var fs$ReadStream = fs2.ReadStream;
|
|
640
|
+
if (fs$ReadStream) {
|
|
641
|
+
ReadStream.prototype = Object.create(fs$ReadStream.prototype);
|
|
642
|
+
ReadStream.prototype.open = ReadStream$open;
|
|
643
|
+
}
|
|
644
|
+
var fs$WriteStream = fs2.WriteStream;
|
|
645
|
+
if (fs$WriteStream) {
|
|
646
|
+
WriteStream.prototype = Object.create(fs$WriteStream.prototype);
|
|
647
|
+
WriteStream.prototype.open = WriteStream$open;
|
|
648
|
+
}
|
|
649
|
+
Object.defineProperty(fs2, "ReadStream", {
|
|
650
|
+
get: function() {
|
|
651
|
+
return ReadStream;
|
|
652
|
+
},
|
|
653
|
+
set: function(val) {
|
|
654
|
+
ReadStream = val;
|
|
655
|
+
},
|
|
656
|
+
enumerable: true,
|
|
657
|
+
configurable: true
|
|
658
|
+
});
|
|
659
|
+
Object.defineProperty(fs2, "WriteStream", {
|
|
660
|
+
get: function() {
|
|
661
|
+
return WriteStream;
|
|
662
|
+
},
|
|
663
|
+
set: function(val) {
|
|
664
|
+
WriteStream = val;
|
|
665
|
+
},
|
|
666
|
+
enumerable: true,
|
|
667
|
+
configurable: true
|
|
668
|
+
});
|
|
669
|
+
var FileReadStream = ReadStream;
|
|
670
|
+
Object.defineProperty(fs2, "FileReadStream", {
|
|
671
|
+
get: function() {
|
|
672
|
+
return FileReadStream;
|
|
673
|
+
},
|
|
674
|
+
set: function(val) {
|
|
675
|
+
FileReadStream = val;
|
|
676
|
+
},
|
|
677
|
+
enumerable: true,
|
|
678
|
+
configurable: true
|
|
679
|
+
});
|
|
680
|
+
var FileWriteStream = WriteStream;
|
|
681
|
+
Object.defineProperty(fs2, "FileWriteStream", {
|
|
682
|
+
get: function() {
|
|
683
|
+
return FileWriteStream;
|
|
684
|
+
},
|
|
685
|
+
set: function(val) {
|
|
686
|
+
FileWriteStream = val;
|
|
687
|
+
},
|
|
688
|
+
enumerable: true,
|
|
689
|
+
configurable: true
|
|
690
|
+
});
|
|
691
|
+
function ReadStream(path, options) {
|
|
692
|
+
if (this instanceof ReadStream)
|
|
693
|
+
return fs$ReadStream.apply(this, arguments), this;
|
|
694
|
+
else
|
|
695
|
+
return ReadStream.apply(Object.create(ReadStream.prototype), arguments);
|
|
696
|
+
}
|
|
697
|
+
function ReadStream$open() {
|
|
698
|
+
var that = this;
|
|
699
|
+
open(that.path, that.flags, that.mode, function(err, fd) {
|
|
700
|
+
if (err) {
|
|
701
|
+
if (that.autoClose)
|
|
702
|
+
that.destroy();
|
|
703
|
+
that.emit("error", err);
|
|
704
|
+
} else {
|
|
705
|
+
that.fd = fd;
|
|
706
|
+
that.emit("open", fd);
|
|
707
|
+
that.read();
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
function WriteStream(path, options) {
|
|
712
|
+
if (this instanceof WriteStream)
|
|
713
|
+
return fs$WriteStream.apply(this, arguments), this;
|
|
714
|
+
else
|
|
715
|
+
return WriteStream.apply(Object.create(WriteStream.prototype), arguments);
|
|
716
|
+
}
|
|
717
|
+
function WriteStream$open() {
|
|
718
|
+
var that = this;
|
|
719
|
+
open(that.path, that.flags, that.mode, function(err, fd) {
|
|
720
|
+
if (err) {
|
|
721
|
+
that.destroy();
|
|
722
|
+
that.emit("error", err);
|
|
723
|
+
} else {
|
|
724
|
+
that.fd = fd;
|
|
725
|
+
that.emit("open", fd);
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
function createReadStream(path, options) {
|
|
730
|
+
return new fs2.ReadStream(path, options);
|
|
731
|
+
}
|
|
732
|
+
function createWriteStream(path, options) {
|
|
733
|
+
return new fs2.WriteStream(path, options);
|
|
734
|
+
}
|
|
735
|
+
var fs$open = fs2.open;
|
|
736
|
+
fs2.open = open;
|
|
737
|
+
function open(path, flags, mode, cb) {
|
|
738
|
+
if (typeof mode === "function")
|
|
739
|
+
cb = mode, mode = null;
|
|
740
|
+
return go$open(path, flags, mode, cb);
|
|
741
|
+
function go$open(path2, flags2, mode2, cb2, startTime) {
|
|
742
|
+
return fs$open(path2, flags2, mode2, function(err, fd) {
|
|
743
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
744
|
+
enqueue([go$open, [path2, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
745
|
+
else {
|
|
746
|
+
if (typeof cb2 === "function")
|
|
747
|
+
cb2.apply(this, arguments);
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
return fs2;
|
|
753
|
+
}
|
|
754
|
+
function enqueue(elem) {
|
|
755
|
+
debug("ENQUEUE", elem[0].name, elem[1]);
|
|
756
|
+
fs[gracefulQueue].push(elem);
|
|
757
|
+
retry();
|
|
758
|
+
}
|
|
759
|
+
var retryTimer;
|
|
760
|
+
function resetQueue() {
|
|
761
|
+
var now = Date.now();
|
|
762
|
+
for (var i = 0;i < fs[gracefulQueue].length; ++i) {
|
|
763
|
+
if (fs[gracefulQueue][i].length > 2) {
|
|
764
|
+
fs[gracefulQueue][i][3] = now;
|
|
765
|
+
fs[gracefulQueue][i][4] = now;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
retry();
|
|
769
|
+
}
|
|
770
|
+
function retry() {
|
|
771
|
+
clearTimeout(retryTimer);
|
|
772
|
+
retryTimer = undefined;
|
|
773
|
+
if (fs[gracefulQueue].length === 0)
|
|
774
|
+
return;
|
|
775
|
+
var elem = fs[gracefulQueue].shift();
|
|
776
|
+
var fn = elem[0];
|
|
777
|
+
var args = elem[1];
|
|
778
|
+
var err = elem[2];
|
|
779
|
+
var startTime = elem[3];
|
|
780
|
+
var lastTime = elem[4];
|
|
781
|
+
if (startTime === undefined) {
|
|
782
|
+
debug("RETRY", fn.name, args);
|
|
783
|
+
fn.apply(null, args);
|
|
784
|
+
} else if (Date.now() - startTime >= 60000) {
|
|
785
|
+
debug("TIMEOUT", fn.name, args);
|
|
786
|
+
var cb = args.pop();
|
|
787
|
+
if (typeof cb === "function")
|
|
788
|
+
cb.call(null, err);
|
|
789
|
+
} else {
|
|
790
|
+
var sinceAttempt = Date.now() - lastTime;
|
|
791
|
+
var sinceStart = Math.max(lastTime - startTime, 1);
|
|
792
|
+
var desiredDelay = Math.min(sinceStart * 1.2, 100);
|
|
793
|
+
if (sinceAttempt >= desiredDelay) {
|
|
794
|
+
debug("RETRY", fn.name, args);
|
|
795
|
+
fn.apply(null, args.concat([startTime]));
|
|
796
|
+
} else {
|
|
797
|
+
fs[gracefulQueue].push(elem);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
if (retryTimer === undefined) {
|
|
801
|
+
retryTimer = setTimeout(retry, 0);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
// node_modules/retry/lib/retry_operation.js
|
|
807
|
+
var require_retry_operation = __commonJS(function(exports, module) {
|
|
808
|
+
function RetryOperation(timeouts, options) {
|
|
809
|
+
if (typeof options === "boolean") {
|
|
810
|
+
options = { forever: options };
|
|
811
|
+
}
|
|
812
|
+
this._originalTimeouts = JSON.parse(JSON.stringify(timeouts));
|
|
813
|
+
this._timeouts = timeouts;
|
|
814
|
+
this._options = options || {};
|
|
815
|
+
this._maxRetryTime = options && options.maxRetryTime || Infinity;
|
|
816
|
+
this._fn = null;
|
|
817
|
+
this._errors = [];
|
|
818
|
+
this._attempts = 1;
|
|
819
|
+
this._operationTimeout = null;
|
|
820
|
+
this._operationTimeoutCb = null;
|
|
821
|
+
this._timeout = null;
|
|
822
|
+
this._operationStart = null;
|
|
823
|
+
if (this._options.forever) {
|
|
824
|
+
this._cachedTimeouts = this._timeouts.slice(0);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
module.exports = RetryOperation;
|
|
828
|
+
RetryOperation.prototype.reset = function() {
|
|
829
|
+
this._attempts = 1;
|
|
830
|
+
this._timeouts = this._originalTimeouts;
|
|
831
|
+
};
|
|
832
|
+
RetryOperation.prototype.stop = function() {
|
|
833
|
+
if (this._timeout) {
|
|
834
|
+
clearTimeout(this._timeout);
|
|
835
|
+
}
|
|
836
|
+
this._timeouts = [];
|
|
837
|
+
this._cachedTimeouts = null;
|
|
838
|
+
};
|
|
839
|
+
RetryOperation.prototype.retry = function(err) {
|
|
840
|
+
if (this._timeout) {
|
|
841
|
+
clearTimeout(this._timeout);
|
|
842
|
+
}
|
|
843
|
+
if (!err) {
|
|
844
|
+
return false;
|
|
845
|
+
}
|
|
846
|
+
var currentTime = new Date().getTime();
|
|
847
|
+
if (err && currentTime - this._operationStart >= this._maxRetryTime) {
|
|
848
|
+
this._errors.unshift(new Error("RetryOperation timeout occurred"));
|
|
849
|
+
return false;
|
|
850
|
+
}
|
|
851
|
+
this._errors.push(err);
|
|
852
|
+
var timeout = this._timeouts.shift();
|
|
853
|
+
if (timeout === undefined) {
|
|
854
|
+
if (this._cachedTimeouts) {
|
|
855
|
+
this._errors.splice(this._errors.length - 1, this._errors.length);
|
|
856
|
+
this._timeouts = this._cachedTimeouts.slice(0);
|
|
857
|
+
timeout = this._timeouts.shift();
|
|
858
|
+
} else {
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
var self = this;
|
|
863
|
+
var timer = setTimeout(function() {
|
|
864
|
+
self._attempts++;
|
|
865
|
+
if (self._operationTimeoutCb) {
|
|
866
|
+
self._timeout = setTimeout(function() {
|
|
867
|
+
self._operationTimeoutCb(self._attempts);
|
|
868
|
+
}, self._operationTimeout);
|
|
869
|
+
if (self._options.unref) {
|
|
870
|
+
self._timeout.unref();
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
self._fn(self._attempts);
|
|
874
|
+
}, timeout);
|
|
875
|
+
if (this._options.unref) {
|
|
876
|
+
timer.unref();
|
|
877
|
+
}
|
|
878
|
+
return true;
|
|
879
|
+
};
|
|
880
|
+
RetryOperation.prototype.attempt = function(fn, timeoutOps) {
|
|
881
|
+
this._fn = fn;
|
|
882
|
+
if (timeoutOps) {
|
|
883
|
+
if (timeoutOps.timeout) {
|
|
884
|
+
this._operationTimeout = timeoutOps.timeout;
|
|
885
|
+
}
|
|
886
|
+
if (timeoutOps.cb) {
|
|
887
|
+
this._operationTimeoutCb = timeoutOps.cb;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
var self = this;
|
|
891
|
+
if (this._operationTimeoutCb) {
|
|
892
|
+
this._timeout = setTimeout(function() {
|
|
893
|
+
self._operationTimeoutCb();
|
|
894
|
+
}, self._operationTimeout);
|
|
895
|
+
}
|
|
896
|
+
this._operationStart = new Date().getTime();
|
|
897
|
+
this._fn(this._attempts);
|
|
898
|
+
};
|
|
899
|
+
RetryOperation.prototype.try = function(fn) {
|
|
900
|
+
console.log("Using RetryOperation.try() is deprecated");
|
|
901
|
+
this.attempt(fn);
|
|
902
|
+
};
|
|
903
|
+
RetryOperation.prototype.start = function(fn) {
|
|
904
|
+
console.log("Using RetryOperation.start() is deprecated");
|
|
905
|
+
this.attempt(fn);
|
|
906
|
+
};
|
|
907
|
+
RetryOperation.prototype.start = RetryOperation.prototype.try;
|
|
908
|
+
RetryOperation.prototype.errors = function() {
|
|
909
|
+
return this._errors;
|
|
910
|
+
};
|
|
911
|
+
RetryOperation.prototype.attempts = function() {
|
|
912
|
+
return this._attempts;
|
|
913
|
+
};
|
|
914
|
+
RetryOperation.prototype.mainError = function() {
|
|
915
|
+
if (this._errors.length === 0) {
|
|
916
|
+
return null;
|
|
917
|
+
}
|
|
918
|
+
var counts = {};
|
|
919
|
+
var mainError = null;
|
|
920
|
+
var mainErrorCount = 0;
|
|
921
|
+
for (var i = 0;i < this._errors.length; i++) {
|
|
922
|
+
var error = this._errors[i];
|
|
923
|
+
var message = error.message;
|
|
924
|
+
var count = (counts[message] || 0) + 1;
|
|
925
|
+
counts[message] = count;
|
|
926
|
+
if (count >= mainErrorCount) {
|
|
927
|
+
mainError = error;
|
|
928
|
+
mainErrorCount = count;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
return mainError;
|
|
932
|
+
};
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
// node_modules/retry/lib/retry.js
|
|
936
|
+
var require_retry = __commonJS(function(exports) {
|
|
937
|
+
var RetryOperation = require_retry_operation();
|
|
938
|
+
exports.operation = function(options) {
|
|
939
|
+
var timeouts = exports.timeouts(options);
|
|
940
|
+
return new RetryOperation(timeouts, {
|
|
941
|
+
forever: options && options.forever,
|
|
942
|
+
unref: options && options.unref,
|
|
943
|
+
maxRetryTime: options && options.maxRetryTime
|
|
944
|
+
});
|
|
945
|
+
};
|
|
946
|
+
exports.timeouts = function(options) {
|
|
947
|
+
if (options instanceof Array) {
|
|
948
|
+
return [].concat(options);
|
|
949
|
+
}
|
|
950
|
+
var opts = {
|
|
951
|
+
retries: 10,
|
|
952
|
+
factor: 2,
|
|
953
|
+
minTimeout: 1 * 1000,
|
|
954
|
+
maxTimeout: Infinity,
|
|
955
|
+
randomize: false
|
|
956
|
+
};
|
|
957
|
+
for (var key in options) {
|
|
958
|
+
opts[key] = options[key];
|
|
959
|
+
}
|
|
960
|
+
if (opts.minTimeout > opts.maxTimeout) {
|
|
961
|
+
throw new Error("minTimeout is greater than maxTimeout");
|
|
962
|
+
}
|
|
963
|
+
var timeouts = [];
|
|
964
|
+
for (var i = 0;i < opts.retries; i++) {
|
|
965
|
+
timeouts.push(this.createTimeout(i, opts));
|
|
966
|
+
}
|
|
967
|
+
if (options && options.forever && !timeouts.length) {
|
|
968
|
+
timeouts.push(this.createTimeout(i, opts));
|
|
969
|
+
}
|
|
970
|
+
timeouts.sort(function(a, b) {
|
|
971
|
+
return a - b;
|
|
972
|
+
});
|
|
973
|
+
return timeouts;
|
|
974
|
+
};
|
|
975
|
+
exports.createTimeout = function(attempt, opts) {
|
|
976
|
+
var random = opts.randomize ? Math.random() + 1 : 1;
|
|
977
|
+
var timeout = Math.round(random * opts.minTimeout * Math.pow(opts.factor, attempt));
|
|
978
|
+
timeout = Math.min(timeout, opts.maxTimeout);
|
|
979
|
+
return timeout;
|
|
980
|
+
};
|
|
981
|
+
exports.wrap = function(obj, options, methods) {
|
|
982
|
+
if (options instanceof Array) {
|
|
983
|
+
methods = options;
|
|
984
|
+
options = null;
|
|
985
|
+
}
|
|
986
|
+
if (!methods) {
|
|
987
|
+
methods = [];
|
|
988
|
+
for (var key in obj) {
|
|
989
|
+
if (typeof obj[key] === "function") {
|
|
990
|
+
methods.push(key);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
for (var i = 0;i < methods.length; i++) {
|
|
995
|
+
var method = methods[i];
|
|
996
|
+
var original = obj[method];
|
|
997
|
+
obj[method] = function retryWrapper(original2) {
|
|
998
|
+
var op = exports.operation(options);
|
|
999
|
+
var args = Array.prototype.slice.call(arguments, 1);
|
|
1000
|
+
var callback = args.pop();
|
|
1001
|
+
args.push(function(err) {
|
|
1002
|
+
if (op.retry(err)) {
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
if (err) {
|
|
1006
|
+
arguments[0] = op.mainError();
|
|
1007
|
+
}
|
|
1008
|
+
callback.apply(this, arguments);
|
|
1009
|
+
});
|
|
1010
|
+
op.attempt(function() {
|
|
1011
|
+
original2.apply(obj, args);
|
|
1012
|
+
});
|
|
1013
|
+
}.bind(obj, original);
|
|
1014
|
+
obj[method].options = options;
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
});
|
|
1018
|
+
|
|
1019
|
+
// node_modules/proper-lockfile/lib/mtime-precision.js
|
|
1020
|
+
var require_mtime_precision = __commonJS(function(exports, module) {
|
|
1021
|
+
var cacheSymbol = Symbol();
|
|
1022
|
+
function probe(file, fs, callback) {
|
|
1023
|
+
const cachedPrecision = fs[cacheSymbol];
|
|
1024
|
+
if (cachedPrecision) {
|
|
1025
|
+
return fs.stat(file, (err, stat) => {
|
|
1026
|
+
if (err) {
|
|
1027
|
+
return callback(err);
|
|
1028
|
+
}
|
|
1029
|
+
callback(null, stat.mtime, cachedPrecision);
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
const mtime = new Date(Math.ceil(Date.now() / 1000) * 1000 + 5);
|
|
1033
|
+
fs.utimes(file, mtime, mtime, (err) => {
|
|
1034
|
+
if (err) {
|
|
1035
|
+
return callback(err);
|
|
1036
|
+
}
|
|
1037
|
+
fs.stat(file, (err2, stat) => {
|
|
1038
|
+
if (err2) {
|
|
1039
|
+
return callback(err2);
|
|
1040
|
+
}
|
|
1041
|
+
const precision = stat.mtime.getTime() % 1000 === 0 ? "s" : "ms";
|
|
1042
|
+
Object.defineProperty(fs, cacheSymbol, { value: precision });
|
|
1043
|
+
callback(null, stat.mtime, precision);
|
|
1044
|
+
});
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
function getMtime(precision) {
|
|
1048
|
+
let now = Date.now();
|
|
1049
|
+
if (precision === "s") {
|
|
1050
|
+
now = Math.ceil(now / 1000) * 1000;
|
|
1051
|
+
}
|
|
1052
|
+
return new Date(now);
|
|
1053
|
+
}
|
|
1054
|
+
exports.probe = probe;
|
|
1055
|
+
exports.getMtime = getMtime;
|
|
1056
|
+
});
|
|
1057
|
+
|
|
1058
|
+
// node_modules/proper-lockfile/lib/lockfile.js
|
|
1059
|
+
var require_lockfile = __commonJS(function(exports, module) {
|
|
1060
|
+
var path = __require("path");
|
|
1061
|
+
var fs = require_graceful_fs();
|
|
1062
|
+
var retry = require_retry();
|
|
1063
|
+
var onExit = require_signal_exit();
|
|
1064
|
+
var mtimePrecision = require_mtime_precision();
|
|
1065
|
+
var locks = {};
|
|
1066
|
+
function getLockFile(file, options) {
|
|
1067
|
+
return options.lockfilePath || `${file}.lock`;
|
|
1068
|
+
}
|
|
1069
|
+
function resolveCanonicalPath(file, options, callback) {
|
|
1070
|
+
if (!options.realpath) {
|
|
1071
|
+
return callback(null, path.resolve(file));
|
|
1072
|
+
}
|
|
1073
|
+
options.fs.realpath(file, callback);
|
|
1074
|
+
}
|
|
1075
|
+
function acquireLock(file, options, callback) {
|
|
1076
|
+
const lockfilePath = getLockFile(file, options);
|
|
1077
|
+
options.fs.mkdir(lockfilePath, (err) => {
|
|
1078
|
+
if (!err) {
|
|
1079
|
+
return mtimePrecision.probe(lockfilePath, options.fs, (err2, mtime, mtimePrecision2) => {
|
|
1080
|
+
if (err2) {
|
|
1081
|
+
options.fs.rmdir(lockfilePath, () => {});
|
|
1082
|
+
return callback(err2);
|
|
1083
|
+
}
|
|
1084
|
+
callback(null, mtime, mtimePrecision2);
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
if (err.code !== "EEXIST") {
|
|
1088
|
+
return callback(err);
|
|
1089
|
+
}
|
|
1090
|
+
if (options.stale <= 0) {
|
|
1091
|
+
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
|
|
1092
|
+
}
|
|
1093
|
+
options.fs.stat(lockfilePath, (err2, stat) => {
|
|
1094
|
+
if (err2) {
|
|
1095
|
+
if (err2.code === "ENOENT") {
|
|
1096
|
+
return acquireLock(file, { ...options, stale: 0 }, callback);
|
|
1097
|
+
}
|
|
1098
|
+
return callback(err2);
|
|
1099
|
+
}
|
|
1100
|
+
if (!isLockStale(stat, options)) {
|
|
1101
|
+
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
|
|
1102
|
+
}
|
|
1103
|
+
removeLock(file, options, (err3) => {
|
|
1104
|
+
if (err3) {
|
|
1105
|
+
return callback(err3);
|
|
1106
|
+
}
|
|
1107
|
+
acquireLock(file, { ...options, stale: 0 }, callback);
|
|
1108
|
+
});
|
|
1109
|
+
});
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
function isLockStale(stat, options) {
|
|
1113
|
+
return stat.mtime.getTime() < Date.now() - options.stale;
|
|
1114
|
+
}
|
|
1115
|
+
function removeLock(file, options, callback) {
|
|
1116
|
+
options.fs.rmdir(getLockFile(file, options), (err) => {
|
|
1117
|
+
if (err && err.code !== "ENOENT") {
|
|
1118
|
+
return callback(err);
|
|
1119
|
+
}
|
|
1120
|
+
callback();
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
function updateLock(file, options) {
|
|
1124
|
+
const lock2 = locks[file];
|
|
1125
|
+
if (lock2.updateTimeout) {
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
1128
|
+
lock2.updateDelay = lock2.updateDelay || options.update;
|
|
1129
|
+
lock2.updateTimeout = setTimeout(() => {
|
|
1130
|
+
lock2.updateTimeout = null;
|
|
1131
|
+
options.fs.stat(lock2.lockfilePath, (err, stat) => {
|
|
1132
|
+
const isOverThreshold = lock2.lastUpdate + options.stale < Date.now();
|
|
1133
|
+
if (err) {
|
|
1134
|
+
if (err.code === "ENOENT" || isOverThreshold) {
|
|
1135
|
+
return setLockAsCompromised(file, lock2, Object.assign(err, { code: "ECOMPROMISED" }));
|
|
1136
|
+
}
|
|
1137
|
+
lock2.updateDelay = 1000;
|
|
1138
|
+
return updateLock(file, options);
|
|
1139
|
+
}
|
|
1140
|
+
const isMtimeOurs = lock2.mtime.getTime() === stat.mtime.getTime();
|
|
1141
|
+
if (!isMtimeOurs) {
|
|
1142
|
+
return setLockAsCompromised(file, lock2, Object.assign(new Error("Unable to update lock within the stale threshold"), { code: "ECOMPROMISED" }));
|
|
1143
|
+
}
|
|
1144
|
+
const mtime = mtimePrecision.getMtime(lock2.mtimePrecision);
|
|
1145
|
+
options.fs.utimes(lock2.lockfilePath, mtime, mtime, (err2) => {
|
|
1146
|
+
const isOverThreshold2 = lock2.lastUpdate + options.stale < Date.now();
|
|
1147
|
+
if (lock2.released) {
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
if (err2) {
|
|
1151
|
+
if (err2.code === "ENOENT" || isOverThreshold2) {
|
|
1152
|
+
return setLockAsCompromised(file, lock2, Object.assign(err2, { code: "ECOMPROMISED" }));
|
|
1153
|
+
}
|
|
1154
|
+
lock2.updateDelay = 1000;
|
|
1155
|
+
return updateLock(file, options);
|
|
1156
|
+
}
|
|
1157
|
+
lock2.mtime = mtime;
|
|
1158
|
+
lock2.lastUpdate = Date.now();
|
|
1159
|
+
lock2.updateDelay = null;
|
|
1160
|
+
updateLock(file, options);
|
|
1161
|
+
});
|
|
1162
|
+
});
|
|
1163
|
+
}, lock2.updateDelay);
|
|
1164
|
+
if (lock2.updateTimeout.unref) {
|
|
1165
|
+
lock2.updateTimeout.unref();
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
function setLockAsCompromised(file, lock2, err) {
|
|
1169
|
+
lock2.released = true;
|
|
1170
|
+
if (lock2.updateTimeout) {
|
|
1171
|
+
clearTimeout(lock2.updateTimeout);
|
|
1172
|
+
}
|
|
1173
|
+
if (locks[file] === lock2) {
|
|
1174
|
+
delete locks[file];
|
|
1175
|
+
}
|
|
1176
|
+
lock2.options.onCompromised(err);
|
|
1177
|
+
}
|
|
1178
|
+
function lock(file, options, callback) {
|
|
1179
|
+
options = {
|
|
1180
|
+
stale: 1e4,
|
|
1181
|
+
update: null,
|
|
1182
|
+
realpath: true,
|
|
1183
|
+
retries: 0,
|
|
1184
|
+
fs,
|
|
1185
|
+
onCompromised: (err) => {
|
|
1186
|
+
throw err;
|
|
1187
|
+
},
|
|
1188
|
+
...options
|
|
1189
|
+
};
|
|
1190
|
+
options.retries = options.retries || 0;
|
|
1191
|
+
options.retries = typeof options.retries === "number" ? { retries: options.retries } : options.retries;
|
|
1192
|
+
options.stale = Math.max(options.stale || 0, 2000);
|
|
1193
|
+
options.update = options.update == null ? options.stale / 2 : options.update || 0;
|
|
1194
|
+
options.update = Math.max(Math.min(options.update, options.stale / 2), 1000);
|
|
1195
|
+
resolveCanonicalPath(file, options, (err, file2) => {
|
|
1196
|
+
if (err) {
|
|
1197
|
+
return callback(err);
|
|
1198
|
+
}
|
|
1199
|
+
const operation = retry.operation(options.retries);
|
|
1200
|
+
operation.attempt(() => {
|
|
1201
|
+
acquireLock(file2, options, (err2, mtime, mtimePrecision2) => {
|
|
1202
|
+
if (operation.retry(err2)) {
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
if (err2) {
|
|
1206
|
+
return callback(operation.mainError());
|
|
1207
|
+
}
|
|
1208
|
+
const lock2 = locks[file2] = {
|
|
1209
|
+
lockfilePath: getLockFile(file2, options),
|
|
1210
|
+
mtime,
|
|
1211
|
+
mtimePrecision: mtimePrecision2,
|
|
1212
|
+
options,
|
|
1213
|
+
lastUpdate: Date.now()
|
|
1214
|
+
};
|
|
1215
|
+
updateLock(file2, options);
|
|
1216
|
+
callback(null, (releasedCallback) => {
|
|
1217
|
+
if (lock2.released) {
|
|
1218
|
+
return releasedCallback && releasedCallback(Object.assign(new Error("Lock is already released"), { code: "ERELEASED" }));
|
|
1219
|
+
}
|
|
1220
|
+
unlock(file2, { ...options, realpath: false }, releasedCallback);
|
|
1221
|
+
});
|
|
1222
|
+
});
|
|
1223
|
+
});
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
function unlock(file, options, callback) {
|
|
1227
|
+
options = {
|
|
1228
|
+
fs,
|
|
1229
|
+
realpath: true,
|
|
1230
|
+
...options
|
|
1231
|
+
};
|
|
1232
|
+
resolveCanonicalPath(file, options, (err, file2) => {
|
|
1233
|
+
if (err) {
|
|
1234
|
+
return callback(err);
|
|
1235
|
+
}
|
|
1236
|
+
const lock2 = locks[file2];
|
|
1237
|
+
if (!lock2) {
|
|
1238
|
+
return callback(Object.assign(new Error("Lock is not acquired/owned by you"), { code: "ENOTACQUIRED" }));
|
|
1239
|
+
}
|
|
1240
|
+
lock2.updateTimeout && clearTimeout(lock2.updateTimeout);
|
|
1241
|
+
lock2.released = true;
|
|
1242
|
+
delete locks[file2];
|
|
1243
|
+
removeLock(file2, options, callback);
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
function check(file, options, callback) {
|
|
1247
|
+
options = {
|
|
1248
|
+
stale: 1e4,
|
|
1249
|
+
realpath: true,
|
|
1250
|
+
fs,
|
|
1251
|
+
...options
|
|
1252
|
+
};
|
|
1253
|
+
options.stale = Math.max(options.stale || 0, 2000);
|
|
1254
|
+
resolveCanonicalPath(file, options, (err, file2) => {
|
|
1255
|
+
if (err) {
|
|
1256
|
+
return callback(err);
|
|
1257
|
+
}
|
|
1258
|
+
options.fs.stat(getLockFile(file2, options), (err2, stat) => {
|
|
1259
|
+
if (err2) {
|
|
1260
|
+
return err2.code === "ENOENT" ? callback(null, false) : callback(err2);
|
|
1261
|
+
}
|
|
1262
|
+
return callback(null, !isLockStale(stat, options));
|
|
1263
|
+
});
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
function getLocks() {
|
|
1267
|
+
return locks;
|
|
1268
|
+
}
|
|
1269
|
+
onExit(() => {
|
|
1270
|
+
for (const file in locks) {
|
|
1271
|
+
const options = locks[file].options;
|
|
1272
|
+
try {
|
|
1273
|
+
options.fs.rmdirSync(getLockFile(file, options));
|
|
1274
|
+
} catch (e) {}
|
|
1275
|
+
}
|
|
1276
|
+
});
|
|
1277
|
+
exports.lock = lock;
|
|
1278
|
+
exports.unlock = unlock;
|
|
1279
|
+
exports.check = check;
|
|
1280
|
+
exports.getLocks = getLocks;
|
|
1281
|
+
});
|
|
1282
|
+
|
|
1283
|
+
// node_modules/proper-lockfile/lib/adapter.js
|
|
1284
|
+
var require_adapter = __commonJS(function(exports, module) {
|
|
1285
|
+
var fs = require_graceful_fs();
|
|
1286
|
+
function createSyncFs(fs2) {
|
|
1287
|
+
const methods = ["mkdir", "realpath", "stat", "rmdir", "utimes"];
|
|
1288
|
+
const newFs = { ...fs2 };
|
|
1289
|
+
methods.forEach((method) => {
|
|
1290
|
+
newFs[method] = (...args) => {
|
|
1291
|
+
const callback = args.pop();
|
|
1292
|
+
let ret;
|
|
1293
|
+
try {
|
|
1294
|
+
ret = fs2[`${method}Sync`](...args);
|
|
1295
|
+
} catch (err) {
|
|
1296
|
+
return callback(err);
|
|
1297
|
+
}
|
|
1298
|
+
callback(null, ret);
|
|
1299
|
+
};
|
|
1300
|
+
});
|
|
1301
|
+
return newFs;
|
|
1302
|
+
}
|
|
1303
|
+
function toPromise(method) {
|
|
1304
|
+
return (...args) => new Promise((resolve, reject) => {
|
|
1305
|
+
args.push((err, result) => {
|
|
1306
|
+
if (err) {
|
|
1307
|
+
reject(err);
|
|
1308
|
+
} else {
|
|
1309
|
+
resolve(result);
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
method(...args);
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
1315
|
+
function toSync(method) {
|
|
1316
|
+
return (...args) => {
|
|
1317
|
+
let err;
|
|
1318
|
+
let result;
|
|
1319
|
+
args.push((_err, _result) => {
|
|
1320
|
+
err = _err;
|
|
1321
|
+
result = _result;
|
|
1322
|
+
});
|
|
1323
|
+
method(...args);
|
|
1324
|
+
if (err) {
|
|
1325
|
+
throw err;
|
|
1326
|
+
}
|
|
1327
|
+
return result;
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
function toSyncOptions(options) {
|
|
1331
|
+
options = { ...options };
|
|
1332
|
+
options.fs = createSyncFs(options.fs || fs);
|
|
1333
|
+
if (typeof options.retries === "number" && options.retries > 0 || options.retries && typeof options.retries.retries === "number" && options.retries.retries > 0) {
|
|
1334
|
+
throw Object.assign(new Error("Cannot use retries with the sync api"), { code: "ESYNC" });
|
|
1335
|
+
}
|
|
1336
|
+
return options;
|
|
1337
|
+
}
|
|
1338
|
+
module.exports = {
|
|
1339
|
+
toPromise,
|
|
1340
|
+
toSync,
|
|
1341
|
+
toSyncOptions
|
|
1342
|
+
};
|
|
1343
|
+
});
|
|
1344
|
+
|
|
1345
|
+
// node_modules/proper-lockfile/index.js
|
|
1346
|
+
var require_proper_lockfile = __commonJS(function(exports, module) {
|
|
1347
|
+
var lockfile = require_lockfile();
|
|
1348
|
+
var { toPromise, toSync, toSyncOptions } = require_adapter();
|
|
1349
|
+
async function lock(file, options) {
|
|
1350
|
+
const release = await toPromise(lockfile.lock)(file, options);
|
|
1351
|
+
return toPromise(release);
|
|
1352
|
+
}
|
|
1353
|
+
function lockSync(file, options) {
|
|
1354
|
+
const release = toSync(lockfile.lock)(file, toSyncOptions(options));
|
|
1355
|
+
return toSync(release);
|
|
1356
|
+
}
|
|
1357
|
+
function unlock(file, options) {
|
|
1358
|
+
return toPromise(lockfile.unlock)(file, options);
|
|
1359
|
+
}
|
|
1360
|
+
function unlockSync(file, options) {
|
|
1361
|
+
return toSync(lockfile.unlock)(file, toSyncOptions(options));
|
|
1362
|
+
}
|
|
1363
|
+
function check(file, options) {
|
|
1364
|
+
return toPromise(lockfile.check)(file, options);
|
|
1365
|
+
}
|
|
1366
|
+
function checkSync(file, options) {
|
|
1367
|
+
return toSync(lockfile.check)(file, toSyncOptions(options));
|
|
1368
|
+
}
|
|
1369
|
+
module.exports = lock;
|
|
1370
|
+
module.exports.lock = lock;
|
|
1371
|
+
module.exports.unlock = unlock;
|
|
1372
|
+
module.exports.lockSync = lockSync;
|
|
1373
|
+
module.exports.unlockSync = unlockSync;
|
|
1374
|
+
module.exports.check = check;
|
|
1375
|
+
module.exports.checkSync = checkSync;
|
|
1376
|
+
});
|
|
1377
|
+
|
|
1378
|
+
// node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js
|
|
1379
|
+
import { execSync, spawnSync } from "child_process";
|
|
1380
|
+
var commandResultCache = new Map;
|
|
1381
|
+
var ENV_VAR_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
1382
|
+
var ENV_VAR_NAME_PREFIX_RE = /^[A-Za-z_][A-Za-z0-9_]*/;
|
|
1383
|
+
function appendLiteral(parts, value) {
|
|
1384
|
+
if (!value)
|
|
1385
|
+
return;
|
|
1386
|
+
const previousPart = parts[parts.length - 1];
|
|
1387
|
+
if (previousPart?.type === "literal") {
|
|
1388
|
+
previousPart.value += value;
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
parts.push({ type: "literal", value });
|
|
1392
|
+
}
|
|
1393
|
+
function parseConfigValueTemplate(config) {
|
|
1394
|
+
const parts = [];
|
|
1395
|
+
let index = 0;
|
|
1396
|
+
while (index < config.length) {
|
|
1397
|
+
const dollarIndex = config.indexOf("$", index);
|
|
1398
|
+
if (dollarIndex < 0) {
|
|
1399
|
+
appendLiteral(parts, config.slice(index));
|
|
1400
|
+
break;
|
|
1401
|
+
}
|
|
1402
|
+
appendLiteral(parts, config.slice(index, dollarIndex));
|
|
1403
|
+
const nextChar = config[dollarIndex + 1];
|
|
1404
|
+
if (nextChar === "$" || nextChar === "!") {
|
|
1405
|
+
appendLiteral(parts, nextChar);
|
|
1406
|
+
index = dollarIndex + 2;
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
if (nextChar === "{") {
|
|
1410
|
+
const endIndex = config.indexOf("}", dollarIndex + 2);
|
|
1411
|
+
if (endIndex < 0) {
|
|
1412
|
+
appendLiteral(parts, "$");
|
|
1413
|
+
index = dollarIndex + 1;
|
|
1414
|
+
continue;
|
|
1415
|
+
}
|
|
1416
|
+
const name = config.slice(dollarIndex + 2, endIndex);
|
|
1417
|
+
if (ENV_VAR_NAME_RE.test(name)) {
|
|
1418
|
+
parts.push({ type: "env", name });
|
|
1419
|
+
} else {
|
|
1420
|
+
appendLiteral(parts, config.slice(dollarIndex, endIndex + 1));
|
|
1421
|
+
}
|
|
1422
|
+
index = endIndex + 1;
|
|
1423
|
+
continue;
|
|
1424
|
+
}
|
|
1425
|
+
const match = config.slice(dollarIndex + 1).match(ENV_VAR_NAME_PREFIX_RE);
|
|
1426
|
+
if (match) {
|
|
1427
|
+
parts.push({ type: "env", name: match[0] });
|
|
1428
|
+
index = dollarIndex + 1 + match[0].length;
|
|
1429
|
+
continue;
|
|
1430
|
+
}
|
|
1431
|
+
appendLiteral(parts, "$");
|
|
1432
|
+
index = dollarIndex + 1;
|
|
1433
|
+
}
|
|
1434
|
+
return parts;
|
|
1435
|
+
}
|
|
1436
|
+
function parseConfigValueReference(config) {
|
|
1437
|
+
if (config.startsWith("!")) {
|
|
1438
|
+
return { type: "command", config };
|
|
1439
|
+
}
|
|
1440
|
+
return { type: "template", parts: parseConfigValueTemplate(config) };
|
|
1441
|
+
}
|
|
1442
|
+
function resolveEnvConfigValue(name, env) {
|
|
1443
|
+
return env?.[name] || process.env[name] || undefined;
|
|
1444
|
+
}
|
|
1445
|
+
function getTemplateEnvVarNames(parts) {
|
|
1446
|
+
const names = [];
|
|
1447
|
+
for (const part of parts) {
|
|
1448
|
+
if (part.type !== "env" || names.includes(part.name))
|
|
1449
|
+
continue;
|
|
1450
|
+
names.push(part.name);
|
|
1451
|
+
}
|
|
1452
|
+
return names;
|
|
1453
|
+
}
|
|
1454
|
+
function resolveTemplate(parts, env) {
|
|
1455
|
+
let resolved = "";
|
|
1456
|
+
for (const part of parts) {
|
|
1457
|
+
if (part.type === "literal") {
|
|
1458
|
+
resolved += part.value;
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
const envValue = resolveEnvConfigValue(part.name, env);
|
|
1462
|
+
if (envValue === undefined)
|
|
1463
|
+
return;
|
|
1464
|
+
resolved += envValue;
|
|
1465
|
+
}
|
|
1466
|
+
return resolved;
|
|
1467
|
+
}
|
|
1468
|
+
function getConfigValueEnvVarNames(config) {
|
|
1469
|
+
const reference = parseConfigValueReference(config);
|
|
1470
|
+
return reference.type === "template" ? getTemplateEnvVarNames(reference.parts) : [];
|
|
1471
|
+
}
|
|
1472
|
+
function getMissingConfigValueEnvVarNames(config, env) {
|
|
1473
|
+
return getConfigValueEnvVarNames(config).filter((name) => resolveEnvConfigValue(name, env) === undefined);
|
|
1474
|
+
}
|
|
1475
|
+
function isCommandConfigValue(config) {
|
|
1476
|
+
return parseConfigValueReference(config).type === "command";
|
|
1477
|
+
}
|
|
1478
|
+
function isConfigValueConfigured(config, env) {
|
|
1479
|
+
return getMissingConfigValueEnvVarNames(config, env).length === 0;
|
|
1480
|
+
}
|
|
1481
|
+
function resolveConfigValue(config, env) {
|
|
1482
|
+
const reference = parseConfigValueReference(config);
|
|
1483
|
+
if (reference.type === "command") {
|
|
1484
|
+
return executeCommand(reference.config);
|
|
1485
|
+
}
|
|
1486
|
+
return resolveTemplate(reference.parts, env);
|
|
1487
|
+
}
|
|
1488
|
+
function executeWithConfiguredShell(command) {
|
|
1489
|
+
try {
|
|
1490
|
+
const { shell, args, commandTransport } = getShellConfig();
|
|
1491
|
+
const commandFromStdin = commandTransport === "stdin";
|
|
1492
|
+
const result = spawnSync(shell, commandFromStdin ? args : [...args, command], {
|
|
1493
|
+
encoding: "utf-8",
|
|
1494
|
+
input: commandFromStdin ? command : undefined,
|
|
1495
|
+
timeout: 1e4,
|
|
1496
|
+
stdio: [commandFromStdin ? "pipe" : "ignore", "pipe", "ignore"],
|
|
1497
|
+
shell: false,
|
|
1498
|
+
windowsHide: true
|
|
1499
|
+
});
|
|
1500
|
+
if (result.error) {
|
|
1501
|
+
const error = result.error;
|
|
1502
|
+
if (error.code === "ENOENT") {
|
|
1503
|
+
return { executed: false, value: undefined };
|
|
1504
|
+
}
|
|
1505
|
+
return { executed: true, value: undefined };
|
|
1506
|
+
}
|
|
1507
|
+
if (result.status !== 0) {
|
|
1508
|
+
return { executed: true, value: undefined };
|
|
1509
|
+
}
|
|
1510
|
+
const value = (result.stdout ?? "").trim();
|
|
1511
|
+
return { executed: true, value: value || undefined };
|
|
1512
|
+
} catch {
|
|
1513
|
+
return { executed: false, value: undefined };
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
function executeWithDefaultShell(command) {
|
|
1517
|
+
try {
|
|
1518
|
+
const output = execSync(command, {
|
|
1519
|
+
encoding: "utf-8",
|
|
1520
|
+
timeout: 1e4,
|
|
1521
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1522
|
+
});
|
|
1523
|
+
return output.trim() || undefined;
|
|
1524
|
+
} catch {
|
|
1525
|
+
return;
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
function executeCommandUncached(commandConfig) {
|
|
1529
|
+
const command = commandConfig.slice(1);
|
|
1530
|
+
return process.platform === "win32" ? (() => {
|
|
1531
|
+
const configuredResult = executeWithConfiguredShell(command);
|
|
1532
|
+
return configuredResult.executed ? configuredResult.value : executeWithDefaultShell(command);
|
|
1533
|
+
})() : executeWithDefaultShell(command);
|
|
1534
|
+
}
|
|
1535
|
+
function executeCommand(commandConfig) {
|
|
1536
|
+
if (commandResultCache.has(commandConfig)) {
|
|
1537
|
+
return commandResultCache.get(commandConfig);
|
|
1538
|
+
}
|
|
1539
|
+
const result = executeCommandUncached(commandConfig);
|
|
1540
|
+
commandResultCache.set(commandConfig, result);
|
|
1541
|
+
return result;
|
|
1542
|
+
}
|
|
1543
|
+
function resolveConfigValueUncached(config, env) {
|
|
1544
|
+
const reference = parseConfigValueReference(config);
|
|
1545
|
+
if (reference.type === "command") {
|
|
1546
|
+
return executeCommandUncached(reference.config);
|
|
1547
|
+
}
|
|
1548
|
+
return resolveTemplate(reference.parts, env);
|
|
1549
|
+
}
|
|
1550
|
+
function resolveConfigValueOrThrow(config, description, env) {
|
|
1551
|
+
const resolvedValue = resolveConfigValueUncached(config, env);
|
|
1552
|
+
if (resolvedValue !== undefined) {
|
|
1553
|
+
return resolvedValue;
|
|
1554
|
+
}
|
|
1555
|
+
const reference = parseConfigValueReference(config);
|
|
1556
|
+
if (reference.type === "command") {
|
|
1557
|
+
throw new Error(`Failed to resolve ${description} from shell command: ${reference.config.slice(1)}`);
|
|
1558
|
+
}
|
|
1559
|
+
if (reference.type === "template") {
|
|
1560
|
+
const missingEnvVars = getMissingConfigValueEnvVarNames(config, env);
|
|
1561
|
+
if (missingEnvVars.length === 1) {
|
|
1562
|
+
throw new Error(`Failed to resolve ${description} from environment variable: ${missingEnvVars[0]}`);
|
|
1563
|
+
}
|
|
1564
|
+
if (missingEnvVars.length > 1) {
|
|
1565
|
+
throw new Error(`Failed to resolve ${description} from environment variables: ${missingEnvVars.join(", ")}`);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
throw new Error(`Failed to resolve ${description}`);
|
|
1569
|
+
}
|
|
1570
|
+
function resolveHeadersOrThrow(headers, description, env) {
|
|
1571
|
+
if (!headers)
|
|
1572
|
+
return;
|
|
1573
|
+
const resolved = {};
|
|
1574
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
1575
|
+
resolved[key] = resolveConfigValueOrThrow(value, `${description} header "${key}"`, env);
|
|
1576
|
+
}
|
|
1577
|
+
return Object.keys(resolved).length > 0 ? resolved : undefined;
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
// node_modules/@earendil-works/pi-mcp/dist/protocol/jsonrpc.js
|
|
1581
|
+
var JSON_RPC_ERROR_CODES = {
|
|
1582
|
+
parseError: -32700,
|
|
1583
|
+
invalidRequest: -32600,
|
|
1584
|
+
methodNotFound: -32601,
|
|
1585
|
+
invalidParams: -32602,
|
|
1586
|
+
internalError: -32603
|
|
1587
|
+
};
|
|
1588
|
+
|
|
1589
|
+
class McpError extends Error {
|
|
1590
|
+
code;
|
|
1591
|
+
data;
|
|
1592
|
+
constructor(code, message, data) {
|
|
1593
|
+
super(message);
|
|
1594
|
+
this.name = "McpError";
|
|
1595
|
+
this.code = code;
|
|
1596
|
+
this.data = data;
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
class McpConnectionClosedError extends Error {
|
|
1601
|
+
constructor(message = "MCP connection closed") {
|
|
1602
|
+
super(message);
|
|
1603
|
+
this.name = "McpConnectionClosedError";
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
class McpTimeoutError extends Error {
|
|
1608
|
+
timeoutMs;
|
|
1609
|
+
constructor(timeoutMs) {
|
|
1610
|
+
super(`MCP request timed out after ${timeoutMs}ms`);
|
|
1611
|
+
this.name = "McpTimeoutError";
|
|
1612
|
+
this.timeoutMs = timeoutMs;
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
class McpAbortError extends Error {
|
|
1617
|
+
constructor(message = "MCP request aborted") {
|
|
1618
|
+
super(message);
|
|
1619
|
+
this.name = "AbortError";
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
function isObject(value) {
|
|
1623
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1624
|
+
}
|
|
1625
|
+
function toError(value) {
|
|
1626
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
1627
|
+
}
|
|
1628
|
+
function isJsonRpcId(value) {
|
|
1629
|
+
return typeof value === "string" || typeof value === "number" && Number.isFinite(value);
|
|
1630
|
+
}
|
|
1631
|
+
function isJsonRpcRequest(message) {
|
|
1632
|
+
return isObject(message) && message.jsonrpc === "2.0" && isJsonRpcId(message.id) && typeof message.method === "string";
|
|
1633
|
+
}
|
|
1634
|
+
function isJsonRpcNotification(message) {
|
|
1635
|
+
return isObject(message) && message.jsonrpc === "2.0" && !("id" in message) && typeof message.method === "string";
|
|
1636
|
+
}
|
|
1637
|
+
function isJsonRpcResponse(message) {
|
|
1638
|
+
if (!isObject(message) || message.jsonrpc !== "2.0" || !isJsonRpcId(message.id))
|
|
1639
|
+
return false;
|
|
1640
|
+
if ("result" in message)
|
|
1641
|
+
return !("error" in message);
|
|
1642
|
+
if (!("error" in message) || !isObject(message.error))
|
|
1643
|
+
return false;
|
|
1644
|
+
return typeof message.error.code === "number" && typeof message.error.message === "string";
|
|
1645
|
+
}
|
|
1646
|
+
function parseJsonRpcMessage(value) {
|
|
1647
|
+
if (isJsonRpcRequest(value) || isJsonRpcNotification(value) || isJsonRpcResponse(value))
|
|
1648
|
+
return value;
|
|
1649
|
+
throw new McpError(JSON_RPC_ERROR_CODES.invalidRequest, "Invalid JSON-RPC message");
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
// node_modules/@earendil-works/pi-mcp/dist/protocol/types.js
|
|
1653
|
+
var LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
1654
|
+
var SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, "2025-06-18", "2025-03-26", "2024-11-05"];
|
|
1655
|
+
|
|
1656
|
+
// node_modules/@earendil-works/pi-mcp/dist/client.js
|
|
1657
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
1658
|
+
var MAX_LIST_PAGES = 1000;
|
|
1659
|
+
function validateInitializeResult(value) {
|
|
1660
|
+
if (!isObject(value) || typeof value.protocolVersion !== "string" || !isObject(value.capabilities) || !isObject(value.serverInfo) || typeof value.serverInfo.name !== "string" || typeof value.serverInfo.version !== "string" || value.instructions !== undefined && typeof value.instructions !== "string") {
|
|
1661
|
+
throw new McpError(JSON_RPC_ERROR_CODES.invalidRequest, "Invalid MCP initialize result");
|
|
1662
|
+
}
|
|
1663
|
+
return value;
|
|
1664
|
+
}
|
|
1665
|
+
function invalid(message) {
|
|
1666
|
+
return new McpError(JSON_RPC_ERROR_CODES.invalidRequest, message);
|
|
1667
|
+
}
|
|
1668
|
+
function validateListPage(method, key, value, isItem) {
|
|
1669
|
+
const items = isObject(value) ? value[key] : undefined;
|
|
1670
|
+
if (!isObject(value) || !Array.isArray(items))
|
|
1671
|
+
throw invalid(`Invalid MCP ${method} result`);
|
|
1672
|
+
for (const item of items) {
|
|
1673
|
+
if (!isObject(item) || !isItem(item))
|
|
1674
|
+
throw invalid(`Invalid entry in MCP ${method} result`);
|
|
1675
|
+
}
|
|
1676
|
+
if (value.nextCursor !== undefined && typeof value.nextCursor !== "string") {
|
|
1677
|
+
throw invalid(`Invalid MCP ${method} cursor`);
|
|
1678
|
+
}
|
|
1679
|
+
return { items, ...value.nextCursor === undefined ? {} : { nextCursor: value.nextCursor } };
|
|
1680
|
+
}
|
|
1681
|
+
var isTool = (tool) => typeof tool.name === "string" && isObject(tool.inputSchema);
|
|
1682
|
+
var isResource = (resource) => typeof resource.uri === "string" && (resource.name === undefined || typeof resource.name === "string");
|
|
1683
|
+
var isResourceTemplate = (template) => typeof template.uriTemplate === "string" && (template.name === undefined || typeof template.name === "string");
|
|
1684
|
+
function toResource(item) {
|
|
1685
|
+
return { ...item, name: item.name ?? item.uri };
|
|
1686
|
+
}
|
|
1687
|
+
function toResourceTemplate(item) {
|
|
1688
|
+
return { ...item, name: item.name ?? item.uriTemplate };
|
|
1689
|
+
}
|
|
1690
|
+
function pageCursor(page) {
|
|
1691
|
+
return page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor };
|
|
1692
|
+
}
|
|
1693
|
+
function validateReadResourceResult(value) {
|
|
1694
|
+
if (!isObject(value) || !Array.isArray(value.contents))
|
|
1695
|
+
throw invalid("Invalid MCP resources/read result");
|
|
1696
|
+
for (const contents of value.contents) {
|
|
1697
|
+
if (!isObject(contents) || typeof contents.uri !== "string" || typeof contents.text !== "string" && typeof contents.blob !== "string") {
|
|
1698
|
+
throw invalid("Invalid contents in MCP resources/read result");
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
return value;
|
|
1702
|
+
}
|
|
1703
|
+
function validateCallToolResult(value) {
|
|
1704
|
+
if (!isObject(value) || value.content !== undefined && !Array.isArray(value.content)) {
|
|
1705
|
+
throw new McpError(JSON_RPC_ERROR_CODES.invalidRequest, "Invalid MCP tools/call result");
|
|
1706
|
+
}
|
|
1707
|
+
if (value.structuredContent !== undefined && !isObject(value.structuredContent)) {
|
|
1708
|
+
throw new McpError(JSON_RPC_ERROR_CODES.invalidRequest, "Invalid MCP tools/call structured content");
|
|
1709
|
+
}
|
|
1710
|
+
return value.content === undefined ? { ...value, content: [] } : value;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
class McpClient {
|
|
1714
|
+
options;
|
|
1715
|
+
state = "idle";
|
|
1716
|
+
transport;
|
|
1717
|
+
nextRequestId = 1;
|
|
1718
|
+
serverInfoValue;
|
|
1719
|
+
serverCapabilitiesValue;
|
|
1720
|
+
instructionsValue;
|
|
1721
|
+
protocolVersionValue;
|
|
1722
|
+
pending = new Map;
|
|
1723
|
+
progressRequests = new Map;
|
|
1724
|
+
incoming = new Map;
|
|
1725
|
+
requestHandlers = new Map;
|
|
1726
|
+
notificationListeners = new Map;
|
|
1727
|
+
errorListeners = new Set;
|
|
1728
|
+
closeListeners = new Set;
|
|
1729
|
+
disposers = [];
|
|
1730
|
+
constructor(options) {
|
|
1731
|
+
this.options = Object.freeze({ ...options });
|
|
1732
|
+
this.requestHandlers.set("ping", () => ({}));
|
|
1733
|
+
const roots = options.roots;
|
|
1734
|
+
if (roots) {
|
|
1735
|
+
this.requestHandlers.set("roots/list", async () => ({
|
|
1736
|
+
roots: [...typeof roots === "function" ? await roots() : roots]
|
|
1737
|
+
}));
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
get connectionState() {
|
|
1741
|
+
return this.state;
|
|
1742
|
+
}
|
|
1743
|
+
get serverInfo() {
|
|
1744
|
+
return this.serverInfoValue;
|
|
1745
|
+
}
|
|
1746
|
+
get serverCapabilities() {
|
|
1747
|
+
return this.serverCapabilitiesValue;
|
|
1748
|
+
}
|
|
1749
|
+
get instructions() {
|
|
1750
|
+
return this.instructionsValue;
|
|
1751
|
+
}
|
|
1752
|
+
get protocolVersion() {
|
|
1753
|
+
return this.protocolVersionValue;
|
|
1754
|
+
}
|
|
1755
|
+
async connect(transport) {
|
|
1756
|
+
if (this.state !== "idle")
|
|
1757
|
+
throw new Error(`Cannot connect MCP client in ${this.state} state`);
|
|
1758
|
+
this.state = "connecting";
|
|
1759
|
+
this.transport = transport;
|
|
1760
|
+
this.disposers = [
|
|
1761
|
+
transport.onMessage((message) => this.handleMessage(message)),
|
|
1762
|
+
transport.onError((error) => this.emitError(error)),
|
|
1763
|
+
transport.onClose(() => this.handleTransportClose())
|
|
1764
|
+
];
|
|
1765
|
+
try {
|
|
1766
|
+
await transport.start();
|
|
1767
|
+
const capabilities = { ...this.options.capabilities };
|
|
1768
|
+
if (this.options.roots && capabilities.roots === undefined)
|
|
1769
|
+
capabilities.roots = {};
|
|
1770
|
+
const result = validateInitializeResult(await this.requestInternal("initialize", {
|
|
1771
|
+
protocolVersion: this.options.protocolVersion ?? LATEST_PROTOCOL_VERSION,
|
|
1772
|
+
capabilities,
|
|
1773
|
+
clientInfo: {
|
|
1774
|
+
name: this.options.name,
|
|
1775
|
+
version: this.options.version,
|
|
1776
|
+
...this.options.title === undefined ? {} : { title: this.options.title }
|
|
1777
|
+
}
|
|
1778
|
+
}, {}, true));
|
|
1779
|
+
if (!SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) {
|
|
1780
|
+
throw new Error(`MCP server selected unsupported protocol version ${result.protocolVersion}`);
|
|
1781
|
+
}
|
|
1782
|
+
this.protocolVersionValue = result.protocolVersion;
|
|
1783
|
+
this.serverInfoValue = result.serverInfo;
|
|
1784
|
+
this.serverCapabilitiesValue = result.capabilities;
|
|
1785
|
+
this.instructionsValue = result.instructions;
|
|
1786
|
+
transport.setProtocolVersion?.(result.protocolVersion);
|
|
1787
|
+
await this.notifyInternal("notifications/initialized", undefined, true);
|
|
1788
|
+
this.state = "connected";
|
|
1789
|
+
return result;
|
|
1790
|
+
} catch (error) {
|
|
1791
|
+
await this.close().catch(() => {});
|
|
1792
|
+
throw error;
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
request(method, params, options = {}) {
|
|
1796
|
+
return this.requestInternal(method, params, options, false);
|
|
1797
|
+
}
|
|
1798
|
+
notify(method, params) {
|
|
1799
|
+
return this.notifyInternal(method, params, false);
|
|
1800
|
+
}
|
|
1801
|
+
setRequestHandler(method, handler) {
|
|
1802
|
+
this.requestHandlers.set(method, handler);
|
|
1803
|
+
return () => {
|
|
1804
|
+
if (this.requestHandlers.get(method) === handler)
|
|
1805
|
+
this.requestHandlers.delete(method);
|
|
1806
|
+
};
|
|
1807
|
+
}
|
|
1808
|
+
onNotification(method, listener) {
|
|
1809
|
+
const listeners = this.notificationListeners.get(method) ?? new Set;
|
|
1810
|
+
this.notificationListeners.set(method, listeners);
|
|
1811
|
+
listeners.add(listener);
|
|
1812
|
+
return () => {
|
|
1813
|
+
listeners.delete(listener);
|
|
1814
|
+
if (listeners.size === 0)
|
|
1815
|
+
this.notificationListeners.delete(method);
|
|
1816
|
+
};
|
|
1817
|
+
}
|
|
1818
|
+
onError(listener) {
|
|
1819
|
+
this.errorListeners.add(listener);
|
|
1820
|
+
return () => this.errorListeners.delete(listener);
|
|
1821
|
+
}
|
|
1822
|
+
onClose(listener) {
|
|
1823
|
+
this.closeListeners.add(listener);
|
|
1824
|
+
return () => this.closeListeners.delete(listener);
|
|
1825
|
+
}
|
|
1826
|
+
async ping(options = {}) {
|
|
1827
|
+
await this.request("ping", undefined, options);
|
|
1828
|
+
}
|
|
1829
|
+
async listTools(options = {}) {
|
|
1830
|
+
return await this.listAll("tools/list", "tools", isTool, options);
|
|
1831
|
+
}
|
|
1832
|
+
async listResources(options = {}) {
|
|
1833
|
+
return (await this.listAll("resources/list", "resources", isResource, options)).map(toResource);
|
|
1834
|
+
}
|
|
1835
|
+
async listResourcesPage(cursor, options = {}) {
|
|
1836
|
+
const page = await this.listPage("resources/list", "resources", isResource, cursor, options);
|
|
1837
|
+
return { resources: page.items.map(toResource), ...pageCursor(page) };
|
|
1838
|
+
}
|
|
1839
|
+
async listResourceTemplates(options = {}) {
|
|
1840
|
+
const templates = await this.listAll("resources/templates/list", "resourceTemplates", isResourceTemplate, options);
|
|
1841
|
+
return templates.map(toResourceTemplate);
|
|
1842
|
+
}
|
|
1843
|
+
async listResourceTemplatesPage(cursor, options = {}) {
|
|
1844
|
+
const page = await this.listPage("resources/templates/list", "resourceTemplates", isResourceTemplate, cursor, options);
|
|
1845
|
+
return { resourceTemplates: page.items.map(toResourceTemplate), ...pageCursor(page) };
|
|
1846
|
+
}
|
|
1847
|
+
async readResource(uri, options = {}) {
|
|
1848
|
+
return validateReadResourceResult(await this.request("resources/read", { uri }, options));
|
|
1849
|
+
}
|
|
1850
|
+
async listPage(method, key, isItem, cursor, options) {
|
|
1851
|
+
return validateListPage(method, key, await this.request(method, cursor === undefined ? undefined : { cursor }, options), isItem);
|
|
1852
|
+
}
|
|
1853
|
+
async listAll(method, key, isItem, options) {
|
|
1854
|
+
const items = [];
|
|
1855
|
+
const cursors = new Set;
|
|
1856
|
+
let cursor;
|
|
1857
|
+
for (let pageNumber = 0;pageNumber < MAX_LIST_PAGES; pageNumber++) {
|
|
1858
|
+
const page = await this.listPage(method, key, isItem, cursor, options);
|
|
1859
|
+
items.push(...page.items);
|
|
1860
|
+
if (page.nextCursor === undefined)
|
|
1861
|
+
return items;
|
|
1862
|
+
if (cursors.has(page.nextCursor))
|
|
1863
|
+
throw new Error(`MCP ${method} returned duplicate cursor: ${page.nextCursor}`);
|
|
1864
|
+
cursors.add(page.nextCursor);
|
|
1865
|
+
cursor = page.nextCursor;
|
|
1866
|
+
}
|
|
1867
|
+
throw new Error(`MCP ${method} exceeded ${MAX_LIST_PAGES} pages`);
|
|
1868
|
+
}
|
|
1869
|
+
async callTool(name, args, options = {}) {
|
|
1870
|
+
return validateCallToolResult(await this.request("tools/call", { name, ...args === undefined ? {} : { arguments: args } }, options));
|
|
1871
|
+
}
|
|
1872
|
+
async close() {
|
|
1873
|
+
const transport = this.transport;
|
|
1874
|
+
this.transport = undefined;
|
|
1875
|
+
this.disposeTransportListeners();
|
|
1876
|
+
this.markClosed(new McpConnectionClosedError);
|
|
1877
|
+
await transport?.close();
|
|
1878
|
+
}
|
|
1879
|
+
async requestInternal(method, params, options, allowConnecting) {
|
|
1880
|
+
const transport = this.requireTransport(allowConnecting);
|
|
1881
|
+
if (options.signal?.aborted)
|
|
1882
|
+
throw new McpAbortError;
|
|
1883
|
+
const id = this.nextRequestId++;
|
|
1884
|
+
const progressToken = options.onProgress ? id : undefined;
|
|
1885
|
+
const requestParams = progressToken === undefined ? params : { ...params, _meta: { ...isObject(params?._meta) ? params._meta : {}, progressToken } };
|
|
1886
|
+
const message = {
|
|
1887
|
+
jsonrpc: "2.0",
|
|
1888
|
+
id,
|
|
1889
|
+
method,
|
|
1890
|
+
...requestParams === undefined ? {} : { params: requestParams }
|
|
1891
|
+
};
|
|
1892
|
+
return new Promise((resolve, reject) => {
|
|
1893
|
+
const entry = {
|
|
1894
|
+
resolve,
|
|
1895
|
+
reject,
|
|
1896
|
+
timeoutMs: options.timeoutMs ?? this.options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
|
|
1897
|
+
timer: undefined,
|
|
1898
|
+
signal: options.signal,
|
|
1899
|
+
onAbort: () => this.cancelPending(id, new McpAbortError, method !== "initialize", String(options.signal?.reason ?? "Aborted")),
|
|
1900
|
+
cancellable: method !== "initialize",
|
|
1901
|
+
onProgress: options.onProgress,
|
|
1902
|
+
progressToken
|
|
1903
|
+
};
|
|
1904
|
+
this.pending.set(id, entry);
|
|
1905
|
+
if (progressToken !== undefined)
|
|
1906
|
+
this.progressRequests.set(progressToken, id);
|
|
1907
|
+
options.signal?.addEventListener("abort", entry.onAbort, { once: true });
|
|
1908
|
+
this.armTimeout(id, entry);
|
|
1909
|
+
transport.send(message).catch((error) => this.cancelPending(id, error, false));
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1912
|
+
async notifyInternal(method, params, allowConnecting) {
|
|
1913
|
+
await this.requireTransport(allowConnecting).send({
|
|
1914
|
+
jsonrpc: "2.0",
|
|
1915
|
+
method,
|
|
1916
|
+
...params === undefined ? {} : { params }
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1919
|
+
requireTransport(allowConnecting) {
|
|
1920
|
+
if (this.transport && (this.state === "connected" || allowConnecting && this.state === "connecting")) {
|
|
1921
|
+
return this.transport;
|
|
1922
|
+
}
|
|
1923
|
+
throw new McpConnectionClosedError(`MCP client is ${this.state}`);
|
|
1924
|
+
}
|
|
1925
|
+
handleMessage(message) {
|
|
1926
|
+
if (isJsonRpcResponse(message)) {
|
|
1927
|
+
this.handleResponse(message);
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1930
|
+
if (isJsonRpcRequest(message)) {
|
|
1931
|
+
this.handleRequest(message);
|
|
1932
|
+
return;
|
|
1933
|
+
}
|
|
1934
|
+
if (isJsonRpcNotification(message)) {
|
|
1935
|
+
this.handleNotification(message.method, message.params);
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1938
|
+
this.emitError(new McpError(JSON_RPC_ERROR_CODES.invalidRequest, "Received invalid JSON-RPC message"));
|
|
1939
|
+
}
|
|
1940
|
+
handleResponse(message) {
|
|
1941
|
+
const entry = this.pending.get(message.id);
|
|
1942
|
+
if (!entry) {
|
|
1943
|
+
this.emitError(new Error(`Received response for unknown MCP request ${String(message.id)}`));
|
|
1944
|
+
return;
|
|
1945
|
+
}
|
|
1946
|
+
this.removePending(message.id, entry);
|
|
1947
|
+
if ("error" in message)
|
|
1948
|
+
entry.reject(new McpError(message.error.code, message.error.message, message.error.data));
|
|
1949
|
+
else
|
|
1950
|
+
entry.resolve(message.result);
|
|
1951
|
+
}
|
|
1952
|
+
async handleRequest(message) {
|
|
1953
|
+
const transport = this.transport;
|
|
1954
|
+
if (!transport)
|
|
1955
|
+
return;
|
|
1956
|
+
const handler = this.requestHandlers.get(message.method);
|
|
1957
|
+
if (!handler) {
|
|
1958
|
+
await transport.send({
|
|
1959
|
+
jsonrpc: "2.0",
|
|
1960
|
+
id: message.id,
|
|
1961
|
+
error: { code: JSON_RPC_ERROR_CODES.methodNotFound, message: `Method not found: ${message.method}` }
|
|
1962
|
+
}).catch((error) => this.emitError(error));
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1965
|
+
const controller = new AbortController;
|
|
1966
|
+
this.incoming.set(message.id, controller);
|
|
1967
|
+
try {
|
|
1968
|
+
const result = await handler(message.params, { signal: controller.signal });
|
|
1969
|
+
await transport.send({ jsonrpc: "2.0", id: message.id, result: result ?? {} });
|
|
1970
|
+
} catch (error) {
|
|
1971
|
+
const responseError = error instanceof McpError ? { code: error.code, message: error.message, data: error.data } : { code: JSON_RPC_ERROR_CODES.internalError, message: toError(error).message };
|
|
1972
|
+
await transport.send({ jsonrpc: "2.0", id: message.id, error: responseError }).catch((sendError) => this.emitError(sendError));
|
|
1973
|
+
} finally {
|
|
1974
|
+
this.incoming.delete(message.id);
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
handleNotification(method, params) {
|
|
1978
|
+
if (method === "notifications/progress")
|
|
1979
|
+
this.handleProgress(params);
|
|
1980
|
+
else if (method === "notifications/cancelled")
|
|
1981
|
+
this.handleCancelled(params);
|
|
1982
|
+
for (const listener of this.notificationListeners.get(method) ?? []) {
|
|
1983
|
+
try {
|
|
1984
|
+
listener(params);
|
|
1985
|
+
} catch (error) {
|
|
1986
|
+
this.emitError(error);
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
handleProgress(params) {
|
|
1991
|
+
if (!isObject(params) || !isJsonRpcId(params.progressToken) || typeof params.progress !== "number")
|
|
1992
|
+
return;
|
|
1993
|
+
const requestId = this.progressRequests.get(params.progressToken);
|
|
1994
|
+
const entry = requestId === undefined ? undefined : this.pending.get(requestId);
|
|
1995
|
+
if (requestId === undefined || !entry)
|
|
1996
|
+
return;
|
|
1997
|
+
this.armTimeout(requestId, entry);
|
|
1998
|
+
try {
|
|
1999
|
+
entry.onProgress?.(params);
|
|
2000
|
+
} catch (error) {
|
|
2001
|
+
this.emitError(error);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
handleCancelled(params) {
|
|
2005
|
+
if (isObject(params) && isJsonRpcId(params.requestId))
|
|
2006
|
+
this.incoming.get(params.requestId)?.abort(params.reason);
|
|
2007
|
+
}
|
|
2008
|
+
armTimeout(id, entry) {
|
|
2009
|
+
if (entry.timer)
|
|
2010
|
+
clearTimeout(entry.timer);
|
|
2011
|
+
if (!Number.isFinite(entry.timeoutMs) || entry.timeoutMs <= 0)
|
|
2012
|
+
return;
|
|
2013
|
+
entry.timer = setTimeout(() => {
|
|
2014
|
+
this.cancelPending(id, new McpTimeoutError(entry.timeoutMs), entry.cancellable, "Request timed out");
|
|
2015
|
+
}, entry.timeoutMs);
|
|
2016
|
+
}
|
|
2017
|
+
cancelPending(id, error, notifyServer, reason) {
|
|
2018
|
+
const entry = this.pending.get(id);
|
|
2019
|
+
if (!entry)
|
|
2020
|
+
return;
|
|
2021
|
+
this.removePending(id, entry);
|
|
2022
|
+
entry.reject(error);
|
|
2023
|
+
if (notifyServer && this.transport) {
|
|
2024
|
+
this.transport.send({
|
|
2025
|
+
jsonrpc: "2.0",
|
|
2026
|
+
method: "notifications/cancelled",
|
|
2027
|
+
params: { requestId: id, ...reason ? { reason } : {} }
|
|
2028
|
+
}).catch((sendError) => this.emitError(sendError));
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
removePending(id, entry) {
|
|
2032
|
+
this.pending.delete(id);
|
|
2033
|
+
if (entry.timer)
|
|
2034
|
+
clearTimeout(entry.timer);
|
|
2035
|
+
if (entry.progressToken !== undefined)
|
|
2036
|
+
this.progressRequests.delete(entry.progressToken);
|
|
2037
|
+
entry.signal?.removeEventListener("abort", entry.onAbort);
|
|
2038
|
+
}
|
|
2039
|
+
rejectPending(error) {
|
|
2040
|
+
for (const [id, entry] of this.pending) {
|
|
2041
|
+
this.removePending(id, entry);
|
|
2042
|
+
entry.reject(error);
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
handleTransportClose() {
|
|
2046
|
+
this.markClosed(new McpConnectionClosedError);
|
|
2047
|
+
}
|
|
2048
|
+
markClosed(error) {
|
|
2049
|
+
const wasClosed = this.state === "closed";
|
|
2050
|
+
this.state = "closed";
|
|
2051
|
+
this.rejectPending(error);
|
|
2052
|
+
for (const controller of this.incoming.values())
|
|
2053
|
+
controller.abort(error);
|
|
2054
|
+
this.incoming.clear();
|
|
2055
|
+
if (wasClosed)
|
|
2056
|
+
return;
|
|
2057
|
+
for (const listener of [...this.closeListeners]) {
|
|
2058
|
+
try {
|
|
2059
|
+
listener();
|
|
2060
|
+
} catch (listenerError) {
|
|
2061
|
+
this.emitError(listenerError);
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
emitError(error) {
|
|
2066
|
+
const normalized = toError(error);
|
|
2067
|
+
for (const listener of this.errorListeners)
|
|
2068
|
+
listener(normalized);
|
|
2069
|
+
}
|
|
2070
|
+
disposeTransportListeners() {
|
|
2071
|
+
for (const dispose of this.disposers.splice(0))
|
|
2072
|
+
dispose();
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
// node_modules/@earendil-works/pi-mcp/dist/transports/stdio.js
|
|
2077
|
+
var import_cross_spawn = __toESM(require_cross_spawn(), 1);
|
|
2078
|
+
import { spawn } from "node:child_process";
|
|
2079
|
+
import process2 from "node:process";
|
|
2080
|
+
|
|
2081
|
+
// node_modules/@earendil-works/pi-mcp/dist/transports/transport.js
|
|
2082
|
+
var DEFAULT_MAX_MESSAGE_BYTES = 16 * 1024 * 1024;
|
|
2083
|
+
|
|
2084
|
+
class TransportEvents {
|
|
2085
|
+
messageListeners = new Set;
|
|
2086
|
+
errorListeners = new Set;
|
|
2087
|
+
closeListeners = new Set;
|
|
2088
|
+
closeEmitted = false;
|
|
2089
|
+
onMessage(listener) {
|
|
2090
|
+
this.messageListeners.add(listener);
|
|
2091
|
+
return () => this.messageListeners.delete(listener);
|
|
2092
|
+
}
|
|
2093
|
+
onError(listener) {
|
|
2094
|
+
this.errorListeners.add(listener);
|
|
2095
|
+
return () => this.errorListeners.delete(listener);
|
|
2096
|
+
}
|
|
2097
|
+
onClose(listener) {
|
|
2098
|
+
this.closeListeners.add(listener);
|
|
2099
|
+
return () => this.closeListeners.delete(listener);
|
|
2100
|
+
}
|
|
2101
|
+
emitMessage(message) {
|
|
2102
|
+
for (const listener of this.messageListeners)
|
|
2103
|
+
listener(message);
|
|
2104
|
+
}
|
|
2105
|
+
emitError(error) {
|
|
2106
|
+
const normalized = toError(error);
|
|
2107
|
+
for (const listener of this.errorListeners)
|
|
2108
|
+
listener(normalized);
|
|
2109
|
+
}
|
|
2110
|
+
emitClose() {
|
|
2111
|
+
if (this.closeEmitted)
|
|
2112
|
+
return;
|
|
2113
|
+
this.closeEmitted = true;
|
|
2114
|
+
for (const listener of this.closeListeners)
|
|
2115
|
+
listener();
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
// node_modules/@earendil-works/pi-mcp/dist/transports/stdio.js
|
|
2120
|
+
var DEFAULT_MAX_STDERR_BYTES = 64 * 1024;
|
|
2121
|
+
var DEFAULT_CLOSE_TIMEOUT_MS = 2000;
|
|
2122
|
+
var STDIN_CLOSE_GRACE_MS = 500;
|
|
2123
|
+
var USE_PROCESS_GROUPS = process2.platform !== "win32";
|
|
2124
|
+
var liveProcessGroups = new Set;
|
|
2125
|
+
var exitHookInstalled = false;
|
|
2126
|
+
function killProcessTree(child, signal) {
|
|
2127
|
+
const pid = child.pid;
|
|
2128
|
+
if (process2.platform === "win32" && pid !== undefined) {
|
|
2129
|
+
if (child.exitCode !== null)
|
|
2130
|
+
return;
|
|
2131
|
+
spawn("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true }).on("error", () => {});
|
|
2132
|
+
return;
|
|
2133
|
+
}
|
|
2134
|
+
if (USE_PROCESS_GROUPS && pid !== undefined) {
|
|
2135
|
+
try {
|
|
2136
|
+
process2.kill(-pid, signal);
|
|
2137
|
+
return;
|
|
2138
|
+
} catch {}
|
|
2139
|
+
}
|
|
2140
|
+
try {
|
|
2141
|
+
child.kill(signal);
|
|
2142
|
+
} catch {}
|
|
2143
|
+
}
|
|
2144
|
+
function installExitHook() {
|
|
2145
|
+
if (exitHookInstalled)
|
|
2146
|
+
return;
|
|
2147
|
+
exitHookInstalled = true;
|
|
2148
|
+
process2.once("exit", () => {
|
|
2149
|
+
for (const pid of liveProcessGroups) {
|
|
2150
|
+
try {
|
|
2151
|
+
process2.kill(-pid, "SIGTERM");
|
|
2152
|
+
} catch {}
|
|
2153
|
+
}
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
class StdioTransport extends TransportEvents {
|
|
2158
|
+
options;
|
|
2159
|
+
child;
|
|
2160
|
+
stdoutBuffer = Buffer.alloc(0);
|
|
2161
|
+
stderrBuffer = Buffer.alloc(0);
|
|
2162
|
+
started = false;
|
|
2163
|
+
closed = false;
|
|
2164
|
+
constructor(options) {
|
|
2165
|
+
super();
|
|
2166
|
+
this.options = Object.freeze({ ...options, args: options.args ? [...options.args] : undefined });
|
|
2167
|
+
}
|
|
2168
|
+
get pid() {
|
|
2169
|
+
return this.child?.pid;
|
|
2170
|
+
}
|
|
2171
|
+
get stderr() {
|
|
2172
|
+
return this.stderrBuffer.toString("utf8");
|
|
2173
|
+
}
|
|
2174
|
+
async start() {
|
|
2175
|
+
if (this.started)
|
|
2176
|
+
throw new Error("MCP stdio transport already started");
|
|
2177
|
+
if (this.closed)
|
|
2178
|
+
throw new McpConnectionClosedError;
|
|
2179
|
+
this.started = true;
|
|
2180
|
+
const env = this.options.inheritEnv === false ? { ...this.options.env } : { ...process2.env, ...this.options.env };
|
|
2181
|
+
const child = import_cross_spawn.default(this.options.command, this.options.args ?? [], {
|
|
2182
|
+
cwd: this.options.cwd,
|
|
2183
|
+
env,
|
|
2184
|
+
stdio: ["pipe", "pipe", this.options.stderr === "inherit" ? "inherit" : "pipe"],
|
|
2185
|
+
windowsHide: true,
|
|
2186
|
+
detached: USE_PROCESS_GROUPS
|
|
2187
|
+
});
|
|
2188
|
+
this.child = child;
|
|
2189
|
+
const pid = child.pid;
|
|
2190
|
+
if (USE_PROCESS_GROUPS && pid !== undefined) {
|
|
2191
|
+
installExitHook();
|
|
2192
|
+
liveProcessGroups.add(pid);
|
|
2193
|
+
child.once("exit", () => liveProcessGroups.delete(pid));
|
|
2194
|
+
}
|
|
2195
|
+
child.stdout?.on("data", (chunk) => this.handleStdout(chunk));
|
|
2196
|
+
child.stdout?.on("error", (error) => this.emitError(error));
|
|
2197
|
+
child.stdin?.on("error", (error) => {
|
|
2198
|
+
if (!this.closed)
|
|
2199
|
+
this.emitError(error);
|
|
2200
|
+
});
|
|
2201
|
+
child.stderr?.on("data", (chunk) => this.handleStderr(chunk));
|
|
2202
|
+
child.stderr?.on("error", (error) => this.emitError(error));
|
|
2203
|
+
child.on("close", () => {
|
|
2204
|
+
this.child = undefined;
|
|
2205
|
+
if (this.stdoutBuffer.toString("utf8").trim()) {
|
|
2206
|
+
this.emitError(new Error("MCP stdio server closed with an incomplete JSON-RPC message"));
|
|
2207
|
+
}
|
|
2208
|
+
this.stdoutBuffer = Buffer.alloc(0);
|
|
2209
|
+
this.emitClose();
|
|
2210
|
+
});
|
|
2211
|
+
await new Promise((resolve, reject) => {
|
|
2212
|
+
const onSpawn = () => {
|
|
2213
|
+
child.off("error", onError);
|
|
2214
|
+
resolve();
|
|
2215
|
+
};
|
|
2216
|
+
const onError = (error) => {
|
|
2217
|
+
child.off("spawn", onSpawn);
|
|
2218
|
+
reject(error);
|
|
2219
|
+
};
|
|
2220
|
+
child.once("spawn", onSpawn);
|
|
2221
|
+
child.once("error", onError);
|
|
2222
|
+
});
|
|
2223
|
+
child.on("error", (error) => {
|
|
2224
|
+
if (!this.closed)
|
|
2225
|
+
this.emitError(error);
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
async send(message) {
|
|
2229
|
+
const stdin = this.child?.stdin;
|
|
2230
|
+
if (!this.started || this.closed || !stdin?.writable)
|
|
2231
|
+
throw new McpConnectionClosedError;
|
|
2232
|
+
const payload = `${JSON.stringify(message)}
|
|
2233
|
+
`;
|
|
2234
|
+
await new Promise((resolve, reject) => {
|
|
2235
|
+
stdin.write(payload, (error) => error ? reject(error) : resolve());
|
|
2236
|
+
});
|
|
2237
|
+
}
|
|
2238
|
+
async close() {
|
|
2239
|
+
if (this.closed)
|
|
2240
|
+
return;
|
|
2241
|
+
this.closed = true;
|
|
2242
|
+
const child = this.child;
|
|
2243
|
+
if (!child) {
|
|
2244
|
+
this.emitClose();
|
|
2245
|
+
return;
|
|
2246
|
+
}
|
|
2247
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
2248
|
+
child.stdin?.end();
|
|
2249
|
+
return;
|
|
2250
|
+
}
|
|
2251
|
+
const closeTimeoutMs = this.options.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS;
|
|
2252
|
+
await new Promise((resolve) => {
|
|
2253
|
+
const timers = [];
|
|
2254
|
+
child.once("close", () => {
|
|
2255
|
+
for (const timer of timers)
|
|
2256
|
+
clearTimeout(timer);
|
|
2257
|
+
killProcessTree(child, "SIGTERM");
|
|
2258
|
+
resolve();
|
|
2259
|
+
});
|
|
2260
|
+
const grace = Math.min(STDIN_CLOSE_GRACE_MS, closeTimeoutMs);
|
|
2261
|
+
timers.push(setTimeout(() => killProcessTree(child, "SIGTERM"), grace));
|
|
2262
|
+
timers.push(setTimeout(() => killProcessTree(child, "SIGKILL"), grace + closeTimeoutMs));
|
|
2263
|
+
child.stdin?.end();
|
|
2264
|
+
});
|
|
2265
|
+
}
|
|
2266
|
+
handleStdout(chunk) {
|
|
2267
|
+
this.stdoutBuffer = Buffer.concat([this.stdoutBuffer, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)]);
|
|
2268
|
+
const maxMessageBytes = this.options.maxMessageBytes ?? DEFAULT_MAX_MESSAGE_BYTES;
|
|
2269
|
+
while (true) {
|
|
2270
|
+
const newline = this.stdoutBuffer.indexOf(10);
|
|
2271
|
+
if (newline < 0) {
|
|
2272
|
+
if (this.stdoutBuffer.length > maxMessageBytes) {
|
|
2273
|
+
this.stdoutBuffer = Buffer.alloc(0);
|
|
2274
|
+
this.emitError(new Error(`MCP stdio message exceeds ${maxMessageBytes} bytes`));
|
|
2275
|
+
}
|
|
2276
|
+
return;
|
|
2277
|
+
}
|
|
2278
|
+
const line = this.stdoutBuffer.subarray(0, newline);
|
|
2279
|
+
this.stdoutBuffer = this.stdoutBuffer.subarray(newline + 1);
|
|
2280
|
+
if (line.length > maxMessageBytes) {
|
|
2281
|
+
this.emitError(new Error(`MCP stdio message exceeds ${maxMessageBytes} bytes`));
|
|
2282
|
+
continue;
|
|
2283
|
+
}
|
|
2284
|
+
const text = line.toString("utf8").replace(/\r$/, "");
|
|
2285
|
+
if (!text.trim())
|
|
2286
|
+
continue;
|
|
2287
|
+
try {
|
|
2288
|
+
this.emitMessage(parseJsonRpcMessage(JSON.parse(text)));
|
|
2289
|
+
} catch (error) {
|
|
2290
|
+
this.emitError(error);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
handleStderr(chunk) {
|
|
2295
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
2296
|
+
const maxStderrBytes = this.options.maxStderrBytes ?? DEFAULT_MAX_STDERR_BYTES;
|
|
2297
|
+
this.stderrBuffer = Buffer.concat([this.stderrBuffer, buffer]);
|
|
2298
|
+
if (this.stderrBuffer.length > maxStderrBytes)
|
|
2299
|
+
this.stderrBuffer = this.stderrBuffer.subarray(-maxStderrBytes);
|
|
2300
|
+
this.options.onStderr?.(buffer.toString("utf8"));
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
// node_modules/@earendil-works/pi-mcp/dist/transports/streamable-http.js
|
|
2305
|
+
var MAX_ERROR_BODY_BYTES = 8 * 1024;
|
|
2306
|
+
var ERROR_MESSAGE_BODY_CHARS = 500;
|
|
2307
|
+
var DEFAULT_RECONNECT_INITIAL_DELAY_MS = 1000;
|
|
2308
|
+
var DEFAULT_RECONNECT_MAX_DELAY_MS = 30000;
|
|
2309
|
+
var DEFAULT_RECONNECT_MAX_RETRIES = 5;
|
|
2310
|
+
async function consumeSseStream(stream, options) {
|
|
2311
|
+
const reader = stream.getReader();
|
|
2312
|
+
const decoder = new TextDecoder;
|
|
2313
|
+
let buffered = "";
|
|
2314
|
+
let eventName;
|
|
2315
|
+
let eventId;
|
|
2316
|
+
let dataLines = [];
|
|
2317
|
+
let dataBytes = 0;
|
|
2318
|
+
const maxEventBytes = options.maxEventBytes ?? DEFAULT_MAX_MESSAGE_BYTES;
|
|
2319
|
+
const dispatch = () => {
|
|
2320
|
+
if (dataLines.length === 0) {
|
|
2321
|
+
eventName = undefined;
|
|
2322
|
+
eventId = undefined;
|
|
2323
|
+
return;
|
|
2324
|
+
}
|
|
2325
|
+
const data = dataLines.join(`
|
|
2326
|
+
`);
|
|
2327
|
+
options.onEvent({ ...eventName ? { event: eventName } : {}, data, ...eventId ? { id: eventId } : {} });
|
|
2328
|
+
eventName = undefined;
|
|
2329
|
+
eventId = undefined;
|
|
2330
|
+
dataLines = [];
|
|
2331
|
+
dataBytes = 0;
|
|
2332
|
+
};
|
|
2333
|
+
const processLine = (rawLine) => {
|
|
2334
|
+
const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
|
|
2335
|
+
if (line === "") {
|
|
2336
|
+
dispatch();
|
|
2337
|
+
return;
|
|
2338
|
+
}
|
|
2339
|
+
if (line.startsWith(":"))
|
|
2340
|
+
return;
|
|
2341
|
+
const colon = line.indexOf(":");
|
|
2342
|
+
const field = colon < 0 ? line : line.slice(0, colon);
|
|
2343
|
+
let value = colon < 0 ? "" : line.slice(colon + 1);
|
|
2344
|
+
if (value.startsWith(" "))
|
|
2345
|
+
value = value.slice(1);
|
|
2346
|
+
if (field === "data") {
|
|
2347
|
+
dataBytes += Buffer.byteLength(value) + (dataLines.length > 0 ? 1 : 0);
|
|
2348
|
+
if (dataBytes > maxEventBytes)
|
|
2349
|
+
throw new Error(`MCP SSE event exceeds ${maxEventBytes} bytes`);
|
|
2350
|
+
dataLines.push(value);
|
|
2351
|
+
} else if (field === "event")
|
|
2352
|
+
eventName = value;
|
|
2353
|
+
else if (field === "id" && !value.includes("\x00")) {
|
|
2354
|
+
eventId = value;
|
|
2355
|
+
options.onId?.(value);
|
|
2356
|
+
} else if (field === "retry" && /^\d+$/.test(value))
|
|
2357
|
+
options.onRetry?.(Number(value));
|
|
2358
|
+
};
|
|
2359
|
+
try {
|
|
2360
|
+
while (true) {
|
|
2361
|
+
const { done, value } = await reader.read();
|
|
2362
|
+
if (done)
|
|
2363
|
+
break;
|
|
2364
|
+
buffered += decoder.decode(value, { stream: true });
|
|
2365
|
+
let newline = buffered.indexOf(`
|
|
2366
|
+
`);
|
|
2367
|
+
while (newline >= 0) {
|
|
2368
|
+
processLine(buffered.slice(0, newline));
|
|
2369
|
+
buffered = buffered.slice(newline + 1);
|
|
2370
|
+
newline = buffered.indexOf(`
|
|
2371
|
+
`);
|
|
2372
|
+
}
|
|
2373
|
+
if (Buffer.byteLength(buffered) > maxEventBytes)
|
|
2374
|
+
throw new Error(`MCP SSE event exceeds ${maxEventBytes} bytes`);
|
|
2375
|
+
}
|
|
2376
|
+
buffered += decoder.decode();
|
|
2377
|
+
if (buffered)
|
|
2378
|
+
processLine(buffered);
|
|
2379
|
+
dispatch();
|
|
2380
|
+
} finally {
|
|
2381
|
+
reader.releaseLock();
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
class McpHttpError extends Error {
|
|
2386
|
+
status;
|
|
2387
|
+
body;
|
|
2388
|
+
constructor(status, message, body = "") {
|
|
2389
|
+
super(message);
|
|
2390
|
+
this.name = "McpHttpError";
|
|
2391
|
+
this.status = status;
|
|
2392
|
+
this.body = body;
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2396
|
+
class McpAuthRequiredError extends McpHttpError {
|
|
2397
|
+
wwwAuthenticate;
|
|
2398
|
+
constructor(response, body = "") {
|
|
2399
|
+
super(401, "MCP server requires authentication", body);
|
|
2400
|
+
this.name = "McpAuthRequiredError";
|
|
2401
|
+
this.wwwAuthenticate = response.headers.get("www-authenticate");
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
class McpSessionExpiredError extends McpHttpError {
|
|
2406
|
+
constructor(body = "") {
|
|
2407
|
+
super(404, "MCP session expired", body);
|
|
2408
|
+
this.name = "McpSessionExpiredError";
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
function contentType(response) {
|
|
2412
|
+
return response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
2413
|
+
}
|
|
2414
|
+
function needsAuthorization(response) {
|
|
2415
|
+
if (response.status === 401)
|
|
2416
|
+
return true;
|
|
2417
|
+
if (response.status !== 403)
|
|
2418
|
+
return false;
|
|
2419
|
+
return /(?:^|[\s,])error="?insufficient_scope"?/i.test(response.headers.get("www-authenticate") ?? "");
|
|
2420
|
+
}
|
|
2421
|
+
function isTransientStatus(status) {
|
|
2422
|
+
return status === 408 || status === 429 || status >= 500;
|
|
2423
|
+
}
|
|
2424
|
+
function discard(response) {
|
|
2425
|
+
return response.body?.cancel().catch(() => {}) ?? Promise.resolve();
|
|
2426
|
+
}
|
|
2427
|
+
function describeHttpFailure(status, body) {
|
|
2428
|
+
const text = body.trim();
|
|
2429
|
+
const snippet = text.length > ERROR_MESSAGE_BODY_CHARS ? `${text.slice(0, ERROR_MESSAGE_BODY_CHARS - 3)}...` : text;
|
|
2430
|
+
return `MCP HTTP request failed with status ${status}${snippet ? `: ${snippet}` : ""}`;
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
class StreamableHttpTransport extends TransportEvents {
|
|
2434
|
+
url;
|
|
2435
|
+
options;
|
|
2436
|
+
fetch;
|
|
2437
|
+
controller = new AbortController;
|
|
2438
|
+
started = false;
|
|
2439
|
+
closed = false;
|
|
2440
|
+
sessionIdValue;
|
|
2441
|
+
protocolVersion;
|
|
2442
|
+
getStreamStarted = false;
|
|
2443
|
+
constructor(options) {
|
|
2444
|
+
super();
|
|
2445
|
+
this.options = Object.freeze({ ...options, headers: options.headers ? { ...options.headers } : undefined });
|
|
2446
|
+
this.url = new URL(options.url);
|
|
2447
|
+
const fetch = options.fetch ?? globalThis.fetch;
|
|
2448
|
+
this.fetch = (input, init) => fetch(input, init);
|
|
2449
|
+
}
|
|
2450
|
+
get sessionId() {
|
|
2451
|
+
return this.sessionIdValue;
|
|
2452
|
+
}
|
|
2453
|
+
async start() {
|
|
2454
|
+
if (this.started)
|
|
2455
|
+
throw new Error("MCP Streamable HTTP transport already started");
|
|
2456
|
+
if (this.closed)
|
|
2457
|
+
throw new McpConnectionClosedError;
|
|
2458
|
+
this.started = true;
|
|
2459
|
+
}
|
|
2460
|
+
setProtocolVersion(version) {
|
|
2461
|
+
this.protocolVersion = version;
|
|
2462
|
+
}
|
|
2463
|
+
async send(message) {
|
|
2464
|
+
if (!this.started || this.closed)
|
|
2465
|
+
throw new McpConnectionClosedError;
|
|
2466
|
+
const response = await this.authorizedFetch("POST", {
|
|
2467
|
+
headers: { accept: "application/json, text/event-stream", "content-type": "application/json" },
|
|
2468
|
+
body: JSON.stringify(message)
|
|
2469
|
+
});
|
|
2470
|
+
await this.checkResponse(response);
|
|
2471
|
+
this.captureSession(response);
|
|
2472
|
+
if (!isJsonRpcRequest(message)) {
|
|
2473
|
+
await discard(response);
|
|
2474
|
+
if ("method" in message && message.method === "notifications/initialized")
|
|
2475
|
+
this.startGetStream();
|
|
2476
|
+
return;
|
|
2477
|
+
}
|
|
2478
|
+
if (response.status === 202 || response.status === 204) {
|
|
2479
|
+
throw new McpHttpError(response.status, `MCP server accepted request ${message.method} without a response`);
|
|
2480
|
+
}
|
|
2481
|
+
const type = contentType(response);
|
|
2482
|
+
if (type === "application/json") {
|
|
2483
|
+
const body = await response.json();
|
|
2484
|
+
for (const item of Array.isArray(body) ? body : [body])
|
|
2485
|
+
this.emitMessage(parseJsonRpcMessage(item));
|
|
2486
|
+
return;
|
|
2487
|
+
}
|
|
2488
|
+
if (type === "text/event-stream" && response.body) {
|
|
2489
|
+
this.consumeResponseStream(response.body, message.id);
|
|
2490
|
+
return;
|
|
2491
|
+
}
|
|
2492
|
+
await discard(response);
|
|
2493
|
+
throw new McpHttpError(response.status, `Unsupported MCP response content type: ${type ?? "missing"}`);
|
|
2494
|
+
}
|
|
2495
|
+
async close() {
|
|
2496
|
+
if (this.closed)
|
|
2497
|
+
return;
|
|
2498
|
+
this.closed = true;
|
|
2499
|
+
this.controller.abort();
|
|
2500
|
+
if (this.started && this.sessionIdValue) {
|
|
2501
|
+
const controller = new AbortController;
|
|
2502
|
+
const timeout = setTimeout(() => controller.abort(), 1000);
|
|
2503
|
+
try {
|
|
2504
|
+
const { headers } = await this.headers();
|
|
2505
|
+
await this.fetch(this.url, { method: "DELETE", headers, signal: controller.signal }).then(discard).catch(() => {
|
|
2506
|
+
return;
|
|
2507
|
+
});
|
|
2508
|
+
} catch {} finally {
|
|
2509
|
+
clearTimeout(timeout);
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
this.emitClose();
|
|
2513
|
+
}
|
|
2514
|
+
async authorizedFetch(method, init) {
|
|
2515
|
+
const onUnauthorized = this.options.authProvider?.onUnauthorized?.bind(this.options.authProvider);
|
|
2516
|
+
for (let attempt = 0;; attempt++) {
|
|
2517
|
+
const { headers, token } = await this.headers(init.headers);
|
|
2518
|
+
const response = await this.fetch(this.url, {
|
|
2519
|
+
method,
|
|
2520
|
+
headers,
|
|
2521
|
+
body: init.body,
|
|
2522
|
+
signal: this.controller.signal
|
|
2523
|
+
});
|
|
2524
|
+
if (attempt > 0 || !onUnauthorized || !needsAuthorization(response))
|
|
2525
|
+
return response;
|
|
2526
|
+
try {
|
|
2527
|
+
await onUnauthorized({ response, serverUrl: this.url, fetch: this.fetch, token });
|
|
2528
|
+
} finally {
|
|
2529
|
+
await discard(response);
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
async headers(extra = {}) {
|
|
2534
|
+
const headers = new Headers(this.options.headers);
|
|
2535
|
+
for (const [name, value] of Object.entries(extra))
|
|
2536
|
+
headers.set(name, value);
|
|
2537
|
+
if (this.sessionIdValue)
|
|
2538
|
+
headers.set("Mcp-Session-Id", this.sessionIdValue);
|
|
2539
|
+
if (this.protocolVersion)
|
|
2540
|
+
headers.set("MCP-Protocol-Version", this.protocolVersion);
|
|
2541
|
+
const token = await this.options.authProvider?.token();
|
|
2542
|
+
if (token)
|
|
2543
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
2544
|
+
return { headers, ...token ? { token } : {} };
|
|
2545
|
+
}
|
|
2546
|
+
captureSession(response) {
|
|
2547
|
+
const sessionId = response.headers.get("mcp-session-id");
|
|
2548
|
+
if (sessionId)
|
|
2549
|
+
this.sessionIdValue = sessionId;
|
|
2550
|
+
}
|
|
2551
|
+
async checkResponse(response) {
|
|
2552
|
+
if (response.ok)
|
|
2553
|
+
return;
|
|
2554
|
+
const body = (await response.text().catch(() => "")).slice(0, MAX_ERROR_BODY_BYTES);
|
|
2555
|
+
if (response.status === 401)
|
|
2556
|
+
throw new McpAuthRequiredError(response, body);
|
|
2557
|
+
if (response.status === 404 && this.sessionIdValue)
|
|
2558
|
+
throw new McpSessionExpiredError(body);
|
|
2559
|
+
throw new McpHttpError(response.status, describeHttpFailure(response.status, body), body);
|
|
2560
|
+
}
|
|
2561
|
+
async consumeSse(stream, cursor, onMessage) {
|
|
2562
|
+
await consumeSseStream(stream, {
|
|
2563
|
+
maxEventBytes: this.options.maxMessageBytes ?? DEFAULT_MAX_MESSAGE_BYTES,
|
|
2564
|
+
onId: (id) => {
|
|
2565
|
+
cursor.lastEventId = id;
|
|
2566
|
+
},
|
|
2567
|
+
onRetry: (delayMs) => {
|
|
2568
|
+
cursor.retryMs = delayMs;
|
|
2569
|
+
},
|
|
2570
|
+
onEvent: (event) => {
|
|
2571
|
+
cursor.received = true;
|
|
2572
|
+
if (!event.data.trim() || event.event !== undefined && event.event !== "message")
|
|
2573
|
+
return;
|
|
2574
|
+
let message;
|
|
2575
|
+
try {
|
|
2576
|
+
message = parseJsonRpcMessage(JSON.parse(event.data));
|
|
2577
|
+
} catch (error) {
|
|
2578
|
+
this.emitError(error);
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2581
|
+
onMessage?.(message);
|
|
2582
|
+
this.emitMessage(message);
|
|
2583
|
+
}
|
|
2584
|
+
});
|
|
2585
|
+
}
|
|
2586
|
+
async consumeResponseStream(body, requestId) {
|
|
2587
|
+
const cursor = { lastEventId: undefined, retryMs: undefined, received: false };
|
|
2588
|
+
let answered = false;
|
|
2589
|
+
const onMessage = (message) => {
|
|
2590
|
+
if (isJsonRpcResponse(message) && message.id === requestId)
|
|
2591
|
+
answered = true;
|
|
2592
|
+
};
|
|
2593
|
+
let stream = body;
|
|
2594
|
+
let failure;
|
|
2595
|
+
for (let attempt = 0;; ) {
|
|
2596
|
+
if (stream) {
|
|
2597
|
+
try {
|
|
2598
|
+
await this.consumeSse(stream, cursor, onMessage);
|
|
2599
|
+
failure = undefined;
|
|
2600
|
+
} catch (error) {
|
|
2601
|
+
failure = error;
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
if (answered || this.closed)
|
|
2605
|
+
return;
|
|
2606
|
+
if (failure !== undefined && !this.isRetryable(failure))
|
|
2607
|
+
break;
|
|
2608
|
+
if (cursor.lastEventId === undefined || attempt >= this.maxRetries())
|
|
2609
|
+
break;
|
|
2610
|
+
if (cursor.received)
|
|
2611
|
+
attempt = 0;
|
|
2612
|
+
cursor.received = false;
|
|
2613
|
+
if (!await this.sleep(this.reconnectDelay(attempt++, cursor.retryMs)))
|
|
2614
|
+
return;
|
|
2615
|
+
try {
|
|
2616
|
+
stream = await this.openSseStream(cursor.lastEventId);
|
|
2617
|
+
} catch (error) {
|
|
2618
|
+
failure = error;
|
|
2619
|
+
if (!this.isRetryable(error))
|
|
2620
|
+
break;
|
|
2621
|
+
stream = undefined;
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
if (this.closed)
|
|
2625
|
+
return;
|
|
2626
|
+
const reason = failure === undefined ? "stream ended without a response" : toError(failure).message;
|
|
2627
|
+
this.emitMessage({
|
|
2628
|
+
jsonrpc: "2.0",
|
|
2629
|
+
id: requestId,
|
|
2630
|
+
error: { code: JSON_RPC_ERROR_CODES.internalError, message: `MCP response stream failed: ${reason}` }
|
|
2631
|
+
});
|
|
2632
|
+
}
|
|
2633
|
+
startGetStream() {
|
|
2634
|
+
if (this.options.openGetStream === false || this.getStreamStarted || this.closed)
|
|
2635
|
+
return;
|
|
2636
|
+
this.getStreamStarted = true;
|
|
2637
|
+
this.runGetStream();
|
|
2638
|
+
}
|
|
2639
|
+
async runGetStream() {
|
|
2640
|
+
const cursor = { lastEventId: undefined, retryMs: undefined, received: false };
|
|
2641
|
+
for (let attempt = 0;!this.closed; ) {
|
|
2642
|
+
try {
|
|
2643
|
+
const stream = await this.openSseStream(cursor.lastEventId);
|
|
2644
|
+
if (!stream)
|
|
2645
|
+
return;
|
|
2646
|
+
const openedAt = Date.now();
|
|
2647
|
+
await this.consumeSse(stream, cursor);
|
|
2648
|
+
if (cursor.received || Date.now() - openedAt > this.maxDelay())
|
|
2649
|
+
attempt = 0;
|
|
2650
|
+
} catch (error) {
|
|
2651
|
+
if (this.closed)
|
|
2652
|
+
return;
|
|
2653
|
+
if (!this.isRetryable(error)) {
|
|
2654
|
+
this.emitError(error);
|
|
2655
|
+
return;
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
cursor.received = false;
|
|
2659
|
+
if (attempt >= this.maxRetries()) {
|
|
2660
|
+
this.emitError(new Error("MCP server-to-client stream dropped and could not be reopened"));
|
|
2661
|
+
return;
|
|
2662
|
+
}
|
|
2663
|
+
if (!await this.sleep(this.reconnectDelay(attempt++, cursor.retryMs)))
|
|
2664
|
+
return;
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
async openSseStream(lastEventId) {
|
|
2668
|
+
const response = await this.authorizedFetch("GET", {
|
|
2669
|
+
headers: {
|
|
2670
|
+
accept: "text/event-stream",
|
|
2671
|
+
...lastEventId === undefined ? {} : { "last-event-id": lastEventId }
|
|
2672
|
+
}
|
|
2673
|
+
});
|
|
2674
|
+
if (response.status === 405) {
|
|
2675
|
+
await discard(response);
|
|
2676
|
+
return;
|
|
2677
|
+
}
|
|
2678
|
+
await this.checkResponse(response);
|
|
2679
|
+
this.captureSession(response);
|
|
2680
|
+
const type = contentType(response);
|
|
2681
|
+
if (type !== "text/event-stream" || !response.body) {
|
|
2682
|
+
await discard(response);
|
|
2683
|
+
throw new McpHttpError(response.status, `Unsupported MCP GET response content type: ${type ?? "missing"}`);
|
|
2684
|
+
}
|
|
2685
|
+
return response.body;
|
|
2686
|
+
}
|
|
2687
|
+
isRetryable(error) {
|
|
2688
|
+
if (error instanceof McpHttpError)
|
|
2689
|
+
return isTransientStatus(error.status);
|
|
2690
|
+
if (error instanceof TypeError)
|
|
2691
|
+
return true;
|
|
2692
|
+
const code = error?.code;
|
|
2693
|
+
return typeof code === "string" && (code.startsWith("E") || code.startsWith("UND_ERR"));
|
|
2694
|
+
}
|
|
2695
|
+
reconnectDelay(attempt, serverDelayMs) {
|
|
2696
|
+
if (serverDelayMs !== undefined)
|
|
2697
|
+
return serverDelayMs;
|
|
2698
|
+
const initial = this.options.reconnect?.initialDelayMs ?? DEFAULT_RECONNECT_INITIAL_DELAY_MS;
|
|
2699
|
+
return Math.min(initial * 2 ** attempt, this.maxDelay());
|
|
2700
|
+
}
|
|
2701
|
+
maxDelay() {
|
|
2702
|
+
return this.options.reconnect?.maxDelayMs ?? DEFAULT_RECONNECT_MAX_DELAY_MS;
|
|
2703
|
+
}
|
|
2704
|
+
maxRetries() {
|
|
2705
|
+
return this.options.reconnect?.maxRetries ?? DEFAULT_RECONNECT_MAX_RETRIES;
|
|
2706
|
+
}
|
|
2707
|
+
sleep(ms) {
|
|
2708
|
+
const signal = this.controller.signal;
|
|
2709
|
+
if (signal.aborted)
|
|
2710
|
+
return Promise.resolve(false);
|
|
2711
|
+
return new Promise((resolve) => {
|
|
2712
|
+
const onAbort = () => {
|
|
2713
|
+
clearTimeout(timer);
|
|
2714
|
+
resolve(false);
|
|
2715
|
+
};
|
|
2716
|
+
const timer = setTimeout(() => {
|
|
2717
|
+
signal.removeEventListener("abort", onAbort);
|
|
2718
|
+
resolve(true);
|
|
2719
|
+
}, ms);
|
|
2720
|
+
timer.unref?.();
|
|
2721
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2722
|
+
});
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
// node_modules/@earendil-works/pi-mcp/dist/protocol/content.js
|
|
2726
|
+
function blockToLlmContent(block) {
|
|
2727
|
+
switch (block.type) {
|
|
2728
|
+
case "text":
|
|
2729
|
+
return { type: "text", text: block.text };
|
|
2730
|
+
case "image":
|
|
2731
|
+
return { type: "image", data: block.data, mimeType: block.mimeType };
|
|
2732
|
+
case "audio":
|
|
2733
|
+
return { type: "text", text: `[audio ${block.mimeType} omitted]` };
|
|
2734
|
+
case "resource_link":
|
|
2735
|
+
return { type: "text", text: `${block.name}: ${block.uri}` };
|
|
2736
|
+
case "resource": {
|
|
2737
|
+
const resource = block.resource;
|
|
2738
|
+
if ("text" in resource)
|
|
2739
|
+
return { type: "text", text: resource.text };
|
|
2740
|
+
if (resource.mimeType?.startsWith("image/")) {
|
|
2741
|
+
return { type: "image", data: resource.blob, mimeType: resource.mimeType };
|
|
2742
|
+
}
|
|
2743
|
+
return {
|
|
2744
|
+
type: "text",
|
|
2745
|
+
text: `[binary resource ${resource.uri} (${resource.mimeType ?? "unknown type"}) omitted]`
|
|
2746
|
+
};
|
|
2747
|
+
}
|
|
2748
|
+
default:
|
|
2749
|
+
return { type: "text", text: `[unsupported MCP content ${block.type}]` };
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
function toLlmContent(result) {
|
|
2753
|
+
const content = (result.content ?? []).map(blockToLlmContent);
|
|
2754
|
+
if (content.length === 0 && result.structuredContent !== undefined) {
|
|
2755
|
+
content.push({ type: "text", text: JSON.stringify(result.structuredContent, null, 2) });
|
|
2756
|
+
}
|
|
2757
|
+
return content;
|
|
2758
|
+
}
|
|
2759
|
+
// node_modules/@earendil-works/pi-coding-agent/dist/extensions/mcp/tools.js
|
|
2760
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2761
|
+
import { writeFile } from "node:fs/promises";
|
|
2762
|
+
import { tmpdir } from "node:os";
|
|
2763
|
+
import { join } from "node:path";
|
|
2764
|
+
|
|
2765
|
+
// node_modules/@earendil-works/pi-coding-agent/dist/core/tools/truncate.js
|
|
2766
|
+
var DEFAULT_MAX_LINES = 2000;
|
|
2767
|
+
var DEFAULT_MAX_BYTES = 50 * 1024;
|
|
2768
|
+
var GREP_MAX_LINE_LENGTH = 500;
|
|
2769
|
+
function splitLinesForCounting(content) {
|
|
2770
|
+
if (content.length === 0) {
|
|
2771
|
+
return [];
|
|
2772
|
+
}
|
|
2773
|
+
const lines = content.split(`
|
|
2774
|
+
`);
|
|
2775
|
+
if (content.endsWith(`
|
|
2776
|
+
`)) {
|
|
2777
|
+
lines.pop();
|
|
2778
|
+
}
|
|
2779
|
+
return lines;
|
|
2780
|
+
}
|
|
2781
|
+
function formatSize(bytes) {
|
|
2782
|
+
if (bytes < 1024) {
|
|
2783
|
+
return `${bytes}B`;
|
|
2784
|
+
} else if (bytes < 1024 * 1024) {
|
|
2785
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
2786
|
+
} else {
|
|
2787
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
function truncateHead(content, options = {}) {
|
|
2791
|
+
const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
|
|
2792
|
+
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
2793
|
+
const totalBytes = Buffer.byteLength(content, "utf-8");
|
|
2794
|
+
const lines = splitLinesForCounting(content);
|
|
2795
|
+
const totalLines = lines.length;
|
|
2796
|
+
if (totalLines <= maxLines && totalBytes <= maxBytes) {
|
|
2797
|
+
return {
|
|
2798
|
+
content,
|
|
2799
|
+
truncated: false,
|
|
2800
|
+
truncatedBy: null,
|
|
2801
|
+
totalLines,
|
|
2802
|
+
totalBytes,
|
|
2803
|
+
outputLines: totalLines,
|
|
2804
|
+
outputBytes: totalBytes,
|
|
2805
|
+
lastLinePartial: false,
|
|
2806
|
+
firstLineExceedsLimit: false,
|
|
2807
|
+
maxLines,
|
|
2808
|
+
maxBytes
|
|
2809
|
+
};
|
|
2810
|
+
}
|
|
2811
|
+
const firstLineBytes = Buffer.byteLength(lines[0], "utf-8");
|
|
2812
|
+
if (firstLineBytes > maxBytes) {
|
|
2813
|
+
return {
|
|
2814
|
+
content: "",
|
|
2815
|
+
truncated: true,
|
|
2816
|
+
truncatedBy: "bytes",
|
|
2817
|
+
totalLines,
|
|
2818
|
+
totalBytes,
|
|
2819
|
+
outputLines: 0,
|
|
2820
|
+
outputBytes: 0,
|
|
2821
|
+
lastLinePartial: false,
|
|
2822
|
+
firstLineExceedsLimit: true,
|
|
2823
|
+
maxLines,
|
|
2824
|
+
maxBytes
|
|
2825
|
+
};
|
|
2826
|
+
}
|
|
2827
|
+
const outputLinesArr = [];
|
|
2828
|
+
let outputBytesCount = 0;
|
|
2829
|
+
let truncatedBy = "lines";
|
|
2830
|
+
for (let i = 0;i < lines.length && i < maxLines; i++) {
|
|
2831
|
+
const line = lines[i];
|
|
2832
|
+
const lineBytes = Buffer.byteLength(line, "utf-8") + (i > 0 ? 1 : 0);
|
|
2833
|
+
if (outputBytesCount + lineBytes > maxBytes) {
|
|
2834
|
+
truncatedBy = "bytes";
|
|
2835
|
+
break;
|
|
2836
|
+
}
|
|
2837
|
+
outputLinesArr.push(line);
|
|
2838
|
+
outputBytesCount += lineBytes;
|
|
2839
|
+
}
|
|
2840
|
+
if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {
|
|
2841
|
+
truncatedBy = "lines";
|
|
2842
|
+
}
|
|
2843
|
+
const outputContent = outputLinesArr.join(`
|
|
2844
|
+
`);
|
|
2845
|
+
const finalOutputBytes = Buffer.byteLength(outputContent, "utf-8");
|
|
2846
|
+
return {
|
|
2847
|
+
content: outputContent,
|
|
2848
|
+
truncated: true,
|
|
2849
|
+
truncatedBy,
|
|
2850
|
+
totalLines,
|
|
2851
|
+
totalBytes,
|
|
2852
|
+
outputLines: outputLinesArr.length,
|
|
2853
|
+
outputBytes: finalOutputBytes,
|
|
2854
|
+
lastLinePartial: false,
|
|
2855
|
+
firstLineExceedsLimit: false,
|
|
2856
|
+
maxLines,
|
|
2857
|
+
maxBytes
|
|
2858
|
+
};
|
|
2859
|
+
}
|
|
2860
|
+
function truncateTail(content, options = {}) {
|
|
2861
|
+
const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
|
|
2862
|
+
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
2863
|
+
const totalBytes = Buffer.byteLength(content, "utf-8");
|
|
2864
|
+
const lines = splitLinesForCounting(content);
|
|
2865
|
+
const totalLines = lines.length;
|
|
2866
|
+
if (totalLines <= maxLines && totalBytes <= maxBytes) {
|
|
2867
|
+
return {
|
|
2868
|
+
content,
|
|
2869
|
+
truncated: false,
|
|
2870
|
+
truncatedBy: null,
|
|
2871
|
+
totalLines,
|
|
2872
|
+
totalBytes,
|
|
2873
|
+
outputLines: totalLines,
|
|
2874
|
+
outputBytes: totalBytes,
|
|
2875
|
+
lastLinePartial: false,
|
|
2876
|
+
firstLineExceedsLimit: false,
|
|
2877
|
+
maxLines,
|
|
2878
|
+
maxBytes
|
|
2879
|
+
};
|
|
2880
|
+
}
|
|
2881
|
+
const outputLinesArr = [];
|
|
2882
|
+
let outputBytesCount = 0;
|
|
2883
|
+
let truncatedBy = "lines";
|
|
2884
|
+
let lastLinePartial = false;
|
|
2885
|
+
for (let i = lines.length - 1;i >= 0 && outputLinesArr.length < maxLines; i--) {
|
|
2886
|
+
const line = lines[i];
|
|
2887
|
+
const lineBytes = Buffer.byteLength(line, "utf-8") + (outputLinesArr.length > 0 ? 1 : 0);
|
|
2888
|
+
if (outputBytesCount + lineBytes > maxBytes) {
|
|
2889
|
+
truncatedBy = "bytes";
|
|
2890
|
+
if (outputLinesArr.length === 0) {
|
|
2891
|
+
const truncatedLine = truncateStringToBytesFromEnd(line, maxBytes);
|
|
2892
|
+
outputLinesArr.unshift(truncatedLine);
|
|
2893
|
+
outputBytesCount = Buffer.byteLength(truncatedLine, "utf-8");
|
|
2894
|
+
lastLinePartial = true;
|
|
2895
|
+
}
|
|
2896
|
+
break;
|
|
2897
|
+
}
|
|
2898
|
+
outputLinesArr.unshift(line);
|
|
2899
|
+
outputBytesCount += lineBytes;
|
|
2900
|
+
}
|
|
2901
|
+
if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {
|
|
2902
|
+
truncatedBy = "lines";
|
|
2903
|
+
}
|
|
2904
|
+
const outputContent = outputLinesArr.join(`
|
|
2905
|
+
`);
|
|
2906
|
+
const finalOutputBytes = Buffer.byteLength(outputContent, "utf-8");
|
|
2907
|
+
return {
|
|
2908
|
+
content: outputContent,
|
|
2909
|
+
truncated: true,
|
|
2910
|
+
truncatedBy,
|
|
2911
|
+
totalLines,
|
|
2912
|
+
totalBytes,
|
|
2913
|
+
outputLines: outputLinesArr.length,
|
|
2914
|
+
outputBytes: finalOutputBytes,
|
|
2915
|
+
lastLinePartial,
|
|
2916
|
+
firstLineExceedsLimit: false,
|
|
2917
|
+
maxLines,
|
|
2918
|
+
maxBytes
|
|
2919
|
+
};
|
|
2920
|
+
}
|
|
2921
|
+
function truncateStringToBytesFromEnd(str, maxBytes) {
|
|
2922
|
+
const buf = Buffer.from(str, "utf-8");
|
|
2923
|
+
if (buf.length <= maxBytes) {
|
|
2924
|
+
return str;
|
|
2925
|
+
}
|
|
2926
|
+
let start = buf.length - maxBytes;
|
|
2927
|
+
while (start < buf.length && (buf[start] & 192) === 128) {
|
|
2928
|
+
start++;
|
|
2929
|
+
}
|
|
2930
|
+
return buf.slice(start).toString("utf-8");
|
|
2931
|
+
}
|
|
2932
|
+
function truncateLine(line, maxChars = GREP_MAX_LINE_LENGTH) {
|
|
2933
|
+
if (line.length <= maxChars) {
|
|
2934
|
+
return { text: line, wasTruncated: false };
|
|
2935
|
+
}
|
|
2936
|
+
return { text: `${line.slice(0, maxChars)}... [truncated]`, wasTruncated: true };
|
|
2937
|
+
}
|
|
2938
|
+
function truncateMiddle(content, maxBytes) {
|
|
2939
|
+
const buf = Buffer.from(content, "utf-8");
|
|
2940
|
+
const totalLines = splitLinesForCounting(content).length;
|
|
2941
|
+
if (buf.length <= maxBytes) {
|
|
2942
|
+
return { content, truncated: false, removedChars: 0, totalBytes: buf.length, totalLines };
|
|
2943
|
+
}
|
|
2944
|
+
const isBoundary = (index) => index >= buf.length || (buf[index] & 192) !== 128;
|
|
2945
|
+
let headEnd = Math.floor(maxBytes / 2);
|
|
2946
|
+
while (headEnd > 0 && !isBoundary(headEnd))
|
|
2947
|
+
headEnd--;
|
|
2948
|
+
let tailStart = buf.length - (maxBytes - Math.floor(maxBytes / 2));
|
|
2949
|
+
while (tailStart < buf.length && !isBoundary(tailStart))
|
|
2950
|
+
tailStart++;
|
|
2951
|
+
const head = buf.subarray(0, headEnd).toString("utf-8");
|
|
2952
|
+
const tail = buf.subarray(tailStart).toString("utf-8");
|
|
2953
|
+
const removedChars = Array.from(buf.subarray(headEnd, tailStart).toString("utf-8")).length;
|
|
2954
|
+
return {
|
|
2955
|
+
content: `${head}…${removedChars} chars truncated…${tail}`,
|
|
2956
|
+
truncated: true,
|
|
2957
|
+
removedChars,
|
|
2958
|
+
totalBytes: buf.length,
|
|
2959
|
+
totalLines
|
|
2960
|
+
};
|
|
2961
|
+
}
|
|
2962
|
+
|
|
2963
|
+
// node_modules/@earendil-works/pi-coding-agent/dist/extensions/mcp/tools.js
|
|
2964
|
+
function toToolExposure(exposure) {
|
|
2965
|
+
return exposure === "codemode" ? "deferred" : exposure;
|
|
2966
|
+
}
|
|
2967
|
+
var MAX_TOOL_NAME_LENGTH = 64;
|
|
2968
|
+
var MCP_OUTPUT_MAX_BYTES = 20 * 1024;
|
|
2969
|
+
var OUTPUT_PREVIEW_LINES = 5;
|
|
2970
|
+
var READ_MCP_RESOURCE_TOOL = "read_mcp_resource";
|
|
2971
|
+
async function saveToTempFile(data, extension) {
|
|
2972
|
+
const path = join(tmpdir(), `pi-mcp-${randomBytes(8).toString("hex")}${extension}`);
|
|
2973
|
+
await writeFile(path, data, { mode: 384 });
|
|
2974
|
+
return path;
|
|
2975
|
+
}
|
|
2976
|
+
function createMcpToolName(server, tool, isTaken = () => false) {
|
|
2977
|
+
const name = `mcp__${server}__${tool}`.replace(/[^A-Za-z0-9_]/g, "_");
|
|
2978
|
+
if (name.length <= MAX_TOOL_NAME_LENGTH && !isTaken(name))
|
|
2979
|
+
return name;
|
|
2980
|
+
const hash = createHash("sha256").update(`${server}\x00${tool}`).digest("hex").slice(0, 8);
|
|
2981
|
+
return `${name.slice(0, MAX_TOOL_NAME_LENGTH - hash.length - 1)}_${hash}`;
|
|
2982
|
+
}
|
|
2983
|
+
function textOf(content) {
|
|
2984
|
+
return content.filter((block) => block.type === "text").map((block) => block.text).join(`
|
|
2985
|
+
`);
|
|
2986
|
+
}
|
|
2987
|
+
function createMcpResultSchema(structuredContentSchema) {
|
|
2988
|
+
return {
|
|
2989
|
+
type: "object",
|
|
2990
|
+
properties: {
|
|
2991
|
+
content: { type: "array", items: { type: "object" } },
|
|
2992
|
+
...structuredContentSchema ? { structuredContent: structuredContentSchema } : {},
|
|
2993
|
+
isError: { type: "boolean" },
|
|
2994
|
+
_meta: { type: "object" }
|
|
2995
|
+
},
|
|
2996
|
+
required: ["content"]
|
|
2997
|
+
};
|
|
2998
|
+
}
|
|
2999
|
+
async function limitMcpContent(content, saveOutput = saveToTempFile) {
|
|
3000
|
+
const combined = textOf(content);
|
|
3001
|
+
const truncation = truncateMiddle(combined, MCP_OUTPUT_MAX_BYTES);
|
|
3002
|
+
if (!truncation.truncated)
|
|
3003
|
+
return { content };
|
|
3004
|
+
let fullOutputPath;
|
|
3005
|
+
let where;
|
|
3006
|
+
try {
|
|
3007
|
+
fullOutputPath = await saveOutput(combined, ".txt");
|
|
3008
|
+
where = `[Full output: ${fullOutputPath} (read it with offset/limit)]`;
|
|
3009
|
+
} catch (error) {
|
|
3010
|
+
where = `[Could not save the full output: ${error instanceof Error ? error.message : String(error)}]`;
|
|
3011
|
+
}
|
|
3012
|
+
const tokens = Math.ceil(truncation.totalBytes / 4);
|
|
3013
|
+
const text = `Warning: truncated output (original token count: ${tokens})
|
|
3014
|
+
Total output lines: ${truncation.totalLines}
|
|
3015
|
+
|
|
3016
|
+
${truncation.content}
|
|
3017
|
+
|
|
3018
|
+
${where}`;
|
|
3019
|
+
return {
|
|
3020
|
+
content: [{ type: "text", text }, ...content.filter((block) => block.type === "image")],
|
|
3021
|
+
...fullOutputPath ? { fullOutputPath } : {}
|
|
3022
|
+
};
|
|
3023
|
+
}
|
|
3024
|
+
function extensionOf(uri) {
|
|
3025
|
+
const path = URL.canParse(uri) ? new URL(uri).pathname : uri;
|
|
3026
|
+
return /\.[A-Za-z0-9]{1,8}$/.exec(path)?.[0] ?? ".bin";
|
|
3027
|
+
}
|
|
3028
|
+
function isTextMimeType(mimeType) {
|
|
3029
|
+
if (!mimeType)
|
|
3030
|
+
return false;
|
|
3031
|
+
const type = mimeType.split(";", 1)[0].trim().toLowerCase();
|
|
3032
|
+
return type.startsWith("text/") || type === "application/json" || type.endsWith("+json") || type.endsWith("+xml");
|
|
3033
|
+
}
|
|
3034
|
+
async function blockToContent(server, block, options) {
|
|
3035
|
+
if (block.type === "resource_link") {
|
|
3036
|
+
const details = [block.mimeType, block.size === undefined ? undefined : formatSize(block.size)].filter(Boolean);
|
|
3037
|
+
const read = options.readableResources ? `. Read it with ${READ_MCP_RESOURCE_TOOL} (server "${server}")` : "";
|
|
3038
|
+
const description = block.description ? `: ${block.description}` : "";
|
|
3039
|
+
return [
|
|
3040
|
+
{
|
|
3041
|
+
type: "text",
|
|
3042
|
+
text: `[Resource ${block.uri} "${block.title ?? block.name}"${details.length > 0 ? ` (${details.join(", ")})` : ""}${description}${read}]`
|
|
3043
|
+
}
|
|
3044
|
+
];
|
|
3045
|
+
}
|
|
3046
|
+
if (block.type === "resource" && "blob" in block.resource && !block.resource.mimeType?.startsWith("image/")) {
|
|
3047
|
+
const { uri, mimeType, blob } = block.resource;
|
|
3048
|
+
const data = Buffer.from(blob, "base64");
|
|
3049
|
+
if (isTextMimeType(mimeType))
|
|
3050
|
+
return [{ type: "text", text: data.toString("utf8") }];
|
|
3051
|
+
const kind = `${mimeType ?? "unknown type"}, ${formatSize(data.length)}`;
|
|
3052
|
+
try {
|
|
3053
|
+
const path = await (options.saveOutput ?? saveToTempFile)(data, extensionOf(uri));
|
|
3054
|
+
return [{ type: "text", text: `[Binary resource ${uri} (${kind}) saved to ${path}]` }];
|
|
3055
|
+
} catch (error) {
|
|
3056
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
3057
|
+
return [{ type: "text", text: `[Binary resource ${uri} (${kind}) could not be saved: ${reason}]` }];
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
return toLlmContent({ content: [block] });
|
|
3061
|
+
}
|
|
3062
|
+
async function toModelContent(server, blocks, options = {}) {
|
|
3063
|
+
return (await Promise.all(blocks.map((block) => blockToContent(server, block, options)))).flat();
|
|
3064
|
+
}
|
|
3065
|
+
async function convertMcpResult(server, tool, result, options = {}) {
|
|
3066
|
+
const converted = result.content.length > 0 ? await toModelContent(server, result.content, options) : toLlmContent(result);
|
|
3067
|
+
if (result.isError && textOf(converted) === "") {
|
|
3068
|
+
converted.push({ type: "text", text: `MCP tool ${server}/${tool} returned an error` });
|
|
3069
|
+
}
|
|
3070
|
+
const { content, fullOutputPath } = await limitMcpContent(converted, options.saveOutput);
|
|
3071
|
+
const { _meta: _ignored, ...scriptResult } = result;
|
|
3072
|
+
return {
|
|
3073
|
+
content,
|
|
3074
|
+
details: { server, tool, ...fullOutputPath ? { fullOutputPath } : {} },
|
|
3075
|
+
structuredContent: scriptResult,
|
|
3076
|
+
...result.isError ? { isError: true } : {}
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
function toParameters(schema) {
|
|
3080
|
+
return {
|
|
3081
|
+
...schema,
|
|
3082
|
+
type: schema.type ?? "object",
|
|
3083
|
+
...schema.properties === undefined ? { properties: {} } : {}
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
var ANNOTATION_HINTS = ["readOnlyHint", "destructiveHint", "idempotentHint", "openWorldHint"];
|
|
3087
|
+
function toToolAnnotations(tool) {
|
|
3088
|
+
const annotations = {};
|
|
3089
|
+
for (const hint of ANNOTATION_HINTS) {
|
|
3090
|
+
const value = tool.annotations?.[hint];
|
|
3091
|
+
if (typeof value === "boolean")
|
|
3092
|
+
annotations[hint] = value;
|
|
3093
|
+
}
|
|
3094
|
+
return Object.keys(annotations).length > 0 ? annotations : undefined;
|
|
3095
|
+
}
|
|
3096
|
+
function createMcpToolDefinition(options) {
|
|
3097
|
+
const { server, tool } = options;
|
|
3098
|
+
const title = tool.title ?? tool.annotations?.title;
|
|
3099
|
+
const annotations = toToolAnnotations(tool);
|
|
3100
|
+
const label = `${server}/${tool.name}`;
|
|
3101
|
+
return {
|
|
3102
|
+
name: options.name,
|
|
3103
|
+
label,
|
|
3104
|
+
description: tool.description?.trim() || title || `MCP tool ${tool.name} from server ${server}`,
|
|
3105
|
+
parameters: toParameters(tool.inputSchema),
|
|
3106
|
+
outputSchema: createMcpResultSchema(tool.outputSchema),
|
|
3107
|
+
exposure: toToolExposure(options.exposure),
|
|
3108
|
+
namespace: options.namespace,
|
|
3109
|
+
...annotations ? { annotations } : {},
|
|
3110
|
+
renderCall(args, theme, context) {
|
|
3111
|
+
const component = context.lastComponent ?? new Text("", 0, 0);
|
|
3112
|
+
component.setText(formatToolCallWithArgs(label, args, theme, context.expanded));
|
|
3113
|
+
return component;
|
|
3114
|
+
},
|
|
3115
|
+
renderResult(result, options2, theme, context) {
|
|
3116
|
+
const component = context.lastComponent ?? new Container;
|
|
3117
|
+
component.clear();
|
|
3118
|
+
const output = getTextOutput(result, context.showImages).trim();
|
|
3119
|
+
if (!output)
|
|
3120
|
+
return component;
|
|
3121
|
+
const color = context.isError ? "error" : "toolOutput";
|
|
3122
|
+
const styled = replaceTabs(output).split(`
|
|
3123
|
+
`).map((line) => theme.fg(color, line)).join(`
|
|
3124
|
+
`);
|
|
3125
|
+
component.addChild(new Spacer(1));
|
|
3126
|
+
if (options2.expanded) {
|
|
3127
|
+
component.addChild(new Text(styled, 0, 0));
|
|
3128
|
+
} else {
|
|
3129
|
+
component.addChild(new VisualLinePreview({
|
|
3130
|
+
text: styled,
|
|
3131
|
+
maxVisualLines: OUTPUT_PREVIEW_LINES,
|
|
3132
|
+
keep: "start",
|
|
3133
|
+
formatHint: (hidden) => `${theme.fg("muted", `... (${hidden} more lines,`)} ${keyHint("app.tools.expand", "to expand")}${theme.fg("muted", ")")}`
|
|
3134
|
+
}));
|
|
3135
|
+
const fullOutputPath = result.details?.fullOutputPath;
|
|
3136
|
+
if (fullOutputPath)
|
|
3137
|
+
component.addChild(new Text(theme.fg("muted", `Full output: ${fullOutputPath}`), 0, 0));
|
|
3138
|
+
}
|
|
3139
|
+
return component;
|
|
3140
|
+
},
|
|
3141
|
+
async execute(_toolCallId, params, signal, onUpdate) {
|
|
3142
|
+
const client = await options.getClient();
|
|
3143
|
+
const result = await client.callTool(tool.name, params ?? {}, {
|
|
3144
|
+
signal,
|
|
3145
|
+
timeoutMs: options.timeoutMs,
|
|
3146
|
+
onProgress: (progress) => {
|
|
3147
|
+
const total = progress.total === undefined ? "" : `/${progress.total}`;
|
|
3148
|
+
const text = progress.message ?? `Progress ${progress.progress}${total}`;
|
|
3149
|
+
onUpdate?.({ content: [{ type: "text", text }], details: { server, tool: tool.name } });
|
|
3150
|
+
}
|
|
3151
|
+
});
|
|
3152
|
+
return convertMcpResult(server, tool.name, result, { readableResources: options.readableResources?.() });
|
|
3153
|
+
}
|
|
3154
|
+
};
|
|
3155
|
+
}
|
|
3156
|
+
|
|
3157
|
+
// node_modules/@earendil-works/pi-coding-agent/dist/extensions/mcp/resources.js
|
|
3158
|
+
var LIST_MCP_RESOURCES_TOOL = "list_mcp_resources";
|
|
3159
|
+
var LIST_MCP_RESOURCE_TEMPLATES_TOOL = "list_mcp_resource_templates";
|
|
3160
|
+
function isMcpAppResource(item) {
|
|
3161
|
+
const uri = item.uri ?? item.uriTemplate ?? "";
|
|
3162
|
+
return uri.startsWith("ui://") || /;\s*profile\s*=\s*"?mcp-app"?/i.test(item.mimeType ?? "");
|
|
3163
|
+
}
|
|
3164
|
+
function listed(server, item) {
|
|
3165
|
+
const { _meta, icons: _icons, ...rest } = item;
|
|
3166
|
+
return { server, ...rest };
|
|
3167
|
+
}
|
|
3168
|
+
var stringProperty = (description) => ({ type: "string", description });
|
|
3169
|
+
var SERVER_FILTER = stringProperty("MCP server name. Omit to list every server with resources.");
|
|
3170
|
+
var CURSOR = stringProperty("Opaque cursor from a previous call with the same server; omit for the first page.");
|
|
3171
|
+
var LIST_PARAMETERS = {
|
|
3172
|
+
type: "object",
|
|
3173
|
+
properties: { server: SERVER_FILTER, cursor: CURSOR },
|
|
3174
|
+
additionalProperties: false
|
|
3175
|
+
};
|
|
3176
|
+
var READ_PARAMETERS = {
|
|
3177
|
+
type: "object",
|
|
3178
|
+
properties: {
|
|
3179
|
+
server: stringProperty("MCP server name exactly as configured. Must match the 'server' field returned by list_mcp_resources."),
|
|
3180
|
+
uri: stringProperty("Resource URI to read. Must be one of the URIs returned by list_mcp_resources.")
|
|
3181
|
+
},
|
|
3182
|
+
required: ["server", "uri"],
|
|
3183
|
+
additionalProperties: false
|
|
3184
|
+
};
|
|
3185
|
+
var optionalString = { type: "string" };
|
|
3186
|
+
var LISTING_ERRORS = {
|
|
3187
|
+
type: "array",
|
|
3188
|
+
description: "Servers that could not be listed",
|
|
3189
|
+
items: {
|
|
3190
|
+
type: "object",
|
|
3191
|
+
properties: { server: { type: "string" }, error: { type: "string" } },
|
|
3192
|
+
required: ["server", "error"]
|
|
3193
|
+
}
|
|
3194
|
+
};
|
|
3195
|
+
var LIST_OUTPUT_SCHEMA = {
|
|
3196
|
+
type: "object",
|
|
3197
|
+
properties: {
|
|
3198
|
+
server: optionalString,
|
|
3199
|
+
resources: {
|
|
3200
|
+
type: "array",
|
|
3201
|
+
items: {
|
|
3202
|
+
type: "object",
|
|
3203
|
+
properties: {
|
|
3204
|
+
server: { type: "string" },
|
|
3205
|
+
uri: { type: "string" },
|
|
3206
|
+
name: { type: "string" },
|
|
3207
|
+
title: optionalString,
|
|
3208
|
+
description: optionalString,
|
|
3209
|
+
mimeType: optionalString,
|
|
3210
|
+
size: { type: "number" }
|
|
3211
|
+
},
|
|
3212
|
+
required: ["server", "uri", "name"]
|
|
3213
|
+
}
|
|
3214
|
+
},
|
|
3215
|
+
nextCursor: optionalString,
|
|
3216
|
+
errors: LISTING_ERRORS
|
|
3217
|
+
},
|
|
3218
|
+
required: ["resources"]
|
|
3219
|
+
};
|
|
3220
|
+
var LIST_TEMPLATES_OUTPUT_SCHEMA = {
|
|
3221
|
+
type: "object",
|
|
3222
|
+
properties: {
|
|
3223
|
+
server: optionalString,
|
|
3224
|
+
resourceTemplates: {
|
|
3225
|
+
type: "array",
|
|
3226
|
+
items: {
|
|
3227
|
+
type: "object",
|
|
3228
|
+
properties: {
|
|
3229
|
+
server: { type: "string" },
|
|
3230
|
+
uriTemplate: { type: "string", description: "RFC 6570 URI template" },
|
|
3231
|
+
name: { type: "string" },
|
|
3232
|
+
title: optionalString,
|
|
3233
|
+
description: optionalString,
|
|
3234
|
+
mimeType: optionalString
|
|
3235
|
+
},
|
|
3236
|
+
required: ["server", "uriTemplate", "name"]
|
|
3237
|
+
}
|
|
3238
|
+
},
|
|
3239
|
+
nextCursor: optionalString,
|
|
3240
|
+
errors: LISTING_ERRORS
|
|
3241
|
+
},
|
|
3242
|
+
required: ["resourceTemplates"]
|
|
3243
|
+
};
|
|
3244
|
+
var READ_OUTPUT_SCHEMA = {
|
|
3245
|
+
type: "object",
|
|
3246
|
+
properties: {
|
|
3247
|
+
server: { type: "string" },
|
|
3248
|
+
uri: { type: "string" },
|
|
3249
|
+
contents: {
|
|
3250
|
+
type: "array",
|
|
3251
|
+
items: {
|
|
3252
|
+
anyOf: [
|
|
3253
|
+
{
|
|
3254
|
+
type: "object",
|
|
3255
|
+
properties: { uri: { type: "string" }, mimeType: optionalString, text: { type: "string" } },
|
|
3256
|
+
required: ["uri", "text"]
|
|
3257
|
+
},
|
|
3258
|
+
{
|
|
3259
|
+
type: "object",
|
|
3260
|
+
properties: {
|
|
3261
|
+
uri: { type: "string" },
|
|
3262
|
+
mimeType: optionalString,
|
|
3263
|
+
blob: { type: "string", description: "base64" }
|
|
3264
|
+
},
|
|
3265
|
+
required: ["uri", "blob"]
|
|
3266
|
+
}
|
|
3267
|
+
]
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
},
|
|
3271
|
+
required: ["server", "uri", "contents"]
|
|
3272
|
+
};
|
|
3273
|
+
function stringArgument(params, key) {
|
|
3274
|
+
const value = params?.[key];
|
|
3275
|
+
if (value === undefined || value === null)
|
|
3276
|
+
return;
|
|
3277
|
+
if (typeof value !== "string")
|
|
3278
|
+
throw new Error(`${key} must be a string`);
|
|
3279
|
+
return value.trim() || undefined;
|
|
3280
|
+
}
|
|
3281
|
+
function errorMessage(error) {
|
|
3282
|
+
return error instanceof Error ? error.message : String(error);
|
|
3283
|
+
}
|
|
3284
|
+
async function jsonResult(tool, server, payload) {
|
|
3285
|
+
const { content, fullOutputPath } = await limitMcpContent([{ type: "text", text: JSON.stringify(payload) }]);
|
|
3286
|
+
return {
|
|
3287
|
+
content,
|
|
3288
|
+
details: { server: server ?? "", tool, ...fullOutputPath ? { fullOutputPath } : {} },
|
|
3289
|
+
structuredContent: payload
|
|
3290
|
+
};
|
|
3291
|
+
}
|
|
3292
|
+
function createMcpResourceToolDefinitions(options) {
|
|
3293
|
+
const readOnly = { readOnlyHint: true };
|
|
3294
|
+
const findServer = (name) => {
|
|
3295
|
+
const servers = options.servers();
|
|
3296
|
+
const server = servers.find((candidate) => candidate.name === name);
|
|
3297
|
+
if (server)
|
|
3298
|
+
return server;
|
|
3299
|
+
const available = servers.map((candidate) => candidate.name).join(", ");
|
|
3300
|
+
throw new Error(`MCP server "${name}" has no resources${available ? `. Servers with resources: ${available}` : ""}`);
|
|
3301
|
+
};
|
|
3302
|
+
const list = async (params, signal, key, page, all) => {
|
|
3303
|
+
const serverName = stringArgument(params, "server");
|
|
3304
|
+
const cursor = stringArgument(params, "cursor");
|
|
3305
|
+
const visible = (item) => !isMcpAppResource(item);
|
|
3306
|
+
if (serverName) {
|
|
3307
|
+
const server = findServer(serverName);
|
|
3308
|
+
const result = await page(server, cursor, { signal, timeoutMs: server.timeoutMs });
|
|
3309
|
+
return {
|
|
3310
|
+
server: server.name,
|
|
3311
|
+
[key]: result.items.filter(visible).map((item) => listed(server.name, item)),
|
|
3312
|
+
...result.nextCursor === undefined ? {} : { nextCursor: result.nextCursor }
|
|
3313
|
+
};
|
|
3314
|
+
}
|
|
3315
|
+
if (cursor)
|
|
3316
|
+
throw new Error("cursor can only be used when a server is specified");
|
|
3317
|
+
const servers = [...options.servers()].sort((a, b) => a.name.localeCompare(b.name));
|
|
3318
|
+
const results = await Promise.allSettled(servers.map((server) => all(server, { signal, timeoutMs: server.timeoutMs })));
|
|
3319
|
+
const items = [];
|
|
3320
|
+
const errors = [];
|
|
3321
|
+
results.forEach((result, index) => {
|
|
3322
|
+
const server = servers[index].name;
|
|
3323
|
+
if (result.status === "fulfilled")
|
|
3324
|
+
items.push(...result.value.filter(visible).map((item) => listed(server, item)));
|
|
3325
|
+
else
|
|
3326
|
+
errors.push({ server, error: errorMessage(result.reason) });
|
|
3327
|
+
});
|
|
3328
|
+
return { [key]: items, ...errors.length > 0 ? { errors } : {} };
|
|
3329
|
+
};
|
|
3330
|
+
const listResources = {
|
|
3331
|
+
name: LIST_MCP_RESOURCES_TOOL,
|
|
3332
|
+
label: LIST_MCP_RESOURCES_TOOL,
|
|
3333
|
+
description: "Lists resources provided by MCP servers. Resources allow servers to share data that provides context to language models, such as files, database schemas, or application-specific information. Prefer resources over web search when possible.",
|
|
3334
|
+
parameters: LIST_PARAMETERS,
|
|
3335
|
+
outputSchema: LIST_OUTPUT_SCHEMA,
|
|
3336
|
+
exposure: toToolExposure(options.exposure),
|
|
3337
|
+
annotations: readOnly,
|
|
3338
|
+
async execute(_toolCallId, params, signal) {
|
|
3339
|
+
const payload = await list(params, signal, "resources", async (server, cursor, requestOptions) => {
|
|
3340
|
+
const result = await server.resourcesPage(cursor, requestOptions);
|
|
3341
|
+
return { items: result.resources, nextCursor: result.nextCursor };
|
|
3342
|
+
}, (server, requestOptions) => server.allResources(requestOptions));
|
|
3343
|
+
return jsonResult(LIST_MCP_RESOURCES_TOOL, stringArgument(params, "server"), payload);
|
|
3344
|
+
}
|
|
3345
|
+
};
|
|
3346
|
+
const listTemplates = {
|
|
3347
|
+
name: LIST_MCP_RESOURCE_TEMPLATES_TOOL,
|
|
3348
|
+
label: LIST_MCP_RESOURCE_TEMPLATES_TOOL,
|
|
3349
|
+
description: "Lists resource templates provided by MCP servers. Parameterized resource templates allow servers to share data that takes parameters and provides context to language models, such as files, database schemas, or application-specific information. Prefer resource templates over web search when possible.",
|
|
3350
|
+
parameters: LIST_PARAMETERS,
|
|
3351
|
+
outputSchema: LIST_TEMPLATES_OUTPUT_SCHEMA,
|
|
3352
|
+
exposure: toToolExposure(options.exposure),
|
|
3353
|
+
annotations: readOnly,
|
|
3354
|
+
async execute(_toolCallId, params, signal) {
|
|
3355
|
+
const payload = await list(params, signal, "resourceTemplates", async (server, cursor, requestOptions) => {
|
|
3356
|
+
const result = await server.resourceTemplatesPage(cursor, requestOptions);
|
|
3357
|
+
return { items: result.resourceTemplates, nextCursor: result.nextCursor };
|
|
3358
|
+
}, (server, requestOptions) => server.allResourceTemplates(requestOptions));
|
|
3359
|
+
return jsonResult(LIST_MCP_RESOURCE_TEMPLATES_TOOL, stringArgument(params, "server"), payload);
|
|
3360
|
+
}
|
|
3361
|
+
};
|
|
3362
|
+
const readResource = {
|
|
3363
|
+
name: READ_MCP_RESOURCE_TOOL,
|
|
3364
|
+
label: READ_MCP_RESOURCE_TOOL,
|
|
3365
|
+
description: "Read a specific resource from an MCP server given the server name and resource URI.",
|
|
3366
|
+
parameters: READ_PARAMETERS,
|
|
3367
|
+
outputSchema: READ_OUTPUT_SCHEMA,
|
|
3368
|
+
exposure: toToolExposure(options.exposure),
|
|
3369
|
+
annotations: readOnly,
|
|
3370
|
+
async execute(_toolCallId, params, signal) {
|
|
3371
|
+
const serverName = stringArgument(params, "server");
|
|
3372
|
+
const uri = stringArgument(params, "uri");
|
|
3373
|
+
if (!serverName)
|
|
3374
|
+
throw new Error("server must be provided");
|
|
3375
|
+
if (!uri)
|
|
3376
|
+
throw new Error("uri must be provided");
|
|
3377
|
+
const server = findServer(serverName);
|
|
3378
|
+
const result = await server.readResource(uri, { signal, timeoutMs: server.timeoutMs });
|
|
3379
|
+
const blocks = result.contents.flatMap((contents2) => [
|
|
3380
|
+
...result.contents.length > 1 ? [{ type: "text", text: `${contents2.uri}:` }] : [],
|
|
3381
|
+
{ type: "resource", resource: contents2 }
|
|
3382
|
+
]);
|
|
3383
|
+
const converted = await toModelContent(server.name, blocks);
|
|
3384
|
+
const { content, fullOutputPath } = await limitMcpContent(converted.length > 0 ? converted : [{ type: "text", text: `Resource ${uri} is empty.` }]);
|
|
3385
|
+
const contents = result.contents.map(({ _meta: _ignored, ...rest }) => rest);
|
|
3386
|
+
return {
|
|
3387
|
+
content,
|
|
3388
|
+
details: {
|
|
3389
|
+
server: server.name,
|
|
3390
|
+
tool: READ_MCP_RESOURCE_TOOL,
|
|
3391
|
+
...fullOutputPath ? { fullOutputPath } : {}
|
|
3392
|
+
},
|
|
3393
|
+
structuredContent: { server: server.name, uri, contents }
|
|
3394
|
+
};
|
|
3395
|
+
}
|
|
3396
|
+
};
|
|
3397
|
+
return [listResources, listTemplates, readResource];
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
// node_modules/@earendil-works/pi-coding-agent/dist/utils/abort.js
|
|
3401
|
+
function abortReason(signal) {
|
|
3402
|
+
if (signal.reason !== undefined)
|
|
3403
|
+
return signal.reason;
|
|
3404
|
+
const error = new Error("The operation was aborted");
|
|
3405
|
+
error.name = "AbortError";
|
|
3406
|
+
return error;
|
|
3407
|
+
}
|
|
3408
|
+
function operationSignal(signal) {
|
|
3409
|
+
return signal ?? new AbortController().signal;
|
|
3410
|
+
}
|
|
3411
|
+
function raceWithAbortSignal(operation, signal) {
|
|
3412
|
+
if (!signal)
|
|
3413
|
+
return operation;
|
|
3414
|
+
if (signal.aborted) {
|
|
3415
|
+
operation.catch(() => {});
|
|
3416
|
+
return Promise.reject(abortReason(signal));
|
|
3417
|
+
}
|
|
3418
|
+
return new Promise((resolve, reject) => {
|
|
3419
|
+
let settled = false;
|
|
3420
|
+
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
3421
|
+
const onAbort = () => {
|
|
3422
|
+
if (settled)
|
|
3423
|
+
return;
|
|
3424
|
+
settled = true;
|
|
3425
|
+
cleanup();
|
|
3426
|
+
reject(abortReason(signal));
|
|
3427
|
+
};
|
|
3428
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
3429
|
+
operation.then((value) => {
|
|
3430
|
+
if (settled)
|
|
3431
|
+
return;
|
|
3432
|
+
settled = true;
|
|
3433
|
+
cleanup();
|
|
3434
|
+
resolve(value);
|
|
3435
|
+
}, (error) => {
|
|
3436
|
+
if (settled)
|
|
3437
|
+
return;
|
|
3438
|
+
settled = true;
|
|
3439
|
+
cleanup();
|
|
3440
|
+
reject(error);
|
|
3441
|
+
});
|
|
3442
|
+
if (signal.aborted)
|
|
3443
|
+
onAbort();
|
|
3444
|
+
});
|
|
3445
|
+
}
|
|
3446
|
+
|
|
3447
|
+
// node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js
|
|
3448
|
+
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
3449
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
3450
|
+
import { dirname, join as join2 } from "path";
|
|
3451
|
+
import { setTimeout as sleep } from "timers/promises";
|
|
3452
|
+
var AUTH_FILE_WRITE_OPTIONS = { encoding: "utf-8", mode: 384 };
|
|
3453
|
+
var sharedAuthFileReadState;
|
|
3454
|
+
|
|
3455
|
+
class FileAuthStorageBackend {
|
|
3456
|
+
authPath;
|
|
3457
|
+
constructor(authPath = join2(getAgentDir(), "auth.json")) {
|
|
3458
|
+
this.authPath = normalizePath(authPath);
|
|
3459
|
+
}
|
|
3460
|
+
ensureParentDir() {
|
|
3461
|
+
const dir = dirname(this.authPath);
|
|
3462
|
+
if (!existsSync(dir)) {
|
|
3463
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
ensureFileExists() {
|
|
3467
|
+
if (!existsSync(this.authPath)) {
|
|
3468
|
+
writeFileSync(this.authPath, "{}", AUTH_FILE_WRITE_OPTIONS);
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
acquireLockSyncWithRetry(path) {
|
|
3472
|
+
const maxAttempts = 10;
|
|
3473
|
+
const delayMs = 20;
|
|
3474
|
+
let lastError;
|
|
3475
|
+
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
3476
|
+
try {
|
|
3477
|
+
return import_proper_lockfile.default.lockSync(path, { realpath: false });
|
|
3478
|
+
} catch (error) {
|
|
3479
|
+
const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : undefined;
|
|
3480
|
+
if (code !== "ELOCKED" || attempt === maxAttempts) {
|
|
3481
|
+
throw error;
|
|
3482
|
+
}
|
|
3483
|
+
lastError = error;
|
|
3484
|
+
const start = Date.now();
|
|
3485
|
+
while (Date.now() - start < delayMs) {}
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
throw lastError ?? new Error("Failed to acquire auth storage lock");
|
|
3489
|
+
}
|
|
3490
|
+
withLock(fn) {
|
|
3491
|
+
this.ensureParentDir();
|
|
3492
|
+
this.ensureFileExists();
|
|
3493
|
+
let release;
|
|
3494
|
+
try {
|
|
3495
|
+
release = this.acquireLockSyncWithRetry(this.authPath);
|
|
3496
|
+
const current = existsSync(this.authPath) ? readFileSync(this.authPath, "utf-8") : undefined;
|
|
3497
|
+
const { result, next } = fn(current);
|
|
3498
|
+
if (next !== undefined) {
|
|
3499
|
+
writeFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);
|
|
3500
|
+
}
|
|
3501
|
+
return result;
|
|
3502
|
+
} finally {
|
|
3503
|
+
if (release) {
|
|
3504
|
+
release();
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
async acquireLockAsync(signal, onCompromised) {
|
|
3509
|
+
const staleMs = 30000;
|
|
3510
|
+
const maxDelayMs = 2000;
|
|
3511
|
+
const deadline = Date.now() + staleMs;
|
|
3512
|
+
let retry = 0;
|
|
3513
|
+
while (true) {
|
|
3514
|
+
signal?.throwIfAborted();
|
|
3515
|
+
let release;
|
|
3516
|
+
try {
|
|
3517
|
+
release = await import_proper_lockfile.default.lock(this.authPath, {
|
|
3518
|
+
realpath: false,
|
|
3519
|
+
retries: 0,
|
|
3520
|
+
stale: staleMs,
|
|
3521
|
+
onCompromised
|
|
3522
|
+
});
|
|
3523
|
+
} catch (error) {
|
|
3524
|
+
signal?.throwIfAborted();
|
|
3525
|
+
const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : undefined;
|
|
3526
|
+
const remainingMs = deadline - Date.now();
|
|
3527
|
+
if (code !== "ELOCKED" || remainingMs <= 0)
|
|
3528
|
+
throw error;
|
|
3529
|
+
const baseDelayMs = Math.min(10 * 2 ** retry, maxDelayMs / 2);
|
|
3530
|
+
retry++;
|
|
3531
|
+
const delayMs = Math.min(Math.round(baseDelayMs * (1 + Math.random())), remainingMs);
|
|
3532
|
+
if (signal)
|
|
3533
|
+
await sleep(delayMs, undefined, { signal });
|
|
3534
|
+
else
|
|
3535
|
+
await sleep(delayMs);
|
|
3536
|
+
continue;
|
|
3537
|
+
}
|
|
3538
|
+
if (signal?.aborted) {
|
|
3539
|
+
await release();
|
|
3540
|
+
signal.throwIfAborted();
|
|
3541
|
+
}
|
|
3542
|
+
return release;
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
async withLockAsync(fn, options) {
|
|
3546
|
+
options?.signal?.throwIfAborted();
|
|
3547
|
+
this.ensureParentDir();
|
|
3548
|
+
this.ensureFileExists();
|
|
3549
|
+
let release;
|
|
3550
|
+
let lockCompromised = false;
|
|
3551
|
+
let lockCompromisedError;
|
|
3552
|
+
const throwIfCompromised = () => {
|
|
3553
|
+
if (lockCompromised) {
|
|
3554
|
+
throw lockCompromisedError ?? new Error("Auth storage lock was compromised");
|
|
3555
|
+
}
|
|
3556
|
+
};
|
|
3557
|
+
try {
|
|
3558
|
+
release = await this.acquireLockAsync(options?.signal, (error) => {
|
|
3559
|
+
lockCompromised = true;
|
|
3560
|
+
lockCompromisedError = error;
|
|
3561
|
+
});
|
|
3562
|
+
throwIfCompromised();
|
|
3563
|
+
options?.signal?.throwIfAborted();
|
|
3564
|
+
const current = existsSync(this.authPath) ? readFileSync(this.authPath, "utf-8") : undefined;
|
|
3565
|
+
const { result, next } = await fn(current);
|
|
3566
|
+
throwIfCompromised();
|
|
3567
|
+
options?.signal?.throwIfAborted();
|
|
3568
|
+
if (next !== undefined) {
|
|
3569
|
+
writeFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);
|
|
3570
|
+
}
|
|
3571
|
+
throwIfCompromised();
|
|
3572
|
+
return result;
|
|
3573
|
+
} finally {
|
|
3574
|
+
if (release) {
|
|
3575
|
+
try {
|
|
3576
|
+
await release();
|
|
3577
|
+
} catch {}
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
class ReadOnlyAuthStorage {
|
|
3584
|
+
authPath;
|
|
3585
|
+
data;
|
|
3586
|
+
constructor(authPath = join2(getAgentDir(), "auth.json")) {
|
|
3587
|
+
this.authPath = normalizePath(authPath);
|
|
3588
|
+
}
|
|
3589
|
+
load() {
|
|
3590
|
+
if (this.data)
|
|
3591
|
+
return this.data;
|
|
3592
|
+
let parsed;
|
|
3593
|
+
try {
|
|
3594
|
+
parsed = JSON.parse(stripBom(readFileSync(this.authPath, "utf-8")));
|
|
3595
|
+
} catch (error) {
|
|
3596
|
+
if (error.code === "ENOENT") {
|
|
3597
|
+
this.data = {};
|
|
3598
|
+
return this.data;
|
|
3599
|
+
}
|
|
3600
|
+
throw new Error(`Failed to read auth.json: ${error instanceof Error ? error.message : String(error)}`);
|
|
3601
|
+
}
|
|
3602
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
3603
|
+
throw new Error("Invalid auth.json: expected an object");
|
|
3604
|
+
}
|
|
3605
|
+
for (const [providerId, credential] of Object.entries(parsed)) {
|
|
3606
|
+
if (typeof credential !== "object" || credential === null || Array.isArray(credential)) {
|
|
3607
|
+
throw new Error(`Invalid auth.json credential for provider "${providerId}"`);
|
|
3608
|
+
}
|
|
3609
|
+
const value = credential;
|
|
3610
|
+
if (value.type === "api_key") {
|
|
3611
|
+
const validKey = value.key === undefined || typeof value.key === "string";
|
|
3612
|
+
const validEnv = value.env === undefined || typeof value.env === "object" && value.env !== null && !Array.isArray(value.env) && Object.values(value.env).every((entry) => typeof entry === "string");
|
|
3613
|
+
if (validKey && validEnv)
|
|
3614
|
+
continue;
|
|
3615
|
+
} else if (value.type === "oauth" && typeof value.access === "string" && typeof value.refresh === "string" && typeof value.expires === "number" && Number.isFinite(value.expires)) {
|
|
3616
|
+
continue;
|
|
3617
|
+
}
|
|
3618
|
+
throw new Error(`Invalid auth.json credential for provider "${providerId}"`);
|
|
3619
|
+
}
|
|
3620
|
+
this.data = parsed;
|
|
3621
|
+
return this.data;
|
|
3622
|
+
}
|
|
3623
|
+
async read(providerId, options) {
|
|
3624
|
+
options?.signal?.throwIfAborted();
|
|
3625
|
+
const credential = this.load()[providerId];
|
|
3626
|
+
options?.signal?.throwIfAborted();
|
|
3627
|
+
if (!credential)
|
|
3628
|
+
return;
|
|
3629
|
+
if (credential.type !== "api_key" || !credential.key || isCommandConfigValue(credential.key)) {
|
|
3630
|
+
return structuredClone(credential);
|
|
3631
|
+
}
|
|
3632
|
+
return { ...credential, key: resolveConfigValue(credential.key, credential.env) };
|
|
3633
|
+
}
|
|
3634
|
+
async list(options) {
|
|
3635
|
+
options?.signal?.throwIfAborted();
|
|
3636
|
+
const credentials = Object.entries(this.load()).map(([providerId, credential]) => ({
|
|
3637
|
+
providerId,
|
|
3638
|
+
type: credential.type
|
|
3639
|
+
}));
|
|
3640
|
+
options?.signal?.throwIfAborted();
|
|
3641
|
+
return credentials;
|
|
3642
|
+
}
|
|
3643
|
+
async modify(_providerId, _fn, _options) {
|
|
3644
|
+
throw new Error("Read-only credential storage cannot modify auth.json");
|
|
3645
|
+
}
|
|
3646
|
+
async delete(_providerId, _options) {
|
|
3647
|
+
throw new Error("Read-only credential storage cannot modify auth.json");
|
|
3648
|
+
}
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3651
|
+
class InMemoryAuthStorageBackend {
|
|
3652
|
+
value;
|
|
3653
|
+
asyncChain = Promise.resolve();
|
|
3654
|
+
withLock(fn) {
|
|
3655
|
+
const { result, next } = fn(this.value);
|
|
3656
|
+
if (next !== undefined) {
|
|
3657
|
+
this.value = next;
|
|
3658
|
+
}
|
|
3659
|
+
return result;
|
|
3660
|
+
}
|
|
3661
|
+
withLockAsync(fn, options) {
|
|
3662
|
+
const previous = this.asyncChain;
|
|
3663
|
+
const operation = (async () => {
|
|
3664
|
+
await previous.catch(() => {});
|
|
3665
|
+
options?.signal?.throwIfAborted();
|
|
3666
|
+
const { result, next } = await fn(this.value);
|
|
3667
|
+
options?.signal?.throwIfAborted();
|
|
3668
|
+
if (next !== undefined) {
|
|
3669
|
+
this.value = next;
|
|
3670
|
+
}
|
|
3671
|
+
return result;
|
|
3672
|
+
})();
|
|
3673
|
+
this.asyncChain = operation.catch(() => {});
|
|
3674
|
+
return raceWithAbortSignal(operation, options?.signal);
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
|
|
3678
|
+
class AuthStorage {
|
|
3679
|
+
storage;
|
|
3680
|
+
authPath;
|
|
3681
|
+
readState;
|
|
3682
|
+
constructor(storage, authPath) {
|
|
3683
|
+
this.storage = storage;
|
|
3684
|
+
this.authPath = authPath;
|
|
3685
|
+
this.readState = authPath && sharedAuthFileReadState?.authPath === authPath ? sharedAuthFileReadState.readState : { data: {} };
|
|
3686
|
+
if (authPath && !sharedAuthFileReadState) {
|
|
3687
|
+
sharedAuthFileReadState = { authPath, readState: this.readState };
|
|
3688
|
+
}
|
|
3689
|
+
if (authPath) {
|
|
3690
|
+
const revision = getFileRevision(authPath);
|
|
3691
|
+
if (revision !== undefined && revision === this.readState.revision)
|
|
3692
|
+
return;
|
|
3693
|
+
}
|
|
3694
|
+
this.reload();
|
|
3695
|
+
}
|
|
3696
|
+
static create(authPath = join2(getAgentDir(), "auth.json")) {
|
|
3697
|
+
const normalizedAuthPath = normalizePath(authPath);
|
|
3698
|
+
return new AuthStorage(new FileAuthStorageBackend(normalizedAuthPath), normalizedAuthPath);
|
|
3699
|
+
}
|
|
3700
|
+
static fromStorage(storage) {
|
|
3701
|
+
return new AuthStorage(storage);
|
|
3702
|
+
}
|
|
3703
|
+
static inMemory(data = {}) {
|
|
3704
|
+
const storage = new InMemoryAuthStorageBackend;
|
|
3705
|
+
storage.withLock(() => ({ result: undefined, next: JSON.stringify(data, null, 2) }));
|
|
3706
|
+
return AuthStorage.fromStorage(storage);
|
|
3707
|
+
}
|
|
3708
|
+
parseStorageData(content) {
|
|
3709
|
+
if (!content) {
|
|
3710
|
+
return {};
|
|
3711
|
+
}
|
|
3712
|
+
return JSON.parse(stripBom(content));
|
|
3713
|
+
}
|
|
3714
|
+
updateReadState(data, revision) {
|
|
3715
|
+
this.readState.data = data;
|
|
3716
|
+
this.readState.revision = revision;
|
|
3717
|
+
}
|
|
3718
|
+
reload() {
|
|
3719
|
+
let content;
|
|
3720
|
+
let revision;
|
|
3721
|
+
try {
|
|
3722
|
+
this.storage.withLock((current) => {
|
|
3723
|
+
content = current;
|
|
3724
|
+
revision = this.authPath ? getFileRevision(this.authPath) : undefined;
|
|
3725
|
+
return { result: undefined };
|
|
3726
|
+
});
|
|
3727
|
+
this.updateReadState(this.parseStorageData(content), revision);
|
|
3728
|
+
} catch {}
|
|
3729
|
+
}
|
|
3730
|
+
async reloadFromStorageAsync(options) {
|
|
3731
|
+
return this.storage.withLockAsync(async (content) => {
|
|
3732
|
+
const currentData = this.parseStorageData(content);
|
|
3733
|
+
const revision = this.authPath ? getFileRevision(this.authPath) : undefined;
|
|
3734
|
+
this.updateReadState(currentData, revision);
|
|
3735
|
+
return { result: currentData };
|
|
3736
|
+
}, options);
|
|
3737
|
+
}
|
|
3738
|
+
async readLatestData(options) {
|
|
3739
|
+
options?.signal?.throwIfAborted();
|
|
3740
|
+
if (!this.authPath) {
|
|
3741
|
+
const reload2 = this.reloadFromStorageAsync(options);
|
|
3742
|
+
return options?.signal ? reload2 : reload2.catch(() => this.readState.data);
|
|
3743
|
+
}
|
|
3744
|
+
const revision = getFileRevision(this.authPath);
|
|
3745
|
+
if (revision !== undefined && revision === this.readState.revision)
|
|
3746
|
+
return this.readState.data;
|
|
3747
|
+
if (!this.readState.reload) {
|
|
3748
|
+
const controller = new AbortController;
|
|
3749
|
+
const reload2 = {
|
|
3750
|
+
controller,
|
|
3751
|
+
promise: this.reloadFromStorageAsync({ signal: controller.signal }),
|
|
3752
|
+
readers: 0
|
|
3753
|
+
};
|
|
3754
|
+
this.readState.reload = reload2;
|
|
3755
|
+
reload2.promise.then(() => {
|
|
3756
|
+
if (this.readState.reload === reload2)
|
|
3757
|
+
this.readState.reload = undefined;
|
|
3758
|
+
}, () => {
|
|
3759
|
+
if (this.readState.reload === reload2)
|
|
3760
|
+
this.readState.reload = undefined;
|
|
3761
|
+
});
|
|
3762
|
+
}
|
|
3763
|
+
const reload = this.readState.reload;
|
|
3764
|
+
reload.readers++;
|
|
3765
|
+
try {
|
|
3766
|
+
const result = raceWithAbortSignal(reload.promise, options?.signal);
|
|
3767
|
+
return options?.signal ? await result : await result.catch(() => this.readState.data);
|
|
3768
|
+
} finally {
|
|
3769
|
+
reload.readers--;
|
|
3770
|
+
if (reload.readers === 0 && this.readState.reload === reload) {
|
|
3771
|
+
this.readState.reload = undefined;
|
|
3772
|
+
reload.controller.abort();
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
async read(provider, options) {
|
|
3777
|
+
const credential = (await this.readLatestData(options))[provider];
|
|
3778
|
+
options?.signal?.throwIfAborted();
|
|
3779
|
+
if (credential?.type !== "api_key")
|
|
3780
|
+
return credential;
|
|
3781
|
+
if (credential.key === undefined)
|
|
3782
|
+
return credential;
|
|
3783
|
+
return { ...credential, key: resolveConfigValue(credential.key, credential.env) };
|
|
3784
|
+
}
|
|
3785
|
+
async modify(provider, fn, options) {
|
|
3786
|
+
let latestData = this.readState.data;
|
|
3787
|
+
let revision;
|
|
3788
|
+
const result = await this.storage.withLockAsync(async (content) => {
|
|
3789
|
+
const currentData = this.parseStorageData(content);
|
|
3790
|
+
const next = await fn(currentData[provider]);
|
|
3791
|
+
if (next === undefined) {
|
|
3792
|
+
latestData = currentData;
|
|
3793
|
+
revision = this.authPath ? getFileRevision(this.authPath) : undefined;
|
|
3794
|
+
return { result: currentData[provider] };
|
|
3795
|
+
}
|
|
3796
|
+
const merged = { ...currentData, [provider]: next };
|
|
3797
|
+
latestData = merged;
|
|
3798
|
+
return { result: next, next: JSON.stringify(merged, null, 2) };
|
|
3799
|
+
}, options);
|
|
3800
|
+
this.updateReadState(latestData, revision);
|
|
3801
|
+
return result;
|
|
3802
|
+
}
|
|
3803
|
+
async delete(provider, options) {
|
|
3804
|
+
let latestData = this.readState.data;
|
|
3805
|
+
await this.storage.withLockAsync(async (content) => {
|
|
3806
|
+
const currentData = this.parseStorageData(content);
|
|
3807
|
+
delete currentData[provider];
|
|
3808
|
+
latestData = currentData;
|
|
3809
|
+
return { result: undefined, next: JSON.stringify(currentData, null, 2) };
|
|
3810
|
+
}, options);
|
|
3811
|
+
this.updateReadState(latestData);
|
|
3812
|
+
}
|
|
3813
|
+
async list(options) {
|
|
3814
|
+
const entries = Object.entries(await this.readLatestData(options));
|
|
3815
|
+
options?.signal?.throwIfAborted();
|
|
3816
|
+
return entries.map(([providerId, credential]) => ({ providerId, type: credential.type }));
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
function readStoredCredential(providerId, authPath = join2(getAgentDir(), "auth.json")) {
|
|
3820
|
+
try {
|
|
3821
|
+
const data = JSON.parse(stripBom(readFileSync(normalizePath(authPath), "utf-8")));
|
|
3822
|
+
return data[providerId];
|
|
3823
|
+
} catch {
|
|
3824
|
+
return;
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
|
|
3828
|
+
export { DEFAULT_MAX_LINES, DEFAULT_MAX_BYTES, GREP_MAX_LINE_LENGTH, formatSize, truncateHead, truncateTail, truncateLine, getConfigValueEnvVarNames, isCommandConfigValue, isConfigValueConfigured, resolveConfigValueOrThrow, resolveHeadersOrThrow, require_proper_lockfile, operationSignal, raceWithAbortSignal, FileAuthStorageBackend, ReadOnlyAuthStorage, AuthStorage, readStoredCredential, JSON_RPC_ERROR_CODES, McpError, isObject, LATEST_PROTOCOL_VERSION, McpClient, StdioTransport, McpHttpError, McpAuthRequiredError, McpSessionExpiredError, StreamableHttpTransport, READ_MCP_RESOURCE_TOOL, createMcpToolName, createMcpToolDefinition, LIST_MCP_RESOURCES_TOOL, LIST_MCP_RESOURCE_TEMPLATES_TOOL, isMcpAppResource, createMcpResourceToolDefinitions };
|