clawmini 0.0.7 → 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/{G_zz-Gou.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.CYS8iApT.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.Dr0ot9sV.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.BBGQ_i84.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 +42 -13
- 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 -176
- package/web/.svelte-kit/generated/server/internal.js +1 -1
- package/web/.svelte-kit/output/client/.vite/manifest.json +127 -137
- 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/{G_zz-Gou.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.CYS8iApT.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.Dr0ot9sV.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.BBGQ_i84.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/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/chunks/bBmtyQMj.js +0 -1
- package/dist/web/_app/immutable/entry/app.CJmSwntr.js +0 -2
- package/dist/web/_app/immutable/entry/start.ZpUrT2ak.js +0 -1
- package/dist/web/_app/immutable/nodes/1.Bli0Hqzn.js +0 -1
- package/dist/web/_app/immutable/nodes/4.oBhvQhcA.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/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/chunks/bBmtyQMj.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/entry/app.CJmSwntr.js +0 -2
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.ZpUrT2ak.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.Bli0Hqzn.js +0 -1
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.oBhvQhcA.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
|
@@ -13,12 +13,14 @@ import { createUnixSocketEventSource } from '../shared/event-source.js';
|
|
|
13
13
|
import type { GoogleChatConfig } from './config.js';
|
|
14
14
|
import { isAuthorized, updateGoogleChatConfig } from './config.js';
|
|
15
15
|
import { readGoogleChatState, updateGoogleChatState } from './state.js';
|
|
16
|
-
import {
|
|
16
|
+
import { recordInbound } from './inbound-cache.js';
|
|
17
|
+
import { downloadAttachment as defaultDownloadAttachment } from './utils.js';
|
|
17
18
|
import { handleAdapterCommand, type CommandTrpcClient } from '../shared/adapters/commands.js';
|
|
18
19
|
import { formatMessage, type FilteringConfig } from '../shared/adapters/filtering.js';
|
|
19
20
|
import { google } from 'googleapis';
|
|
20
21
|
import { getAuthClient } from './auth.js';
|
|
21
22
|
import { handleRoutingCommand, type RoutingTrpcClient } from '../shared/adapters/routing.js';
|
|
23
|
+
import { prependBlockquote } from '../shared/adapters/blockquote.js';
|
|
22
24
|
|
|
23
25
|
import { handleAddedToSpace, handleRemovedFromSpace } from './subscriptions.js';
|
|
24
26
|
import { handleCardClicked } from './cards.js';
|
|
@@ -52,13 +54,74 @@ export function getTRPCClient(options: { socketPath?: string } = {}) {
|
|
|
52
54
|
});
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
export type GoogleChatApi = ReturnType<typeof google.chat>;
|
|
58
|
+
|
|
59
|
+
interface QuotedSender {
|
|
60
|
+
type?: string | null;
|
|
61
|
+
email?: string | null;
|
|
62
|
+
name?: string | null;
|
|
63
|
+
displayName?: string | null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Map a quoted message's sender to a short attribution label. Returns "Bot"
|
|
68
|
+
* for the assistant, "You" if it's one of the configured authorized users,
|
|
69
|
+
* and otherwise the sender's email (preferred) or `users/{id}` resource name.
|
|
70
|
+
*/
|
|
71
|
+
export function formatQuotedSender(
|
|
72
|
+
sender: QuotedSender | undefined,
|
|
73
|
+
authorizedUsers: string[]
|
|
74
|
+
): string | undefined {
|
|
75
|
+
if (!sender) return undefined;
|
|
76
|
+
if (sender.type === 'BOT') return 'Assistant';
|
|
77
|
+
const email = sender.email ?? undefined;
|
|
78
|
+
const name = sender.name ?? undefined;
|
|
79
|
+
if (
|
|
80
|
+
(email && isAuthorized(email, authorizedUsers)) ||
|
|
81
|
+
(name && isAuthorized(name, authorizedUsers))
|
|
82
|
+
) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
return email || sender.displayName || name || undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface MessageSourceLike {
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
90
|
+
on(event: string, listener: (...args: any[]) => void | Promise<void>): unknown;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface GoogleChatIngestionDeps {
|
|
94
|
+
/** Inbound message source (defaults to a real Pub/Sub subscription). */
|
|
95
|
+
subscription?: MessageSourceLike;
|
|
96
|
+
/** Google Chat API client (defaults to `google.chat()` with ADC credentials). */
|
|
97
|
+
chatApi?: GoogleChatApi;
|
|
98
|
+
/** Root directory for resolving adapter state/config (defaults to `process.cwd()`). */
|
|
99
|
+
startDir?: string;
|
|
100
|
+
/** Attachment downloader (defaults to the real Chat media endpoint). */
|
|
101
|
+
downloadAttachment?: (resourceName: string, maxSizeMB?: number) => Promise<Buffer>;
|
|
102
|
+
}
|
|
103
|
+
|
|
55
104
|
export function startGoogleChatIngestion(
|
|
56
105
|
config: GoogleChatConfig,
|
|
57
106
|
trpc: ReturnType<typeof getTRPCClient>,
|
|
58
|
-
filteringConfig: FilteringConfig
|
|
107
|
+
filteringConfig: FilteringConfig,
|
|
108
|
+
deps: GoogleChatIngestionDeps = {}
|
|
59
109
|
) {
|
|
60
|
-
const
|
|
61
|
-
const subscription =
|
|
110
|
+
const startDir = deps.startDir ?? process.cwd();
|
|
111
|
+
const subscription: MessageSourceLike =
|
|
112
|
+
deps.subscription ??
|
|
113
|
+
(() => {
|
|
114
|
+
const pubsub = new PubSub({ projectId: config.projectId });
|
|
115
|
+
return pubsub.subscription(config.subscriptionName);
|
|
116
|
+
})();
|
|
117
|
+
|
|
118
|
+
const getChatApi = async (): Promise<GoogleChatApi> => {
|
|
119
|
+
if (deps.chatApi) return deps.chatApi;
|
|
120
|
+
const authClient = await getAuthClient();
|
|
121
|
+
return google.chat({ version: 'v1', auth: authClient });
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const downloadAttachment = deps.downloadAttachment ?? defaultDownloadAttachment;
|
|
62
125
|
|
|
63
126
|
const seenMessageIds = new Map<string, number>();
|
|
64
127
|
|
|
@@ -99,9 +162,13 @@ export function startGoogleChatIngestion(
|
|
|
99
162
|
: parsedData.space || eventMessage?.space;
|
|
100
163
|
const senderType = eventMessage?.sender?.type || '';
|
|
101
164
|
const messageId = eventMessage?.name || '';
|
|
102
|
-
const text = (eventMessage?.
|
|
165
|
+
const text = (eventMessage?.text || '').trim();
|
|
103
166
|
|
|
104
|
-
|
|
167
|
+
// CARD_CLICKED events carry the bot's original card message as
|
|
168
|
+
// `parsedData.message`, so `sender.type` is BOT even though the
|
|
169
|
+
// interaction was initiated by a real user (`parsedData.user`).
|
|
170
|
+
// Only drop BOT-authored MESSAGE events here.
|
|
171
|
+
if (senderType === 'BOT' && eventType !== 'CARD_CLICKED') return void message.ack();
|
|
105
172
|
|
|
106
173
|
if (messageId) {
|
|
107
174
|
if (seenMessageIds.has(messageId)) return void message.ack();
|
|
@@ -142,7 +209,7 @@ export function startGoogleChatIngestion(
|
|
|
142
209
|
`Automatically authorizing user ID ${senderName} based on authorized email ${email}`
|
|
143
210
|
);
|
|
144
211
|
config.authorizedUsers.push(senderName);
|
|
145
|
-
updateGoogleChatConfig(config).catch((err) =>
|
|
212
|
+
updateGoogleChatConfig(config, startDir).catch((err) =>
|
|
146
213
|
console.error('Failed to update config with new user ID:', err)
|
|
147
214
|
);
|
|
148
215
|
}
|
|
@@ -157,7 +224,7 @@ export function startGoogleChatIngestion(
|
|
|
157
224
|
return;
|
|
158
225
|
}
|
|
159
226
|
|
|
160
|
-
const currentState = await readGoogleChatState();
|
|
227
|
+
const currentState = await readGoogleChatState(startDir);
|
|
161
228
|
|
|
162
229
|
const externalContextId = spaceName;
|
|
163
230
|
const mappedChatId = currentState.channelChatMap?.[externalContextId]?.chatId;
|
|
@@ -170,7 +237,8 @@ export function startGoogleChatIngestion(
|
|
|
170
237
|
space?.type,
|
|
171
238
|
mappedChatId,
|
|
172
239
|
mappedChatId,
|
|
173
|
-
config
|
|
240
|
+
config,
|
|
241
|
+
startDir
|
|
174
242
|
);
|
|
175
243
|
if (!text) {
|
|
176
244
|
message.ack();
|
|
@@ -179,7 +247,7 @@ export function startGoogleChatIngestion(
|
|
|
179
247
|
}
|
|
180
248
|
|
|
181
249
|
if (eventType === 'REMOVED_FROM_SPACE') {
|
|
182
|
-
await handleRemovedFromSpace(externalContextId, currentState, config);
|
|
250
|
+
await handleRemovedFromSpace(externalContextId, currentState, config, startDir);
|
|
183
251
|
message.ack();
|
|
184
252
|
return;
|
|
185
253
|
}
|
|
@@ -198,20 +266,22 @@ export function startGoogleChatIngestion(
|
|
|
198
266
|
|
|
199
267
|
if (routingResult) {
|
|
200
268
|
if (routingResult.type === 'mapped') {
|
|
201
|
-
await updateGoogleChatState(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
269
|
+
await updateGoogleChatState(
|
|
270
|
+
(latestState) => ({
|
|
271
|
+
channelChatMap: {
|
|
272
|
+
...(latestState.channelChatMap || {}),
|
|
273
|
+
[externalContextId]: {
|
|
274
|
+
...(latestState.channelChatMap?.[externalContextId] || {}),
|
|
275
|
+
chatId: routingResult.newChatId,
|
|
276
|
+
},
|
|
207
277
|
},
|
|
208
|
-
},
|
|
209
|
-
|
|
278
|
+
}),
|
|
279
|
+
startDir
|
|
280
|
+
);
|
|
210
281
|
}
|
|
211
282
|
|
|
212
283
|
try {
|
|
213
|
-
const
|
|
214
|
-
const chatApi = google.chat({ version: 'v1', auth: authClient });
|
|
284
|
+
const chatApi = await getChatApi();
|
|
215
285
|
await chatApi.spaces.messages.create({
|
|
216
286
|
parent: externalContextId,
|
|
217
287
|
requestBody: { text: routingResult.text },
|
|
@@ -237,15 +307,18 @@ export function startGoogleChatIngestion(
|
|
|
237
307
|
console.log(
|
|
238
308
|
`First contact detected. Automatically mapping space ${externalContextId} to chat ${targetChatId}.`
|
|
239
309
|
);
|
|
240
|
-
await updateGoogleChatState(
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
310
|
+
await updateGoogleChatState(
|
|
311
|
+
(latestState) => ({
|
|
312
|
+
channelChatMap: {
|
|
313
|
+
...(latestState.channelChatMap || {}),
|
|
314
|
+
[externalContextId]: {
|
|
315
|
+
...(latestState.channelChatMap?.[externalContextId] || {}),
|
|
316
|
+
chatId: targetChatId as string,
|
|
317
|
+
},
|
|
246
318
|
},
|
|
247
|
-
},
|
|
248
|
-
|
|
319
|
+
}),
|
|
320
|
+
startDir
|
|
321
|
+
);
|
|
249
322
|
} else {
|
|
250
323
|
const isDirectMessage =
|
|
251
324
|
space?.type === 'DIRECT_MESSAGE' || space?.singleUserBotDm === true;
|
|
@@ -257,8 +330,7 @@ export function startGoogleChatIngestion(
|
|
|
257
330
|
if (isDirectMessage || isMentioned || isSlashCommand) {
|
|
258
331
|
console.log(`Unmapped space ${externalContextId}, sending first contact warning.`);
|
|
259
332
|
try {
|
|
260
|
-
const
|
|
261
|
-
const chatApi = google.chat({ version: 'v1', auth: authClient });
|
|
333
|
+
const chatApi = await getChatApi();
|
|
262
334
|
await chatApi.spaces.messages.create({
|
|
263
335
|
parent: externalContextId,
|
|
264
336
|
requestBody: {
|
|
@@ -300,8 +372,7 @@ export function startGoogleChatIngestion(
|
|
|
300
372
|
let isReplyToBot = false;
|
|
301
373
|
if (eventMessage?.threadReply && eventMessage.thread?.name) {
|
|
302
374
|
try {
|
|
303
|
-
const
|
|
304
|
-
const chatApi = google.chat({ version: 'v1', auth: authClient });
|
|
375
|
+
const chatApi = await getChatApi();
|
|
305
376
|
const response = await chatApi.spaces.messages.list({
|
|
306
377
|
parent: externalContextId,
|
|
307
378
|
filter: `thread.name="${eventMessage.thread.name}"`,
|
|
@@ -332,7 +403,8 @@ export function startGoogleChatIngestion(
|
|
|
332
403
|
await handleCardClicked(
|
|
333
404
|
parsedData,
|
|
334
405
|
targetChatId as string,
|
|
335
|
-
trpc as unknown as RoutingTrpcClient
|
|
406
|
+
trpc as unknown as RoutingTrpcClient,
|
|
407
|
+
getChatApi
|
|
336
408
|
);
|
|
337
409
|
message.ack();
|
|
338
410
|
return;
|
|
@@ -350,7 +422,7 @@ export function startGoogleChatIngestion(
|
|
|
350
422
|
if (commandResult.type === 'text') {
|
|
351
423
|
if (commandResult.newConfig) {
|
|
352
424
|
filteringConfig.filters = commandResult.newConfig.filters;
|
|
353
|
-
await updateGoogleChatState({ filters: filteringConfig.filters });
|
|
425
|
+
await updateGoogleChatState({ filters: filteringConfig.filters }, startDir);
|
|
354
426
|
}
|
|
355
427
|
resultText = commandResult.text;
|
|
356
428
|
} else if (commandResult.type === 'debug') {
|
|
@@ -361,8 +433,7 @@ export function startGoogleChatIngestion(
|
|
|
361
433
|
commandResult.messages.map((msg) => formatMessage(msg)).join('\n\n---\n\n');
|
|
362
434
|
}
|
|
363
435
|
|
|
364
|
-
const
|
|
365
|
-
const chatApi = google.chat({ version: 'v1', auth: authClient });
|
|
436
|
+
const chatApi = await getChatApi();
|
|
366
437
|
await chatApi.spaces.messages.create({
|
|
367
438
|
parent: spaceName as string,
|
|
368
439
|
requestBody: { text: resultText },
|
|
@@ -373,7 +444,7 @@ export function startGoogleChatIngestion(
|
|
|
373
444
|
const attachments = eventMessage?.attachment || [];
|
|
374
445
|
|
|
375
446
|
if (attachments.length > 0) {
|
|
376
|
-
const tmpDir = path.join(getClawminiDir(
|
|
447
|
+
const tmpDir = path.join(getClawminiDir(startDir), 'tmp', 'google-chat');
|
|
377
448
|
await fsPromises.mkdir(tmpDir, { recursive: true });
|
|
378
449
|
|
|
379
450
|
for (const att of attachments) {
|
|
@@ -392,15 +463,44 @@ export function startGoogleChatIngestion(
|
|
|
392
463
|
}
|
|
393
464
|
}
|
|
394
465
|
|
|
466
|
+
let forwardedText = text;
|
|
467
|
+
const quotedMetadata = eventMessage?.quotedMessageMetadata;
|
|
468
|
+
if (quotedMetadata) {
|
|
469
|
+
let quotedText: string | undefined = quotedMetadata.quotedMessageSnapshot?.text;
|
|
470
|
+
let quotedSender: QuotedSender | undefined = quotedMetadata.quotedMessageSnapshot?.sender;
|
|
471
|
+
if ((!quotedText || !quotedSender) && quotedMetadata.name) {
|
|
472
|
+
try {
|
|
473
|
+
const chatApi = await getChatApi();
|
|
474
|
+
const quotedRes = await chatApi.spaces.messages.get({ name: quotedMetadata.name });
|
|
475
|
+
quotedText = quotedText || quotedRes.data?.text || undefined;
|
|
476
|
+
quotedSender =
|
|
477
|
+
quotedSender || (quotedRes.data?.sender as QuotedSender | undefined) || undefined;
|
|
478
|
+
} catch (err) {
|
|
479
|
+
console.error('Failed to fetch quoted message:', err);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
if (quotedText) {
|
|
483
|
+
const senderLabel = formatQuotedSender(quotedSender, config.authorizedUsers);
|
|
484
|
+
forwardedText = prependBlockquote(quotedText, text, senderLabel);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const gchatThreadName: string | undefined =
|
|
489
|
+
eventMessage?.thread?.name ?? eventMessage?.threadName ?? undefined;
|
|
490
|
+
if (messageId && gchatThreadName) {
|
|
491
|
+
recordInbound({ gchatMessageName: messageId, gchatThreadName });
|
|
492
|
+
}
|
|
493
|
+
|
|
395
494
|
await trpc.sendMessage.mutate({
|
|
396
495
|
type: 'send-message',
|
|
397
496
|
client: 'cli',
|
|
398
497
|
data: {
|
|
399
|
-
message:
|
|
498
|
+
message: forwardedText,
|
|
400
499
|
chatId: targetChatId,
|
|
401
500
|
files: downloadedFiles.length > 0 ? downloadedFiles : undefined,
|
|
402
501
|
adapter: 'google-chat',
|
|
403
502
|
noWait: true,
|
|
503
|
+
...(messageId ? { externalRef: messageId } : {}),
|
|
404
504
|
},
|
|
405
505
|
});
|
|
406
506
|
|
|
@@ -4,6 +4,24 @@ import { z } from 'zod';
|
|
|
4
4
|
import { getClawminiDir } from '../shared/workspace.js';
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
|
|
7
|
+
export const ThreadVisibilitySchema = z.object({
|
|
8
|
+
threads: z.boolean().default(true).optional(),
|
|
9
|
+
threadLog: z
|
|
10
|
+
.object({
|
|
11
|
+
maxToolPreview: z.number().default(400).optional(),
|
|
12
|
+
maxLogMessageChars: z.number().default(3500).optional(),
|
|
13
|
+
editDebounceMs: z.number().default(1000).optional(),
|
|
14
|
+
})
|
|
15
|
+
.optional(),
|
|
16
|
+
// Proactive (cron) turns have no inbound user message. `silent` (default)
|
|
17
|
+
// drops the cron system message and anchors any thread-log activity on the
|
|
18
|
+
// agent's eventual top-level reply; if the agent never replies, nothing
|
|
19
|
+
// posts. `header` posts a terse `🕒 <jobId>` header top-level to serve as
|
|
20
|
+
// the anchor, making scheduled work visible even when the agent stays
|
|
21
|
+
// silent.
|
|
22
|
+
jobs: z.enum(['silent', 'header']).default('silent').optional(),
|
|
23
|
+
});
|
|
24
|
+
|
|
7
25
|
export const GoogleChatConfigSchema = z.looseObject({
|
|
8
26
|
projectId: z.string().min(1, 'GCP Project ID is required.'),
|
|
9
27
|
subscriptionName: z.string().min(1, 'Pub/Sub Subscription Name is required.'),
|
|
@@ -16,6 +34,7 @@ export const GoogleChatConfigSchema = z.looseObject({
|
|
|
16
34
|
requireMention: z.boolean().default(false),
|
|
17
35
|
oauthClientId: z.string().optional(),
|
|
18
36
|
oauthClientSecret: z.string().optional(),
|
|
37
|
+
visibility: ThreadVisibilitySchema.optional(),
|
|
19
38
|
});
|
|
20
39
|
|
|
21
40
|
export type GoogleChatConfig = z.infer<typeof GoogleChatConfigSchema>;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { startDaemonToGoogleChatForwarder } from './forwarder.js';
|
|
3
3
|
|
|
4
|
+
// `waitForMessages` yields `ChatStreamItem` envelopes (discriminated by
|
|
5
|
+
// `kind`). Tests send raw message shapes; wrap them here.
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
const asEnvelopes = (messages: any[]) => messages.map((message) => ({ kind: 'message', message }));
|
|
8
|
+
|
|
4
9
|
const mockConfig = {
|
|
5
10
|
projectId: 'test',
|
|
6
11
|
subscriptionName: 'test',
|
|
@@ -77,7 +82,7 @@ vi.mock('./state.js', () => ({
|
|
|
77
82
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
83
|
updateGoogleChatState: (updates: any) => {
|
|
79
84
|
const currentState = { lastSyncedMessageIds: { otherChat: 'msg-other' } };
|
|
80
|
-
const result = typeof updates === 'function' ? updates(currentState
|
|
85
|
+
const result = typeof updates === 'function' ? updates(currentState) : updates;
|
|
81
86
|
mockStateDeps.mockWriteState(result);
|
|
82
87
|
return Promise.resolve(result);
|
|
83
88
|
},
|
|
@@ -158,14 +163,16 @@ describe('Daemon to Google Chat Forwarder', () => {
|
|
|
158
163
|
expect.any(Object)
|
|
159
164
|
);
|
|
160
165
|
|
|
161
|
-
subscribeCallbacks.onData(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
subscribeCallbacks.onData(
|
|
167
|
+
asEnvelopes([
|
|
168
|
+
{
|
|
169
|
+
id: 'msg-2',
|
|
170
|
+
role: 'agent',
|
|
171
|
+
content: 'Agent response',
|
|
172
|
+
timestamp: '',
|
|
173
|
+
},
|
|
174
|
+
])
|
|
175
|
+
);
|
|
169
176
|
|
|
170
177
|
await vi.waitFor(() => expect(mockMessagesCreate).toHaveBeenCalled());
|
|
171
178
|
|
|
@@ -190,14 +197,16 @@ describe('Daemon to Google Chat Forwarder', () => {
|
|
|
190
197
|
|
|
191
198
|
await vi.waitFor(() => expect(subscribeCallbacks).toBeTruthy());
|
|
192
199
|
|
|
193
|
-
subscribeCallbacks.onData(
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
200
|
+
subscribeCallbacks.onData(
|
|
201
|
+
asEnvelopes([
|
|
202
|
+
{
|
|
203
|
+
id: 'msg-2',
|
|
204
|
+
role: 'agent',
|
|
205
|
+
content: 'Here are the files',
|
|
206
|
+
files: ['/tmp/file1.png', '/tmp/file2.txt'],
|
|
207
|
+
},
|
|
208
|
+
])
|
|
209
|
+
);
|
|
201
210
|
|
|
202
211
|
await vi.waitFor(() => expect(mockMessagesCreate).toHaveBeenCalled());
|
|
203
212
|
|
|
@@ -232,14 +241,16 @@ describe('Daemon to Google Chat Forwarder', () => {
|
|
|
232
241
|
|
|
233
242
|
await vi.waitFor(() => expect(subscribeCallbacks).toBeTruthy());
|
|
234
243
|
|
|
235
|
-
subscribeCallbacks.onData(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
244
|
+
subscribeCallbacks.onData(
|
|
245
|
+
asEnvelopes([
|
|
246
|
+
{
|
|
247
|
+
id: 'msg-3',
|
|
248
|
+
role: 'agent',
|
|
249
|
+
content: 'Here are the files',
|
|
250
|
+
files: ['/tmp/file1.png', '/tmp/file2.txt'],
|
|
251
|
+
},
|
|
252
|
+
])
|
|
253
|
+
);
|
|
243
254
|
|
|
244
255
|
await vi.waitFor(() => expect(mockMessagesCreate).toHaveBeenCalled());
|
|
245
256
|
|
|
@@ -270,14 +281,16 @@ describe('Daemon to Google Chat Forwarder', () => {
|
|
|
270
281
|
|
|
271
282
|
mockDriveFilesCreate.mockRejectedValueOnce(new Error('Drive Auth Failed'));
|
|
272
283
|
|
|
273
|
-
subscribeCallbacks.onData(
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
284
|
+
subscribeCallbacks.onData(
|
|
285
|
+
asEnvelopes([
|
|
286
|
+
{
|
|
287
|
+
id: 'msg-drive-fail',
|
|
288
|
+
role: 'agent',
|
|
289
|
+
content: 'Here are the files',
|
|
290
|
+
files: ['/tmp/file1.png'],
|
|
291
|
+
},
|
|
292
|
+
])
|
|
293
|
+
);
|
|
281
294
|
|
|
282
295
|
await vi.waitFor(() => expect(mockMessagesCreate).toHaveBeenCalled());
|
|
283
296
|
|
|
@@ -313,10 +326,12 @@ describe('Daemon to Google Chat Forwarder', () => {
|
|
|
313
326
|
return Promise.resolve();
|
|
314
327
|
});
|
|
315
328
|
|
|
316
|
-
subscribeCallbacks.onData(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
329
|
+
subscribeCallbacks.onData(
|
|
330
|
+
asEnvelopes([
|
|
331
|
+
{ id: 'msg-err-1', role: 'agent', content: 'Agent response 1' },
|
|
332
|
+
{ id: 'msg-err-2', role: 'agent', content: 'Agent response 2' },
|
|
333
|
+
])
|
|
334
|
+
);
|
|
320
335
|
|
|
321
336
|
// Wait for the second message to be processed, meaning the first one didn't break the loop
|
|
322
337
|
await vi.waitFor(() => expect(callCount).toBe(2));
|
|
@@ -348,14 +363,16 @@ describe('Daemon to Google Chat Forwarder', () => {
|
|
|
348
363
|
|
|
349
364
|
await vi.waitFor(() => expect(subscribeCallbacks).toBeTruthy());
|
|
350
365
|
|
|
351
|
-
subscribeCallbacks.onData(
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
366
|
+
subscribeCallbacks.onData(
|
|
367
|
+
asEnvelopes([
|
|
368
|
+
{
|
|
369
|
+
id: 'msg-2',
|
|
370
|
+
role: 'policy',
|
|
371
|
+
status: 'pending',
|
|
372
|
+
content: 'Please approve this action',
|
|
373
|
+
},
|
|
374
|
+
])
|
|
375
|
+
);
|
|
359
376
|
|
|
360
377
|
await vi.waitFor(() => expect(mockMessagesCreate).toHaveBeenCalled());
|
|
361
378
|
|
|
@@ -434,14 +451,16 @@ describe('Daemon to Google Chat Forwarder', () => {
|
|
|
434
451
|
.mockRejectedValueOnce(new Error('Cannot send cardsV2'))
|
|
435
452
|
.mockResolvedValueOnce({});
|
|
436
453
|
|
|
437
|
-
subscribeCallbacks.onData(
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
454
|
+
subscribeCallbacks.onData(
|
|
455
|
+
asEnvelopes([
|
|
456
|
+
{
|
|
457
|
+
id: 'msg-2',
|
|
458
|
+
role: 'policy',
|
|
459
|
+
status: 'pending',
|
|
460
|
+
content: 'Please approve this action',
|
|
461
|
+
},
|
|
462
|
+
])
|
|
463
|
+
);
|
|
445
464
|
|
|
446
465
|
await vi.waitFor(() => expect(mockMessagesCreate).toHaveBeenCalledTimes(2));
|
|
447
466
|
|
|
@@ -473,7 +492,9 @@ describe('Daemon to Google Chat Forwarder', () => {
|
|
|
473
492
|
await vi.waitFor(() => expect(subscribeCallbacks).toBeTruthy(), { timeout: 1000 });
|
|
474
493
|
|
|
475
494
|
// Send a message, this updates the local memory cache to msg-local
|
|
476
|
-
subscribeCallbacks.onData(
|
|
495
|
+
subscribeCallbacks.onData(
|
|
496
|
+
asEnvelopes([{ id: 'msg-local', role: 'agent', content: 'Agent response' }])
|
|
497
|
+
);
|
|
477
498
|
|
|
478
499
|
await vi.waitFor(
|
|
479
500
|
() =>
|
|
@@ -500,7 +521,9 @@ describe('Daemon to Google Chat Forwarder', () => {
|
|
|
500
521
|
await vi.runAllTicks();
|
|
501
522
|
|
|
502
523
|
// Send another message to verify what the local cache holds
|
|
503
|
-
subscribeCallbacks.onData(
|
|
524
|
+
subscribeCallbacks.onData(
|
|
525
|
+
asEnvelopes([{ id: 'msg-latest', role: 'agent', content: 'Agent response 2' }])
|
|
526
|
+
);
|
|
504
527
|
|
|
505
528
|
// If local memory wins, the new write state will only contain msg-latest and not msg-stale
|
|
506
529
|
// If disk won, it would have reverted to msg-stale and then updated to msg-latest?
|
|
@@ -515,7 +538,9 @@ describe('Daemon to Google Chat Forwarder', () => {
|
|
|
515
538
|
|
|
516
539
|
await vi.advanceTimersByTimeAsync(6000);
|
|
517
540
|
|
|
518
|
-
subscribeCallbacks.onData(
|
|
541
|
+
subscribeCallbacks.onData(
|
|
542
|
+
asEnvelopes([{ id: 'msg-latest', role: 'agent', content: 'Agent response 2' }])
|
|
543
|
+
);
|
|
519
544
|
|
|
520
545
|
await vi.waitFor(
|
|
521
546
|
() =>
|