@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
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { createTelegramAdapter } from "@chat-adapter/telegram";
|
|
3
|
+
import { escapeTelegramHashLines, postChatMessage } from "../integrations/chat-sdk/outbound";
|
|
4
|
+
import { startTelegramHarness, type TelegramHarness } from "./chat-sdk-harness";
|
|
5
|
+
|
|
6
|
+
describe("escapeTelegramHashLines", () => {
|
|
7
|
+
test("escapes a line-leading # that is not a heading", () => {
|
|
8
|
+
expect(escapeTelegramHashLines("#2203 is still an open draft")).toBe(
|
|
9
|
+
"\\#2203 is still an open draft",
|
|
10
|
+
);
|
|
11
|
+
expect(escapeTelegramHashLines("#tag")).toBe("\\#tag");
|
|
12
|
+
expect(escapeTelegramHashLines("#1 priority")).toBe("\\#1 priority");
|
|
13
|
+
expect(escapeTelegramHashLines("##x")).toBe("\\##x");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("keeps CommonMark ATX headings", () => {
|
|
17
|
+
for (const heading of ["# Title", "## Title", "###### Six", "#", "## ", " # Indented"]) {
|
|
18
|
+
expect(escapeTelegramHashLines(heading)).toBe(heading);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("escapes a run of seven or more #", () => {
|
|
23
|
+
expect(escapeTelegramHashLines("####### seven")).toBe("\\####### seven");
|
|
24
|
+
expect(escapeTelegramHashLines("#######")).toBe("\\#######");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("leaves a mid-line # alone", () => {
|
|
28
|
+
expect(escapeTelegramHashLines("PR #2203 is open, see #tag")).toBe(
|
|
29
|
+
"PR #2203 is open, see #tag",
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("escapes after a paragraph, a bold line, list and quote markers", () => {
|
|
34
|
+
expect(escapeTelegramHashLines("Status:\n#2203 open")).toBe("Status:\n\\#2203 open");
|
|
35
|
+
expect(escapeTelegramHashLines("**Status**\n#2203 open")).toBe("**Status**\n\\#2203 open");
|
|
36
|
+
expect(escapeTelegramHashLines("- #2203 open")).toBe("- \\#2203 open");
|
|
37
|
+
expect(escapeTelegramHashLines("1. #2203 open")).toBe("1. \\#2203 open");
|
|
38
|
+
expect(escapeTelegramHashLines("- [ ] #2203 open")).toBe("- [ ] \\#2203 open");
|
|
39
|
+
expect(escapeTelegramHashLines("> #2203 open")).toBe("> \\#2203 open");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("leaves fenced code alone", () => {
|
|
43
|
+
const text = "```sh\n#!/bin/sh\n#2203\n```\n#2203 after";
|
|
44
|
+
expect(escapeTelegramHashLines(text)).toBe("```sh\n#!/bin/sh\n#2203\n```\n\\#2203 after");
|
|
45
|
+
expect(escapeTelegramHashLines("~~~\n#x\n```\n#y\n~~~\n#z")).toBe(
|
|
46
|
+
"~~~\n#x\n```\n#y\n~~~\n\\#z",
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("the MarkdownV2 fallback renders the escape as a literal #", () => {
|
|
51
|
+
const adapter = createTelegramAdapter({
|
|
52
|
+
botToken: "t",
|
|
53
|
+
mode: "webhook",
|
|
54
|
+
secretToken: "s",
|
|
55
|
+
} as Parameters<typeof createTelegramAdapter>[0]) as unknown as {
|
|
56
|
+
formatConverter: { fromMarkdown(markdown: string): string };
|
|
57
|
+
};
|
|
58
|
+
const render = (text: string) =>
|
|
59
|
+
adapter.formatConverter.fromMarkdown(escapeTelegramHashLines(text));
|
|
60
|
+
expect(render("#2203 is still an open draft")).toBe("\\#2203 is still an open draft");
|
|
61
|
+
expect(render("# Title")).toBe("*Title*");
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("Telegram outbound markdown", () => {
|
|
66
|
+
let harness: TelegramHarness;
|
|
67
|
+
|
|
68
|
+
beforeAll(async () => {
|
|
69
|
+
harness = await startTelegramHarness();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
afterAll(async () => {
|
|
73
|
+
await harness.stop();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
async function sentMarkdown(text: string): Promise<string | undefined> {
|
|
77
|
+
const before = harness.mock.calls.length;
|
|
78
|
+
await postChatMessage({ adapter: "telegram", threadId: "telegram:4242", text });
|
|
79
|
+
const send = harness.mock.calls.slice(before).find((call) => call.method === "sendRichMessage");
|
|
80
|
+
return (send?.body.rich_message as { markdown?: string } | undefined)?.markdown;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
test("a line-leading #2203 reaches sendRichMessage escaped; headings do not", async () => {
|
|
84
|
+
expect(await sentMarkdown("#2203 is still an open draft...")).toBe(
|
|
85
|
+
"\\#2203 is still an open draft...",
|
|
86
|
+
);
|
|
87
|
+
expect(await sentMarkdown("Done.\n#2203 is still an open draft...")).toBe(
|
|
88
|
+
"Done.\n\\#2203 is still an open draft...",
|
|
89
|
+
);
|
|
90
|
+
expect(await sentMarkdown("# Title\n## Sub\nPR #2203")).toBe("# Title\n## Sub\nPR #2203");
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -7,7 +7,16 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
lstatSync,
|
|
12
|
+
mkdirSync,
|
|
13
|
+
mkdtempSync,
|
|
14
|
+
readlinkSync,
|
|
15
|
+
realpathSync,
|
|
16
|
+
rmSync,
|
|
17
|
+
symlinkSync,
|
|
18
|
+
} from "node:fs";
|
|
19
|
+
import { homedir, tmpdir } from "node:os";
|
|
11
20
|
import { join } from "node:path";
|
|
12
21
|
import type {
|
|
13
22
|
AgentMessageItem,
|
|
@@ -17,7 +26,6 @@ import type {
|
|
|
17
26
|
ThreadItem,
|
|
18
27
|
} from "../providers/codex-adapter";
|
|
19
28
|
import { buildCodexConfig, CodexAdapter } from "../providers/codex-adapter";
|
|
20
|
-
import { writeCodexAgentsMd } from "../providers/codex-agents-md";
|
|
21
29
|
import {
|
|
22
30
|
CODEX_DEFAULT_MODEL,
|
|
23
31
|
computeCodexCostUsd,
|
|
@@ -863,7 +871,7 @@ describe("CodexSession event mapping", () => {
|
|
|
863
871
|
|
|
864
872
|
const config = testConfig({
|
|
865
873
|
logFile: join(tmpLogDir, "happy.log"),
|
|
866
|
-
cwd: "",
|
|
874
|
+
cwd: "",
|
|
867
875
|
});
|
|
868
876
|
|
|
869
877
|
const { emitted, result } = await runSessionWithFakeThread(events, config);
|
|
@@ -1268,242 +1276,161 @@ describe("CodexAdapter.canResume", () => {
|
|
|
1268
1276
|
});
|
|
1269
1277
|
});
|
|
1270
1278
|
|
|
1271
|
-
describe("
|
|
1272
|
-
const
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
const after = await Bun.file(agentsMd).text();
|
|
1360
|
-
expect(after).not.toContain("<swarm_system_prompt>");
|
|
1361
|
-
expect(after).toContain("# Keep me");
|
|
1362
|
-
});
|
|
1363
|
-
|
|
1364
|
-
test("prepends block when existing AGENTS.md has no block", async () => {
|
|
1365
|
-
const dir = join(tmpDir, "prepend-block");
|
|
1366
|
-
mkdirSync(dir, { recursive: true });
|
|
1367
|
-
await Bun.write(join(dir, "AGENTS.md"), "# Project instructions");
|
|
1368
|
-
|
|
1369
|
-
const handle = await writeCodexAgentsMd(dir, "swarm prompt");
|
|
1370
|
-
const agentsMd = join(dir, "AGENTS.md");
|
|
1371
|
-
|
|
1372
|
-
const updated = await Bun.file(agentsMd).text();
|
|
1373
|
-
expect(updated).toContain("swarm prompt");
|
|
1374
|
-
expect(updated).toContain("# Project instructions");
|
|
1375
|
-
expect(updated.indexOf("<swarm_system_prompt>")).toBeLessThan(
|
|
1376
|
-
updated.indexOf("# Project instructions"),
|
|
1279
|
+
describe("Codex session instructions", () => {
|
|
1280
|
+
for (const kind of [
|
|
1281
|
+
"file",
|
|
1282
|
+
"in-tree link",
|
|
1283
|
+
"out-of-tree link",
|
|
1284
|
+
"dangling link",
|
|
1285
|
+
"missing link",
|
|
1286
|
+
]) {
|
|
1287
|
+
// Windows requires symlink privileges; CI exercises the link cases on Linux.
|
|
1288
|
+
test.skipIf(kind !== "file" && process.platform === "win32")(
|
|
1289
|
+
`recovers a crashed legacy session before starting Codex (${kind})`,
|
|
1290
|
+
async () => {
|
|
1291
|
+
const dir = mkdtempSync(join(tmpdir(), "codex-legacy-instructions-"));
|
|
1292
|
+
const cwd = join(dir, "repo");
|
|
1293
|
+
mkdirSync(cwd);
|
|
1294
|
+
const agentsMd = join(cwd, "AGENTS.md");
|
|
1295
|
+
const claudeMd = join(cwd, "CLAUDE.md");
|
|
1296
|
+
const original = "# Repo rules\n";
|
|
1297
|
+
const edited = `${original}- Keep the agent's edit\n`;
|
|
1298
|
+
const outside = join(dir, "outside.md");
|
|
1299
|
+
const linkTarget =
|
|
1300
|
+
kind === "out-of-tree link"
|
|
1301
|
+
? "../outside.md"
|
|
1302
|
+
: kind === "dangling link"
|
|
1303
|
+
? "missing.md"
|
|
1304
|
+
: "CLAUDE.md";
|
|
1305
|
+
const realCwd = realpathSync(cwd);
|
|
1306
|
+
const stateDir = join(homedir(), ".cache", "agent-swarm", "codex-agents-md");
|
|
1307
|
+
const key = new Bun.CryptoHasher("sha256").update(realCwd).digest("hex");
|
|
1308
|
+
const recordPath = join(stateDir, `${key}.json`);
|
|
1309
|
+
try {
|
|
1310
|
+
await Bun.write(claudeMd, original);
|
|
1311
|
+
await Bun.write(outside, "OUTSIDE\n");
|
|
1312
|
+
if (kind !== "missing link") {
|
|
1313
|
+
await Bun.write(
|
|
1314
|
+
agentsMd,
|
|
1315
|
+
`<swarm_system_prompt>\nSTALE\n</swarm_system_prompt>\n${edited}`,
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
if (kind !== "file") {
|
|
1319
|
+
mkdirSync(stateDir, { recursive: true });
|
|
1320
|
+
await Bun.write(recordPath, JSON.stringify({ cwd: realCwd, linkTarget }));
|
|
1321
|
+
}
|
|
1322
|
+
const fake = makeFakeAppServer(async (method, params, emit) => {
|
|
1323
|
+
if (method === "thread/start") {
|
|
1324
|
+
expect(params).toMatchObject({ developerInstructions: "new session instructions" });
|
|
1325
|
+
expect(await Bun.file(recordPath).exists()).toBe(false);
|
|
1326
|
+
if (kind === "file") {
|
|
1327
|
+
expect(lstatSync(agentsMd).isFile()).toBe(true);
|
|
1328
|
+
expect(await Bun.file(agentsMd).text()).toBe(edited);
|
|
1329
|
+
} else {
|
|
1330
|
+
expect(lstatSync(agentsMd).isSymbolicLink()).toBe(true);
|
|
1331
|
+
expect(readlinkSync(agentsMd)).toBe(linkTarget);
|
|
1332
|
+
}
|
|
1333
|
+
expect(await Bun.file(claudeMd).text()).toBe(
|
|
1334
|
+
kind === "in-tree link" ? edited : original,
|
|
1335
|
+
);
|
|
1336
|
+
expect(await Bun.file(outside).text()).toBe("OUTSIDE\n");
|
|
1337
|
+
return { thread: { id: "legacy-thread" } };
|
|
1338
|
+
}
|
|
1339
|
+
if (method === "turn/start") {
|
|
1340
|
+
queueMicrotask(() => {
|
|
1341
|
+
emit("turn/completed", {
|
|
1342
|
+
threadId: "legacy-thread",
|
|
1343
|
+
turn: { id: "legacy-turn", status: "completed", error: null },
|
|
1344
|
+
});
|
|
1345
|
+
});
|
|
1346
|
+
return { turn: { id: "legacy-turn" } };
|
|
1347
|
+
}
|
|
1348
|
+
throw new Error(`Unexpected method: ${method}`);
|
|
1349
|
+
});
|
|
1350
|
+
const session = await new CodexAdapter({
|
|
1351
|
+
bypassSubprocess: true,
|
|
1352
|
+
appServerFactory: () => fake.client as never,
|
|
1353
|
+
}).createSession(
|
|
1354
|
+
testConfig({
|
|
1355
|
+
cwd,
|
|
1356
|
+
systemPrompt: "new session instructions",
|
|
1357
|
+
logFile: join(dir, "session.log"),
|
|
1358
|
+
taskId: "",
|
|
1359
|
+
}),
|
|
1360
|
+
);
|
|
1361
|
+
await session.waitForCompletion();
|
|
1362
|
+
} finally {
|
|
1363
|
+
rmSync(recordPath, { force: true });
|
|
1364
|
+
rmSync(dir, { recursive: true, force: true });
|
|
1365
|
+
}
|
|
1366
|
+
},
|
|
1377
1367
|
);
|
|
1368
|
+
}
|
|
1378
1369
|
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
const agentsMd = join(dir, "AGENTS.md");
|
|
1444
|
-
await Bun.write(claudeMd, original);
|
|
1445
|
-
symlinkSync("CLAUDE.md", agentsMd);
|
|
1446
|
-
|
|
1447
|
-
// First session never runs cleanup (crash).
|
|
1448
|
-
await writeCodexAgentsMd(dir, "first prompt", { stateDir });
|
|
1449
|
-
expect(lstatSync(agentsMd).isSymbolicLink()).toBe(false);
|
|
1450
|
-
|
|
1451
|
-
const handle = await writeCodexAgentsMd(dir, "second prompt", { stateDir });
|
|
1452
|
-
const during = readFileSync(agentsMd, "utf8");
|
|
1453
|
-
expect(during).toContain("second prompt");
|
|
1454
|
-
expect(during).not.toContain("first prompt");
|
|
1455
|
-
expect(readFileSync(claudeMd, "utf8")).toBe(original);
|
|
1456
|
-
|
|
1457
|
-
await handle.cleanup();
|
|
1458
|
-
expect(lstatSync(agentsMd).isSymbolicLink()).toBe(true);
|
|
1459
|
-
expect(readFileSync(claudeMd, "utf8")).toBe(original);
|
|
1460
|
-
});
|
|
1461
|
-
|
|
1462
|
-
test("ignores a forged symlink marker pointing out of the repo", async () => {
|
|
1463
|
-
const dir = join(tmpDir, "forged-marker");
|
|
1464
|
-
mkdirSync(dir, { recursive: true });
|
|
1465
|
-
const secretPath = join(tmpDir, "outside-secret.txt");
|
|
1466
|
-
const secret = "TOP-SECRET-CONTENTS\n";
|
|
1467
|
-
await Bun.write(secretPath, secret);
|
|
1468
|
-
const agentsMd = join(dir, "AGENTS.md");
|
|
1469
|
-
|
|
1470
|
-
for (const forged of ["../outside-secret.txt", secretPath]) {
|
|
1471
|
-
const original = `<swarm_system_prompt symlink="${encodeURIComponent(forged)}">\nold\n</swarm_system_prompt>\n# Rules\n`;
|
|
1472
|
-
await Bun.write(agentsMd, original);
|
|
1473
|
-
|
|
1474
|
-
const handle = await writeCodexAgentsMd(dir, "swarm prompt", { stateDir });
|
|
1475
|
-
expect(lstatSync(agentsMd).isSymbolicLink()).toBe(false);
|
|
1476
|
-
expect(readFileSync(agentsMd, "utf8")).not.toContain("TOP-SECRET");
|
|
1477
|
-
expect(readFileSync(secretPath, "utf8")).toBe(secret);
|
|
1478
|
-
|
|
1479
|
-
await handle.cleanup();
|
|
1480
|
-
expect(lstatSync(agentsMd).isSymbolicLink()).toBe(false);
|
|
1481
|
-
expect(readFileSync(agentsMd, "utf8")).toBe(original);
|
|
1482
|
-
expect(readFileSync(secretPath, "utf8")).toBe(secret);
|
|
1483
|
-
}
|
|
1484
|
-
});
|
|
1485
|
-
|
|
1486
|
-
test("never reads or writes an out-of-tree symlink target", async () => {
|
|
1487
|
-
const dir = join(tmpDir, "symlink-out-of-tree");
|
|
1488
|
-
mkdirSync(dir, { recursive: true });
|
|
1489
|
-
const secretPath = join(tmpDir, "outside-target.txt");
|
|
1490
|
-
const secret = "OUT-OF-TREE\n";
|
|
1491
|
-
await Bun.write(secretPath, secret);
|
|
1492
|
-
const agentsMd = join(dir, "AGENTS.md");
|
|
1493
|
-
symlinkSync("../outside-target.txt", agentsMd);
|
|
1494
|
-
|
|
1495
|
-
const handle = await writeCodexAgentsMd(dir, "swarm prompt", { stateDir });
|
|
1496
|
-
expect(lstatSync(agentsMd).isSymbolicLink()).toBe(false);
|
|
1497
|
-
const during = readFileSync(agentsMd, "utf8");
|
|
1498
|
-
expect(during).toContain("swarm prompt");
|
|
1499
|
-
expect(during).not.toContain("OUT-OF-TREE");
|
|
1500
|
-
|
|
1501
|
-
await Bun.write(agentsMd, `${during}- agent edit\n`);
|
|
1502
|
-
await handle.cleanup();
|
|
1503
|
-
|
|
1504
|
-
expect(readlinkSync(agentsMd)).toBe("../outside-target.txt");
|
|
1505
|
-
expect(readFileSync(secretPath, "utf8")).toBe(secret);
|
|
1506
|
-
});
|
|
1370
|
+
for (const kind of ["file", "missing", "symlink"]) {
|
|
1371
|
+
// Windows requires symlink privileges; CI exercises this case on Linux.
|
|
1372
|
+
test.skipIf(kind === "symlink" && process.platform === "win32")(
|
|
1373
|
+
`passes native instructions without changing ${kind} AGENTS.md during the session`,
|
|
1374
|
+
async () => {
|
|
1375
|
+
const dir = mkdtempSync(join(tmpdir(), "codex-instructions-"));
|
|
1376
|
+
const cwd = join(dir, "repo");
|
|
1377
|
+
mkdirSync(cwd);
|
|
1378
|
+
const agentsMd = join(cwd, "AGENTS.md");
|
|
1379
|
+
const claudeMd = join(cwd, "CLAUDE.md");
|
|
1380
|
+
const original = "# Repo rules\r\n\r\nKeep this file unchanged.\r\n";
|
|
1381
|
+
const systemPrompt = 'Swarm instructions: "quoted"\n第二行';
|
|
1382
|
+
await Bun.write(claudeMd, original);
|
|
1383
|
+
if (kind === "file") await Bun.write(agentsMd, original);
|
|
1384
|
+
if (kind === "symlink") symlinkSync("CLAUDE.md", agentsMd);
|
|
1385
|
+
|
|
1386
|
+
let startParams: unknown;
|
|
1387
|
+
const started = Promise.withResolvers<void>();
|
|
1388
|
+
const fake = makeFakeAppServer((method, params) => {
|
|
1389
|
+
if (method === "thread/start") {
|
|
1390
|
+
startParams = params;
|
|
1391
|
+
return { thread: { id: "instructions-thread" } };
|
|
1392
|
+
}
|
|
1393
|
+
if (method === "turn/start") {
|
|
1394
|
+
started.resolve();
|
|
1395
|
+
return { turn: { id: "instructions-turn" } };
|
|
1396
|
+
}
|
|
1397
|
+
throw new Error(`Unexpected method: ${method}`);
|
|
1398
|
+
});
|
|
1399
|
+
const assertRepoUnchanged = async () => {
|
|
1400
|
+
expect(await Bun.file(claudeMd).text()).toBe(original);
|
|
1401
|
+
if (kind === "missing") {
|
|
1402
|
+
expect(await Bun.file(agentsMd).exists()).toBe(false);
|
|
1403
|
+
} else {
|
|
1404
|
+
expect(await Bun.file(agentsMd).text()).toBe(original);
|
|
1405
|
+
expect(lstatSync(agentsMd).isSymbolicLink()).toBe(kind === "symlink");
|
|
1406
|
+
if (kind === "symlink") expect(readlinkSync(agentsMd)).toBe("CLAUDE.md");
|
|
1407
|
+
}
|
|
1408
|
+
};
|
|
1409
|
+
const session = await new CodexAdapter({
|
|
1410
|
+
bypassSubprocess: true,
|
|
1411
|
+
appServerFactory: () => fake.client as never,
|
|
1412
|
+
}).createSession(
|
|
1413
|
+
testConfig({ cwd, systemPrompt, logFile: join(dir, "session.log"), taskId: "" }),
|
|
1414
|
+
);
|
|
1415
|
+
try {
|
|
1416
|
+
await started.promise;
|
|
1417
|
+
await assertRepoUnchanged();
|
|
1418
|
+
expect(startParams).toMatchObject({ developerInstructions: systemPrompt });
|
|
1419
|
+
} finally {
|
|
1420
|
+
fake.emit("turn/completed", {
|
|
1421
|
+
threadId: "instructions-thread",
|
|
1422
|
+
turn: { id: "instructions-turn", status: "completed", error: null },
|
|
1423
|
+
});
|
|
1424
|
+
await session.waitForCompletion();
|
|
1425
|
+
try {
|
|
1426
|
+
await assertRepoUnchanged();
|
|
1427
|
+
} finally {
|
|
1428
|
+
rmSync(dir, { recursive: true, force: true });
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
},
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1507
1434
|
});
|
|
1508
1435
|
|
|
1509
1436
|
// ─── Phase 3: model catalogue ────────────────────────────────────────────────
|
|
@@ -2359,9 +2286,7 @@ describe("CodexSession session-end summarization", () => {
|
|
|
2359
2286
|
expect(indexCalls.length).toBe(0);
|
|
2360
2287
|
});
|
|
2361
2288
|
|
|
2362
|
-
test("runSummarize throws →
|
|
2363
|
-
// Use a real temp dir as cwd so we exercise writeCodexAgentsMd, then spy on
|
|
2364
|
-
// the resulting AGENTS.md file. After cleanup the file MUST be gone.
|
|
2289
|
+
test("runSummarize throws → logFileHandle.end() still runs", async () => {
|
|
2365
2290
|
const cwd = `/tmp/codex-summary-cleanup-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
2366
2291
|
mkdirSync(cwd, { recursive: true });
|
|
2367
2292
|
const agentsMdPath = join(cwd, "AGENTS.md");
|
|
@@ -2377,11 +2302,11 @@ describe("CodexSession session-end summarization", () => {
|
|
|
2377
2302
|
const config = testConfig({
|
|
2378
2303
|
logFile,
|
|
2379
2304
|
cwd,
|
|
2380
|
-
systemPrompt: "test system prompt",
|
|
2305
|
+
systemPrompt: "test system prompt",
|
|
2381
2306
|
});
|
|
2382
2307
|
await runSessionWithFakeThreadAndDeps(events, config, deps);
|
|
2383
2308
|
|
|
2384
|
-
//
|
|
2309
|
+
// Summarization failure must not create an instruction file.
|
|
2385
2310
|
expect(await Bun.file(agentsMdPath).exists()).toBe(false);
|
|
2386
2311
|
|
|
2387
2312
|
// Log file flush must have run despite the summarize throw — the log file
|
|
@@ -56,6 +56,12 @@ beforeAll(async () => {
|
|
|
56
56
|
value: "synthetic-api-only-signing-secret",
|
|
57
57
|
isSecret: true,
|
|
58
58
|
});
|
|
59
|
+
await upsertSwarmConfig({
|
|
60
|
+
scope: "global",
|
|
61
|
+
key: "TRANSCRIPTION_API_KEY",
|
|
62
|
+
value: "synthetic-api-only-transcription-key",
|
|
63
|
+
isSecret: true,
|
|
64
|
+
});
|
|
59
65
|
await upsertSwarmConfig({
|
|
60
66
|
scope: "global",
|
|
61
67
|
key: "SOME_WORKER_SECRET",
|
|
@@ -93,6 +99,7 @@ describe("API-only config keys are never served over HTTP", () => {
|
|
|
93
99
|
const { configs } = await getJson("/api/config/resolved?includeSecrets=true");
|
|
94
100
|
expect(configs.some((c) => c.key === BOOTSTRAP_KEY)).toBe(false);
|
|
95
101
|
expect(configs.some((c) => c.key === "SLACK_SIGNING_SECRET")).toBe(false);
|
|
102
|
+
expect(configs.some((c) => c.key === "TRANSCRIPTION_API_KEY")).toBe(false);
|
|
96
103
|
// A legitimate worker secret still comes through.
|
|
97
104
|
expect(configs.some((c) => c.key === "SOME_WORKER_SECRET")).toBe(true);
|
|
98
105
|
});
|
|
@@ -103,12 +110,14 @@ describe("API-only config keys are never served over HTTP", () => {
|
|
|
103
110
|
);
|
|
104
111
|
expect(configs.some((c) => c.key === BOOTSTRAP_KEY)).toBe(false);
|
|
105
112
|
expect(configs.some((c) => c.key === "SLACK_SIGNING_SECRET")).toBe(false);
|
|
113
|
+
expect(configs.some((c) => c.key === "TRANSCRIPTION_API_KEY")).toBe(false);
|
|
106
114
|
});
|
|
107
115
|
|
|
108
116
|
test("GET /api/config?scope=global strips the bootstrap key", async () => {
|
|
109
117
|
const { configs } = await getJson("/api/config?scope=global&includeSecrets=true");
|
|
110
118
|
expect(configs.some((c) => c.key === BOOTSTRAP_KEY)).toBe(false);
|
|
111
119
|
expect(configs.some((c) => c.key === "SLACK_SIGNING_SECRET")).toBe(false);
|
|
120
|
+
expect(configs.some((c) => c.key === "TRANSCRIPTION_API_KEY")).toBe(false);
|
|
112
121
|
expect(configs.some((c) => c.key === "SOME_WORKER_SECRET")).toBe(true);
|
|
113
122
|
});
|
|
114
123
|
});
|