@desplega.ai/agent-swarm 2.4.4 → 2.5.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 +4 -2
- package/dist/{acp-adapter-thq04adh.js → acp-adapter-11gp67nr.js} +8 -6
- package/dist/{actions-j6ywh6x5.js → actions-8p2kze8j.js} +24 -22
- package/dist/{amp-adapter-k8b5xmj8.js → amp-adapter-z4qvhacj.js} +2 -2
- package/dist/{anthropic-messages-g6pqmqk4.js → anthropic-messages-txs190dd.js} +17 -20
- package/dist/{app-rb7vc02s.js → app-0qp0a2gk.js} +3 -3
- package/dist/{assistant-ftta1zjf.js → assistant-jedd3ktm.js} +27 -25
- package/dist/{azure-openai-responses-9dbmj346.js → azure-openai-responses-9kfwhmn7.js} +18 -13
- package/dist/{boot-reembed-xns7h5h9.js → boot-reembed-4xwq5tg0.js} +1 -1
- package/dist/{boot-reembed-srp6v6af.js → boot-reembed-n4wq5dd2.js} +1 -1
- package/dist/{boot-scrub-sweep-3qqrh2mz.js → boot-scrub-sweep-69h90xcq.js} +4 -4
- package/dist/{boot-seeds-9ks8hce7.js → boot-seeds-3vn0m9sg.js} +4 -4
- package/dist/{claude-adapter-k5ksyres.js → claude-adapter-221mvad5.js} +8 -6
- package/dist/{claude-managed-adapter-h2y889ge.js → claude-managed-adapter-gt6pa35d.js} +2 -2
- package/dist/{claude-managed-setup-n5a5eqks.js → claude-managed-setup-c3hp36ph.js} +4 -4
- package/dist/{claude-sdk-session-2j3j4kwn.js → claude-sdk-session-8thjsk5e.js} +9729 -9628
- package/dist/{cli-b9fcxxev.js → cli-007cnhm1.js} +50 -4
- package/dist/{cli-j4rqdf2n.js → cli-03vpq45j.js} +2 -2
- package/dist/{cli-amyhm3gj.js → cli-0y6f0ckq.js} +1 -1
- package/dist/{cli-4dg55wsk.js → cli-0z3vjrpm.js} +1 -1
- package/dist/{cli-pccfmtb5.js → cli-179xcyky.js} +11 -11
- package/dist/{cli-3r8samv3.js → cli-1f0gp9vz.js} +3 -2
- package/dist/{cli-hj3debgw.js → cli-1pr672hz.js} +3 -3
- package/dist/{cli-0bqteszy.js → cli-2nf3b08t.js} +328 -25
- package/dist/{cli-t7cyef5g.js → cli-36j4jnk3.js} +4 -4
- package/dist/{cli-er83cjbn.js → cli-3qv8naq8.js} +527 -231
- package/dist/cli-3zwye9sn.js +1193 -0
- package/dist/{cli-60cgh1rv.js → cli-459fk97x.js} +7 -7
- package/dist/{cli-xj0re5tm.js → cli-4w24f7z3.js} +1 -1
- package/dist/{cli-v3yr2gbg.js → cli-5kzk3472.js} +2198 -968
- package/dist/{cli-h7gc0b4r.js → cli-5m84zd2k.js} +55 -18
- package/dist/{cli-w6nadkh4.js → cli-5rvg1ddk.js} +5 -5
- package/dist/{cli-dvkmp9bt.js → cli-6ctwrf1z.js} +20 -10
- package/dist/{cli-9qtjfd60.js → cli-6rg2jn2y.js} +3 -2
- package/dist/{cli-2v045xyf.js → cli-7bwtc6yx.js} +3 -3
- package/dist/{cli-3cgngyd8.js → cli-7g40g8hq.js} +35 -17
- package/dist/{cli-q6r7t299.js → cli-92mqenkc.js} +2379 -154
- package/dist/{cli-cynvc9fj.js → cli-9ce2xw98.js} +8 -8
- package/dist/{cli-gqvh8d8a.js → cli-bgdtv62r.js} +36 -22
- package/dist/{cli-wxbn3yfx.js → cli-cz5nmdxt.js} +2 -2
- package/dist/{cli-wt645v7q.js → cli-dabehxhp.js} +1 -1
- package/dist/{cli-vfha21c9.js → cli-e5bxnjps.js} +2 -2
- package/dist/{cli-p20r8w42.js → cli-fcc5qe3f.js} +763 -268
- package/dist/{cli-1ephgwnq.js → cli-fes51ya2.js} +3 -3
- package/dist/{cli-1d70crsy.js → cli-ftmq4nvk.js} +2 -2
- package/dist/{cli-qkhc5aqy.js → cli-fy1jyyym.js} +13 -13
- package/dist/{cli-s95dknxh.js → cli-g1cw7xtt.js} +1 -1
- package/dist/{cli-qje9k2nh.js → cli-g9ypd5en.js} +12 -2
- package/dist/{cli-74c1wpm0.js → cli-gpv60278.js} +1 -1
- package/dist/{cli-pemywhfq.js → cli-ha9rmwgq.js} +2 -1
- package/dist/{cli-bnz0r3kc.js → cli-j1eghqfm.js} +5 -5
- package/dist/{cli-2zqpkvtt.js → cli-jpxsrxcb.js} +1 -1
- package/dist/{cli-ejs3m1sx.js → cli-kxpfx2xr.js} +1 -1
- package/dist/{cli-37yb7307.js → cli-mbfj11fq.js} +1 -1
- package/dist/{cli-pnp2j5zg.js → cli-mmhj8vd7.js} +2 -2
- package/dist/{cli-xf234ws8.js → cli-n4c8e3s5.js} +2 -0
- package/dist/{cli-a0kcty51.js → cli-n6kmqngw.js} +2 -2
- package/dist/{cli-te6b5wvg.js → cli-nnvjb17s.js} +3 -3
- package/dist/{cli-1dmcq2eh.js → cli-nzfnt2gs.js} +1 -1
- package/dist/{cli-625tb7aq.js → cli-p859hcc8.js} +2 -2
- package/dist/{cli-smvcw9z5.js → cli-pasyvjmm.js} +1 -1
- package/dist/cli-pkaqk57w.js +128 -0
- package/dist/{cli-8nyhf7za.js → cli-qqzmjxkf.js} +129 -105
- package/dist/{cli-zrwpctp4.js → cli-r25qpaxt.js} +161 -63
- package/dist/{cli-nc35pxb7.js → cli-rh5smt8t.js} +19 -4
- package/dist/{cli-qwkcwjdn.js → cli-rycdaj0a.js} +1 -1
- package/dist/{cli-esxerzg7.js → cli-s4sntwt4.js} +2 -2
- package/dist/{cli-b8k7epj1.js → cli-segs7hx9.js} +8 -8
- package/dist/{cli-36ckw0wx.js → cli-stxdrqs2.js} +2 -2
- package/dist/{cli-vdm20wej.js → cli-sy8f9705.js} +4 -4
- package/dist/{cli-1m17dc9d.js → cli-ta8bd7th.js} +2 -2
- package/dist/{cli-2y91wnbh.js → cli-we0ra057.js} +222 -10
- package/dist/{cli-55qmbp6z.js → cli-x21dqn18.js} +5 -5
- package/dist/{cli-dqb4n629.js → cli-x6vf4sad.js} +11 -11
- package/dist/{cli-d2mb5s8a.js → cli-x77gen2p.js} +680 -440
- package/dist/{cli-vq97g1jq.js → cli-xawhpgc9.js} +95 -195
- package/dist/{cli-82d3nkc3.js → cli-xd4eqtr2.js} +2 -2
- package/dist/{cli-9fhkkpj5.js → cli-xt768r5m.js} +2 -2
- package/dist/{cli-zrk6jxv8.js → cli-y4x8ww6s.js} +2 -2
- package/dist/{cli-xc27fwzg.js → cli-y9jvxfhk.js} +3 -3
- package/dist/{cli-44159k28.js → cli-z63a269p.js} +2 -2
- package/dist/{cli-sm8rses9.js → cli-zfdp01hn.js} +8 -5
- package/dist/cli.js +31 -29
- package/dist/{cloudflare-workers-ai-system-one-ch2wxfcp.js → cloudflare-workers-ai-system-one-43v9qkjk.js} +7 -2
- package/dist/{codex-adapter-968xwfy7.js → codex-adapter-tcg1q3jk.js} +6 -4
- package/dist/{codex-login-m819c41r.js → codex-login-rn7c5gxt.js} +1 -1
- package/dist/{codex-session-runner-ht4z99fa.js → codex-session-runner-xfx4wd9x.js} +7 -5
- package/dist/{commands-pcymaeg9.js → commands-ew83nj70.js} +2 -2
- package/dist/{controller-fpjyk46r.js → controller-gnq1k1mf.js} +4 -4
- package/dist/{controllers-connect-mwzx1fh6.js → controllers-connect-tw1dan9r.js} +26 -24
- package/dist/{cursor-adapter-cp4s2e2f.js → cursor-adapter-yq5xgfcg.js} +1 -1
- package/dist/{db-xsjg9jqq.js → db-7gbc53fd.js} +14 -2
- package/dist/{db-sgd12bt9.js → db-t86xrnes.js} +3 -3
- package/dist/{devin-adapter-zgqadvnm.js → devin-adapter-4ycy4vrf.js} +1 -1
- package/dist/{dispatcher-x0jfw2c9.js → dispatcher-64bdyhps.js} +23 -21
- package/dist/{docker-fkgtr75t.js → docker-nfy2gc8t.js} +2 -2
- package/dist/{dsh-adapter-jrq7ma7h.js → dsh-adapter-tvhc4k2d.js} +1 -1
- package/dist/{e2b-16d6ch39.js → e2b-9gkdhm3c.js} +2 -2
- package/dist/{e2b-zn0b4w5w.js → e2b-cjtf8k1z.js} +2 -2
- package/dist/{easter-egg-3d-5cgynaja.js → easter-egg-3d-e4qv8dxj.js} +1 -1
- package/dist/{event-bus-9vpk8gmq.js → event-bus-3z78ep5n.js} +1 -1
- package/dist/{execute-t4e6m3rw.js → execute-0xpz8950.js} +85 -23
- package/dist/{external-channel-8njj4h3b.js → external-channel-e9nw24zv.js} +2 -2
- package/dist/{google-generative-ai-bmq8gkf3.js → google-generative-ai-mk9vcpe1.js} +15 -15
- package/dist/{google-vertex-b1rvp52s.js → google-vertex-q580kz8k.js} +20 -20
- package/dist/{grok-adapter-kkr97v2f.js → grok-adapter-v82srhrx.js} +9 -7
- package/dist/handlers-c9ajzhbn.js +41 -0
- package/dist/{heartbeat-wd03zhn0.js → heartbeat-2vqs1319.js} +26 -24
- package/dist/{hook-xzj2ts2p.js → hook-01nk13wx.js} +7 -5
- package/dist/{hook-f0vghj42.js → hook-jzpheegg.js} +9 -7
- package/dist/{http-4hwxv62p.js → http-fc1k6ec8.js} +859 -252
- package/dist/index-07ef7nkm.js +42 -0
- package/dist/{index-g6tbb6ve.js → index-31ceyf42.js} +1 -1
- package/dist/index-7yts8n9s.js +43 -0
- package/dist/{index-c4ykd0f1.js → index-dr94zbnh.js} +13348 -11611
- package/dist/index-q3t40ryv.js +46 -0
- package/dist/{index-ww2vznkp.js → index-sepja052.js} +1 -1
- package/dist/{index-97q4xn03.js → index-zdycv3ja.js} +135 -79
- package/dist/{index-g216q6jr.js → index-zsyx51ap.js} +1 -4
- package/dist/{keepalive-hrh7xnr9.js → keepalive-5nh2rhmr.js} +4 -4
- package/dist/lead-aayq64jn.js +79 -0
- package/dist/{llama-cpp-classify-vv43gswy.js → llama-cpp-classify-ee7vmd7q.js} +4 -1
- package/dist/{maintenance-e8wnwnqx.js → maintenance-hjhzdt3k.js} +1 -1
- package/dist/{mistral-conversations-1medfwv7.js → mistral-conversations-sd0xf1tn.js} +13 -13
- package/dist/{node-3v3f08f7.js → node-jzjj7r9x.js} +10 -9
- package/dist/{oauth-refresh-sweep-zm0yj4sj.js → oauth-refresh-sweep-y3n1knmd.js} +3 -3
- package/dist/{onboard-dtwcq603.js → onboard-1zq3m7db.js} +2 -2
- package/dist/{openai-codex-responses-de9pvs4d.js → openai-codex-responses-79s8xnbh.js} +29 -23
- package/dist/{openai-completions-mtqge3nf.js → openai-completions-tdbyts0x.js} +21 -20
- package/dist/{openai-decisions-ygk4kkxd.js → openai-decisions-bqhnjyfz.js} +2 -1
- package/dist/{openai-responses-dkyng71g.js → openai-responses-dm3t5vqp.js} +26 -17
- package/dist/{opencode-adapter-x4tqzhkh.js → opencode-adapter-e56086m1.js} +7 -5
- package/dist/{openrouter-images-wvv7camj.js → openrouter-images-ssttr1y4.js} +6 -3
- package/dist/{otel-impl-w3fbhpn0.js → otel-impl-h9yyza47.js} +2 -2
- package/dist/{pi-messages-nhh1pkz2.js → pi-messages-3nf8bq1a.js} +6 -4
- package/dist/{pi-mono-adapter-mcfkn9vf.js → pi-mono-adapter-tzps8f38.js} +9 -37
- package/dist/{pricing-refresh-j38dehfs.js → pricing-refresh-nevhat8h.js} +3 -3
- package/dist/{rbac-roles-ae8yttq4.js → rbac-roles-4y6ngvzq.js} +1 -1
- package/dist/{rbac-roles-ejxx9b35.js → rbac-roles-exbg8xb6.js} +2 -2
- package/dist/{registry-rxw10xzg.js → registry-ajhexe44.js} +1 -1
- package/dist/{render-v2-n16n0phe.js → render-v2-cfsh13z3.js} +3 -3
- package/dist/{resume-z0fgjc38.js → resume-5s2t0dbs.js} +10 -8
- package/dist/{runtime-xe3aqy4x.js → runtime-bt5pkpm1.js} +1 -1
- package/dist/{session-access-cv3mq6mc.js → session-access-dnbyp3cn.js} +6 -4
- package/dist/{setup-mafhj3yt.js → setup-1wj1y77j.js} +1 -1
- package/dist/{typesafe-system-one-2hgpayzy.js → typesafe-system-one-bre38hvs.js} +4 -2
- package/dist/{virtual-modules-4r3zkc20.js → virtual-modules-mnfbh5mr.js} +8 -2
- package/dist/{work-objects-8b86mgjp.js → work-objects-7mg6216g.js} +26 -24
- package/dist/worker-nwb789mg.js +79 -0
- package/dist/{x-y45mthwn.js → x-pbpezr0s.js} +2 -2
- package/openapi.json +793 -6
- package/package.json +11 -11
- package/src/apps/catalog.generated.json +206 -4
- package/src/apps/page-validator.ts +13 -1
- package/src/assets/key.ts +17 -0
- package/src/azure-devops/handlers.ts +1 -1
- package/src/be/chunking.ts +42 -9
- package/src/be/db/approvals.ts +18 -0
- package/src/be/db/session-moves.ts +164 -0
- package/src/be/db/session-tree.ts +384 -0
- package/src/be/db/tasks/draft-text.ts +15 -0
- package/src/be/db/tasks/read.ts +54 -5
- package/src/be/db/workflow-runs.ts +96 -0
- package/src/be/db.ts +85 -237
- package/src/be/memory/index-content.ts +36 -17
- package/src/be/memory/providers/openai-embedding.ts +115 -61
- package/src/be/memory/providers/sqlite-store.ts +69 -23
- package/src/be/memory/reranker.ts +31 -1
- package/src/be/memory/search-candidates.ts +47 -0
- package/src/be/memory/types.ts +14 -0
- package/src/be/onboarding.ts +3 -0
- package/src/be/scripts/typecheck.ts +2 -0
- package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +106 -54
- package/src/be/seed-scripts/index.ts +2 -2
- package/src/be/skill-sync.ts +43 -2
- package/src/be/swarm-config-guard.ts +25 -1
- package/src/be/task-attachment-store.ts +30 -0
- package/src/bitbucket/api.ts +81 -0
- package/src/bitbucket/auth.ts +64 -0
- package/src/bitbucket/handlers.ts +434 -0
- package/src/bitbucket/index.ts +28 -0
- package/src/bitbucket/templates.ts +134 -0
- package/src/bitbucket/types.ts +65 -0
- package/src/commands/runner.ts +55 -3
- package/src/e2b/env.ts +1 -0
- package/src/extensions/catalog.generated.json +4 -4
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +9 -2
- package/src/extensions/post-bridge.ts +1 -0
- package/src/fs/provider.ts +13 -1
- package/src/github/handlers.ts +6 -6
- package/src/gitlab/handlers.ts +5 -5
- package/src/heartbeat/heartbeat.ts +31 -11
- package/src/http/assets.ts +14 -2
- package/src/http/core.ts +12 -0
- package/src/http/fs.ts +54 -34
- package/src/http/index.ts +4 -0
- package/src/http/mcp-body.ts +37 -0
- package/src/http/mcp-user.ts +3 -5
- package/src/http/mcp.ts +6 -7
- package/src/http/memory.ts +26 -15
- package/src/http/onboarding.ts +1 -0
- package/src/http/page-proxy.ts +61 -5
- package/src/http/pages-public.ts +27 -44
- package/src/http/pages.ts +4 -4
- package/src/http/script-runs.ts +2 -0
- package/src/http/sessions.ts +366 -12
- package/src/http/skills.ts +48 -1
- package/src/http/tasks.ts +1 -1
- package/src/http/users.ts +13 -1
- package/src/http/webhooks.ts +141 -0
- package/src/integrations/chat-sdk/adapters.ts +24 -4
- package/src/integrations/chat-sdk/attachments.ts +90 -12
- package/src/integrations/chat-sdk/facts.ts +138 -0
- package/src/integrations/chat-sdk/inbound.ts +156 -8
- package/src/integrations/chat-sdk/limits.ts +24 -0
- package/src/integrations/chat-sdk/outbound-files.ts +186 -0
- package/src/integrations/chat-sdk/outbound.ts +272 -5
- package/src/integrations/chat-sdk/relay.ts +4 -1
- package/src/integrations/chat-sdk/router.ts +28 -2
- package/src/integrations/chat-sdk/steering.ts +9 -0
- package/src/integrations/chat-sdk/templates.ts +14 -0
- package/src/integrations/chat-sdk/thread-buffer.ts +4 -0
- package/src/mcp-limits.ts +20 -0
- package/src/pages/browser-sdk.ts +8 -3
- package/src/pages/feedback-overlay.ts +1 -1
- package/src/providers/acp-targets.ts +1 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/codex-adapter.ts +106 -119
- package/src/providers/codex-agents-md.ts +35 -229
- package/src/providers/cursor-adapter.ts +1 -1
- package/src/providers/pi-mono-adapter.ts +5 -53
- package/src/realtime/transport.ts +1 -2
- package/src/script-workflows/workflow-ctx.ts +1 -0
- package/src/scripts-runtime/types/stdlib.d.ts +2 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +14 -4
- package/src/scripts-runtime/types/swarm-sdk.d.ts +2 -0
- package/src/server-user.ts +2 -0
- package/src/server.ts +2 -0
- package/src/slack/assistant.ts +2 -2
- package/src/slack/files.ts +2 -0
- package/src/slack/handlers.test.ts +158 -0
- package/src/slack/handlers.ts +23 -32
- package/src/slack/inbound-files.ts +39 -6
- package/src/slack/thread-buffer.ts +2 -1
- package/src/tasks/context-key.ts +61 -1
- package/src/tasks/task-terminal-effects.ts +21 -17
- package/src/tests/apps-card-grid.test.ts +197 -0
- package/src/tests/apps-catalog-additions.test.ts +120 -0
- package/src/tests/apps-tree.test.ts +129 -0
- package/src/tests/bitbucket-auth.test.ts +156 -0
- package/src/tests/bitbucket-handlers.test.ts +425 -0
- package/src/tests/bitbucket-webhook.test.ts +220 -0
- package/src/tests/chat-sdk-attachments-reply.test.ts +52 -0
- package/src/tests/chat-sdk-config.test.ts +11 -0
- package/src/tests/chat-sdk-facts.test.ts +23 -0
- package/src/tests/chat-sdk-inbound.test.ts +597 -4
- package/src/tests/chat-sdk-outbound-files.test.ts +652 -0
- package/src/tests/chat-sdk-telegram-markdown.test.ts +92 -0
- package/src/tests/codex-adapter.test.ts +167 -242
- package/src/tests/config-api-only-keys.test.ts +9 -0
- package/src/tests/context-key.test.ts +50 -0
- package/src/tests/core-auth.test.ts +5 -0
- package/src/tests/cors-allowlist.test.ts +1 -1
- package/src/tests/db-task-read-contract.test.ts +7 -0
- package/src/tests/db-task-write-contract.test.ts +6 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/extensions-example-slack-reply-gate.test.ts +262 -91
- package/src/tests/fixtures/bitbucket/pullrequest-comment-created-inline.json +174 -0
- package/src/tests/fixtures/bitbucket/pullrequest-comment-created.json +170 -0
- package/src/tests/fixtures/bitbucket/pullrequest-created-mention.json +132 -0
- package/src/tests/fixtures/bitbucket/pullrequest-created-reviewer.json +140 -0
- package/src/tests/fixtures/bitbucket/pullrequest-fulfilled.json +134 -0
- package/src/tests/fixtures/bitbucket/pullrequest-rejected.json +133 -0
- package/src/tests/generate-mcp-docs.test.ts +101 -0
- package/src/tests/gitlab-handlers.test.ts +3 -3
- package/src/tests/gitlab-vcs-db.test.ts +4 -4
- package/src/tests/heartbeat-checklist.test.ts +33 -0
- package/src/tests/heartbeat-jev-gate-credentials.test.ts +44 -0
- package/src/tests/heartbeat-jev-gate.test.ts +242 -1
- package/src/tests/integration-disable-flags.test.ts +36 -0
- package/src/tests/kv-page-proxy.test.ts +91 -5
- package/src/tests/launch-password-rejection.test.ts +2 -2
- package/src/tests/mcp-input-caps.test.ts +294 -0
- package/src/tests/mcp-tools.test.ts +1 -1
- package/src/tests/memory-chunked-search-starvation.test.ts +200 -0
- package/src/tests/memory-embedding-input-cap.test.ts +114 -0
- package/src/tests/memory.test.ts +14 -0
- package/src/tests/onboarding.test.ts +12 -0
- package/src/tests/page-guest-session.test.ts +19 -8
- package/src/tests/page-proxy-authed.test.ts +1 -1
- package/src/tests/page-proxy.test.ts +17 -10
- package/src/tests/page-session.test.ts +102 -1
- package/src/tests/pages-authed-mode.test.ts +82 -12
- package/src/tests/pages-password-mode.test.ts +5 -5
- package/src/tests/pi-codemode.test.ts +8 -2
- package/src/tests/preload-env.test.ts +57 -0
- package/src/tests/preload.ts +21 -0
- package/src/tests/prompt-template-remaining.test.ts +38 -0
- package/src/tests/realtime-transport.test.ts +13 -7
- package/src/tests/run-root-coverage.test.ts +39 -0
- package/src/tests/runner-bitbucket-vcs.test.ts +191 -0
- package/src/tests/runner-skills-refresh.test.ts +58 -0
- package/src/tests/script-runs-http.test.ts +84 -0
- package/src/tests/scripts-http.test.ts +10 -1
- package/src/tests/secret-scrubber.test.ts +15 -0
- package/src/tests/sessions-move.test.ts +576 -0
- package/src/tests/sessions-tree.test.ts +493 -0
- package/src/tests/skill-files-http.test.ts +50 -0
- package/src/tests/skills-bundle.test.ts +99 -0
- package/src/tests/swarm-config-export-to-env.test.ts +23 -3
- package/src/tests/task-audio-transcription.test.ts +299 -0
- package/src/tests/task-completion-memory-chunking.test.ts +434 -0
- package/src/tests/task-terminal-secret-scrub.test.ts +6 -1
- package/src/tests/transcription.test.ts +299 -0
- package/src/tests/vcs-bitbucket.test.ts +91 -0
- package/src/tests/vcs-provider-isolation.test.ts +123 -0
- package/src/tests/vcs-provider.test.ts +16 -1
- package/src/tests/vcs-tracking.test.ts +3 -3
- package/src/tests/workflow-foreach-bodies.test.ts +637 -0
- package/src/tests/workflow-foreach-concurrency.test.ts +342 -0
- package/src/tests/workflow-foreach-retry.test.ts +537 -0
- package/src/tests/workflow-foreach.test.ts +44 -23
- package/src/tests/workflow-step-claims.test.ts +6 -6
- package/src/tests/workflow-system-one-decision-providers.test.ts +98 -1
- package/src/tests/workflow-system-one-decision.test.ts +2 -1
- package/src/tests/workflow-tla-races.test.ts +2 -2
- package/src/tools/chat-access.ts +10 -0
- package/src/tools/chat-post.ts +31 -11
- package/src/tools/chat-reply.ts +32 -10
- package/src/tools/memory-search.ts +3 -1
- package/src/tools/script-delete.ts +1 -1
- package/src/tools/system-one-decide.ts +17 -4
- package/src/tools/workflows/create-workflow.ts +5 -3
- package/src/types.ts +9 -2
- package/src/utils/config-env-export.ts +4 -1
- package/src/utils/page-session.ts +133 -20
- package/src/utils/secret-scrubber.ts +4 -0
- package/src/utils/skills-refresh.ts +83 -43
- package/src/utils/transcription.ts +246 -0
- package/src/vcs/bitbucket.ts +58 -0
- package/src/vcs/index.ts +2 -0
- package/src/vcs/types.ts +2 -2
- package/src/workflows/approval-resolution.ts +4 -1
- package/src/workflows/checkpoint.ts +9 -1
- package/src/workflows/constants.ts +3 -0
- package/src/workflows/definition.ts +48 -17
- package/src/workflows/engine.ts +25 -15
- package/src/workflows/executors/foreach.ts +45 -99
- package/src/workflows/executors/system-one-decision.ts +28 -7
- package/src/workflows/executors/system-one-providers.ts +39 -4
- package/src/workflows/foreach-body.ts +146 -0
- package/src/workflows/foreach-driver.ts +552 -0
- package/src/workflows/foreach-join.ts +206 -7
- package/src/workflows/node-timeout.ts +21 -0
- package/src/workflows/recovery.ts +68 -3
- package/src/workflows/resume.ts +221 -43
- package/src/workflows/retry-poller.ts +39 -24
- package/src/workflows/step-input.ts +59 -0
- package/src/workflows/task-step-routing.ts +114 -56
- package/templates/extensions/slack-reply-gate/README.md +24 -22
- package/templates/extensions/slack-reply-gate/hooks.ts +146 -95
- package/templates/extensions/slack-reply-gate/manifest.json +2 -2
- package/templates/skills/apps/SKILL.md +28 -6
- package/templates/skills/apps/content.md +28 -6
- package/templates/skills/chat-sdk/content.md +6 -2
- package/templates/skills/code-quality/content.md +2 -1
- package/templates/skills/heartbeat-runbook/content.md +5 -5
- package/templates/skills/pages/content.md +6 -4
- package/templates/skills/slack-interaction/content.md +5 -0
- package/templates/skills/swarm-scripts/SKILL.md +2 -2
- package/templates/skills/swarm-scripts/content.md +2 -2
- package/templates/skills/work-on-task/SKILL.md +1 -1
- package/templates/skills/work-on-task/content.md +1 -1
- package/dist/cli-51y09c6p.js +0 -2657
- package/dist/cli-yw91rnmw.js +0 -13
- package/dist/handlers-0pvee9nw.js +0 -39
- package/dist/index-gdh8jrdm.js +0 -43
- package/dist/index-hg0x2cdv.js +0 -40
- package/dist/index-thm0y6a8.js +0 -41
- package/dist/lead-ee8vazz2.js +0 -77
- package/dist/worker-16s75hm5.js +0 -77
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Each task owns a fresh thread inside an isolated session subprocess.
|
|
8
8
|
* Native resume remains disabled. Follow-up tasks use the context preamble.
|
|
9
|
-
* The adapter resolves skills,
|
|
9
|
+
* The adapter resolves skills, supplies session instructions, and reports swarm events.
|
|
10
10
|
*
|
|
11
11
|
* Per-session configuration travels in `thread/start` over stdin. This keeps
|
|
12
12
|
* MCP credentials out of process arguments. The configuration overrides the
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
terminateProcessGroup,
|
|
49
49
|
} from "../utils/process-group";
|
|
50
50
|
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
51
|
-
import {
|
|
51
|
+
import { recoverLegacyCodexAgentsMd } from "./codex-agents-md";
|
|
52
52
|
import {
|
|
53
53
|
CodexAppServer,
|
|
54
54
|
type CodexAppServerNotification,
|
|
@@ -951,7 +951,6 @@ export interface SummarizeSessionForCodexDeps {
|
|
|
951
951
|
export class CodexSession implements ProviderSession {
|
|
952
952
|
private readonly thread: CodexThread;
|
|
953
953
|
private readonly config: ProviderSessionConfig;
|
|
954
|
-
private readonly agentsMdHandle: CodexAgentsMdHandle;
|
|
955
954
|
private readonly resolvedModel: string;
|
|
956
955
|
private readonly contextWindow: number;
|
|
957
956
|
private readonly skillsDir: string;
|
|
@@ -991,7 +990,7 @@ export class CodexSession implements ProviderSession {
|
|
|
991
990
|
/**
|
|
992
991
|
* Result captured by `settle` but held back from `resolveCompletion` until
|
|
993
992
|
* `runSession`'s `finally` block has fully cleaned up (log writer flush,
|
|
994
|
-
*
|
|
993
|
+
* app-server close, session summary). Without this, callers awaiting
|
|
995
994
|
* `waitForCompletion` would race the cleanup. Phase 3 added the session
|
|
996
995
|
* summary path which materially relies on this ordering for testability.
|
|
997
996
|
*/
|
|
@@ -1000,7 +999,6 @@ export class CodexSession implements ProviderSession {
|
|
|
1000
999
|
constructor(
|
|
1001
1000
|
thread: CodexThread,
|
|
1002
1001
|
config: ProviderSessionConfig,
|
|
1003
|
-
agentsMdHandle: CodexAgentsMdHandle,
|
|
1004
1002
|
resolvedModel: string,
|
|
1005
1003
|
initialEvents: ProviderEvent[] = [],
|
|
1006
1004
|
skillsDir?: string,
|
|
@@ -1008,7 +1006,6 @@ export class CodexSession implements ProviderSession {
|
|
|
1008
1006
|
) {
|
|
1009
1007
|
this.thread = thread;
|
|
1010
1008
|
this.config = config;
|
|
1011
|
-
this.agentsMdHandle = agentsMdHandle;
|
|
1012
1009
|
this.resolvedModel = resolvedModel;
|
|
1013
1010
|
this.contextWindow = getCodexContextWindow(resolvedModel);
|
|
1014
1011
|
// `CODEX_SKILLS_DIR` lets tests / non-Docker installs point at a custom
|
|
@@ -1739,7 +1736,7 @@ export class CodexSession implements ProviderSession {
|
|
|
1739
1736
|
} finally {
|
|
1740
1737
|
// Session-end summarization. Pure addition for codex — no behavior to
|
|
1741
1738
|
// preserve. Wrapped in its own try/catch so summary failure must NOT
|
|
1742
|
-
// block the existing log/
|
|
1739
|
+
// block the existing log/transport cleanup below. `SKIP_SESSION_SUMMARY` is
|
|
1743
1740
|
// read with `isSessionSummarySkipped`, the same as the claude Stop hook + pi/opencode.
|
|
1744
1741
|
//
|
|
1745
1742
|
// Skip the summary entirely when the session was aborted. The transcript
|
|
@@ -1778,7 +1775,6 @@ export class CodexSession implements ProviderSession {
|
|
|
1778
1775
|
} catch {
|
|
1779
1776
|
// Ignore log writer cleanup failures.
|
|
1780
1777
|
}
|
|
1781
|
-
await this.agentsMdHandle.cleanup();
|
|
1782
1778
|
|
|
1783
1779
|
// Resolve `waitForCompletion()` only AFTER all cleanup has finished so
|
|
1784
1780
|
// downstream observers (tests + the runner's `.then(...)` chain) don't
|
|
@@ -1941,123 +1937,114 @@ export async function createInProcessCodexSession(
|
|
|
1941
1937
|
threadFactory?: CodexThreadFactory;
|
|
1942
1938
|
} = {},
|
|
1943
1939
|
): Promise<CodexSession> {
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
const bufferedEmit = (event: ProviderEvent) => {
|
|
1960
|
-
preSessionEvents.push(event);
|
|
1961
|
-
};
|
|
1940
|
+
await recoverLegacyCodexAgentsMd(config.cwd);
|
|
1941
|
+
|
|
1942
|
+
// Resolve the model once and thread it through. Claude shortnames map
|
|
1943
|
+
// to Codex equivalents; everything else passes through verbatim — the
|
|
1944
|
+
// CLI is the source of truth for valid model identifiers.
|
|
1945
|
+
const resolvedModel = resolveCodexModel(config.model);
|
|
1946
|
+
|
|
1947
|
+
// Buffer warnings emitted during config-building so they're not lost
|
|
1948
|
+
// before `CodexSession.onEvent` attaches a listener. The buffer is
|
|
1949
|
+
// replayed into the session's event stream right after construction
|
|
1950
|
+
// via the `initialEvents` constructor parameter.
|
|
1951
|
+
const preSessionEvents: ProviderEvent[] = [];
|
|
1952
|
+
const bufferedEmit = (event: ProviderEvent) => {
|
|
1953
|
+
preSessionEvents.push(event);
|
|
1954
|
+
};
|
|
1962
1955
|
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1956
|
+
const mergedConfig = await buildCodexConfig(config, resolvedModel, bufferedEmit);
|
|
1957
|
+
|
|
1958
|
+
// Auth resolution. `codex_oauth` (in the swarm config store) wins over
|
|
1959
|
+
// `OPENAI_API_KEY` so users can keep an OpenAI key set for embeddings
|
|
1960
|
+
// without it shadowing their ChatGPT login. The entrypoint already runs
|
|
1961
|
+
// this same precedence at boot — this block handles local dev (where
|
|
1962
|
+
// the entrypoint didn't run) and any case where auth.json is stale.
|
|
1963
|
+
const authMode = await resolveCodexAuthMode(config, bufferedEmit);
|
|
1964
|
+
|
|
1965
|
+
// The app-server receives an explicit environment. Construct a
|
|
1966
|
+
// minimal env explicitly so the spawned Codex CLI can find its binary
|
|
1967
|
+
// (PATH) and HOME (for ~/.codex/auth.json). `OPENAI_API_KEY` is only
|
|
1968
|
+
// forwarded when auth.json is NOT in chatgpt mode — otherwise it would
|
|
1969
|
+
// override the OAuth login at the Codex CLI layer.
|
|
1970
|
+
const env: Record<string, string> = {
|
|
1971
|
+
PATH: process.env.PATH ?? "",
|
|
1972
|
+
HOME: process.env.HOME ?? "",
|
|
1973
|
+
...(authMode !== "chatgpt" && process.env.OPENAI_API_KEY
|
|
1974
|
+
? { OPENAI_API_KEY: process.env.OPENAI_API_KEY }
|
|
1975
|
+
: {}),
|
|
1976
|
+
...(process.env.NODE_EXTRA_CA_CERTS
|
|
1977
|
+
? { NODE_EXTRA_CA_CERTS: process.env.NODE_EXTRA_CA_CERTS }
|
|
1978
|
+
: {}),
|
|
1979
|
+
CONTEXT_MODE_EXTERNAL_MCP_NUDGE_EVERY: CTX_MODE_NUDGE_EVERY,
|
|
1980
|
+
...(config.env ?? {}),
|
|
1981
|
+
// Gated cross-service OTel linking: when SWARM_ENABLE_HARNESS_OTEL (or
|
|
1982
|
+
// the deprecated SWARM_ENABLE_CLAUDE_CODE_OTEL alias) is on, inject
|
|
1983
|
+
// TRACEPARENT from the active worker span so Codex's spans nest under
|
|
1984
|
+
// our worker.session trace. Codex's Rust OTEL SDK reads W3C trace
|
|
1985
|
+
// context from the env via the default tracecontext propagator.
|
|
1986
|
+
// Returns {} (no-op) when off; spread last so the computed value wins.
|
|
1987
|
+
...buildOtelTraceparentEnv(config.env ?? process.env),
|
|
1988
|
+
SWARM_CODEX_APP_SERVER: "1",
|
|
1989
|
+
};
|
|
1990
|
+
if (authMode === "chatgpt") delete env.OPENAI_API_KEY;
|
|
1998
1991
|
|
|
1999
|
-
|
|
1992
|
+
const codexPathOverride = process.env.CODEX_PATH_OVERRIDE;
|
|
2000
1993
|
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
config,
|
|
2014
|
-
resolvedModel,
|
|
2015
|
-
env,
|
|
2016
|
-
codexConfig: mergedConfig,
|
|
2017
|
-
});
|
|
2018
|
-
} else {
|
|
2019
|
-
const appServerFactory = opts.appServerFactory ?? ((options) => new CodexAppServer(options));
|
|
2020
|
-
const client = appServerFactory({
|
|
2021
|
-
...(codexPathOverride ? { codexPath: codexPathOverride } : {}),
|
|
2022
|
-
env,
|
|
2023
|
-
onStderr: (line) => {
|
|
2024
|
-
if (liveSession) liveSession.emitTransportStderr(line);
|
|
2025
|
-
else bufferedEmit({ type: "raw_stderr", content: `${line}\n` });
|
|
2026
|
-
},
|
|
2027
|
-
});
|
|
2028
|
-
try {
|
|
2029
|
-
const response = await client.request<{ thread: { id: string } }>("thread/start", {
|
|
2030
|
-
model: resolvedModel,
|
|
2031
|
-
cwd: config.cwd,
|
|
2032
|
-
approvalPolicy: "never",
|
|
2033
|
-
sandbox: "danger-full-access",
|
|
2034
|
-
config: mergedConfig,
|
|
2035
|
-
ephemeral: true,
|
|
2036
|
-
});
|
|
2037
|
-
thread = new AppServerCodexThread(client, response.thread.id);
|
|
2038
|
-
} catch (error) {
|
|
2039
|
-
await client.close();
|
|
2040
|
-
throw error;
|
|
2041
|
-
}
|
|
2042
|
-
}
|
|
2043
|
-
|
|
2044
|
-
const session = new CodexSession(
|
|
2045
|
-
thread,
|
|
1994
|
+
// Native resume is deprecated. Follow-up continuity is delivered via the
|
|
1995
|
+
// context preamble (see src/commands/context-preamble.ts). Any stray
|
|
1996
|
+
// resumeSessionId is logged and ignored — we always start a fresh thread.
|
|
1997
|
+
if (config.resumeSessionId) {
|
|
1998
|
+
console.warn(
|
|
1999
|
+
"[codex-adapter] resumeSessionId ignored — native resume is disabled by deprecation plan",
|
|
2000
|
+
);
|
|
2001
|
+
}
|
|
2002
|
+
let thread: CodexThread;
|
|
2003
|
+
let liveSession: CodexSession | undefined;
|
|
2004
|
+
if (opts.threadFactory) {
|
|
2005
|
+
thread = await opts.threadFactory({
|
|
2046
2006
|
config,
|
|
2047
|
-
agentsMdHandle,
|
|
2048
2007
|
resolvedModel,
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2008
|
+
env,
|
|
2009
|
+
codexConfig: mergedConfig,
|
|
2010
|
+
});
|
|
2011
|
+
} else {
|
|
2012
|
+
const appServerFactory = opts.appServerFactory ?? ((options) => new CodexAppServer(options));
|
|
2013
|
+
const client = appServerFactory({
|
|
2014
|
+
...(codexPathOverride ? { codexPath: codexPathOverride } : {}),
|
|
2015
|
+
env,
|
|
2016
|
+
onStderr: (line) => {
|
|
2017
|
+
if (liveSession) liveSession.emitTransportStderr(line);
|
|
2018
|
+
else bufferedEmit({ type: "raw_stderr", content: `${line}\n` });
|
|
2019
|
+
},
|
|
2020
|
+
});
|
|
2021
|
+
try {
|
|
2022
|
+
const response = await client.request<{ thread: { id: string } }>("thread/start", {
|
|
2023
|
+
model: resolvedModel,
|
|
2024
|
+
cwd: config.cwd,
|
|
2025
|
+
developerInstructions: config.systemPrompt,
|
|
2026
|
+
approvalPolicy: "never",
|
|
2027
|
+
sandbox: "danger-full-access",
|
|
2028
|
+
config: mergedConfig,
|
|
2029
|
+
ephemeral: true,
|
|
2030
|
+
});
|
|
2031
|
+
thread = new AppServerCodexThread(client, response.thread.id);
|
|
2032
|
+
} catch (error) {
|
|
2033
|
+
await client.close();
|
|
2034
|
+
throw error;
|
|
2035
|
+
}
|
|
2060
2036
|
}
|
|
2037
|
+
|
|
2038
|
+
const session = new CodexSession(
|
|
2039
|
+
thread,
|
|
2040
|
+
config,
|
|
2041
|
+
resolvedModel,
|
|
2042
|
+
preSessionEvents,
|
|
2043
|
+
opts.skillsDir,
|
|
2044
|
+
opts.summarizeDeps ?? {},
|
|
2045
|
+
);
|
|
2046
|
+
liveSession = session;
|
|
2047
|
+
return session;
|
|
2061
2048
|
}
|
|
2062
2049
|
|
|
2063
2050
|
/**
|
|
@@ -1,242 +1,48 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Codex reads `AGENTS.md` from the session cwd at startup and uses its contents
|
|
5
|
-
* as the agent's base instructions. There is no `ThreadStartParams.systemPrompt`
|
|
6
|
-
* / `developerInstructions` equivalent wired through the SDK 0.118 public
|
|
7
|
-
* surface, so the only way to inject our per-session `config.systemPrompt` is
|
|
8
|
-
* to write it into `AGENTS.md` before `thread.runStreamed()` is called.
|
|
9
|
-
*
|
|
10
|
-
* To avoid stomping on any existing `AGENTS.md` content (or any `CLAUDE.md`
|
|
11
|
-
* that the repo already ships with), we manage a delimited block:
|
|
12
|
-
*
|
|
13
|
-
* <swarm_system_prompt>
|
|
14
|
-
* ...our prompt...
|
|
15
|
-
* </swarm_system_prompt>
|
|
16
|
-
*
|
|
17
|
-
* Rules:
|
|
18
|
-
* - No existing `AGENTS.md`:
|
|
19
|
-
* - If `CLAUDE.md` exists in cwd, prepend the block to the CLAUDE.md
|
|
20
|
-
* contents so Codex sees our prompt plus the repo's existing Claude
|
|
21
|
-
* instructions.
|
|
22
|
-
* - Otherwise, write just the block.
|
|
23
|
-
* - Mark `createdFresh: true` so cleanup removes the file entirely.
|
|
24
|
-
* - `AGENTS.md` is a symlink (many repos ship `AGENTS.md -> CLAUDE.md`):
|
|
25
|
-
* never write through it. Swap in a real file holding the block plus the
|
|
26
|
-
* link target's contents, and restore the symlink on cleanup. The target is
|
|
27
|
-
* only read, and edits only carried back to it, when its real path is a
|
|
28
|
-
* regular file inside the cwd. A crash-recovery record (cwd + link target)
|
|
29
|
-
* is kept OUTSIDE the repo, so the next session can restore the link if
|
|
30
|
-
* this one crashed before cleanup. Repo content never names a path.
|
|
31
|
-
* - Existing `AGENTS.md` already contains the block: replace the block with
|
|
32
|
-
* the fresh contents.
|
|
33
|
-
* - Existing `AGENTS.md` without the block: prepend the block.
|
|
34
|
-
*
|
|
35
|
-
* Cleanup mirrors the creation logic — if we created the file fresh, delete
|
|
36
|
-
* it; if we swapped out a symlink, restore it; otherwise re-read the current
|
|
37
|
-
* AGENTS.md and strip just the managed block so anything the agent appended
|
|
38
|
-
* during the session is preserved.
|
|
39
|
-
*
|
|
40
|
-
* The helper is deliberately isolated from the adapter so it can be
|
|
41
|
-
* unit-tested without pulling in the Codex SDK.
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
|
-
import { lstat, mkdir, readlink, realpath, symlink, unlink } from "node:fs/promises";
|
|
1
|
+
/** Recover AGENTS.md changes left by sessions from before native instructions. */
|
|
2
|
+
import { lstat, realpath, symlink, unlink } from "node:fs/promises";
|
|
45
3
|
import { homedir } from "node:os";
|
|
46
|
-
import {
|
|
4
|
+
import { join, resolve, sep } from "node:path";
|
|
47
5
|
|
|
48
|
-
const BLOCK_OPEN = "<swarm_system_prompt>";
|
|
49
|
-
const BLOCK_CLOSE = "</swarm_system_prompt>";
|
|
50
6
|
const BLOCK_REGEX = /<swarm_system_prompt>[\s\S]*?<\/swarm_system_prompt>\n?/;
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
export interface CodexAgentsMdHandle {
|
|
54
|
-
cleanup(): Promise<void>;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface CodexAgentsMdOptions {
|
|
58
|
-
/** Where symlink crash-recovery records live. Must be outside any repo. */
|
|
59
|
-
stateDir?: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interface SymlinkRecord {
|
|
63
|
-
cwd: string;
|
|
64
|
-
linkTarget: string;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const NOOP_HANDLE: CodexAgentsMdHandle = {
|
|
68
|
-
cleanup: async () => {},
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
async function readIfExists(path: string): Promise<string | null> {
|
|
72
|
-
const file = Bun.file(path);
|
|
73
|
-
return (await file.exists()) ? await file.text() : null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function recordPathFor(stateDir: string, realCwd: string): string {
|
|
77
|
-
const key = new Bun.CryptoHasher("sha256").update(realCwd).digest("hex");
|
|
78
|
-
return join(stateDir, `${key}.json`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async function readRecord(recordPath: string, realCwd: string): Promise<SymlinkRecord | null> {
|
|
82
|
-
try {
|
|
83
|
-
const record = JSON.parse(await Bun.file(recordPath).text()) as Partial<SymlinkRecord>;
|
|
84
|
-
if (record.cwd === realCwd && typeof record.linkTarget === "string") {
|
|
85
|
-
return { cwd: record.cwd, linkTarget: record.linkTarget };
|
|
86
|
-
}
|
|
87
|
-
} catch {
|
|
88
|
-
// Missing or unreadable record: nothing to recover.
|
|
89
|
-
}
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
7
|
+
const STATE_DIR = join(homedir(), ".cache", "agent-swarm", "codex-agents-md");
|
|
92
8
|
|
|
93
9
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
10
|
+
* Strip a legacy prompt block and restore a swapped symlink from the old
|
|
11
|
+
* out-of-repo recovery record. New sessions never create blocks or records.
|
|
96
12
|
*/
|
|
97
|
-
async function
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return stat?.isFile() ? target : null;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Put the `AGENTS.md -> linkTarget` symlink back in place of our swapped-in
|
|
113
|
-
* real file. Edits the agent made to AGENTS.md during the session would have
|
|
114
|
-
* landed in the link target had the link been in place, so carry them over
|
|
115
|
-
* (block stripped) when the target is in-tree and its contents differ.
|
|
116
|
-
*/
|
|
117
|
-
async function restoreSymlink(
|
|
118
|
-
agentsMdPath: string,
|
|
119
|
-
realCwd: string,
|
|
120
|
-
linkTarget: string,
|
|
121
|
-
): Promise<void> {
|
|
13
|
+
export async function recoverLegacyCodexAgentsMd(cwd: string | undefined): Promise<void> {
|
|
14
|
+
if (!cwd) return;
|
|
15
|
+
const realCwd = await realpath(cwd).catch(() => resolve(cwd));
|
|
16
|
+
const agentsMdPath = join(realCwd, "AGENTS.md");
|
|
17
|
+
const key = new Bun.CryptoHasher("sha256").update(realCwd).digest("hex");
|
|
18
|
+
const recordPath = join(STATE_DIR, `${key}.json`);
|
|
19
|
+
const record = (await Bun.file(recordPath)
|
|
20
|
+
.json()
|
|
21
|
+
.catch(() => null)) as { cwd?: unknown; linkTarget?: unknown } | null;
|
|
22
|
+
const linkTarget =
|
|
23
|
+
record?.cwd === realCwd && typeof record.linkTarget === "string" ? record.linkTarget : null;
|
|
122
24
|
const stat = await lstat(agentsMdPath).catch(() => null);
|
|
123
25
|
const current = stat?.isFile() ? await Bun.file(agentsMdPath).text() : null;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Write (or refresh) a managed `<swarm_system_prompt>` block inside
|
|
141
|
-
* `${cwd}/AGENTS.md`. Returns a handle whose `cleanup()` reverses the edit.
|
|
142
|
-
*
|
|
143
|
-
* No-ops gracefully when `cwd` or `systemPrompt` is falsy.
|
|
144
|
-
*/
|
|
145
|
-
export async function writeCodexAgentsMd(
|
|
146
|
-
cwd: string | undefined,
|
|
147
|
-
systemPrompt: string | undefined,
|
|
148
|
-
options: CodexAgentsMdOptions = {},
|
|
149
|
-
): Promise<CodexAgentsMdHandle> {
|
|
150
|
-
if (!cwd || !systemPrompt) {
|
|
151
|
-
return NOOP_HANDLE;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const agentsMdPath = join(cwd, "AGENTS.md");
|
|
155
|
-
const claudeMdPath = join(cwd, "CLAUDE.md");
|
|
156
|
-
const stateDir = options.stateDir ?? DEFAULT_STATE_DIR;
|
|
157
|
-
const realCwd = await realpath(cwd).catch(() => resolve(cwd));
|
|
158
|
-
const recordPath = recordPathFor(stateDir, realCwd);
|
|
159
|
-
const block = `${BLOCK_OPEN}\n${systemPrompt}\n${BLOCK_CLOSE}`;
|
|
160
|
-
|
|
161
|
-
let stat = await lstat(agentsMdPath).catch(() => null);
|
|
162
|
-
|
|
163
|
-
// A previous session swapped a symlink out and crashed before cleanup. Only
|
|
164
|
-
// our own out-of-repo record can trigger a restore, and only while AGENTS.md
|
|
165
|
-
// is still the real file holding our block.
|
|
166
|
-
const record = await readRecord(recordPath, realCwd);
|
|
167
|
-
if (record) {
|
|
168
|
-
if (stat?.isFile() && BLOCK_REGEX.test(await Bun.file(agentsMdPath).text())) {
|
|
169
|
-
await restoreSymlink(agentsMdPath, realCwd, record.linkTarget);
|
|
170
|
-
stat = await lstat(agentsMdPath);
|
|
171
|
-
}
|
|
172
|
-
await unlink(recordPath).catch(() => {});
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (stat?.isSymbolicLink()) {
|
|
176
|
-
const linkTarget = await readlink(agentsMdPath);
|
|
177
|
-
const target = await inTreeTarget(realCwd, agentsMdPath, linkTarget);
|
|
178
|
-
const targetContent = target !== null ? await Bun.file(target).text() : "";
|
|
179
|
-
// Record before swapping, so a crash at any later point stays recoverable.
|
|
180
|
-
await mkdir(stateDir, { recursive: true });
|
|
181
|
-
await Bun.write(recordPath, JSON.stringify({ cwd: realCwd, linkTarget }));
|
|
182
|
-
// Never write through the link: replace it with a real file for the session.
|
|
183
|
-
await unlink(agentsMdPath);
|
|
184
|
-
await Bun.write(agentsMdPath, `${block}\n${targetContent.replace(BLOCK_REGEX, "")}`);
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
async cleanup(): Promise<void> {
|
|
188
|
-
try {
|
|
189
|
-
await restoreSymlink(agentsMdPath, realCwd, linkTarget);
|
|
190
|
-
await unlink(recordPath).catch(() => {});
|
|
191
|
-
} catch {
|
|
192
|
-
// Cleanup is best-effort; the record lets the next session finish
|
|
193
|
-
// the restore.
|
|
26
|
+
const stripped = current === null ? null : current.replace(BLOCK_REGEX, "");
|
|
27
|
+
|
|
28
|
+
if (linkTarget !== null && (!stat || (stripped !== null && stripped !== current))) {
|
|
29
|
+
// Carry edits back before removing the recovery copy, so a failed write
|
|
30
|
+
// leaves both the copy and the record available for the next attempt.
|
|
31
|
+
if (stripped !== null) {
|
|
32
|
+
const target = await realpath(resolve(realCwd, linkTarget)).catch(() => null);
|
|
33
|
+
const prefix = realCwd.endsWith(sep) ? realCwd : `${realCwd}${sep}`;
|
|
34
|
+
if (target !== null && target !== agentsMdPath && target.startsWith(prefix)) {
|
|
35
|
+
const targetStat = await lstat(target);
|
|
36
|
+
if (targetStat.isFile() && stripped !== (await Bun.file(target).text())) {
|
|
37
|
+
await Bun.write(target, stripped);
|
|
194
38
|
}
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
let createdFresh = false;
|
|
200
|
-
let newContent: string;
|
|
201
|
-
|
|
202
|
-
if (!stat) {
|
|
203
|
-
// No AGENTS.md yet — prefer CLAUDE.md content as a base if present.
|
|
204
|
-
const claudeContent = await readIfExists(claudeMdPath);
|
|
205
|
-
newContent = claudeContent !== null ? `${block}\n\n${claudeContent}` : `${block}\n`;
|
|
206
|
-
createdFresh = true;
|
|
207
|
-
} else {
|
|
208
|
-
const existingContent = await Bun.file(agentsMdPath).text();
|
|
209
|
-
if (BLOCK_REGEX.test(existingContent)) {
|
|
210
|
-
// Replace the stale block in place.
|
|
211
|
-
newContent = existingContent.replace(BLOCK_REGEX, `${block}\n`);
|
|
212
|
-
} else {
|
|
213
|
-
// Prepend the block with a single newline so cleanup's strip restores
|
|
214
|
-
// the original bytes exactly.
|
|
215
|
-
newContent = `${block}\n${existingContent}`;
|
|
39
|
+
}
|
|
216
40
|
}
|
|
41
|
+
if (stat) await unlink(agentsMdPath);
|
|
42
|
+
await symlink(linkTarget, agentsMdPath);
|
|
43
|
+
} else if (stripped !== null && stripped !== current) {
|
|
44
|
+
await Bun.write(agentsMdPath, stripped);
|
|
217
45
|
}
|
|
218
46
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return {
|
|
222
|
-
async cleanup(): Promise<void> {
|
|
223
|
-
try {
|
|
224
|
-
if (createdFresh) {
|
|
225
|
-
// Best-effort delete — ignore errors so we never throw from finally.
|
|
226
|
-
await Bun.$`rm -f ${agentsMdPath}`.quiet().nothrow();
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
const currentFile = Bun.file(agentsMdPath);
|
|
230
|
-
if (!(await currentFile.exists())) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
const currentContent = await currentFile.text();
|
|
234
|
-
const stripped = currentContent.replace(BLOCK_REGEX, "");
|
|
235
|
-
await Bun.write(agentsMdPath, stripped);
|
|
236
|
-
} catch {
|
|
237
|
-
// Cleanup is best-effort; swallow errors so we don't mask the real
|
|
238
|
-
// completion/failure path.
|
|
239
|
-
}
|
|
240
|
-
},
|
|
241
|
-
};
|
|
47
|
+
if (linkTarget !== null) await unlink(recordPath);
|
|
242
48
|
}
|
|
@@ -35,7 +35,7 @@ import type {
|
|
|
35
35
|
} from "./types";
|
|
36
36
|
|
|
37
37
|
/** Pinned in package.json and Dockerfile.worker; bump all three together. */
|
|
38
|
-
export const CURSOR_SDK_VERSION = "1.0.
|
|
38
|
+
export const CURSOR_SDK_VERSION = "1.0.40";
|
|
39
39
|
|
|
40
40
|
/** MCP server name; Cursor reports its tools as `mcp` calls with this `providerIdentifier`. */
|
|
41
41
|
const CURSOR_MCP_SERVER_NAME = "agent-swarm";
|
|
@@ -1523,8 +1523,10 @@ const DEFAULT_CODEMODE_LIMITS: CodemodeLimits = {
|
|
|
1523
1523
|
* pi has no option for either: a script runs until it returns unless its own
|
|
1524
1524
|
* `// @options` line sets `timeout_ms`. Both limits abort the signal pi hands
|
|
1525
1525
|
* the sandbox, which interrupts the QuickJS worker and fails the codemode call.
|
|
1526
|
-
*
|
|
1527
|
-
*
|
|
1526
|
+
* pi 1.4 caps live codemode workers per process (two unless
|
|
1527
|
+
* `PI_CODEMODE_MAX_WORKERS` raises it) and queues a script for a free one for
|
|
1528
|
+
* at most 60 seconds. The deadline's abort also ends that wait, before the
|
|
1529
|
+
* script starts.
|
|
1528
1530
|
*
|
|
1529
1531
|
* "on" keeps declared tools declared; "only" would hide the lifecycle tools
|
|
1530
1532
|
* behind scripts. `models` stays off unless `PI_CODEMODE_MODELS` asks for it.
|
|
@@ -1551,43 +1553,6 @@ export function createBoundedCodemodeExtension(
|
|
|
1551
1553
|
);
|
|
1552
1554
|
}
|
|
1553
1555
|
|
|
1554
|
-
const CODEMODE_WORKER_RETRY_MIN_MS = 25;
|
|
1555
|
-
const CODEMODE_WORKER_RETRY_MAX_MS = 250;
|
|
1556
|
-
|
|
1557
|
-
/**
|
|
1558
|
-
* pi 1.3 admits at most two live codemode workers per process, across all
|
|
1559
|
-
* sessions, and counts a stopped worker until its thread exits. A call over
|
|
1560
|
-
* that cap fails before the script runs. The runner hosts every task's pi
|
|
1561
|
-
* session in one process and pi runs a turn's tool calls in parallel, so a
|
|
1562
|
-
* third concurrent script, or one started right after another, can be
|
|
1563
|
-
* refused. Nothing ran (no nested calls, no store writes), so it is safe to
|
|
1564
|
-
* retry until a worker frees up, within the same deadline.
|
|
1565
|
-
*/
|
|
1566
|
-
function isCodemodeWorkerLimitRefusal(result: {
|
|
1567
|
-
content: Array<{ type: string; text?: string }>;
|
|
1568
|
-
details?: unknown;
|
|
1569
|
-
isError?: boolean;
|
|
1570
|
-
}): boolean {
|
|
1571
|
-
if (!result.isError) return false;
|
|
1572
|
-
const calls = (result.details as { calls?: unknown[] } | undefined)?.calls;
|
|
1573
|
-
if (calls && calls.length > 0) return false;
|
|
1574
|
-
return result.content.some((item) =>
|
|
1575
|
-
item.text?.includes("Script sandbox failed: Codemode worker limit reached"),
|
|
1576
|
-
);
|
|
1577
|
-
}
|
|
1578
|
-
|
|
1579
|
-
function abortableSleep(ms: number, signal: AbortSignal): Promise<void> {
|
|
1580
|
-
return new Promise((resolve) => {
|
|
1581
|
-
const timer = setTimeout(done, ms);
|
|
1582
|
-
function done() {
|
|
1583
|
-
clearTimeout(timer);
|
|
1584
|
-
signal.removeEventListener("abort", done);
|
|
1585
|
-
resolve();
|
|
1586
|
-
}
|
|
1587
|
-
signal.addEventListener("abort", done, { once: true });
|
|
1588
|
-
});
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
1556
|
export function boundCodemodeTool(tool: ToolDefinition, limits: CodemodeLimits): ToolDefinition {
|
|
1592
1557
|
return {
|
|
1593
1558
|
...tool,
|
|
@@ -1653,20 +1618,7 @@ export function boundCodemodeTool(tool: ToolDefinition, limits: CodemodeLimits):
|
|
|
1653
1618
|
: ctx;
|
|
1654
1619
|
|
|
1655
1620
|
try {
|
|
1656
|
-
|
|
1657
|
-
for (;;) {
|
|
1658
|
-
const result = await tool.execute(
|
|
1659
|
-
toolCallId,
|
|
1660
|
-
params,
|
|
1661
|
-
script.signal,
|
|
1662
|
-
onUpdate,
|
|
1663
|
-
boundedCtx,
|
|
1664
|
-
);
|
|
1665
|
-
if (!isCodemodeWorkerLimitRefusal(result) || script.signal.aborted) return result;
|
|
1666
|
-
await abortableSleep(delayMs, script.signal);
|
|
1667
|
-
if (script.signal.aborted) return result;
|
|
1668
|
-
delayMs = Math.min(delayMs * 2, CODEMODE_WORKER_RETRY_MAX_MS);
|
|
1669
|
-
}
|
|
1621
|
+
return await tool.execute(toolCallId, params, script.signal, onUpdate, boundedCtx);
|
|
1670
1622
|
} finally {
|
|
1671
1623
|
clearTimeout(timer);
|
|
1672
1624
|
signal?.removeEventListener("abort", onOuterAbort);
|