clawmini 0.0.8 → 0.0.9
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/.changeset/README.md +8 -0
- package/.changeset/config.json +14 -0
- package/.github/workflows/release.yml +49 -0
- package/CHANGELOG.md +36 -0
- package/README.md +5 -4
- package/dist/adapter-discord/index.d.mts.map +1 -1
- package/dist/adapter-discord/index.mjs +465 -282
- package/dist/adapter-discord/index.mjs.map +1 -1
- package/dist/adapter-google-chat/index.mjs +367 -243
- package/dist/adapter-google-chat/index.mjs.map +1 -1
- package/dist/cli/index.mjs +684 -24
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lite.mjs +43 -13
- package/dist/cli/lite.mjs.map +1 -1
- package/dist/cli/{propose-policy.mjs → manage-policies.mjs} +270 -47
- package/dist/cli/manage-policies.mjs.map +1 -0
- package/dist/cli/run-host.d.mts +1 -0
- package/dist/cli/run-host.mjs +3090 -0
- package/dist/cli/run-host.mjs.map +1 -0
- package/dist/config-CPFQIGdG.mjs +57 -0
- package/dist/config-CPFQIGdG.mjs.map +1 -0
- package/dist/config-Dvl-Pov4.mjs +76 -0
- package/dist/config-Dvl-Pov4.mjs.map +1 -0
- package/dist/daemon/index.d.mts.map +1 -1
- package/dist/daemon/index.mjs +970 -332
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/supervisor-actions-CiW56eLi.mjs +843 -0
- package/dist/supervisor-actions-CiW56eLi.mjs.map +1 -0
- package/dist/turn-log-buffer-DRgW53gl.mjs +767 -0
- package/dist/turn-log-buffer-DRgW53gl.mjs.map +1 -0
- package/dist/web/_app/immutable/chunks/{Drm9vgeP.js → 3AZlWB6U.js} +1 -1
- package/dist/web/_app/immutable/chunks/BhRSsUCh.js +2 -0
- package/dist/web/_app/immutable/chunks/BiLeM2i1.js +1 -0
- package/{web/.svelte-kit/output/client/_app/immutable/chunks/CME08kGM.js → dist/web/_app/immutable/chunks/BmBj85Ll.js} +1 -1
- package/dist/web/_app/immutable/chunks/BrERcKAH.js +1 -0
- package/dist/web/_app/immutable/chunks/Bv9252RM.js +1 -0
- package/dist/web/_app/immutable/chunks/CIXNBPKi.js +1 -0
- package/dist/web/_app/immutable/chunks/DISKL3GN.js +2 -0
- package/dist/web/_app/immutable/chunks/{Zeh-C-mx.js → DcpaLzmX.js} +1 -1
- package/dist/web/_app/immutable/chunks/DnQ3vS13.js +1 -0
- package/dist/web/_app/immutable/chunks/KsloHTKS.js +1 -0
- package/{web/.svelte-kit/output/client/_app/immutable/chunks/Ck-be5J2.js → dist/web/_app/immutable/chunks/RsHsUj-8.js} +2 -2
- package/dist/web/_app/immutable/chunks/{vDehDcuJ.js → wpfV79dV.js} +1 -1
- package/dist/web/_app/immutable/entry/app.CIw1Qj0n.js +2 -0
- package/dist/web/_app/immutable/entry/start.Di0-Jhte.js +1 -0
- package/dist/web/_app/immutable/nodes/{0.CUGC2p-K.js → 0.DYyUA1au.js} +1 -1
- package/dist/web/_app/immutable/nodes/1.D-3QEMMZ.js +1 -0
- package/dist/web/_app/immutable/nodes/{2.BnwnD1Ki.js → 2.4olHnH7U.js} +1 -1
- package/{web/.svelte-kit/output/client/_app/immutable/nodes/3.0arZe_Uf.js → dist/web/_app/immutable/nodes/3.4w0bE-m2.js} +3 -3
- package/dist/web/_app/immutable/nodes/4.CZvjhVHt.js +60 -0
- package/dist/web/_app/immutable/nodes/{5.Bq2JzCEj.js → 5.DLbPVJY2.js} +1 -1
- package/dist/web/_app/version.json +1 -1
- package/dist/web/index.html +12 -12
- package/dist/workspace-oWmVh5mi.mjs +1001 -0
- package/dist/workspace-oWmVh5mi.mjs.map +1 -0
- package/docs/23_adapter_slash_autocomplete/development_log.md +19 -0
- package/docs/23_adapter_slash_autocomplete/notes.md +18 -0
- package/docs/23_adapter_slash_autocomplete/prd.md +46 -0
- package/docs/23_adapter_slash_autocomplete/questions.md +6 -0
- package/docs/23_adapter_slash_autocomplete/tickets.md +21 -0
- package/docs/24_subagent_job_policy_fixes/development_log.md +22 -0
- package/docs/24_subagent_job_policy_fixes/notes.md +28 -0
- package/docs/24_subagent_job_policy_fixes/prd.md +59 -0
- package/docs/24_subagent_job_policy_fixes/questions.md +3 -0
- package/docs/24_subagent_job_policy_fixes/tickets.md +49 -0
- package/docs/25_e2e_test_improvements/development_log.md +30 -0
- package/docs/25_e2e_test_improvements/notes.md +29 -0
- package/docs/25_e2e_test_improvements/prd.md +43 -0
- package/docs/25_e2e_test_improvements/questions.md +12 -0
- package/docs/25_e2e_test_improvements/tickets-2.md +22 -0
- package/docs/25_e2e_test_improvements/tickets.md +22 -0
- package/docs/25_policy_cwd/development_log.md +30 -0
- package/docs/25_policy_cwd/notes.md +28 -0
- package/docs/25_policy_cwd/prd.md +77 -0
- package/docs/25_policy_cwd/questions.md +6 -0
- package/docs/25_policy_cwd/tickets.md +77 -0
- package/docs/CLI_REFERENCE.md +3 -1
- package/docs/PHILOSOPHY.md +35 -0
- package/docs/adapter-visibility/SPEC.md +461 -0
- package/docs/adapter-visibility/SPEC_v2.md +202 -0
- package/docs/auto-update/SPEC.md +344 -0
- package/docs/backups/SPEC.md +296 -0
- package/docs/backups/clawmini.gitignore +69 -0
- package/docs/guides/assets/clawmini-avatar.png +0 -0
- package/docs/guides/backups.md +332 -0
- package/docs/guides/discord_adapter_setup.md +1 -1
- package/docs/guides/google_chat_adapter_setup.md +81 -0
- package/docs/unified-startup/SPEC.md +203 -0
- package/e2e/_helpers/test-environment.test.ts +49 -0
- package/e2e/_helpers/test-environment.ts +548 -0
- package/e2e/adapters/_google-chat-fixtures.ts +340 -0
- package/{src/cli/e2e → e2e/adapters}/adapter-discord.test.ts +22 -23
- package/e2e/adapters/adapter-google-chat-downtime.test.ts +157 -0
- package/e2e/adapters/adapter-google-chat-inbound.test.ts +697 -0
- package/e2e/adapters/adapter-google-chat-outbound.test.ts +297 -0
- package/e2e/adapters/adapter-google-chat-roundtrip.test.ts +56 -0
- package/e2e/adapters/adapter-google-chat-threads.test.ts +1078 -0
- package/e2e/agents/custom-api-env.test.ts +80 -0
- package/e2e/agents/export-lite-func.test.ts +104 -0
- package/e2e/agents/fallbacks.test.ts +124 -0
- package/e2e/agents/interrupt.test.ts +50 -0
- package/e2e/agents/no-reply-necessary.test.ts +57 -0
- package/e2e/agents/session-timeout-subagents.test.ts +76 -0
- package/e2e/agents/subagent-authorization.test.ts +246 -0
- package/e2e/agents/subagent-env.test.ts +49 -0
- package/e2e/agents/subagent-lifecycle.test.ts +782 -0
- package/e2e/agents/subagents-depth.test.ts +47 -0
- package/e2e/cli/agents.test.ts +176 -0
- package/e2e/cli/auto-update.test.ts +741 -0
- package/e2e/cli/basic.test.ts +44 -0
- package/{src/cli/e2e → e2e/cli}/export-lite.test.ts +16 -12
- package/e2e/cli/init-gitignore.test.ts +86 -0
- package/e2e/cli/init.test.ts +76 -0
- package/e2e/cli/messages.test.ts +363 -0
- package/e2e/cli/serve.test.ts +76 -0
- package/{src/cli/e2e → e2e/cli}/skills.test.ts +11 -10
- package/{src/cli/e2e → e2e/daemon}/daemon.test.ts +57 -195
- package/e2e/jobs/agent-jobs.test.ts +216 -0
- package/e2e/jobs/cron.test.ts +64 -0
- package/e2e/jobs/restart.test.ts +108 -0
- package/e2e/policies/approval-session.test.ts +69 -0
- package/e2e/policies/auto-create-policies-file.test.ts +35 -0
- package/e2e/policies/builtin-manage-policies.test.ts +184 -0
- package/e2e/policies/builtin-run-host.test.ts +180 -0
- package/e2e/policies/environment-policies.test.ts +177 -0
- package/e2e/policies/manage-policies.test.ts +566 -0
- package/e2e/policies/output-size.test.ts +98 -0
- package/e2e/policies/policies-context-cwd.test.ts +160 -0
- package/e2e/policies/relative-script-path.test.ts +60 -0
- package/e2e/policies/requests-show.test.ts +135 -0
- package/e2e/policies/requests.test.ts +208 -0
- package/e2e/policies/slash-policies.test.ts +308 -0
- package/e2e/policies/startup-cleanup.test.ts +48 -0
- package/e2e/routers/session-timeout.test.ts +106 -0
- package/e2e/routers/slash-model.test.ts +152 -0
- package/e2e/routers/slash-new.test.ts +50 -0
- package/e2e/routers/slash-restart-adapter.test.ts +96 -0
- package/e2e/routers/slash-restart.test.ts +114 -0
- package/e2e/routers/slash-shutdown.test.ts +55 -0
- package/e2e/routers/slash-stop.test.ts +232 -0
- package/e2e/routers/slash-upgrade.test.ts +88 -0
- package/{src/cli/e2e → e2e/sandbox}/environments.test.ts +14 -13
- package/eslint.config.js +6 -0
- package/napkin.md +1 -1
- package/package.json +8 -3
- package/src/adapter-discord/commands.test.ts +42 -0
- package/src/adapter-discord/commands.ts +33 -0
- package/src/adapter-discord/config.ts +12 -0
- package/src/adapter-discord/forwarder.test.ts +499 -21
- package/src/adapter-discord/forwarder.ts +343 -124
- package/src/adapter-discord/inbound-cache.test.ts +47 -0
- package/src/adapter-discord/inbound-cache.ts +37 -0
- package/src/adapter-discord/index.test.ts +67 -2
- package/src/adapter-discord/index.ts +84 -216
- package/src/adapter-discord/interactions.test.ts +54 -3
- package/src/adapter-discord/interactions.ts +97 -53
- package/src/adapter-discord/processMessage.ts +239 -0
- package/src/adapter-discord/state.ts +1 -0
- package/src/adapter-google-chat/auth.test.ts +9 -5
- package/src/adapter-google-chat/auth.ts +29 -23
- package/src/adapter-google-chat/cards.ts +7 -2
- package/src/adapter-google-chat/client.test.ts +37 -2
- package/src/adapter-google-chat/client.ts +138 -38
- package/src/adapter-google-chat/config.ts +19 -0
- package/src/adapter-google-chat/forwarder.test.ts +81 -56
- package/src/adapter-google-chat/forwarder.ts +394 -185
- package/src/adapter-google-chat/inbound-cache.test.ts +61 -0
- package/src/adapter-google-chat/inbound-cache.ts +36 -0
- package/src/adapter-google-chat/state.test.ts +1 -0
- package/src/adapter-google-chat/state.ts +9 -1
- package/src/adapter-google-chat/subscriptions.ts +8 -6
- package/src/cli/builtin-policies.ts +44 -0
- package/src/cli/commands/agents.ts +59 -5
- package/src/cli/commands/down.ts +54 -2
- package/src/cli/commands/environments.ts +8 -2
- package/src/cli/commands/init.ts +31 -0
- package/src/cli/commands/logs.ts +116 -0
- package/src/cli/commands/policies.ts +6 -4
- package/src/cli/commands/serve.test.ts +67 -0
- package/src/cli/commands/serve.ts +284 -0
- package/src/cli/commands/up.ts +122 -2
- package/src/cli/commands/web-api/agents.ts +3 -2
- package/src/cli/index.ts +4 -0
- package/src/cli/install-detection.test.ts +72 -0
- package/src/cli/install-detection.ts +48 -0
- package/src/cli/lite.ts +54 -22
- package/src/cli/manage-policies-utils.ts +104 -0
- package/src/cli/manage-policies.ts +291 -0
- package/src/cli/run-host.ts +45 -0
- package/src/cli/supervisor-actions.ts +267 -0
- package/src/cli/supervisor-control.test.ts +129 -0
- package/src/cli/supervisor-control.ts +155 -0
- package/src/cli/supervisor-pid.ts +68 -0
- package/src/cli/supervisor.ts +277 -0
- package/src/daemon/agent/agent-context.ts +11 -11
- package/src/daemon/agent/agent-session.ts +8 -1
- package/src/daemon/agent/chat-logger.test.ts +78 -9
- package/src/daemon/agent/chat-logger.ts +25 -5
- package/src/daemon/agent/turn-registry.test.ts +89 -0
- package/src/daemon/agent/turn-registry.ts +94 -0
- package/src/daemon/agent/types.ts +2 -0
- package/src/daemon/api/agent-policy-endpoints.ts +263 -0
- package/src/daemon/api/agent-router.ts +47 -126
- package/src/daemon/api/index.test.ts +1 -0
- package/src/daemon/api/policy-request.test.ts +7 -5
- package/src/daemon/api/router-utils.ts +6 -5
- package/src/daemon/api/subagent-router.ts +110 -74
- package/src/daemon/api/subagent-utils.test.ts +60 -0
- package/src/daemon/api/subagent-utils.ts +113 -87
- package/src/daemon/api/user-router.ts +34 -8
- package/src/daemon/auth.ts +1 -0
- package/src/daemon/cron.test.ts +62 -4
- package/src/daemon/cron.ts +42 -16
- package/src/daemon/events.ts +65 -0
- package/src/daemon/index.ts +24 -1
- package/src/daemon/message-interruption.test.ts +1 -0
- package/src/daemon/message-jobs.test.ts +1 -0
- package/src/daemon/message.ts +78 -14
- package/src/daemon/observation.test.ts +26 -18
- package/src/daemon/pending-replies.test.ts +112 -0
- package/src/daemon/pending-replies.ts +162 -0
- package/src/daemon/policy-request-service.ts +3 -1
- package/src/daemon/policy-utils.test.ts +66 -1
- package/src/daemon/policy-utils.ts +126 -1
- package/src/daemon/request-store.ts +31 -0
- package/src/daemon/routers/session-timeout.ts +4 -0
- package/src/daemon/routers/slash-model.test.ts +344 -0
- package/src/daemon/routers/slash-model.ts +207 -0
- package/src/daemon/routers/slash-policies.test.ts +38 -32
- package/src/daemon/routers/slash-policies.ts +84 -33
- package/src/daemon/routers/slash-restart.test.ts +69 -0
- package/src/daemon/routers/slash-restart.ts +36 -0
- package/src/daemon/routers/slash-shutdown.test.ts +50 -0
- package/src/daemon/routers/slash-shutdown.ts +28 -0
- package/src/daemon/routers/slash-upgrade.test.ts +116 -0
- package/src/daemon/routers/slash-upgrade.ts +76 -0
- package/src/daemon/routers/types.ts +7 -0
- package/src/daemon/routers.ts +16 -0
- package/src/shared/adapters/blockquote.test.ts +28 -0
- package/src/shared/adapters/blockquote.ts +20 -0
- package/src/shared/adapters/filtering.test.ts +224 -10
- package/src/shared/adapters/filtering.ts +95 -7
- package/src/shared/adapters/inbound-cache.test.ts +48 -0
- package/src/shared/adapters/inbound-cache.ts +54 -0
- package/src/shared/adapters/turn-log-buffer.ts +266 -0
- package/src/shared/adapters/turn-log.test.ts +389 -0
- package/src/shared/adapters/turn-log.ts +357 -0
- package/src/shared/agent-utils.ts +12 -5
- package/src/shared/chats.test.ts +4 -0
- package/src/shared/chats.ts +9 -0
- package/src/shared/config.ts +16 -1
- package/src/shared/lite.ts +76 -2
- package/src/shared/policies.ts +26 -0
- package/src/shared/template-manifest.ts +267 -0
- package/src/shared/utils/shell.ts +61 -0
- package/src/shared/version.ts +34 -0
- package/src/shared/workspace.test.ts +217 -0
- package/src/shared/workspace.ts +626 -48
- package/templates/environments/cladding/allowlist-domain.mjs +125 -0
- package/templates/environments/cladding/env.json +21 -1
- package/templates/environments/cladding/run-with-network.mjs +54 -0
- package/templates/environments/macos-proxy/allowlist-domain.mjs +95 -0
- package/templates/environments/macos-proxy/env.json +8 -1
- package/templates/environments/macos-proxy/proxy.mjs +0 -1
- package/templates/gemini/template.json +5 -0
- package/templates/gemini-claw/template.json +13 -0
- package/templates/skills/clawmini-requests/SKILL.md +69 -10
- package/templates/skills/run-host/SKILL.md +51 -0
- package/templates/skills/skill-creator/SKILL.md +4 -3
- package/templates/skills/skill-creator/scripts/validate.sh +52 -0
- package/tsdown.config.ts +10 -1
- package/vitest.config.ts +2 -2
- package/web/.svelte-kit/ambient.d.ts +292 -118
- package/web/.svelte-kit/generated/server/internal.js +1 -1
- package/web/.svelte-kit/output/client/.vite/manifest.json +126 -136
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{Drm9vgeP.js → 3AZlWB6U.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BhRSsUCh.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BiLeM2i1.js +1 -0
- package/{dist/web/_app/immutable/chunks/CME08kGM.js → web/.svelte-kit/output/client/_app/immutable/chunks/BmBj85Ll.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BrERcKAH.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Bv9252RM.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CIXNBPKi.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DISKL3GN.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{Zeh-C-mx.js → DcpaLzmX.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DnQ3vS13.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/KsloHTKS.js +1 -0
- package/{dist/web/_app/immutable/chunks/Ck-be5J2.js → web/.svelte-kit/output/client/_app/immutable/chunks/RsHsUj-8.js} +2 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/{vDehDcuJ.js → wpfV79dV.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/entry/app.CIw1Qj0n.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.Di0-Jhte.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{0.CUGC2p-K.js → 0.DYyUA1au.js} +1 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.D-3QEMMZ.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{2.BnwnD1Ki.js → 2.4olHnH7U.js} +1 -1
- package/{dist/web/_app/immutable/nodes/3.0arZe_Uf.js → web/.svelte-kit/output/client/_app/immutable/nodes/3.4w0bE-m2.js} +3 -3
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.CZvjhVHt.js +60 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/{5.Bq2JzCEj.js → 5.DLbPVJY2.js} +1 -1
- package/web/.svelte-kit/output/client/_app/version.json +1 -1
- package/web/.svelte-kit/output/server/.vite/manifest.json +12 -10
- package/web/.svelte-kit/output/server/chunks/Icon.js +1 -1
- package/web/.svelte-kit/output/server/chunks/client.js +1 -1
- package/web/.svelte-kit/output/server/chunks/exports.js +1 -1
- package/web/.svelte-kit/output/server/chunks/index-server.js +2 -1
- package/web/.svelte-kit/output/server/chunks/internal.js +1 -1
- package/web/.svelte-kit/output/server/chunks/render-context.js +77 -0
- package/web/.svelte-kit/output/server/chunks/root.js +739 -788
- package/web/.svelte-kit/output/server/chunks/shared.js +234 -21
- package/web/.svelte-kit/output/server/index.js +126 -90
- package/web/.svelte-kit/output/server/manifest-full.js +1 -1
- package/web/.svelte-kit/output/server/manifest.js +1 -1
- package/web/.svelte-kit/output/server/nodes/0.js +1 -1
- package/web/.svelte-kit/output/server/nodes/1.js +1 -1
- package/web/.svelte-kit/output/server/nodes/2.js +1 -1
- package/web/.svelte-kit/output/server/nodes/3.js +1 -1
- package/web/.svelte-kit/output/server/nodes/4.js +1 -1
- package/web/.svelte-kit/output/server/nodes/5.js +1 -1
- package/web/.svelte-kit/output/server/remote-entry.js +245 -81
- package/web/.svelte-kit/tsconfig.json +4 -1
- package/dist/cli/propose-policy.mjs.map +0 -1
- package/dist/lite-CBxOT1y5.mjs +0 -241
- package/dist/lite-CBxOT1y5.mjs.map +0 -1
- package/dist/routing-D8rTxtaV.mjs +0 -245
- package/dist/routing-D8rTxtaV.mjs.map +0 -1
- package/dist/web/_app/immutable/chunks/B6YN0Nuq.js +0 -1
- package/dist/web/_app/immutable/chunks/BmRlVmv6.js +0 -1
- package/dist/web/_app/immutable/chunks/CK9JZLaG.js +0 -2
- package/dist/web/_app/immutable/chunks/Ck3rYNON.js +0 -1
- package/dist/web/_app/immutable/chunks/D5iV40bG.js +0 -1
- package/dist/web/_app/immutable/chunks/DMtIqaiV.js +0 -2
- package/dist/web/_app/immutable/chunks/DhD271EB.js +0 -1
- package/dist/web/_app/immutable/chunks/DpuLqk8d.js +0 -1
- package/dist/web/_app/immutable/chunks/DsIToJCP.js +0 -1
- package/dist/web/_app/immutable/entry/app.BCSV3nrG.js +0 -2
- package/dist/web/_app/immutable/entry/start.D4eLEZUM.js +0 -1
- package/dist/web/_app/immutable/nodes/1.CGC_42IQ.js +0 -1
- package/dist/web/_app/immutable/nodes/4.ClM1bXLE.js +0 -60
- package/dist/workspace-BJmJBfKi.mjs +0 -456
- package/dist/workspace-BJmJBfKi.mjs.map +0 -1
- package/src/cli/e2e/agents.test.ts +0 -140
- package/src/cli/e2e/basic.test.ts +0 -43
- package/src/cli/e2e/cron.test.ts +0 -132
- package/src/cli/e2e/export-lite-func.test.ts +0 -206
- package/src/cli/e2e/fallbacks.test.ts +0 -175
- package/src/cli/e2e/init.test.ts +0 -77
- package/src/cli/e2e/messages.test.ts +0 -332
- package/src/cli/e2e/propose-policy.test.ts +0 -203
- package/src/cli/e2e/requests.test.ts +0 -180
- package/src/cli/e2e/session-timeout.test.ts +0 -192
- package/src/cli/e2e/slash-new.test.ts +0 -93
- package/src/cli/e2e/subagents.test.ts +0 -106
- package/src/cli/e2e/utils.ts +0 -66
- package/src/cli/propose-policy.ts +0 -91
- package/web/.svelte-kit/output/client/_app/immutable/chunks/B6YN0Nuq.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BmRlVmv6.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/CK9JZLaG.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Ck3rYNON.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/D5iV40bG.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DMtIqaiV.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DhD271EB.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DpuLqk8d.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DsIToJCP.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/entry/app.BCSV3nrG.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.D4eLEZUM.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.CGC_42IQ.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.ClM1bXLE.js +0 -60
- package/web/.svelte-kit/output/server/chunks/false.js +0 -4
- /package/dist/cli/{propose-policy.d.mts → manage-policies.d.mts} +0 -0
- /package/{src/cli/e2e → e2e/_helpers}/global-setup.ts +0 -0
|
@@ -0,0 +1,767 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
|
|
3
|
+
//#region src/shared/adapters/filtering.ts
|
|
4
|
+
/**
|
|
5
|
+
* Legacy boolean. Returns true if the message role is permitted to be
|
|
6
|
+
* displayed at all; adapters that haven't migrated to `routeMessage` keep
|
|
7
|
+
* using this unchanged.
|
|
8
|
+
*/
|
|
9
|
+
function shouldDisplayMessage(message, config) {
|
|
10
|
+
const overrides = config.filters || {};
|
|
11
|
+
if (message.subagentId && overrides["subagent"] !== true) return false;
|
|
12
|
+
if (message.displayRole === "agent" || message.role === "agent" || message.role === "legacy_log" || message.role === "policy" && message.status === "pending") return true;
|
|
13
|
+
if (message.subagentId && overrides["subagent"] === true && (message.role === "user" || message.displayRole === "user")) return true;
|
|
14
|
+
if (overrides[message.role] === true || message.displayRole && overrides[message.displayRole] === true) return true;
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
function defaultDestinationForRole(message) {
|
|
18
|
+
if (message.role === "user") return { kind: "drop" };
|
|
19
|
+
if (message.role === "agent") return { kind: "top-level" };
|
|
20
|
+
if (message.role === "legacy_log") return { kind: "top-level" };
|
|
21
|
+
if (message.role === "tool") return { kind: "thread-log" };
|
|
22
|
+
if (message.role === "subagent_status") return { kind: "thread-log" };
|
|
23
|
+
if (message.role === "command") return { kind: "drop" };
|
|
24
|
+
if (message.role === "policy") return message.status === "pending" ? { kind: "top-level" } : { kind: "thread-log" };
|
|
25
|
+
if (message.role === "system") {
|
|
26
|
+
if (message.event === "cron") return { kind: "drop" };
|
|
27
|
+
if (message.event === "policy_approved" || message.event === "policy_rejected") return { kind: "thread-log" };
|
|
28
|
+
if (message.event === "subagent_update") return { kind: "thread-log" };
|
|
29
|
+
return { kind: "top-level" };
|
|
30
|
+
}
|
|
31
|
+
return { kind: "drop" };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Return the destination for a chat message given the adapter's filtering
|
|
35
|
+
* config. Adapters that support threaded activity logs (Google Chat) use this
|
|
36
|
+
* to decide whether each message becomes a top-level post, a thread-log entry,
|
|
37
|
+
* or is dropped entirely.
|
|
38
|
+
*
|
|
39
|
+
* A filter override of `true` on a role whose default destination is `drop`
|
|
40
|
+
* promotes it to `top-level` (matching the legacy "opted in → show" behavior).
|
|
41
|
+
* A filter override of `false` drops the role.
|
|
42
|
+
*
|
|
43
|
+
* Subagent messages route to their default destination when that default is a
|
|
44
|
+
* thread one (tool calls, command logs, status updates all belong in the turn
|
|
45
|
+
* log). They are dropped when the default is top-level — subagent prompts and
|
|
46
|
+
* final replies are orchestration, not user-facing content — unless
|
|
47
|
+
* `filters.subagent` is `true`, which surfaces them at top-level for debugging.
|
|
48
|
+
*/
|
|
49
|
+
function routeMessage(message, config) {
|
|
50
|
+
const overrides = config.filters || {};
|
|
51
|
+
const defaultDest = defaultDestinationForRole(message);
|
|
52
|
+
if (message.subagentId) {
|
|
53
|
+
if (overrides["subagent"] === true) return defaultDest.kind === "drop" ? { kind: "top-level" } : defaultDest;
|
|
54
|
+
return { kind: "thread-log" };
|
|
55
|
+
}
|
|
56
|
+
if (message.displayRole === "agent" || message.role === "agent" || message.role === "legacy_log" || message.role === "policy" && message.status === "pending") return defaultDest;
|
|
57
|
+
const roleFilter = overrides[message.role];
|
|
58
|
+
const displayRoleFilter = message.displayRole ? overrides[message.displayRole] : void 0;
|
|
59
|
+
if (roleFilter === false || displayRoleFilter === false) return { kind: "drop" };
|
|
60
|
+
if (roleFilter === true || displayRoleFilter === true) return defaultDest.kind === "drop" ? { kind: "top-level" } : defaultDest;
|
|
61
|
+
return defaultDest;
|
|
62
|
+
}
|
|
63
|
+
function formatMessage(message) {
|
|
64
|
+
if (message.role === "system" && !message.displayRole && !message.subagentId) return `[SYSTEM] ${message.content}`;
|
|
65
|
+
if (!message.subagentId) return message.content;
|
|
66
|
+
if (message.role === "user" || message.displayRole === "user") return `[To:${message.subagentId}]\n${message.content}`;
|
|
67
|
+
return `[From:${message.subagentId}]\n${message.content}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/shared/adapters/inbound-cache.ts
|
|
72
|
+
function createInboundCache(ttlMs) {
|
|
73
|
+
const cache = /* @__PURE__ */ new Map();
|
|
74
|
+
const sweep = (now) => {
|
|
75
|
+
for (const [key, entry] of cache) if (now - entry.receivedAt > ttlMs) cache.delete(key);
|
|
76
|
+
};
|
|
77
|
+
return {
|
|
78
|
+
record(key, value) {
|
|
79
|
+
const now = Date.now();
|
|
80
|
+
sweep(now);
|
|
81
|
+
cache.set(key, {
|
|
82
|
+
value,
|
|
83
|
+
receivedAt: now
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
resolve(key) {
|
|
87
|
+
const entry = cache.get(key);
|
|
88
|
+
if (!entry) return null;
|
|
89
|
+
if (Date.now() - entry.receivedAt > ttlMs) {
|
|
90
|
+
cache.delete(key);
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
return entry.value;
|
|
94
|
+
},
|
|
95
|
+
reset() {
|
|
96
|
+
cache.clear();
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/shared/adapters/commands.ts
|
|
103
|
+
const VALID_ROLES = new Set([
|
|
104
|
+
"subagent",
|
|
105
|
+
"command",
|
|
106
|
+
"system",
|
|
107
|
+
"tool",
|
|
108
|
+
"policy",
|
|
109
|
+
"subagent_status",
|
|
110
|
+
"legacy_log"
|
|
111
|
+
]);
|
|
112
|
+
async function handleAdapterCommand(content, config, trpcClient, chatId) {
|
|
113
|
+
const trimmed = content.trim();
|
|
114
|
+
if (trimmed === "/show all") {
|
|
115
|
+
const newConfig = { filters: { ...config.filters } };
|
|
116
|
+
for (const role of VALID_ROLES) newConfig.filters[role] = true;
|
|
117
|
+
return {
|
|
118
|
+
type: "text",
|
|
119
|
+
text: "Configuration updated: Showing all messages.",
|
|
120
|
+
newConfig
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (trimmed === "/hide all") return {
|
|
124
|
+
type: "text",
|
|
125
|
+
text: "Configuration updated: Hidden all overrides (using defaults).",
|
|
126
|
+
newConfig: { filters: {} }
|
|
127
|
+
};
|
|
128
|
+
if (trimmed === "/show" || trimmed === "/hide") return {
|
|
129
|
+
type: "text",
|
|
130
|
+
text: `Valid options for ${trimmed}: ${Array.from(VALID_ROLES).join(", ")}`
|
|
131
|
+
};
|
|
132
|
+
if (trimmed.startsWith("/show ")) {
|
|
133
|
+
const role = trimmed.slice(6).trim();
|
|
134
|
+
if (!VALID_ROLES.has(role)) return {
|
|
135
|
+
type: "text",
|
|
136
|
+
text: `Error: '${role}' is not a valid message role or special value. Valid options: ${Array.from(VALID_ROLES).join(", ")}`
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
type: "text",
|
|
140
|
+
text: `Configuration updated: Showing messages for '${role}'.`,
|
|
141
|
+
newConfig: { filters: {
|
|
142
|
+
...config.filters,
|
|
143
|
+
[role]: true
|
|
144
|
+
} }
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (trimmed.startsWith("/hide ")) {
|
|
148
|
+
const role = trimmed.slice(6).trim();
|
|
149
|
+
if (!VALID_ROLES.has(role)) return {
|
|
150
|
+
type: "text",
|
|
151
|
+
text: `Error: '${role}' is not a valid message role or special value. Valid options: ${Array.from(VALID_ROLES).join(", ")}`
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
type: "text",
|
|
155
|
+
text: `Configuration updated: Hiding messages for '${role}'.`,
|
|
156
|
+
newConfig: { filters: {
|
|
157
|
+
...config.filters,
|
|
158
|
+
[role]: false
|
|
159
|
+
} }
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (trimmed === "/debug" || trimmed.startsWith("/debug ")) {
|
|
163
|
+
const match = trimmed.match(/^\/debug\s+(\d+)$/);
|
|
164
|
+
const limit = match ? parseInt(match[1], 10) : 5;
|
|
165
|
+
const messages = await trpcClient.getMessages.query({
|
|
166
|
+
chatId,
|
|
167
|
+
limit: limit * 10
|
|
168
|
+
});
|
|
169
|
+
const ignoredMessages = [];
|
|
170
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
171
|
+
const msg = messages[i];
|
|
172
|
+
if (!msg) continue;
|
|
173
|
+
if ((msg.role === "user" || msg.displayRole === "user") && !msg.subagentId) continue;
|
|
174
|
+
if (!shouldDisplayMessage(msg, config)) {
|
|
175
|
+
ignoredMessages.push(msg);
|
|
176
|
+
if (ignoredMessages.length >= limit) break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
ignoredMessages.reverse();
|
|
180
|
+
return {
|
|
181
|
+
type: "debug",
|
|
182
|
+
messages: ignoredMessages
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
//#endregion
|
|
189
|
+
//#region src/shared/adapters/routing.ts
|
|
190
|
+
async function handleRoutingCommand(content, externalContextId, currentChannelChatMap, adapterName, trpcClient) {
|
|
191
|
+
const trimmed = content.trim();
|
|
192
|
+
if (trimmed.startsWith("/chat")) {
|
|
193
|
+
const chatId = trimmed.split(/\s+/).slice(1)[0];
|
|
194
|
+
const availableChats = await trpcClient.getChats.query();
|
|
195
|
+
if (!chatId || !availableChats.includes(chatId)) return {
|
|
196
|
+
type: "reply",
|
|
197
|
+
text: `Available chats:\n${availableChats.length > 0 ? availableChats.map((c) => `- ${c}`).join("\n") : "No chats available."}\n\nPlease specify a valid chat ID: \`/chat [chat-id]\``
|
|
198
|
+
};
|
|
199
|
+
for (const [channelId, mappedId] of Object.entries(currentChannelChatMap)) if (mappedId === chatId && channelId !== externalContextId) return {
|
|
200
|
+
type: "reply",
|
|
201
|
+
text: `Error: Chat \`${chatId}\` is already mapped to another channel/space. Strict 1:1 mapping is required.`
|
|
202
|
+
};
|
|
203
|
+
return {
|
|
204
|
+
type: "mapped",
|
|
205
|
+
text: `Successfully mapped this channel/space to chat \`${chatId}\`.`,
|
|
206
|
+
newChatId: chatId
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
if (trimmed.startsWith("/agent")) {
|
|
210
|
+
const agentId = trimmed.split(/\s+/).slice(1)[0];
|
|
211
|
+
const availableAgents = await trpcClient.getAgents.query();
|
|
212
|
+
if (!agentId || !availableAgents.includes(agentId)) return {
|
|
213
|
+
type: "reply",
|
|
214
|
+
text: `Available agents:\n${availableAgents.length > 0 ? availableAgents.map((a) => `- ${a}`).join("\n") : "No agents available."}\n\nPlease specify a valid agent ID: \`/agent [agent-id]\``
|
|
215
|
+
};
|
|
216
|
+
const availableChats = await trpcClient.getChats.query();
|
|
217
|
+
let newChatId = `${agentId}-${adapterName}`;
|
|
218
|
+
let counter = 1;
|
|
219
|
+
while (availableChats.includes(newChatId)) {
|
|
220
|
+
newChatId = `${agentId}-${adapterName}-${counter}`;
|
|
221
|
+
counter++;
|
|
222
|
+
}
|
|
223
|
+
await trpcClient.createChat.mutate({
|
|
224
|
+
chatId: newChatId,
|
|
225
|
+
agent: agentId
|
|
226
|
+
});
|
|
227
|
+
return {
|
|
228
|
+
type: "mapped",
|
|
229
|
+
text: `Successfully created new chat \`${newChatId}\` with agent \`${agentId}\` and mapped it to this channel/space.`,
|
|
230
|
+
newChatId
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
//#endregion
|
|
237
|
+
//#region src/shared/adapters/blockquote.ts
|
|
238
|
+
/**
|
|
239
|
+
* Format `quoted` as a markdown blockquote prefixed before `body`.
|
|
240
|
+
*
|
|
241
|
+
* Each line of `quoted` is prefixed with `> `, and a blank line separates the
|
|
242
|
+
* quote from the body — CommonMark requires the blank line to terminate the
|
|
243
|
+
* blockquote, otherwise the body is lazily folded into it. If `sender` is
|
|
244
|
+
* provided, an attribution line (`> **{sender} said:**`) is rendered as the
|
|
245
|
+
* first line of the quote. Both inputs are trimmed.
|
|
246
|
+
*/
|
|
247
|
+
function prependBlockquote(quoted, body, sender) {
|
|
248
|
+
const trimmedBody = body.trim();
|
|
249
|
+
const lines = quoted.trim().split("\n").map((line) => `> ${line}`);
|
|
250
|
+
if (sender) lines.unshift(`> **${sender} said:**`);
|
|
251
|
+
return `${lines.join("\n")}\n\n${trimmedBody}`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/shared/event-source.ts
|
|
256
|
+
function createUnixSocketEventSource(socketPath) {
|
|
257
|
+
return class UnixSocketEventSource {
|
|
258
|
+
readyState = 0;
|
|
259
|
+
CONNECTING = 0;
|
|
260
|
+
OPEN = 1;
|
|
261
|
+
CLOSED = 2;
|
|
262
|
+
req = null;
|
|
263
|
+
listeners = {};
|
|
264
|
+
constructor(url, init) {
|
|
265
|
+
const parsedUrl = new URL(url);
|
|
266
|
+
const options = {
|
|
267
|
+
socketPath,
|
|
268
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
269
|
+
method: "GET",
|
|
270
|
+
headers: {
|
|
271
|
+
Accept: "text/event-stream",
|
|
272
|
+
"Cache-Control": "no-cache",
|
|
273
|
+
...init?.headers
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
this.req = http.request(options, (res) => {
|
|
277
|
+
if (res.statusCode === 200) {
|
|
278
|
+
this.readyState = this.OPEN;
|
|
279
|
+
this.dispatchEvent({ type: "open" });
|
|
280
|
+
} else {
|
|
281
|
+
this.readyState = this.CLOSED;
|
|
282
|
+
this.dispatchEvent({
|
|
283
|
+
type: "error",
|
|
284
|
+
message: `Unexpected status code: ${res.statusCode}`
|
|
285
|
+
});
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
let buffer = "";
|
|
289
|
+
res.on("data", (chunk) => {
|
|
290
|
+
buffer += chunk.toString("utf-8");
|
|
291
|
+
const lines = buffer.split(/\r?\n\r?\n/);
|
|
292
|
+
buffer = lines.pop() || "";
|
|
293
|
+
for (const block of lines) this.parseBlock(block);
|
|
294
|
+
});
|
|
295
|
+
res.on("end", () => {
|
|
296
|
+
if (buffer) this.parseBlock(buffer);
|
|
297
|
+
this.readyState = this.CLOSED;
|
|
298
|
+
this.dispatchEvent({ type: "close" });
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
this.req.on("error", (err) => {
|
|
302
|
+
this.readyState = this.CLOSED;
|
|
303
|
+
this.dispatchEvent({
|
|
304
|
+
type: "error",
|
|
305
|
+
error: err
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
this.req.end();
|
|
309
|
+
}
|
|
310
|
+
parseBlock(block) {
|
|
311
|
+
if (!block.trim()) return;
|
|
312
|
+
const lines = block.split(/\r?\n/);
|
|
313
|
+
let eventType = "message";
|
|
314
|
+
let data = "";
|
|
315
|
+
let id = "";
|
|
316
|
+
for (const line of lines) if (line.startsWith("event: ")) eventType = line.slice(7).trim();
|
|
317
|
+
else if (line.startsWith("data: ")) data += (data ? "\n" : "") + line.slice(6);
|
|
318
|
+
else if (line.startsWith("id: ")) id = line.slice(4).trim();
|
|
319
|
+
if (data) this.dispatchEvent({
|
|
320
|
+
type: eventType,
|
|
321
|
+
data,
|
|
322
|
+
lastEventId: id
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
addEventListener(type, listener) {
|
|
326
|
+
if (!this.listeners[type]) this.listeners[type] = [];
|
|
327
|
+
this.listeners[type].push(listener);
|
|
328
|
+
}
|
|
329
|
+
removeEventListener(type, listener) {
|
|
330
|
+
if (!this.listeners[type]) return;
|
|
331
|
+
this.listeners[type] = this.listeners[type].filter((l) => l !== listener);
|
|
332
|
+
}
|
|
333
|
+
dispatchEvent(event) {
|
|
334
|
+
const type = event.type;
|
|
335
|
+
if (this.listeners[type]) for (const listener of this.listeners[type]) listener(event);
|
|
336
|
+
}
|
|
337
|
+
close() {
|
|
338
|
+
this.readyState = this.CLOSED;
|
|
339
|
+
if (this.req) this.req.destroy();
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region src/shared/adapters/turn-log.ts
|
|
346
|
+
const DEFAULT_MAX_TOOL_PREVIEW = 400;
|
|
347
|
+
const TRUNCATED_SUFFIX = "…[truncated]";
|
|
348
|
+
const ROLLOVER_MARKER = "• …log continues";
|
|
349
|
+
function pad2(n) {
|
|
350
|
+
return n < 10 ? `0${n}` : String(n);
|
|
351
|
+
}
|
|
352
|
+
function formatRelative(deltaMs) {
|
|
353
|
+
const sec = Math.max(0, Math.floor(deltaMs / 1e3));
|
|
354
|
+
if (sec < 60) return `${sec}s`;
|
|
355
|
+
const m = Math.floor(sec / 60);
|
|
356
|
+
const s = sec % 60;
|
|
357
|
+
return s === 0 ? `${m}m` : `${m}m${s}s`;
|
|
358
|
+
}
|
|
359
|
+
function formatTimestamp(iso, turnStartedAt) {
|
|
360
|
+
if (turnStartedAt) {
|
|
361
|
+
const start = new Date(turnStartedAt).getTime();
|
|
362
|
+
const now = iso ? new Date(iso).getTime() : Date.now();
|
|
363
|
+
if (!Number.isNaN(start) && !Number.isNaN(now)) return formatRelative(now - start);
|
|
364
|
+
}
|
|
365
|
+
const d = iso ? new Date(iso) : /* @__PURE__ */ new Date();
|
|
366
|
+
const valid = !Number.isNaN(d.getTime()) ? d : /* @__PURE__ */ new Date();
|
|
367
|
+
return `${pad2(valid.getHours())}:${pad2(valid.getMinutes())}:${pad2(valid.getSeconds())}`;
|
|
368
|
+
}
|
|
369
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
370
|
+
function shortSubagentId(id) {
|
|
371
|
+
return UUID_RE.test(id) ? id.slice(0, 8) : id;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Extract a (verb, principal-arg) pair from a tool message so the turn log
|
|
375
|
+
* can render `read: foo.md` instead of `read_file({ "file_path": "foo.md" })`.
|
|
376
|
+
* Unknown tool names fall back to `<name>: <stringified-payload>` so we don't
|
|
377
|
+
* silently lose information.
|
|
378
|
+
*/
|
|
379
|
+
function extractToolPrincipal(name, payload) {
|
|
380
|
+
const p = payload ?? {};
|
|
381
|
+
const str = (v) => v == null ? "" : String(v);
|
|
382
|
+
switch (name) {
|
|
383
|
+
case "read_file":
|
|
384
|
+
case "Read": return {
|
|
385
|
+
verb: "read",
|
|
386
|
+
arg: str(p.file_path ?? p.path)
|
|
387
|
+
};
|
|
388
|
+
case "write_file":
|
|
389
|
+
case "create_file":
|
|
390
|
+
case "Write": return {
|
|
391
|
+
verb: "write",
|
|
392
|
+
arg: str(p.file_path ?? p.path)
|
|
393
|
+
};
|
|
394
|
+
case "edit_file":
|
|
395
|
+
case "Edit": return {
|
|
396
|
+
verb: "edit",
|
|
397
|
+
arg: str(p.file_path ?? p.path)
|
|
398
|
+
};
|
|
399
|
+
case "run_shell_command":
|
|
400
|
+
case "shell":
|
|
401
|
+
case "Bash": return {
|
|
402
|
+
verb: "shell",
|
|
403
|
+
arg: str(p.command)
|
|
404
|
+
};
|
|
405
|
+
case "activate_skill":
|
|
406
|
+
case "Skill": return {
|
|
407
|
+
verb: "skill",
|
|
408
|
+
arg: str(p.name ?? p.skill)
|
|
409
|
+
};
|
|
410
|
+
case "glob":
|
|
411
|
+
case "Glob": return {
|
|
412
|
+
verb: "glob",
|
|
413
|
+
arg: str(p.pattern)
|
|
414
|
+
};
|
|
415
|
+
case "grep":
|
|
416
|
+
case "Grep": return {
|
|
417
|
+
verb: "grep",
|
|
418
|
+
arg: str(p.pattern)
|
|
419
|
+
};
|
|
420
|
+
case "web_fetch":
|
|
421
|
+
case "WebFetch": return {
|
|
422
|
+
verb: "fetch",
|
|
423
|
+
arg: str(p.url)
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
verb: name,
|
|
428
|
+
arg: payload === void 0 || payload === null ? "" : JSON.stringify(payload)
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
function statusSigil(status) {
|
|
432
|
+
return status === "completed" ? "✅" : "❌";
|
|
433
|
+
}
|
|
434
|
+
/** Emoji for messages crossing the subagent boundary. */
|
|
435
|
+
const SUBAGENT_TO = "👉";
|
|
436
|
+
const SUBAGENT_FROM = "👈";
|
|
437
|
+
/**
|
|
438
|
+
* Emoji that stands in for a known tool verb. When present, it replaces the
|
|
439
|
+
* verb word entirely (`🐚 sleep 20` instead of `shell: sleep 20`). Unknown
|
|
440
|
+
* tools fall through to the `<name>: <arg>` form, preserving accessibility.
|
|
441
|
+
*/
|
|
442
|
+
const VERB_EMOJI = {
|
|
443
|
+
read: "📖",
|
|
444
|
+
write: "✍️",
|
|
445
|
+
edit: "✏️",
|
|
446
|
+
shell: "🧑💻",
|
|
447
|
+
skill: "📚",
|
|
448
|
+
glob: "📁",
|
|
449
|
+
grep: "🔎",
|
|
450
|
+
fetch: "🌐"
|
|
451
|
+
};
|
|
452
|
+
const SUBAGENT_MARKER = "🤖";
|
|
453
|
+
/** Emoji rendered on the turn's opening entry (posted when the turn starts). */
|
|
454
|
+
const TURN_START_EMOJI = "▶️";
|
|
455
|
+
/**
|
|
456
|
+
* Entries produced *inside* a subagent (a tool call, policy, system event
|
|
457
|
+
* with `subagentId` set) need a marker so the reader knows the activity
|
|
458
|
+
* happened inside the delegated turn. Boundary events (prompt, reply, status)
|
|
459
|
+
* already name the subagent via 👉/👈/✅, so they're excluded.
|
|
460
|
+
*/
|
|
461
|
+
function needsSubagentMarker(entry) {
|
|
462
|
+
if (!entry.subagentId) return false;
|
|
463
|
+
return entry.messageRole !== "user" && entry.messageRole !== "agent" && entry.messageRole !== "subagent_status";
|
|
464
|
+
}
|
|
465
|
+
function truncate(s, max) {
|
|
466
|
+
if (s.length <= max) return s;
|
|
467
|
+
const budget = Math.max(0, max - 12);
|
|
468
|
+
return s.slice(0, budget) + TRUNCATED_SUFFIX;
|
|
469
|
+
}
|
|
470
|
+
function sanitize(s) {
|
|
471
|
+
return s.replace(/\s*\r?\n\s*/g, " ").trim();
|
|
472
|
+
}
|
|
473
|
+
function renderEntry(entry) {
|
|
474
|
+
const prefix = needsSubagentMarker(entry) ? `${SUBAGENT_MARKER} ${shortSubagentId(entry.subagentId)} ` : "";
|
|
475
|
+
return `• ${entry.timestamp} ${prefix}${entry.summary}`;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Build the first entry posted into a turn's activity log so the thread
|
|
479
|
+
* appears as soon as `turnStarted` fires, rather than waiting for the first
|
|
480
|
+
* real event.
|
|
481
|
+
*/
|
|
482
|
+
function buildTurnStartEntry() {
|
|
483
|
+
const summary = `${TURN_START_EMOJI} Started processing…`;
|
|
484
|
+
return {
|
|
485
|
+
timestamp: "0s",
|
|
486
|
+
kind: "system",
|
|
487
|
+
summary,
|
|
488
|
+
rawLength: summary.length,
|
|
489
|
+
messageRole: "turn_start"
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
function formatTurnLogEntry(message, opts = {}) {
|
|
493
|
+
const maxToolPreview = opts.maxToolPreview ?? DEFAULT_MAX_TOOL_PREVIEW;
|
|
494
|
+
const timestamp = formatTimestamp(message.timestamp, opts.turnStartedAt);
|
|
495
|
+
if (message.role === "user" || message.role === "agent") {
|
|
496
|
+
if (!message.subagentId) return null;
|
|
497
|
+
const direction = message.role === "user" ? SUBAGENT_TO : SUBAGENT_FROM;
|
|
498
|
+
const content = sanitize(message.content);
|
|
499
|
+
return {
|
|
500
|
+
timestamp,
|
|
501
|
+
kind: "subagent",
|
|
502
|
+
summary: `${direction} ${shortSubagentId(message.subagentId)}: ${truncate(content, maxToolPreview)}`,
|
|
503
|
+
rawLength: content.length,
|
|
504
|
+
messageRole: message.role,
|
|
505
|
+
subagentId: message.subagentId
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
if (message.role === "tool") {
|
|
509
|
+
const { verb, arg } = extractToolPrincipal(message.name, message.payload);
|
|
510
|
+
const cleanArg = sanitize(arg);
|
|
511
|
+
const emoji = VERB_EMOJI[verb];
|
|
512
|
+
const argPreview = cleanArg ? truncate(cleanArg, maxToolPreview) : "";
|
|
513
|
+
let summary;
|
|
514
|
+
if (emoji) summary = argPreview ? `${emoji} ${argPreview}` : emoji;
|
|
515
|
+
else summary = argPreview ? `${verb}: ${argPreview}` : verb;
|
|
516
|
+
const entry = {
|
|
517
|
+
timestamp,
|
|
518
|
+
kind: "tool",
|
|
519
|
+
summary,
|
|
520
|
+
rawLength: cleanArg.length,
|
|
521
|
+
messageRole: message.role
|
|
522
|
+
};
|
|
523
|
+
if (message.subagentId) entry.subagentId = message.subagentId;
|
|
524
|
+
return entry;
|
|
525
|
+
}
|
|
526
|
+
if (message.role === "subagent_status") {
|
|
527
|
+
const id = shortSubagentId(message.subagentId);
|
|
528
|
+
const summary = `${statusSigil(message.status)} ${id}`;
|
|
529
|
+
return {
|
|
530
|
+
timestamp,
|
|
531
|
+
kind: "subagent",
|
|
532
|
+
summary,
|
|
533
|
+
rawLength: summary.length,
|
|
534
|
+
messageRole: message.role,
|
|
535
|
+
subagentId: message.subagentId
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
if (message.role === "policy") {
|
|
539
|
+
const body = `${message.commandName} ${message.args.join(" ")}`.trim();
|
|
540
|
+
const summary = `policy ${message.status}: ${body}`;
|
|
541
|
+
const entry = {
|
|
542
|
+
timestamp,
|
|
543
|
+
kind: "policy",
|
|
544
|
+
summary: truncate(sanitize(summary), maxToolPreview),
|
|
545
|
+
rawLength: summary.length,
|
|
546
|
+
messageRole: message.role
|
|
547
|
+
};
|
|
548
|
+
if (message.subagentId) entry.subagentId = message.subagentId;
|
|
549
|
+
return entry;
|
|
550
|
+
}
|
|
551
|
+
if (message.role === "system") {
|
|
552
|
+
if (message.event === "subagent_update") return null;
|
|
553
|
+
const content = sanitize(message.content || "");
|
|
554
|
+
const summary = content ? `${message.event}: ${content}` : message.event;
|
|
555
|
+
const entry = {
|
|
556
|
+
timestamp,
|
|
557
|
+
kind: "system",
|
|
558
|
+
summary: truncate(summary, maxToolPreview),
|
|
559
|
+
rawLength: summary.length,
|
|
560
|
+
messageRole: message.role
|
|
561
|
+
};
|
|
562
|
+
if (message.subagentId) entry.subagentId = message.subagentId;
|
|
563
|
+
return entry;
|
|
564
|
+
}
|
|
565
|
+
if (message.role === "command") return null;
|
|
566
|
+
if (message.role === "legacy_log") {
|
|
567
|
+
const content = sanitize(message.content);
|
|
568
|
+
const entry = {
|
|
569
|
+
timestamp,
|
|
570
|
+
kind: "system",
|
|
571
|
+
summary: truncate(content ? `log: ${content}` : "log", maxToolPreview),
|
|
572
|
+
rawLength: content.length,
|
|
573
|
+
messageRole: message.role
|
|
574
|
+
};
|
|
575
|
+
if (message.subagentId) entry.subagentId = message.subagentId;
|
|
576
|
+
return entry;
|
|
577
|
+
}
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
function joinLines(entries) {
|
|
581
|
+
return entries.map(renderEntry).join("\n");
|
|
582
|
+
}
|
|
583
|
+
function condenseTurnLog(entries, opts) {
|
|
584
|
+
const snapshot = entries.slice();
|
|
585
|
+
if (snapshot.length === 0) return {
|
|
586
|
+
kind: "fits",
|
|
587
|
+
text: ""
|
|
588
|
+
};
|
|
589
|
+
const fullText = joinLines(snapshot);
|
|
590
|
+
if (fullText.length <= opts.maxChars) return {
|
|
591
|
+
kind: "fits",
|
|
592
|
+
text: fullText
|
|
593
|
+
};
|
|
594
|
+
const budget = Math.max(0, opts.maxChars - 17);
|
|
595
|
+
const kept = [];
|
|
596
|
+
let runningLength = 0;
|
|
597
|
+
for (let i = 0; i < snapshot.length; i++) {
|
|
598
|
+
const line = renderEntry(snapshot[i]);
|
|
599
|
+
const next = runningLength === 0 ? line.length : runningLength + 1 + line.length;
|
|
600
|
+
if (next > budget) {
|
|
601
|
+
if (kept.length === 0) return {
|
|
602
|
+
kind: "rollover",
|
|
603
|
+
finalText: truncate(line, opts.maxChars),
|
|
604
|
+
carryEntries: snapshot.slice(i + 1)
|
|
605
|
+
};
|
|
606
|
+
const carryEntries = snapshot.slice(i);
|
|
607
|
+
return {
|
|
608
|
+
kind: "rollover",
|
|
609
|
+
finalText: `${joinLines(kept)}\n${ROLLOVER_MARKER}`,
|
|
610
|
+
carryEntries
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
runningLength = next;
|
|
614
|
+
kept.push(snapshot[i]);
|
|
615
|
+
}
|
|
616
|
+
return {
|
|
617
|
+
kind: "fits",
|
|
618
|
+
text: fullText
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
//#endregion
|
|
623
|
+
//#region src/shared/adapters/turn-log-buffer.ts
|
|
624
|
+
function createTurnLogBuffer(deps) {
|
|
625
|
+
const { options, threadsEnabled, postThreaded, editThreaded, isMissingMessageError } = deps;
|
|
626
|
+
const ctxs = /* @__PURE__ */ new Map();
|
|
627
|
+
const engaged = (ctx) => threadsEnabled && !ctx.threadsDisabled && !ctx.aborted;
|
|
628
|
+
const runFlush = async (ctx) => {
|
|
629
|
+
if (!engaged(ctx)) {
|
|
630
|
+
ctx.entries = [];
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
if (ctx.anchor === void 0) return;
|
|
634
|
+
if (ctx.entries.length === 0) return;
|
|
635
|
+
let result = condenseTurnLog(ctx.entries, { maxChars: options.maxLogMessageChars });
|
|
636
|
+
const send = async () => {
|
|
637
|
+
const text = result.kind === "fits" ? result.text : result.finalText;
|
|
638
|
+
if (!ctx.activityLogMessageId) {
|
|
639
|
+
try {
|
|
640
|
+
const id = await postThreaded(ctx.anchor, text);
|
|
641
|
+
if (id) ctx.activityLogMessageId = id;
|
|
642
|
+
} catch (err) {
|
|
643
|
+
console.error(`Failed to open thread-log for turn ${ctx.turnId}; dropping further thread-log events for this turn.`, err);
|
|
644
|
+
ctx.aborted = true;
|
|
645
|
+
ctx.entries = [];
|
|
646
|
+
}
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
try {
|
|
650
|
+
await editThreaded(ctx.anchor, ctx.activityLogMessageId, text);
|
|
651
|
+
} catch (err) {
|
|
652
|
+
if (isMissingMessageError(err)) {
|
|
653
|
+
console.warn("Log message missing on edit — opening a fresh log message.");
|
|
654
|
+
ctx.activityLogMessageId = void 0;
|
|
655
|
+
try {
|
|
656
|
+
const id = await postThreaded(ctx.anchor, text);
|
|
657
|
+
if (id) ctx.activityLogMessageId = id;
|
|
658
|
+
} catch (innerErr) {
|
|
659
|
+
console.error("Failed to re-open log message after missing edit:", innerErr);
|
|
660
|
+
ctx.activityLogMessageId = void 0;
|
|
661
|
+
}
|
|
662
|
+
} else {
|
|
663
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
664
|
+
try {
|
|
665
|
+
await editThreaded(ctx.anchor, ctx.activityLogMessageId, text);
|
|
666
|
+
} catch (retryErr) {
|
|
667
|
+
console.warn("Edit failed twice — finalizing log message.", retryErr);
|
|
668
|
+
ctx.activityLogMessageId = void 0;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
await send();
|
|
674
|
+
while (!ctx.aborted && result.kind === "rollover") {
|
|
675
|
+
const prevLen = ctx.entries.length;
|
|
676
|
+
ctx.entries = result.carryEntries.slice();
|
|
677
|
+
ctx.activityLogMessageId = void 0;
|
|
678
|
+
if (ctx.entries.length === 0) break;
|
|
679
|
+
if (ctx.entries.length >= prevLen) {
|
|
680
|
+
console.warn(`Turn-log entry larger than maxLogMessageChars — dropping head for turn ${ctx.turnId}`);
|
|
681
|
+
ctx.entries = ctx.entries.slice(1);
|
|
682
|
+
if (ctx.entries.length === 0) break;
|
|
683
|
+
}
|
|
684
|
+
result = condenseTurnLog(ctx.entries, { maxChars: options.maxLogMessageChars });
|
|
685
|
+
await send();
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
const enqueueFlush = (ctx) => {
|
|
689
|
+
ctx.flushChain = ctx.flushChain.then(() => runFlush(ctx)).catch((err) => console.error("Flush error:", err));
|
|
690
|
+
};
|
|
691
|
+
const scheduleFlush = (ctx) => {
|
|
692
|
+
if (!engaged(ctx)) return;
|
|
693
|
+
if (ctx.editTimer) return;
|
|
694
|
+
ctx.editTimer = setTimeout(() => {
|
|
695
|
+
ctx.editTimer = null;
|
|
696
|
+
enqueueFlush(ctx);
|
|
697
|
+
}, options.editDebounceMs);
|
|
698
|
+
};
|
|
699
|
+
return {
|
|
700
|
+
start(params) {
|
|
701
|
+
const ctx = {
|
|
702
|
+
turnId: params.turnId,
|
|
703
|
+
threadsDisabled: params.threadsDisabled,
|
|
704
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
705
|
+
anchor: params.anchorThread,
|
|
706
|
+
activityLogMessageId: void 0,
|
|
707
|
+
entries: threadsEnabled && !params.threadsDisabled ? [buildTurnStartEntry()] : [],
|
|
708
|
+
editTimer: null,
|
|
709
|
+
flushChain: Promise.resolve(),
|
|
710
|
+
aborted: false
|
|
711
|
+
};
|
|
712
|
+
ctxs.set(params.turnId, ctx);
|
|
713
|
+
if (ctx.anchor !== void 0 && engaged(ctx)) enqueueFlush(ctx);
|
|
714
|
+
},
|
|
715
|
+
append(turnId, message) {
|
|
716
|
+
const ctx = ctxs.get(turnId);
|
|
717
|
+
if (!ctx) return;
|
|
718
|
+
if (!engaged(ctx)) return;
|
|
719
|
+
const entry = formatTurnLogEntry(message, {
|
|
720
|
+
maxToolPreview: options.maxToolPreview,
|
|
721
|
+
turnStartedAt: ctx.startedAt
|
|
722
|
+
});
|
|
723
|
+
if (!entry) return;
|
|
724
|
+
ctx.entries.push(entry);
|
|
725
|
+
if (ctx.anchor !== void 0) scheduleFlush(ctx);
|
|
726
|
+
},
|
|
727
|
+
assignAnchor(turnId, anchor) {
|
|
728
|
+
const ctx = ctxs.get(turnId);
|
|
729
|
+
if (!ctx) return;
|
|
730
|
+
if (ctx.anchor !== void 0) return;
|
|
731
|
+
ctx.anchor = anchor;
|
|
732
|
+
if (engaged(ctx) && ctx.entries.length > 0) enqueueFlush(ctx);
|
|
733
|
+
},
|
|
734
|
+
async end(turnId) {
|
|
735
|
+
const ctx = ctxs.get(turnId);
|
|
736
|
+
if (!ctx) return;
|
|
737
|
+
if (ctx.editTimer) {
|
|
738
|
+
clearTimeout(ctx.editTimer);
|
|
739
|
+
ctx.editTimer = null;
|
|
740
|
+
}
|
|
741
|
+
enqueueFlush(ctx);
|
|
742
|
+
try {
|
|
743
|
+
await ctx.flushChain;
|
|
744
|
+
} catch (err) {
|
|
745
|
+
console.error("Final flush error:", err);
|
|
746
|
+
}
|
|
747
|
+
ctxs.delete(turnId);
|
|
748
|
+
},
|
|
749
|
+
has(turnId) {
|
|
750
|
+
return ctxs.has(turnId);
|
|
751
|
+
},
|
|
752
|
+
isAnchored(turnId) {
|
|
753
|
+
return ctxs.get(turnId)?.anchor !== void 0;
|
|
754
|
+
},
|
|
755
|
+
threadsDisabledFor(turnId) {
|
|
756
|
+
return ctxs.get(turnId)?.threadsDisabled ?? false;
|
|
757
|
+
},
|
|
758
|
+
shutdown() {
|
|
759
|
+
for (const ctx of ctxs.values()) if (ctx.editTimer) clearTimeout(ctx.editTimer);
|
|
760
|
+
ctxs.clear();
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
//#endregion
|
|
766
|
+
export { handleAdapterCommand as a, routeMessage as c, handleRoutingCommand as i, createUnixSocketEventSource as n, createInboundCache as o, prependBlockquote as r, formatMessage as s, createTurnLogBuffer as t };
|
|
767
|
+
//# sourceMappingURL=turn-log-buffer-DRgW53gl.mjs.map
|