crewly 1.20.197 → 1.20.199
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/config/roles/orchestrator/prompt.md +8 -9
- package/config/roles/team-leader/prompt.md +6 -0
- package/config/skills/agent/computer-use/SKILL.md +16 -0
- package/config/skills/agent/core/ask-owner/SKILL.md +14 -0
- package/config/skills/agent/core/ask-owner/execute.sh +19 -1
- package/config/skills/agent/core/ask-owner/execute.test.sh +12 -0
- package/config/skills/agent/core/gmail-send/SKILL.md +16 -0
- package/config/skills/agent/core/reply-channel/SKILL.md +16 -0
- package/config/skills/agent/core/slack-post/SKILL.md +16 -0
- package/config/skills/agent/core/whatsapp-send/SKILL.md +16 -0
- package/config/skills/agent/remote-browser/SKILL.md +43 -7
- package/config/skills/registry.json +7 -7
- package/dist/backend/backend/src/constants.d.ts +159 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +175 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts +12 -1
- package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/browser/browser.controller.js +118 -3
- package/dist/backend/backend/src/controllers/browser/browser.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/browser/browser.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/browser/browser.routes.js +5 -1
- package/dist/backend/backend/src/controllers/browser/browser.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +37 -52
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/system/usage.controller.d.ts +14 -0
- package/dist/backend/backend/src/controllers/system/usage.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/system/usage.controller.js +35 -1
- package/dist/backend/backend/src/controllers/system/usage.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +13 -0
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +17 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +113 -2
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-heartbeat-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-heartbeat-monitor.service.js +5 -8
- package/dist/backend/backend/src/services/agent/agent-heartbeat-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +12 -0
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +275 -241
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js +5 -6
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.d.ts +6 -0
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.js +2 -1
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.js +12 -8
- package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/gemini-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/gemini-runtime.service.js +32 -27
- package/dist/backend/backend/src/services/agent/gemini-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/owner-stopped.registry.d.ts +44 -0
- package/dist/backend/backend/src/services/agent/owner-stopped.registry.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/owner-stopped.registry.js +54 -0
- package/dist/backend/backend/src/services/agent/owner-stopped.registry.js.map +1 -0
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +4 -4
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js +4 -8
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts +19 -4
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.js +28 -5
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.js.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-approval.service.d.ts +2 -2
- package/dist/backend/backend/src/services/browser/browser-approval.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-approval.service.js +13 -2
- package/dist/backend/backend/src/services/browser/browser-approval.service.js.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-outbound-guard.d.ts +214 -0
- package/dist/backend/backend/src/services/browser/browser-outbound-guard.d.ts.map +1 -0
- package/dist/backend/backend/src/services/browser/browser-outbound-guard.js +466 -0
- package/dist/backend/backend/src/services/browser/browser-outbound-guard.js.map +1 -0
- package/dist/backend/backend/src/services/browser/browser-session.service.d.ts +23 -2
- package/dist/backend/backend/src/services/browser/browser-session.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-session.service.js +110 -62
- package/dist/backend/backend/src/services/browser/browser-session.service.js.map +1 -1
- package/dist/backend/backend/src/services/browser/held-action-store.d.ts +4 -0
- package/dist/backend/backend/src/services/browser/held-action-store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/browser/held-action-store.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-initializer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-initializer.js +6 -8
- package/dist/backend/backend/src/services/cloud/cloud-initializer.js.map +1 -1
- package/dist/backend/backend/src/services/experiments/experiment.service.d.ts +15 -1
- package/dist/backend/backend/src/services/experiments/experiment.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/experiments/experiment.service.js +41 -12
- package/dist/backend/backend/src/services/experiments/experiment.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/input-blocked-retry.service.d.ts +129 -0
- package/dist/backend/backend/src/services/messaging/input-blocked-retry.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/messaging/input-blocked-retry.service.js +196 -0
- package/dist/backend/backend/src/services/messaging/input-blocked-retry.service.js.map +1 -0
- package/dist/backend/backend/src/services/messaging/message-queue.service.d.ts +21 -0
- package/dist/backend/backend/src/services/messaging/message-queue.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/message-queue.service.js +86 -11
- package/dist/backend/backend/src/services/messaging/message-queue.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.d.ts +46 -0
- package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.js +143 -22
- package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/agent-hook-state.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/agent-hook-state.js +5 -0
- package/dist/backend/backend/src/services/monitoring/agent-hook-state.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.d.ts +7 -0
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.js +21 -6
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.d.ts +49 -2
- package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.js +160 -55
- package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.d.ts +7 -0
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.js +21 -7
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts +71 -1
- package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/token-usage.service.js +193 -20
- package/dist/backend/backend/src/services/monitoring/token-usage.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js +5 -9
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts +11 -0
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +14 -0
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-terminal-buffer.d.ts +37 -0
- package/dist/backend/backend/src/services/session/pty/pty-terminal-buffer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-terminal-buffer.js +78 -0
- package/dist/backend/backend/src/services/session/pty/pty-terminal-buffer.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-backend.interface.d.ts +13 -0
- package/dist/backend/backend/src/services/session/session-backend.interface.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-backend.interface.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-command-helper.d.ts +118 -105
- package/dist/backend/backend/src/services/session/session-command-helper.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-command-helper.js +267 -298
- package/dist/backend/backend/src/services/session/session-command-helper.js.map +1 -1
- package/dist/backend/backend/src/services/session/tui-input-guard.d.ts +144 -0
- package/dist/backend/backend/src/services/session/tui-input-guard.d.ts.map +1 -0
- package/dist/backend/backend/src/services/session/tui-input-guard.js +312 -0
- package/dist/backend/backend/src/services/session/tui-input-guard.js.map +1 -0
- package/dist/backend/backend/src/services/slack/slack-agent-identity.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-identity.service.js +5 -0
- package/dist/backend/backend/src/services/slack/slack-agent-identity.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-cloud-config.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-cloud-config.service.js +5 -0
- package/dist/backend/backend/src/services/slack/slack-cloud-config.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +14 -0
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts +31 -0
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +87 -4
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.service.d.ts +24 -1
- package/dist/backend/backend/src/services/spend/spend-cap.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.service.js +57 -0
- package/dist/backend/backend/src/services/spend/spend-cap.service.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.store.d.ts +37 -1
- package/dist/backend/backend/src/services/spend/spend-cap.store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.store.js +85 -14
- package/dist/backend/backend/src/services/spend/spend-cap.store.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.wiring.js +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/trace/trace-store.d.ts +3 -1
- package/dist/backend/backend/src/services/trace/trace-store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/trace/trace-store.js +27 -15
- package/dist/backend/backend/src/services/trace/trace-store.js.map +1 -1
- package/dist/backend/backend/src/services/trace/trace.types.d.ts +2 -2
- package/dist/backend/backend/src/services/trace/trace.types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/trace/trace.types.js +4 -0
- package/dist/backend/backend/src/services/trace/trace.types.js.map +1 -1
- package/dist/backend/backend/src/services/trace/turn-origin.d.ts +70 -0
- package/dist/backend/backend/src/services/trace/turn-origin.d.ts.map +1 -0
- package/dist/backend/backend/src/services/trace/turn-origin.js +198 -0
- package/dist/backend/backend/src/services/trace/turn-origin.js.map +1 -0
- package/dist/backend/backend/src/services/usage/usage-backfill.service.d.ts +96 -0
- package/dist/backend/backend/src/services/usage/usage-backfill.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage/usage-backfill.service.js +257 -0
- package/dist/backend/backend/src/services/usage/usage-backfill.service.js.map +1 -0
- package/dist/backend/backend/src/services/v3/kr-tracking.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/kr-tracking.service.js +2 -1
- package/dist/backend/backend/src/services/v3/kr-tracking.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/okr-cascade.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/okr-cascade.service.js +2 -1
- package/dist/backend/backend/src/services/v3/okr-cascade.service.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts +28 -0
- package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/cron-task.service.js +121 -68
- package/dist/backend/backend/src/services/workflow/cron-task.service.js.map +1 -1
- package/dist/backend/backend/src/types/slack.types.d.ts +8 -0
- package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/slack.types.js.map +1 -1
- package/dist/backend/backend/src/utils/file-io.utils.d.ts +114 -1
- package/dist/backend/backend/src/utils/file-io.utils.d.ts.map +1 -1
- package/dist/backend/backend/src/utils/file-io.utils.js +236 -6
- package/dist/backend/backend/src/utils/file-io.utils.js.map +1 -1
- package/dist/backend/backend/src/utils/terminal-string-ops.d.ts.map +1 -1
- package/dist/backend/backend/src/utils/terminal-string-ops.js +3 -2
- package/dist/backend/backend/src/utils/terminal-string-ops.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +159 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +175 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +12 -0
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.js +275 -241
- package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/context-window-monitor.service.js +5 -6
- package/dist/cli/backend/src/services/agent/context-window-monitor.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.d.ts +6 -0
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.js +2 -1
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.js +12 -8
- package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/gemini-runtime.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/gemini-runtime.service.js +32 -27
- package/dist/cli/backend/src/services/agent/gemini-runtime.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js +4 -4
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.js +4 -8
- package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts +19 -4
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.js +28 -5
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/input-blocked-retry.service.d.ts +129 -0
- package/dist/cli/backend/src/services/messaging/input-blocked-retry.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/messaging/input-blocked-retry.service.js +196 -0
- package/dist/cli/backend/src/services/messaging/input-blocked-retry.service.js.map +1 -0
- package/dist/cli/backend/src/services/messaging/message-queue.service.d.ts +21 -0
- package/dist/cli/backend/src/services/messaging/message-queue.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/messaging/message-queue.service.js +86 -11
- package/dist/cli/backend/src/services/messaging/message-queue.service.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.d.ts +46 -0
- package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.js +143 -22
- package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.js.map +1 -1
- package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts +71 -1
- package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/monitoring/token-usage.service.js +193 -20
- package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -1
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.d.ts +11 -0
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.js +14 -0
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.d.ts +37 -0
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.d.ts.map +1 -1
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.js +78 -0
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.js.map +1 -1
- package/dist/cli/backend/src/services/session/session-backend.interface.d.ts +13 -0
- package/dist/cli/backend/src/services/session/session-backend.interface.d.ts.map +1 -1
- package/dist/cli/backend/src/services/session/session-backend.interface.js.map +1 -1
- package/dist/cli/backend/src/services/session/session-command-helper.d.ts +118 -105
- package/dist/cli/backend/src/services/session/session-command-helper.d.ts.map +1 -1
- package/dist/cli/backend/src/services/session/session-command-helper.js +267 -298
- package/dist/cli/backend/src/services/session/session-command-helper.js.map +1 -1
- package/dist/cli/backend/src/services/session/tui-input-guard.d.ts +144 -0
- package/dist/cli/backend/src/services/session/tui-input-guard.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/tui-input-guard.js +312 -0
- package/dist/cli/backend/src/services/session/tui-input-guard.js.map +1 -0
- package/dist/cli/backend/src/services/slack/slack-agent-identity.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-identity.service.js +5 -0
- package/dist/cli/backend/src/services/slack/slack-agent-identity.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js +14 -0
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts +31 -0
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +87 -4
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/cli/backend/src/services/trace/trace-store.d.ts +3 -1
- package/dist/cli/backend/src/services/trace/trace-store.d.ts.map +1 -1
- package/dist/cli/backend/src/services/trace/trace-store.js +27 -15
- package/dist/cli/backend/src/services/trace/trace-store.js.map +1 -1
- package/dist/cli/backend/src/services/trace/trace.types.d.ts +2 -2
- package/dist/cli/backend/src/services/trace/trace.types.d.ts.map +1 -1
- package/dist/cli/backend/src/services/trace/trace.types.js +4 -0
- package/dist/cli/backend/src/services/trace/trace.types.js.map +1 -1
- package/dist/cli/backend/src/services/trace/turn-origin.d.ts +70 -0
- package/dist/cli/backend/src/services/trace/turn-origin.d.ts.map +1 -0
- package/dist/cli/backend/src/services/trace/turn-origin.js +198 -0
- package/dist/cli/backend/src/services/trace/turn-origin.js.map +1 -0
- package/dist/cli/backend/src/services/v3/kr-tracking.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/kr-tracking.service.js +2 -1
- package/dist/cli/backend/src/services/v3/kr-tracking.service.js.map +1 -1
- package/dist/cli/backend/src/services/workflow/cron-task.service.d.ts +28 -0
- package/dist/cli/backend/src/services/workflow/cron-task.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/workflow/cron-task.service.js +121 -68
- package/dist/cli/backend/src/services/workflow/cron-task.service.js.map +1 -1
- package/dist/cli/backend/src/types/slack.types.d.ts +8 -0
- package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/slack.types.js.map +1 -1
- package/dist/cli/backend/src/utils/file-io.utils.d.ts +114 -1
- package/dist/cli/backend/src/utils/file-io.utils.d.ts.map +1 -1
- package/dist/cli/backend/src/utils/file-io.utils.js +236 -6
- package/dist/cli/backend/src/utils/file-io.utils.js.map +1 -1
- package/dist/cli/backend/src/utils/terminal-string-ops.d.ts.map +1 -1
- package/dist/cli/backend/src/utils/terminal-string-ops.js +3 -2
- package/dist/cli/backend/src/utils/terminal-string-ops.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/backend/src/services/agent/agent-suspend.service.d.ts +0 -118
- package/dist/cli/backend/src/services/agent/agent-suspend.service.d.ts.map +0 -1
- package/dist/cli/backend/src/services/agent/agent-suspend.service.js +0 -304
- package/dist/cli/backend/src/services/agent/agent-suspend.service.js.map +0 -1
- package/dist/cli/backend/src/services/agent/disk-cleanup.service.d.ts +0 -100
- package/dist/cli/backend/src/services/agent/disk-cleanup.service.d.ts.map +0 -1
- package/dist/cli/backend/src/services/agent/disk-cleanup.service.js +0 -149
- package/dist/cli/backend/src/services/agent/disk-cleanup.service.js.map +0 -1
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser outbound guard — which agent browser actions publish something as
|
|
3
|
+
* the owner, so they must be held for an owner approval card.
|
|
4
|
+
*
|
|
5
|
+
* Why (2026-10-03): an agent posted a LinkedIn reply as the owner without
|
|
6
|
+
* approval. The existing check (`matchIrreversible`) only read a short word
|
|
7
|
+
* list against the agent's selector, so a LinkedIn reply went through:
|
|
8
|
+
* `button.comments-comment-box__submit-button` hides "submit" behind `__`
|
|
9
|
+
* (a word character, so `\bsubmit\b` never matched), "Reply" and "Comment"
|
|
10
|
+
* were not on the list, a click by coordinates or by element ref carried no
|
|
11
|
+
* words at all, `type` with a trailing newline and `Ctrl+Enter`/`Cmd+Enter`
|
|
12
|
+
* keys were not checked, and `el['click']()` in a page script was not seen
|
|
13
|
+
* as acting.
|
|
14
|
+
*
|
|
15
|
+
* This module closes those paths, without holding what only reads:
|
|
16
|
+
*
|
|
17
|
+
* - Descriptors are split into words at punctuation (`__submit-button` →
|
|
18
|
+
* "submit button"), not at camelCase (code identifiers are not controls).
|
|
19
|
+
* - A control whose whole label is Reply/Comment/Post/Send/Tweet (plus
|
|
20
|
+
* Share/Connect/Invite on social sites) is held; bare "comment"/"tweet"
|
|
21
|
+
* in class names (a comment item, a tweet being read) are not.
|
|
22
|
+
* - Any key that submits (Enter, Return, with or without modifiers) and any
|
|
23
|
+
* typed text containing a newline or a submit flag is held.
|
|
24
|
+
* - A page script is held when it acts AND sends a writing request or names
|
|
25
|
+
* a submit control — not for clicking "See more".
|
|
26
|
+
* - On social and messaging sites (LinkedIn, X, Facebook, Instagram, Reddit,
|
|
27
|
+
* Gmail/Outlook web, Slack web, WhatsApp web, …) a click that names no
|
|
28
|
+
* control (coordinates, refs) is held: there the harness cannot tell a
|
|
29
|
+
* "Post" from any other button.
|
|
30
|
+
*
|
|
31
|
+
* @module services/browser/browser-outbound-guard
|
|
32
|
+
*/
|
|
33
|
+
/** Where the action happens, as far as the harness knows. */
|
|
34
|
+
export interface OutboundContext {
|
|
35
|
+
/** URL of the tab the action is in (read from the browser), when known */
|
|
36
|
+
url?: string;
|
|
37
|
+
/** The tab the action is in, when known */
|
|
38
|
+
tabId?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Host of a URL, lower case, '' when unknown or unparsable.
|
|
42
|
+
*
|
|
43
|
+
* @param url - URL
|
|
44
|
+
* @returns Host
|
|
45
|
+
*/
|
|
46
|
+
export declare function siteOf(url: string | undefined): string;
|
|
47
|
+
/**
|
|
48
|
+
* The page an action is on, for scoping a draft: host + path + hash (Gmail
|
|
49
|
+
* keeps the compose/thread context in the hash). '' when unknown.
|
|
50
|
+
*
|
|
51
|
+
* @param url - URL
|
|
52
|
+
* @returns Page key
|
|
53
|
+
*/
|
|
54
|
+
export declare function pageOf(url: string | undefined): string;
|
|
55
|
+
/**
|
|
56
|
+
* Whether an input is a search field — typing a query there is not a draft:
|
|
57
|
+
* `type=search`, `role=searchbox`, a name of `q`/`query`/`search` (Gmail's
|
|
58
|
+
* `input[name="q"]`), an aria-label or placeholder naming search, or a
|
|
59
|
+
* `role=combobox` input. A combobox that is contenteditable or a textarea is
|
|
60
|
+
* a compose box (LinkedIn, X), not search.
|
|
61
|
+
*
|
|
62
|
+
* @param params - Tool params
|
|
63
|
+
* @returns True for a search field
|
|
64
|
+
*/
|
|
65
|
+
export declare function isSearchField(params: Record<string, unknown> | undefined): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Whether a key press pastes (Cmd/Ctrl+V): pasting into an editable writes a
|
|
68
|
+
* draft the harness cannot read.
|
|
69
|
+
*
|
|
70
|
+
* @param params - pressKey params
|
|
71
|
+
* @returns True for a paste chord
|
|
72
|
+
*/
|
|
73
|
+
export declare function isPasteKey(params: Record<string, unknown> | undefined): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Whether a key press activates a focused button or link (Space / Enter).
|
|
76
|
+
*
|
|
77
|
+
* @param params - pressKey params
|
|
78
|
+
* @returns True for Space or Enter
|
|
79
|
+
*/
|
|
80
|
+
export declare function isActivateKey(params: Record<string, unknown> | undefined): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Whether a URL is on a social or messaging site, where posting reaches
|
|
83
|
+
* other people as the owner.
|
|
84
|
+
*
|
|
85
|
+
* @param url - Page URL
|
|
86
|
+
* @returns True for a listed host or any of its subdomains
|
|
87
|
+
*/
|
|
88
|
+
export declare function isSocialOrMessagingSite(url: string | undefined): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Split a selector/label/script into words at punctuation, so word-boundary
|
|
91
|
+
* matching sees through CSS naming (`comments-comment-box__submit-button` →
|
|
92
|
+
* "comments comment box submit button"). camelCase is NOT split: code
|
|
93
|
+
* identifiers (`postCount`, `commentsList`) are not controls.
|
|
94
|
+
*
|
|
95
|
+
* @param text - Raw descriptor
|
|
96
|
+
* @returns Space-separated words
|
|
97
|
+
*/
|
|
98
|
+
export declare function toWords(text: string): string;
|
|
99
|
+
/**
|
|
100
|
+
* The words that describe what a click/select names: selector, text, value,
|
|
101
|
+
* aria label, label, name, title.
|
|
102
|
+
*
|
|
103
|
+
* @param params - Tool params
|
|
104
|
+
* @returns Descriptor text ('' when the action names nothing)
|
|
105
|
+
*/
|
|
106
|
+
export declare function descriptorOf(params: Record<string, unknown> | undefined): string;
|
|
107
|
+
/**
|
|
108
|
+
* Whole labels an action names: its `text`/`ariaLabel`/`label`, and labels
|
|
109
|
+
* quoted inside a selector (`:has-text("Reply")`, `[aria-label="Post"]`,
|
|
110
|
+
* `text=Send`) or a script (`b.innerText === 'Reply'`).
|
|
111
|
+
*
|
|
112
|
+
* @param params - Tool params
|
|
113
|
+
* @returns Labels, lower case, trimmed
|
|
114
|
+
*/
|
|
115
|
+
export declare function labelsOf(params: Record<string, unknown> | undefined): string[];
|
|
116
|
+
/**
|
|
117
|
+
* Whether a key name submits: Enter/Return in any spelling, alone or with
|
|
118
|
+
* modifiers ("Enter", "NumpadEnter", "Return", "Ctrl+Enter", "Cmd+Enter",
|
|
119
|
+
* "Meta+Enter", "\n").
|
|
120
|
+
*
|
|
121
|
+
* @param key - Key name as passed
|
|
122
|
+
* @returns True for a submitting key
|
|
123
|
+
*/
|
|
124
|
+
export declare function isSubmitKey(key: string): boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Whether typed text submits: it contains a newline, or the call asks to
|
|
127
|
+
* press Enter / submit after typing.
|
|
128
|
+
*
|
|
129
|
+
* @param params - `type` / `fill` / `insertText` params
|
|
130
|
+
* @returns True when the call submits
|
|
131
|
+
*/
|
|
132
|
+
export declare function typedTextSubmits(params: Record<string, unknown> | undefined): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Whether a page script sends a request that writes: `sendBeacon`, an XHR
|
|
135
|
+
* opened with a writing method, or a `fetch` that is not provably a GET —
|
|
136
|
+
* a literal writing method anywhere in the script, or any options argument
|
|
137
|
+
* (it may carry `method: 'POST'` through a variable).
|
|
138
|
+
*
|
|
139
|
+
* @param code - Script source
|
|
140
|
+
* @returns True when it may write
|
|
141
|
+
*/
|
|
142
|
+
export declare function scriptWritesRequest(code: string): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Whether a page script acts (rather than reads): clicks in any form,
|
|
145
|
+
* submits, fires events, edits content, or sends a request that writes.
|
|
146
|
+
*
|
|
147
|
+
* @param code - Script source
|
|
148
|
+
* @returns True when it acts
|
|
149
|
+
*/
|
|
150
|
+
export declare function scriptActs(code: string): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Whether a script writes text into the page — a draft being composed.
|
|
153
|
+
*
|
|
154
|
+
* @param code - Script source
|
|
155
|
+
* @returns True when it edits content
|
|
156
|
+
*/
|
|
157
|
+
export declare function scriptEditsContent(code: string): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* The selectors a script looks elements up by (`querySelector('…')`,
|
|
160
|
+
* `closest('…')`, `getElementById('…')`, …). Words are matched in these
|
|
161
|
+
* only — never in identifiers (`x.send()` is not sending, `postCount` is not
|
|
162
|
+
* posting) nor in text the script writes (a draft saying "Agree.").
|
|
163
|
+
*
|
|
164
|
+
* @param code - Script source
|
|
165
|
+
* @returns The selectors joined with spaces
|
|
166
|
+
*/
|
|
167
|
+
export declare function scriptLiterals(code: string): string;
|
|
168
|
+
/**
|
|
169
|
+
* Match the outward-facing words against a descriptor (already split into
|
|
170
|
+
* words at punctuation).
|
|
171
|
+
*
|
|
172
|
+
* @param words - Descriptor words
|
|
173
|
+
* @returns Label, or null
|
|
174
|
+
*/
|
|
175
|
+
export declare function matchOutboundWords(words: string): string | null;
|
|
176
|
+
/**
|
|
177
|
+
* Decide whether an action publishes or submits something outward, beyond
|
|
178
|
+
* the base irreversible-word check. Returns a short label, or null.
|
|
179
|
+
*
|
|
180
|
+
* @param tool - Browser tool
|
|
181
|
+
* @param params - Its params
|
|
182
|
+
* @param context - Where it happens
|
|
183
|
+
* @returns Label for the hold, or null
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* matchOutbound('click', { selector: 'button.comments-comment-box__submit-button' }, { url: 'https://www.linkedin.com/feed/' });
|
|
188
|
+
* // 'submitting'
|
|
189
|
+
* matchOutbound('click', { selector: 'article[data-testid="tweet"]' }, { url: 'https://x.com/home' });
|
|
190
|
+
* // null — reading a tweet
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export declare function matchOutbound(tool: string, params: Record<string, unknown> | undefined, context?: OutboundContext): string | null;
|
|
194
|
+
/**
|
|
195
|
+
* The text an action would put on the page (what a post would say), for the
|
|
196
|
+
* approval card. Only `type`/`fill`/`insertText` carry it directly; a script
|
|
197
|
+
* is shown as source. Never for a field that looks secret (password, code,
|
|
198
|
+
* token): the card goes to Slack.
|
|
199
|
+
*
|
|
200
|
+
* @param tool - Browser tool
|
|
201
|
+
* @param params - Its params
|
|
202
|
+
* @returns Text, or undefined
|
|
203
|
+
*/
|
|
204
|
+
export declare function draftTextOf(tool: string, params: Record<string, unknown> | undefined): string | undefined;
|
|
205
|
+
/**
|
|
206
|
+
* Identity of an action for one-time approvals: an approval is spent only
|
|
207
|
+
* by the action the owner approved (same tool, same target, same text).
|
|
208
|
+
*
|
|
209
|
+
* @param tool - Browser tool
|
|
210
|
+
* @param params - Its params
|
|
211
|
+
* @returns Stable fingerprint
|
|
212
|
+
*/
|
|
213
|
+
export declare function actionFingerprint(tool: string, params: Record<string, unknown> | undefined): string;
|
|
214
|
+
//# sourceMappingURL=browser-outbound-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-outbound-guard.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/browser/browser-outbound-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,6DAA6D;AAC7D,MAAM,WAAW,eAAe;IAC/B,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAEtD;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQtD;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,OAAO,CAelF;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,OAAO,CAQ/E;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,OAAO,CAGlF;AAiBD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAIxE;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK5C;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAMhF;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,EAAE,CAsB9E;AAgCD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,OAAO,CAIrF;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAsBzD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAIhD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK/D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC3C,OAAO,GAAE,eAAoB,GAC3B,MAAM,GAAG,IAAI,CA+Cf;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAYzG;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAMnG"}
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser outbound guard — which agent browser actions publish something as
|
|
3
|
+
* the owner, so they must be held for an owner approval card.
|
|
4
|
+
*
|
|
5
|
+
* Why (2026-10-03): an agent posted a LinkedIn reply as the owner without
|
|
6
|
+
* approval. The existing check (`matchIrreversible`) only read a short word
|
|
7
|
+
* list against the agent's selector, so a LinkedIn reply went through:
|
|
8
|
+
* `button.comments-comment-box__submit-button` hides "submit" behind `__`
|
|
9
|
+
* (a word character, so `\bsubmit\b` never matched), "Reply" and "Comment"
|
|
10
|
+
* were not on the list, a click by coordinates or by element ref carried no
|
|
11
|
+
* words at all, `type` with a trailing newline and `Ctrl+Enter`/`Cmd+Enter`
|
|
12
|
+
* keys were not checked, and `el['click']()` in a page script was not seen
|
|
13
|
+
* as acting.
|
|
14
|
+
*
|
|
15
|
+
* This module closes those paths, without holding what only reads:
|
|
16
|
+
*
|
|
17
|
+
* - Descriptors are split into words at punctuation (`__submit-button` →
|
|
18
|
+
* "submit button"), not at camelCase (code identifiers are not controls).
|
|
19
|
+
* - A control whose whole label is Reply/Comment/Post/Send/Tweet (plus
|
|
20
|
+
* Share/Connect/Invite on social sites) is held; bare "comment"/"tweet"
|
|
21
|
+
* in class names (a comment item, a tweet being read) are not.
|
|
22
|
+
* - Any key that submits (Enter, Return, with or without modifiers) and any
|
|
23
|
+
* typed text containing a newline or a submit flag is held.
|
|
24
|
+
* - A page script is held when it acts AND sends a writing request or names
|
|
25
|
+
* a submit control — not for clicking "See more".
|
|
26
|
+
* - On social and messaging sites (LinkedIn, X, Facebook, Instagram, Reddit,
|
|
27
|
+
* Gmail/Outlook web, Slack web, WhatsApp web, …) a click that names no
|
|
28
|
+
* control (coordinates, refs) is held: there the harness cannot tell a
|
|
29
|
+
* "Post" from any other button.
|
|
30
|
+
*
|
|
31
|
+
* @module services/browser/browser-outbound-guard
|
|
32
|
+
*/
|
|
33
|
+
import { createHash } from 'crypto';
|
|
34
|
+
import { BROWSER_OUTBOUND_GUARD } from '../../constants.js';
|
|
35
|
+
/**
|
|
36
|
+
* Host of a URL, lower case, '' when unknown or unparsable.
|
|
37
|
+
*
|
|
38
|
+
* @param url - URL
|
|
39
|
+
* @returns Host
|
|
40
|
+
*/
|
|
41
|
+
export function siteOf(url) {
|
|
42
|
+
return hostOf(url);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The page an action is on, for scoping a draft: host + path + hash (Gmail
|
|
46
|
+
* keeps the compose/thread context in the hash). '' when unknown.
|
|
47
|
+
*
|
|
48
|
+
* @param url - URL
|
|
49
|
+
* @returns Page key
|
|
50
|
+
*/
|
|
51
|
+
export function pageOf(url) {
|
|
52
|
+
if (!url)
|
|
53
|
+
return '';
|
|
54
|
+
try {
|
|
55
|
+
const u = new URL(url.includes('://') ? url : `https://${url}`);
|
|
56
|
+
return `${u.hostname.toLowerCase()}${u.pathname.replace(/\/+$/, '')}${u.hash}`;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return '';
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Whether an input is a search field — typing a query there is not a draft:
|
|
64
|
+
* `type=search`, `role=searchbox`, a name of `q`/`query`/`search` (Gmail's
|
|
65
|
+
* `input[name="q"]`), an aria-label or placeholder naming search, or a
|
|
66
|
+
* `role=combobox` input. A combobox that is contenteditable or a textarea is
|
|
67
|
+
* a compose box (LinkedIn, X), not search.
|
|
68
|
+
*
|
|
69
|
+
* @param params - Tool params
|
|
70
|
+
* @returns True for a search field
|
|
71
|
+
*/
|
|
72
|
+
export function isSearchField(params) {
|
|
73
|
+
const str = (v) => (typeof v === 'string' ? v : '');
|
|
74
|
+
const selector = str(params?.selector);
|
|
75
|
+
const role = `${str(params?.role)} ${(/\[\s*role\s*=\s*["']?([a-z]+)/i.exec(selector) ?? [])[1] ?? ''}`.toLowerCase();
|
|
76
|
+
const compose = /contenteditable|textarea/i.test(selector) || params?.contentEditable === true || /textarea/i.test(str(params?.tagName));
|
|
77
|
+
if (/combobox/.test(role) && compose)
|
|
78
|
+
return false;
|
|
79
|
+
if (/searchbox/.test(role) || /combobox/.test(role))
|
|
80
|
+
return true;
|
|
81
|
+
const name = str(params?.name) || ((/\[\s*name\s*=\s*["']?([^"'\]\s]+)/i.exec(selector) ?? [])[1] ?? '');
|
|
82
|
+
if (/^(q|query|search|search_query|keywords?)$/i.test(name))
|
|
83
|
+
return true;
|
|
84
|
+
if (/^search$/i.test(str(params?.type)) || /\[\s*type\s*=\s*["']?search/i.test(selector))
|
|
85
|
+
return true;
|
|
86
|
+
const labelled = [params?.ariaLabel, params?.label, params?.placeholder]
|
|
87
|
+
.map(str)
|
|
88
|
+
.join(' ');
|
|
89
|
+
if (/search|搜索/i.test(labelled) || /aria-label\s*=\s*["'][^"']*search/i.test(selector))
|
|
90
|
+
return true;
|
|
91
|
+
return !compose && /search|搜索/i.test(selector);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Whether a key press pastes (Cmd/Ctrl+V): pasting into an editable writes a
|
|
95
|
+
* draft the harness cannot read.
|
|
96
|
+
*
|
|
97
|
+
* @param params - pressKey params
|
|
98
|
+
* @returns True for a paste chord
|
|
99
|
+
*/
|
|
100
|
+
export function isPasteKey(params) {
|
|
101
|
+
const key = typeof params?.key === 'string' ? params.key.trim() : '';
|
|
102
|
+
const modifiers = (Array.isArray(params?.modifiers) ? params.modifiers : [])
|
|
103
|
+
.filter((v) => typeof v === 'string')
|
|
104
|
+
.join('+');
|
|
105
|
+
const chord = `${modifiers}+${key}`;
|
|
106
|
+
const keyIsV = /(^|\+)v$/i.test(key);
|
|
107
|
+
return keyIsV && /(meta|cmd|command|ctrl|control)/i.test(chord);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Whether a key press activates a focused button or link (Space / Enter).
|
|
111
|
+
*
|
|
112
|
+
* @param params - pressKey params
|
|
113
|
+
* @returns True for Space or Enter
|
|
114
|
+
*/
|
|
115
|
+
export function isActivateKey(params) {
|
|
116
|
+
const key = typeof params?.key === 'string' ? params.key : '';
|
|
117
|
+
return key === ' ' || /^space(bar)?$/i.test(key) || isSubmitKey(key);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Host of a URL, lower case, '' when it cannot be parsed.
|
|
121
|
+
*
|
|
122
|
+
* @param url - URL
|
|
123
|
+
* @returns Host
|
|
124
|
+
*/
|
|
125
|
+
function hostOf(url) {
|
|
126
|
+
if (!url)
|
|
127
|
+
return '';
|
|
128
|
+
try {
|
|
129
|
+
return new URL(url.includes('://') ? url : `https://${url}`).hostname.toLowerCase();
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return '';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Whether a URL is on a social or messaging site, where posting reaches
|
|
137
|
+
* other people as the owner.
|
|
138
|
+
*
|
|
139
|
+
* @param url - Page URL
|
|
140
|
+
* @returns True for a listed host or any of its subdomains
|
|
141
|
+
*/
|
|
142
|
+
export function isSocialOrMessagingSite(url) {
|
|
143
|
+
const host = hostOf(url);
|
|
144
|
+
if (!host)
|
|
145
|
+
return false;
|
|
146
|
+
return BROWSER_OUTBOUND_GUARD.SOCIAL_MESSAGING_HOSTS.some((h) => host === h || host.endsWith(`.${h}`));
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Split a selector/label/script into words at punctuation, so word-boundary
|
|
150
|
+
* matching sees through CSS naming (`comments-comment-box__submit-button` →
|
|
151
|
+
* "comments comment box submit button"). camelCase is NOT split: code
|
|
152
|
+
* identifiers (`postCount`, `commentsList`) are not controls.
|
|
153
|
+
*
|
|
154
|
+
* @param text - Raw descriptor
|
|
155
|
+
* @returns Space-separated words
|
|
156
|
+
*/
|
|
157
|
+
export function toWords(text) {
|
|
158
|
+
return text
|
|
159
|
+
.replace(/[_\-.#[\]=:"'`()>+~*^$|/\\,;{}]+/g, ' ')
|
|
160
|
+
.replace(/\s+/g, ' ')
|
|
161
|
+
.trim();
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The words that describe what a click/select names: selector, text, value,
|
|
165
|
+
* aria label, label, name, title.
|
|
166
|
+
*
|
|
167
|
+
* @param params - Tool params
|
|
168
|
+
* @returns Descriptor text ('' when the action names nothing)
|
|
169
|
+
*/
|
|
170
|
+
export function descriptorOf(params) {
|
|
171
|
+
const fields = ['selector', 'text', 'value', 'ariaLabel', 'label', 'name', 'title'];
|
|
172
|
+
return fields
|
|
173
|
+
.map((f) => params?.[f])
|
|
174
|
+
.filter((v) => typeof v === 'string' && v.trim() !== '')
|
|
175
|
+
.join(' ');
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Whole labels an action names: its `text`/`ariaLabel`/`label`, and labels
|
|
179
|
+
* quoted inside a selector (`:has-text("Reply")`, `[aria-label="Post"]`,
|
|
180
|
+
* `text=Send`) or a script (`b.innerText === 'Reply'`).
|
|
181
|
+
*
|
|
182
|
+
* @param params - Tool params
|
|
183
|
+
* @returns Labels, lower case, trimmed
|
|
184
|
+
*/
|
|
185
|
+
export function labelsOf(params) {
|
|
186
|
+
const labels = [];
|
|
187
|
+
for (const f of ['text', 'ariaLabel', 'label', 'value']) {
|
|
188
|
+
const v = params?.[f];
|
|
189
|
+
if (typeof v === 'string' && v.trim())
|
|
190
|
+
labels.push(v);
|
|
191
|
+
}
|
|
192
|
+
for (const f of ['selector', 'code']) {
|
|
193
|
+
const v = params?.[f];
|
|
194
|
+
if (typeof v !== 'string')
|
|
195
|
+
continue;
|
|
196
|
+
// Attribute labels and text pseudo-selectors (in a selector, or a
|
|
197
|
+
// selector string inside a script). Not data-testid & co: those name
|
|
198
|
+
// what an element is (a tweet), not what a button says.
|
|
199
|
+
for (const m of v.matchAll(/\[\s*(?:aria-label|title|value|name|alt)\s*[*^$~|]?=\s*\\?["']([^"'\\]{1,40})\\?["']\s*\]/gi))
|
|
200
|
+
labels.push(m[1]);
|
|
201
|
+
for (const m of v.matchAll(/:(?:has-text|text|contains|text-is)\(\s*\\?["']([^"'\\]{1,40})\\?["']\s*\)/gi))
|
|
202
|
+
labels.push(m[1]);
|
|
203
|
+
const textEq = /^text\s*=\s*(.+)$/i.exec(v.trim());
|
|
204
|
+
if (f === 'selector' && textEq)
|
|
205
|
+
labels.push(textEq[1]);
|
|
206
|
+
if (f === 'code') {
|
|
207
|
+
// A script finding a button by its text: `b.innerText === 'Reply'`.
|
|
208
|
+
for (const m of v.matchAll(/(?:===?|includes\(|startsWith\()\s*['"`]([^'"`\n]{1,40})['"`]/g))
|
|
209
|
+
labels.push(m[1]);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return labels.map((l) => l.trim().toLowerCase()).filter((l) => l.length > 0);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Whether an action names a control whose whole label submits.
|
|
216
|
+
*
|
|
217
|
+
* @param params - Tool params
|
|
218
|
+
* @param social - On a social/messaging site (adds Share/Connect/…)
|
|
219
|
+
* @returns The label, or null
|
|
220
|
+
*/
|
|
221
|
+
function submitLabel(params, social) {
|
|
222
|
+
const set = new Set([
|
|
223
|
+
...BROWSER_OUTBOUND_GUARD.SUBMIT_LABELS,
|
|
224
|
+
...(social ? BROWSER_OUTBOUND_GUARD.SOCIAL_ONLY_LABELS : []),
|
|
225
|
+
]);
|
|
226
|
+
return labelsOf(params).find((l) => set.has(l)) ?? null;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* What a submit label does, in the hold's words: "Send" → sending,
|
|
230
|
+
* "Reply"/"Comment" → replying, "Post"/"Tweet" → publishing, …
|
|
231
|
+
*
|
|
232
|
+
* @param label - Lower-case label
|
|
233
|
+
* @returns Short description
|
|
234
|
+
*/
|
|
235
|
+
function labelCategory(label) {
|
|
236
|
+
const byWords = matchOutboundWords(label);
|
|
237
|
+
if (byWords)
|
|
238
|
+
return byWords;
|
|
239
|
+
if (/reply|comment|回复|评论/.test(label))
|
|
240
|
+
return 'replying';
|
|
241
|
+
if (/post|tweet|发布|发表/.test(label))
|
|
242
|
+
return 'publishing';
|
|
243
|
+
return 'sharing';
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Whether a key name submits: Enter/Return in any spelling, alone or with
|
|
247
|
+
* modifiers ("Enter", "NumpadEnter", "Return", "Ctrl+Enter", "Cmd+Enter",
|
|
248
|
+
* "Meta+Enter", "\n").
|
|
249
|
+
*
|
|
250
|
+
* @param key - Key name as passed
|
|
251
|
+
* @returns True for a submitting key
|
|
252
|
+
*/
|
|
253
|
+
export function isSubmitKey(key) {
|
|
254
|
+
return /enter|return/i.test(key) || /[\r\n]/.test(key);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Whether typed text submits: it contains a newline, or the call asks to
|
|
258
|
+
* press Enter / submit after typing.
|
|
259
|
+
*
|
|
260
|
+
* @param params - `type` / `fill` / `insertText` params
|
|
261
|
+
* @returns True when the call submits
|
|
262
|
+
*/
|
|
263
|
+
export function typedTextSubmits(params) {
|
|
264
|
+
const text = [params?.text, params?.value].filter((v) => typeof v === 'string').join('');
|
|
265
|
+
if (/[\r\n]/.test(text))
|
|
266
|
+
return true;
|
|
267
|
+
return ['submit', 'pressEnter', 'enter', 'sendEnter'].some((k) => params?.[k] === true);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Whether a page script sends a request that writes: `sendBeacon`, an XHR
|
|
271
|
+
* opened with a writing method, or a `fetch` that is not provably a GET —
|
|
272
|
+
* a literal writing method anywhere in the script, or any options argument
|
|
273
|
+
* (it may carry `method: 'POST'` through a variable).
|
|
274
|
+
*
|
|
275
|
+
* @param code - Script source
|
|
276
|
+
* @returns True when it may write
|
|
277
|
+
*/
|
|
278
|
+
export function scriptWritesRequest(code) {
|
|
279
|
+
if (/sendBeacon\s*\(/.test(code))
|
|
280
|
+
return true;
|
|
281
|
+
if (/\.open\s*\(\s*['"`](POST|PUT|PATCH|DELETE)['"`]/i.test(code))
|
|
282
|
+
return true;
|
|
283
|
+
if (!/\bfetch\s*\(/.test(code))
|
|
284
|
+
return false;
|
|
285
|
+
if (/method\s*:\s*['"`](POST|PUT|PATCH|DELETE)['"`]/i.test(code))
|
|
286
|
+
return true;
|
|
287
|
+
const onlyGet = /method\s*:\s*['"`]GET['"`]/i.test(code);
|
|
288
|
+
for (const m of code.matchAll(/\bfetch\s*\(/g)) {
|
|
289
|
+
// Walk the call's arguments; a top-level comma means an options argument.
|
|
290
|
+
let depth = 0;
|
|
291
|
+
for (let i = (m.index ?? 0) + m[0].length; i < code.length; i++) {
|
|
292
|
+
const c = code[i];
|
|
293
|
+
if (c === '(' || c === '[' || c === '{')
|
|
294
|
+
depth++;
|
|
295
|
+
else if (c === ')' || c === ']' || c === '}') {
|
|
296
|
+
if (depth === 0)
|
|
297
|
+
break;
|
|
298
|
+
depth--;
|
|
299
|
+
}
|
|
300
|
+
else if (c === ',' && depth === 0) {
|
|
301
|
+
if (!onlyGet)
|
|
302
|
+
return true;
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Whether a page script acts (rather than reads): clicks in any form,
|
|
311
|
+
* submits, fires events, edits content, or sends a request that writes.
|
|
312
|
+
*
|
|
313
|
+
* @param code - Script source
|
|
314
|
+
* @returns True when it acts
|
|
315
|
+
*/
|
|
316
|
+
export function scriptActs(code) {
|
|
317
|
+
return BROWSER_OUTBOUND_GUARD.SCRIPT_ACTS.test(code)
|
|
318
|
+
|| BROWSER_OUTBOUND_GUARD.SCRIPT_EDITS_CONTENT.test(code)
|
|
319
|
+
|| scriptWritesRequest(code);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Whether a script writes text into the page — a draft being composed.
|
|
323
|
+
*
|
|
324
|
+
* @param code - Script source
|
|
325
|
+
* @returns True when it edits content
|
|
326
|
+
*/
|
|
327
|
+
export function scriptEditsContent(code) {
|
|
328
|
+
return BROWSER_OUTBOUND_GUARD.SCRIPT_EDITS_CONTENT.test(code);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* The selectors a script looks elements up by (`querySelector('…')`,
|
|
332
|
+
* `closest('…')`, `getElementById('…')`, …). Words are matched in these
|
|
333
|
+
* only — never in identifiers (`x.send()` is not sending, `postCount` is not
|
|
334
|
+
* posting) nor in text the script writes (a draft saying "Agree.").
|
|
335
|
+
*
|
|
336
|
+
* @param code - Script source
|
|
337
|
+
* @returns The selectors joined with spaces
|
|
338
|
+
*/
|
|
339
|
+
export function scriptLiterals(code) {
|
|
340
|
+
const re = /(?:querySelector(?:All)?|closest|matches|getElementById|getElementsByClassName|getElementsByName|getElementsByTagName)\s*\(\s*(['"`])((?:\\.|(?!\1)[^\\\n])*)\1/g;
|
|
341
|
+
return [...code.matchAll(re)].map((m) => m[2]).join(' ');
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Match the outward-facing words against a descriptor (already split into
|
|
345
|
+
* words at punctuation).
|
|
346
|
+
*
|
|
347
|
+
* @param words - Descriptor words
|
|
348
|
+
* @returns Label, or null
|
|
349
|
+
*/
|
|
350
|
+
export function matchOutboundWords(words) {
|
|
351
|
+
for (const [pattern, label] of BROWSER_OUTBOUND_GUARD.OUTBOUND_WORDS) {
|
|
352
|
+
if (pattern.test(words))
|
|
353
|
+
return label;
|
|
354
|
+
}
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Decide whether an action publishes or submits something outward, beyond
|
|
359
|
+
* the base irreversible-word check. Returns a short label, or null.
|
|
360
|
+
*
|
|
361
|
+
* @param tool - Browser tool
|
|
362
|
+
* @param params - Its params
|
|
363
|
+
* @param context - Where it happens
|
|
364
|
+
* @returns Label for the hold, or null
|
|
365
|
+
*
|
|
366
|
+
* @example
|
|
367
|
+
* ```typescript
|
|
368
|
+
* matchOutbound('click', { selector: 'button.comments-comment-box__submit-button' }, { url: 'https://www.linkedin.com/feed/' });
|
|
369
|
+
* // 'submitting'
|
|
370
|
+
* matchOutbound('click', { selector: 'article[data-testid="tweet"]' }, { url: 'https://x.com/home' });
|
|
371
|
+
* // null — reading a tweet
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
export function matchOutbound(tool, params, context = {}) {
|
|
375
|
+
const social = isSocialOrMessagingSite(context.url);
|
|
376
|
+
switch (tool) {
|
|
377
|
+
case 'pressKey': {
|
|
378
|
+
const key = [params?.key, ...(Array.isArray(params?.modifiers) ? params.modifiers : [])]
|
|
379
|
+
.filter((v) => typeof v === 'string')
|
|
380
|
+
.join('+');
|
|
381
|
+
return isSubmitKey(key) ? 'submitting with a keystroke' : null;
|
|
382
|
+
}
|
|
383
|
+
case 'type':
|
|
384
|
+
case 'fill':
|
|
385
|
+
case 'insertText':
|
|
386
|
+
return typedTextSubmits(params) ? 'submitting typed text' : null;
|
|
387
|
+
case 'executeJs':
|
|
388
|
+
case 'executeScript': {
|
|
389
|
+
const code = typeof params?.code === 'string' ? params.code : '';
|
|
390
|
+
const operation = typeof params?.operation === 'string' ? params.operation : '';
|
|
391
|
+
const acts = scriptActs(code) || /click|submit|press|dispatch/i.test(operation);
|
|
392
|
+
if (!acts)
|
|
393
|
+
return null;
|
|
394
|
+
// Acting alone is not outbound ("See more", expanding a thread):
|
|
395
|
+
// held when it submits a form, sends a writing request, or names a
|
|
396
|
+
// submit control in its strings.
|
|
397
|
+
if (BROWSER_OUTBOUND_GUARD.SCRIPT_SUBMITS_FORM.test(code))
|
|
398
|
+
return 'submitting';
|
|
399
|
+
const label = submitLabel(params, social);
|
|
400
|
+
if (label)
|
|
401
|
+
return labelCategory(label);
|
|
402
|
+
const words = matchOutboundWords(toWords(`${scriptLiterals(code)} ${descriptorOf(params)}`));
|
|
403
|
+
if (words)
|
|
404
|
+
return words;
|
|
405
|
+
return scriptWritesRequest(code) ? 'sending a request' : null;
|
|
406
|
+
}
|
|
407
|
+
case 'setFileInput':
|
|
408
|
+
return matchOutboundWords(toWords(descriptorOf(params)));
|
|
409
|
+
case 'click':
|
|
410
|
+
case 'selectOption': {
|
|
411
|
+
const descriptor = descriptorOf(params);
|
|
412
|
+
if (!descriptor) {
|
|
413
|
+
// Coordinates or an element ref: on a social site there is no
|
|
414
|
+
// telling a "Post" from any other button.
|
|
415
|
+
return social ? 'clicking an unnamed control on a social or messaging site' : null;
|
|
416
|
+
}
|
|
417
|
+
const label = submitLabel(params, social);
|
|
418
|
+
if (label)
|
|
419
|
+
return labelCategory(label);
|
|
420
|
+
return matchOutboundWords(toWords(descriptor));
|
|
421
|
+
}
|
|
422
|
+
default:
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* The text an action would put on the page (what a post would say), for the
|
|
428
|
+
* approval card. Only `type`/`fill`/`insertText` carry it directly; a script
|
|
429
|
+
* is shown as source. Never for a field that looks secret (password, code,
|
|
430
|
+
* token): the card goes to Slack.
|
|
431
|
+
*
|
|
432
|
+
* @param tool - Browser tool
|
|
433
|
+
* @param params - Its params
|
|
434
|
+
* @returns Text, or undefined
|
|
435
|
+
*/
|
|
436
|
+
export function draftTextOf(tool, params) {
|
|
437
|
+
if (BROWSER_OUTBOUND_GUARD.SECRET_FIELD.test(toWords(descriptorOf(params))) || params?.isPassword === true) {
|
|
438
|
+
return undefined;
|
|
439
|
+
}
|
|
440
|
+
if (tool === 'type' || tool === 'fill' || tool === 'insertText') {
|
|
441
|
+
const text = [params?.text, params?.value].find((v) => typeof v === 'string' && v.trim() !== '');
|
|
442
|
+
return text?.trim();
|
|
443
|
+
}
|
|
444
|
+
if ((tool === 'executeJs' || tool === 'executeScript') && typeof params?.code === 'string') {
|
|
445
|
+
return params.code.trim();
|
|
446
|
+
}
|
|
447
|
+
return undefined;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Identity of an action for one-time approvals: an approval is spent only
|
|
451
|
+
* by the action the owner approved (same tool, same target, same text).
|
|
452
|
+
*
|
|
453
|
+
* @param tool - Browser tool
|
|
454
|
+
* @param params - Its params
|
|
455
|
+
* @returns Stable fingerprint
|
|
456
|
+
*/
|
|
457
|
+
export function actionFingerprint(tool, params) {
|
|
458
|
+
const keys = ['selector', 'text', 'value', 'code', 'key', 'modifiers', 'x', 'y', 'ref', 'index', 'operation', 'ariaLabel', 'label', 'name'];
|
|
459
|
+
const picked = {};
|
|
460
|
+
for (const k of keys)
|
|
461
|
+
if (params?.[k] !== undefined)
|
|
462
|
+
picked[k] = params[k];
|
|
463
|
+
// Hashed: held actions are persisted, and their params (typed text) must not be.
|
|
464
|
+
return `${tool}:${createHash('sha256').update(JSON.stringify(picked)).digest('hex').slice(0, 32)}`;
|
|
465
|
+
}
|
|
466
|
+
//# sourceMappingURL=browser-outbound-guard.js.map
|