mixdog 1.2.5 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSES/simple-icons-CC0-1.0.txt +30 -0
- package/NOTICE.md +19 -0
- package/package.json +4 -1
- package/scripts/check-model-recommendations.mjs +89 -0
- package/scripts/gate-local.mjs +7 -0
- package/scripts/lib/gate-scheduler.mjs +2 -2
- package/scripts/lib/isolated-test-env.mjs +16 -0
- package/scripts/lib/run-node-tests.mjs +5 -14
- package/scripts/provider-pingpong-live.mjs +9 -9
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +5 -4
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +17 -0
- package/src/defaults/skills/browser-use/SKILL.md +7 -1
- package/src/defaults/skills/computer-use/SKILL.md +3 -1
- package/src/defaults/skills/memory-management/SKILL.md +4 -1
- package/src/defaults/skills/setup/references/actions.md +11 -4
- package/src/defaults/skills/setup-guide/SKILL.md +175 -0
- package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
- package/src/defaults/skills/visualize/SKILL.md +3 -2
- package/src/lib/rules-builder.cjs +56 -7
- package/src/output-styles/common.md +22 -6
- package/src/output-styles/detailed.md +7 -5
- package/src/output-styles/minimal.md +7 -3
- package/src/output-styles/simple.md +2 -3
- package/src/rules/agent/AGENT.md +7 -1
- package/src/rules/agent-mode/AGENT_MODE.md +24 -0
- package/src/rules/agent-mode/MIXY.md +21 -0
- package/src/rules/agent-mode/ROUTINE.md +6 -0
- package/src/rules/lead/LEAD.md +9 -4
- package/src/rules/shared/10-tool-workflow.md +2 -1
- package/src/rules/shared/60-verification.md +4 -5
- package/src/rules/shared/70-delivery.md +3 -0
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
- package/src/runtime/agent/orchestrator/config.mjs +6 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +182 -13
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +5 -3
- package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +215 -0
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +58 -64
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +122 -15
- package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
- package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +41 -19
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +11 -5
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
- package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
- package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
- package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +98 -4
- package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +15 -8
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +50 -20
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
- package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
- package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +162 -0
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +641 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +165 -0
- package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
- package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +82 -33
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +11 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -5
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +55 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +24 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
- package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +70 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +277 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
- package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
- package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
- package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
- package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +325 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +84 -21
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
- package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +44 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
- package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
- package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +123 -32
- package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
- package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
- package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +64 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +10 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +104 -55
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/attachments/office-extract.mjs +11 -9
- package/src/runtime/browser-bridge/client.mjs +24 -0
- package/src/runtime/channels/lib/scheduler.mjs +40 -12
- package/src/runtime/channels/lib/schedules-db.mjs +71 -12
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
- package/src/runtime/channels/lib/webhook.mjs +0 -1
- package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
- package/src/runtime/channels/lib/worker-main.mjs +17 -20
- package/src/runtime/computer-bridge/client.mjs +28 -1
- package/src/runtime/connectors/gmail-app-password.mjs +690 -0
- package/src/runtime/connectors/google-mcp.mjs +446 -0
- package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
- package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
- package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
- package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
- package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
- package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
- package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
- package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
- package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
- package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
- package/src/runtime/memory/lib/memory.mjs +7 -1
- package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
- package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
- package/src/runtime/memory/lib/tool-call-handler.mjs +9 -5
- package/src/runtime/memory/tool-defs.mjs +5 -0
- package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
- package/src/runtime/office/core/tabular.mjs +1 -1
- package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
- package/src/runtime/office/portable/docx-formatting.mjs +1 -1
- package/src/runtime/office/portable/docx-runs.mjs +1 -1
- package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
- package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
- package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
- package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
- package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
- package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
- package/src/runtime/office/portable/portable-opc.mjs +27 -13
- package/src/runtime/office/portable/portable-pivot.mjs +3 -3
- package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
- package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
- package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
- package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
- package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
- package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
- package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
- package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
- package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
- package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
- package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
- package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
- package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
- package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
- package/src/runtime/office/portable/portable-xml.mjs +1 -1
- package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
- package/src/runtime/shared/agent-avatar.d.mts +64 -0
- package/src/runtime/shared/agent-avatar.mjs +320 -0
- package/src/runtime/shared/agent-route-config.d.mts +3 -0
- package/src/runtime/shared/agent-route-config.mjs +16 -0
- package/src/runtime/shared/atomic-file.mjs +36 -14
- package/src/runtime/shared/background-tasks.mjs +60 -20
- package/src/runtime/shared/child-spawn-gate.mjs +26 -16
- package/src/runtime/shared/config.mjs +8 -11
- package/src/runtime/shared/connector-accounts.mjs +15 -0
- package/src/runtime/shared/connector-catalog.d.mts +52 -0
- package/src/runtime/shared/connector-catalog.mjs +230 -0
- package/src/runtime/shared/connector-triggers.d.mts +3 -0
- package/src/runtime/shared/connector-triggers.mjs +43 -0
- package/src/runtime/shared/file-lock.mjs +7 -1
- package/src/runtime/shared/file-permissions-worker.mjs +38 -0
- package/src/runtime/shared/file-permissions.d.mts +19 -4
- package/src/runtime/shared/file-permissions.mjs +310 -4
- package/src/runtime/shared/git-runner-worker.mjs +6 -78
- package/src/runtime/shared/google-oauth-client.mjs +24 -0
- package/src/runtime/shared/held-request-host.d.mts +12 -0
- package/src/runtime/shared/held-request-host.mjs +71 -0
- package/src/runtime/shared/llm/http-agent.mjs +7 -3
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
- package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
- package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
- package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
- package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
- package/src/runtime/shared/memory-snapshot.mjs +5 -1
- package/src/runtime/shared/notify-trace.mjs +8 -1
- package/src/runtime/shared/plain-preview.d.mts +1 -0
- package/src/runtime/shared/plain-preview.mjs +28 -0
- package/src/runtime/shared/pristine-execution-contract.json +5 -1
- package/src/runtime/shared/process-runner-worker.mjs +7 -0
- package/src/runtime/shared/process-runner.mjs +38 -0
- package/src/runtime/shared/provider-accounts.mjs +2 -1
- package/src/runtime/shared/provider-api-key.mjs +0 -1
- package/src/runtime/shared/read-row-numbers.mjs +1 -1
- package/src/runtime/shared/resource-admission.mjs +60 -18
- package/src/runtime/shared/routine-limits.d.mts +11 -0
- package/src/runtime/shared/routine-limits.mjs +21 -0
- package/src/runtime/shared/routine-trigger.d.mts +10 -0
- package/src/runtime/shared/routine-trigger.mjs +44 -0
- package/src/runtime/shared/run-child.mjs +84 -0
- package/src/runtime/shared/schedule-model-ref.mjs +9 -10
- package/src/runtime/shared/session-activity-signal.mjs +23 -0
- package/src/runtime/shared/shell-output-summary.mjs +23 -0
- package/src/runtime/shared/singleton-owner.mjs +126 -42
- package/src/runtime/shared/slow-span.mjs +4 -12
- package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
- package/src/runtime/shared/tool-output-limit.mjs +4 -2
- package/src/runtime/shared/tool-output-marker.mjs +58 -0
- package/src/runtime/shared/transcript-metadata.mjs +10 -0
- package/src/runtime/shared/turn-changes.mjs +0 -8
- package/src/runtime/shared/usage-readout-totals.mjs +56 -0
- package/src/runtime/shared/user-data-guard.mjs +131 -34
- package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
- package/src/runtime/shared/worktrees/git-head.mjs +20 -2
- package/src/runtime/shared/worktrees/lock.mjs +3 -2
- package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
- package/src/runtime/tidy/runners/biome.mjs +3 -1
- package/src/runtime/tidy/shadow.mjs +2 -1
- package/src/runtime/web-search/index.mjs +5 -7
- package/src/runtime/web-search/lib/formatter.mjs +42 -6
- package/src/runtime/web-search/tool-defs.mjs +6 -1
- package/src/session-runtime/agent-home-delivery.mjs +459 -0
- package/src/session-runtime/agent-profile-changes.mjs +21 -0
- package/src/session-runtime/agent-room-delivery.mjs +92 -0
- package/src/session-runtime/agent-task-sessions.mjs +200 -0
- package/src/session-runtime/boot/apis.mjs +50 -18
- package/src/session-runtime/boot/facade.mjs +5 -8
- package/src/session-runtime/boot/infrastructure.mjs +28 -17
- package/src/session-runtime/boot/tools.mjs +3 -0
- package/src/session-runtime/channel-config-api.mjs +53 -5
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
- package/src/session-runtime/held-requests.mjs +228 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +31 -2
- package/src/session-runtime/internal-tool-executor.mjs +2 -0
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
- package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +11 -4
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
- package/src/session-runtime/lifecycle/shared.mjs +25 -2
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
- package/src/session-runtime/lifecycle/teardown.mjs +5 -2
- package/src/session-runtime/lifecycle-api.mjs +3 -1
- package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
- package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
- package/src/session-runtime/mcp-oauth-login.mjs +112 -15
- package/src/session-runtime/model-route/set-route.mjs +14 -3
- package/src/session-runtime/owned-automation-run.mjs +229 -0
- package/src/session-runtime/provider-auth/login.mjs +10 -6
- package/src/session-runtime/provider-auth/setup.mjs +19 -2
- package/src/session-runtime/provider-catalog-cache.mjs +101 -25
- package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
- package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
- package/src/session-runtime/provider-models.mjs +76 -10
- package/src/session-runtime/provider-readiness.mjs +4 -0
- package/src/session-runtime/resource-api.mjs +5 -0
- package/src/session-runtime/resource-mcp-api.mjs +107 -13
- package/src/session-runtime/resource-skills-api.mjs +12 -0
- package/src/session-runtime/room-member-gate.mjs +48 -0
- package/src/session-runtime/routine-home-turn.mjs +156 -0
- package/src/session-runtime/routine-owner.mjs +48 -0
- package/src/session-runtime/schedule-session-run.mjs +30 -64
- package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +10 -0
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
- package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
- package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
- package/src/session-runtime/services/agent-tool.mjs +20 -0
- package/src/session-runtime/services/channel-admin.mjs +93 -24
- package/src/session-runtime/services/memory-access.mjs +37 -0
- package/src/session-runtime/services/provider-admin.mjs +166 -59
- package/src/session-runtime/services/schedule-access.mjs +91 -0
- package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
- package/src/session-runtime/services/usage-dashboard.mjs +27 -69
- package/src/session-runtime/session-create/session-options.mjs +34 -7
- package/src/session-runtime/session-hooks.mjs +16 -8
- package/src/session-runtime/setup-tool/executor.mjs +68 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +72 -14
- package/src/session-runtime/setup-tool/settings-contract.mjs +8 -6
- package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
- package/src/session-runtime/skills-api.mjs +16 -1
- package/src/session-runtime/tool-policy-refresh.mjs +238 -29
- package/src/session-runtime/turn/session-ops.mjs +10 -3
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +11 -2
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +3 -0
- package/src/session-runtime/usage-stats-api.mjs +6 -1
- package/src/session-runtime/webhook-session-run.mjs +49 -67
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +556 -22
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
- package/src/session-runtime/workflow-agents-api.mjs +4 -1
- package/src/standalone/channel-transport/http-routes.mjs +10 -9
- package/src/standalone/daemon-agent-control.mjs +1 -8
- package/src/standalone/daemon-desktop-runtime.mjs +20 -7
- package/src/standalone/daemon-owner.mjs +117 -25
- package/src/standalone/daemon-session-control.mjs +11 -2
- package/src/standalone/daemon.mjs +61 -17
- package/src/standalone/session-call-cache.mjs +6 -0
- package/src/standalone/session-protocol.mjs +28 -1
- package/src/standalone/session-service/retention/busy.mjs +7 -2
- package/src/standalone/session-service/session-calls/session-turns.mjs +9 -0
- package/src/standalone/session-service.mjs +19 -0
- package/src/standalone/session-transport/routes.mjs +7 -6
- package/src/tui/app/model-options.mjs +39 -2
- package/src/tui/app/model-picker.mjs +16 -2
- package/src/tui/app/provider-setup-picker.mjs +1 -2
- package/src/tui/app/slash-commands.mjs +20 -0
- package/src/tui/dist/index.mjs +487 -128
- package/src/tui/session/context-state.mjs +6 -1
- package/src/tui/session/notice-surface.mjs +35 -4
- package/src/tui/session/notice-text.mjs +0 -1
- package/src/tui/session/queue-helpers.mjs +2 -1
- package/src/tui/session/session-api/extensions.mjs +4 -0
- package/src/tui/session/session-api/intake/submission.mjs +12 -13
- package/src/tui/session/session-api/integrations.mjs +9 -5
- package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
- package/src/tui/session/session-api/lifecycle.mjs +17 -1
- package/src/tui/session/session-api/routes.mjs +48 -3
- package/src/tui/session/session-flow/drain.mjs +20 -3
- package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
- package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
- package/src/tui/session/session-flow/steering.mjs +104 -24
- package/src/tui/session/session-flow.mjs +2 -0
- package/src/tui/session/tool-approval.mjs +26 -5
- package/src/tui/session/transcript-intake.mjs +6 -2
- package/src/tui/session/transcript-spill.mjs +5 -1
- package/src/tui/session/tui-steering-persist.mjs +65 -42
- package/src/tui/session/turn-live-call.mjs +56 -0
- package/src/tui/session/turn-stream.mjs +33 -0
- package/src/tui/session/turn.mjs +50 -7
- package/src/ui/statusline.mjs +1 -6
- package/src/ui/streaming-markdown-heal.mjs +24 -7
- package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
- package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
- package/src/workflows/default/WORKFLOW.md +9 -13
- package/src/session-runtime/automation-agents.mjs +0 -94
- package/src/session-runtime/automation-workflow.mjs +0 -59
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// session/human-gate/outbound-policy.mjs
|
|
2
|
+
// Which calls post, send or spend outside the machine and so need the user's
|
|
3
|
+
// approval by default: PR comment and review, issue comment, email or message
|
|
4
|
+
// send, social publish, form submit, payment or purchase, and a permanent
|
|
5
|
+
// delete. Classified by name against a small explicit list, with the tool's
|
|
6
|
+
// annotations: a known send name stays outbound whatever the tool declares;
|
|
7
|
+
// any other tool that declares itself read-only is never outbound, and an MCP
|
|
8
|
+
// tool may opt in with `outboundHint: true`. Browser form submits are
|
|
9
|
+
// confirmed by the desktop browser host itself (main/browser/action-approval.ts),
|
|
10
|
+
// so `browser` is not classified here.
|
|
11
|
+
//
|
|
12
|
+
// The category is the "action kind" a remembered grant is keyed by (agent +
|
|
13
|
+
// kind). Payments and permanent deletes are never remembered.
|
|
14
|
+
|
|
15
|
+
/** Every action kind, in the order the profile's permission table lists them. */
|
|
16
|
+
export const ACTION_KINDS = Object.freeze([
|
|
17
|
+
'comment',
|
|
18
|
+
'review',
|
|
19
|
+
'message',
|
|
20
|
+
'email',
|
|
21
|
+
'publish',
|
|
22
|
+
'form',
|
|
23
|
+
'payment',
|
|
24
|
+
'delete',
|
|
25
|
+
'trash',
|
|
26
|
+
]);
|
|
27
|
+
const UNREMEMBERED_ACTIONS = new Set(['payment', 'delete']);
|
|
28
|
+
|
|
29
|
+
/** Whether "don't ask again" (an `allow` grant) may exist for `kind`. */
|
|
30
|
+
export function isRememberableAction(kind) {
|
|
31
|
+
return ACTION_KINDS.includes(kind) && !UNREMEMBERED_ACTIONS.has(kind);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const GITHUB_OUTBOUND = new Map([
|
|
35
|
+
['issue.comment', 'comment'],
|
|
36
|
+
['pr.comment', 'comment'],
|
|
37
|
+
['pr.review', 'review'],
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
/** Bare MCP tool names (lowercase, `-` → `_`) and what they send. */
|
|
41
|
+
const MCP_OUTBOUND = new Map([
|
|
42
|
+
...[
|
|
43
|
+
'add_issue_comment',
|
|
44
|
+
'create_issue_comment',
|
|
45
|
+
'add_reply_to_pull_request_comment',
|
|
46
|
+
'add_comment_to_pending_review',
|
|
47
|
+
'add_pull_request_review_comment',
|
|
48
|
+
].map((name) => [name, 'comment']),
|
|
49
|
+
...['create_pull_request_review', 'create_and_submit_pull_request_review', 'submit_pending_pull_request_review'].map(
|
|
50
|
+
(name) => [name, 'review']
|
|
51
|
+
),
|
|
52
|
+
...['send_email', 'send_mail', 'gmail_send', 'gmail_send_email', 'send_gmail_message', 'reply_email'].map((name) => [
|
|
53
|
+
name,
|
|
54
|
+
'email',
|
|
55
|
+
]),
|
|
56
|
+
...[
|
|
57
|
+
'send_message',
|
|
58
|
+
'post_message',
|
|
59
|
+
'reply_to_message',
|
|
60
|
+
'slack_post_message',
|
|
61
|
+
'slack_reply_to_thread',
|
|
62
|
+
'chat_post_message',
|
|
63
|
+
'discord_send_message',
|
|
64
|
+
'telegram_send_message',
|
|
65
|
+
].map((name) => [name, 'message']),
|
|
66
|
+
...['create_post', 'publish_post', 'create_tweet', 'post_tweet', 'send_tweet'].map((name) => [name, 'publish']),
|
|
67
|
+
['submit_form', 'form'],
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
const PAYLOAD_FIELDS = ['body', 'text', 'message', 'content', 'comment', 'subject'];
|
|
71
|
+
const TARGET_FIELDS = ['to', 'recipient', 'recipients', 'channel', 'channel_id', 'chat_id', 'thread', 'url', 'page'];
|
|
72
|
+
|
|
73
|
+
// Name tokens (split on `_`) that make a send, a payment or a permanent delete.
|
|
74
|
+
// A name opening with a read verb (list_payments, get_purchase) only reads.
|
|
75
|
+
const READ_VERBS = new Set([
|
|
76
|
+
'get',
|
|
77
|
+
'list',
|
|
78
|
+
'search',
|
|
79
|
+
'read',
|
|
80
|
+
'fetch',
|
|
81
|
+
'retrieve',
|
|
82
|
+
'find',
|
|
83
|
+
'view',
|
|
84
|
+
'describe',
|
|
85
|
+
'lookup',
|
|
86
|
+
]);
|
|
87
|
+
const MAIL_TOKENS = new Set(['mail', 'email', 'gmail', 'outlook', 'smtp']);
|
|
88
|
+
const SEND_TOKENS = new Set(['send', 'reply', 'forward']);
|
|
89
|
+
const PAYMENT_TOKENS = new Set(['pay', 'payment', 'purchase', 'buy', 'checkout', 'charge']);
|
|
90
|
+
const PAYMENT_NAMES = new Set(['place_order', 'send_money', 'transfer_money', 'transfer_funds']);
|
|
91
|
+
const PERMANENT_TOKENS = new Set(['permanent', 'permanently', 'hard', 'forever']);
|
|
92
|
+
|
|
93
|
+
const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
94
|
+
const bareName = (value) =>
|
|
95
|
+
String(value || '')
|
|
96
|
+
.toLowerCase()
|
|
97
|
+
.replace(/-/g, '_');
|
|
98
|
+
const tokensOf = (value) =>
|
|
99
|
+
bareName(value)
|
|
100
|
+
.split(/[^a-z0-9]+/)
|
|
101
|
+
.filter(Boolean);
|
|
102
|
+
|
|
103
|
+
function payloadOf(args, fields) {
|
|
104
|
+
const editable = fields.filter((name) => typeof args[name] === 'string');
|
|
105
|
+
return { payload: editable.length ? String(args[editable[0]]) : '', editable };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const firstOf = (args, names) => {
|
|
109
|
+
for (const name of names) {
|
|
110
|
+
const value = args[name];
|
|
111
|
+
if (typeof value === 'string' && value.trim()) return value.trim();
|
|
112
|
+
if (typeof value === 'number' && Number.isFinite(value)) return String(value);
|
|
113
|
+
if (Array.isArray(value) && value.length) return value.map(String).join(', ');
|
|
114
|
+
}
|
|
115
|
+
return '';
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** The category a bare MCP tool name (and its server) makes, or ''. */
|
|
119
|
+
function categoryByName(bare, server) {
|
|
120
|
+
const tokens = tokensOf(bare);
|
|
121
|
+
const listed = MCP_OUTBOUND.get(bare) || '';
|
|
122
|
+
if (READ_VERBS.has(tokens[0])) return listed;
|
|
123
|
+
const mail = [...tokens, ...tokensOf(server)].some((token) => MAIL_TOKENS.has(token));
|
|
124
|
+
if (mail && tokens.some((token) => SEND_TOKENS.has(token))) return 'email';
|
|
125
|
+
if (listed) return listed;
|
|
126
|
+
if (PAYMENT_NAMES.has(bare) || tokens.some((token) => PAYMENT_TOKENS.has(token))) return 'payment';
|
|
127
|
+
if (bare === 'empty_trash' || tokens.includes('purge')) return 'delete';
|
|
128
|
+
// Recoverable (Gmail Trash): asks, and unlike a permanent delete it may be remembered.
|
|
129
|
+
if (bare === 'trash_emails') return 'trash';
|
|
130
|
+
if (tokens.includes('delete') && tokens.some((token) => PERMANENT_TOKENS.has(token))) return 'delete';
|
|
131
|
+
return '';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** What a card shows besides the payload: mail headers, the payment, the delete (empty lines left out). */
|
|
135
|
+
function detailsOf(category, args) {
|
|
136
|
+
return Object.fromEntries(Object.entries(detailLines(category, args)).filter(([, value]) => value));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function detailLines(category, args) {
|
|
140
|
+
if (category === 'email') {
|
|
141
|
+
return {
|
|
142
|
+
to: firstOf(args, ['to', 'recipient', 'recipients']),
|
|
143
|
+
cc: firstOf(args, ['cc']),
|
|
144
|
+
subject: firstOf(args, ['subject']),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (category === 'payment') {
|
|
148
|
+
return {
|
|
149
|
+
merchant: firstOf(args, ['merchant', 'payee', 'vendor', 'seller', 'recipient', 'to', 'description']),
|
|
150
|
+
amount: firstOf(args, ['amount', 'price', 'total', 'value']),
|
|
151
|
+
currency: firstOf(args, ['currency']).toUpperCase(),
|
|
152
|
+
recurrence: firstOf(args, ['recurrence', 'interval', 'frequency', 'billing_cycle']),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (category === 'trash') return { count: String(Array.isArray(args.ids) ? args.ids.length : 1) };
|
|
156
|
+
if (category === 'delete') {
|
|
157
|
+
const listed = ['ids', 'paths', 'files', 'file_ids', 'items'].map((name) => args[name]).find(Array.isArray);
|
|
158
|
+
return {
|
|
159
|
+
count: firstOf(args, ['count']) || String(listed ? listed.length : 1),
|
|
160
|
+
size: firstOf(args, ['size', 'total_size', 'bytes']),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return {};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function mcpTarget(args, server) {
|
|
167
|
+
const repo = [args.owner, args.repo].filter((part) => typeof part === 'string' && part).join('/');
|
|
168
|
+
const number = args.issue_number ?? args.pull_number ?? args.number;
|
|
169
|
+
if (repo) return number != null ? `${repo}#${number}` : repo;
|
|
170
|
+
for (const name of TARGET_FIELDS) {
|
|
171
|
+
const value = args[name];
|
|
172
|
+
if (typeof value === 'string' && value.trim()) return value.trim();
|
|
173
|
+
if (Array.isArray(value) && value.length) return value.map(String).join(', ');
|
|
174
|
+
}
|
|
175
|
+
return server;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* `{ category, tool, target, account, payload, editable, details }` for a call
|
|
180
|
+
* that posts, sends, pays or permanently deletes, else null. `category` is the
|
|
181
|
+
* action kind; `tool` the GitHub action or the MCP tool's full name.
|
|
182
|
+
*/
|
|
183
|
+
export function classifyOutboundCall({ name, args, annotations } = {}) {
|
|
184
|
+
const input = isRecord(args) ? args : {};
|
|
185
|
+
const toolName = String(name || '');
|
|
186
|
+
if (toolName === 'github') {
|
|
187
|
+
const category = GITHUB_OUTBOUND.get(input.action);
|
|
188
|
+
if (!category) return null;
|
|
189
|
+
return {
|
|
190
|
+
category,
|
|
191
|
+
tool: `github:${input.action}`,
|
|
192
|
+
target: `${input.repo || '(current project)'}#${input.number ?? '?'}`,
|
|
193
|
+
account: String(input.hostname || 'github.com'),
|
|
194
|
+
...payloadOf(input, ['body']),
|
|
195
|
+
details: {},
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (!toolName.startsWith('mcp__')) return null;
|
|
199
|
+
const [, server = '', ...rest] = toolName.split('__');
|
|
200
|
+
const bare = bareName(annotations?.mcpToolName || rest.join('__'));
|
|
201
|
+
let category = categoryByName(bare, server);
|
|
202
|
+
if (!category && tokensOf(bare).includes('delete') && input.permanent === true) category = 'delete';
|
|
203
|
+
// A known send, payment or delete name stays outbound whatever the tool says.
|
|
204
|
+
if (!category && annotations?.readOnlyHint === true) return null;
|
|
205
|
+
if (!category && annotations?.outboundHint === true) category = 'message';
|
|
206
|
+
if (!category) return null;
|
|
207
|
+
const details = detailsOf(category, input);
|
|
208
|
+
const spends = category === 'payment' || category === 'delete';
|
|
209
|
+
return {
|
|
210
|
+
category,
|
|
211
|
+
tool: toolName,
|
|
212
|
+
target:
|
|
213
|
+
(category === 'payment' && details.merchant) ||
|
|
214
|
+
(category === 'trash' && firstOf(input, ['ids'])) ||
|
|
215
|
+
(category === 'delete' && firstOf(input, ['path', 'name', 'folder', 'paths', 'ids', 'file_ids'])) ||
|
|
216
|
+
mcpTarget(input, server),
|
|
217
|
+
account: (category === 'email' && firstOf(input, ['from', 'account'])) || server,
|
|
218
|
+
...(spends || category === 'trash' ? { payload: '', editable: [] } : payloadOf(input, PAYLOAD_FIELDS)),
|
|
219
|
+
details,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// session/human-gate/requests.mjs
|
|
2
|
+
// The data model of a human-in-the-loop prompt. A request has one `kind`:
|
|
3
|
+
// approval — allow or deny one tool call;
|
|
4
|
+
// outbound — a call that posts, sends, pays or deletes outside (its action
|
|
5
|
+
// kind, target, account, the exact payload text, which fields
|
|
6
|
+
// the card may edit, and the mail/payment/delete detail lines);
|
|
7
|
+
// secret — the user types a value into a target field; the request names
|
|
8
|
+
// the target and the field label, never a value;
|
|
9
|
+
// takeover — the user does a step themselves and says "done";
|
|
10
|
+
// permission — the user picks one of the offered scopes.
|
|
11
|
+
// A response is one of HUMAN_RESPONSES plus a `remember` scope; a policy lists
|
|
12
|
+
// the scopes it allows and can leave out `always`. Nothing here ever carries a
|
|
13
|
+
// secret value: a decision that names one is stripped to its verdict.
|
|
14
|
+
|
|
15
|
+
export const HUMAN_REQUEST_KINDS = Object.freeze(['approval', 'outbound', 'secret', 'takeover', 'permission']);
|
|
16
|
+
export const HUMAN_RESPONSES = Object.freeze(['approve', 'deny', 'edit-and-approve', 'provide-secret', 'skip', 'done']);
|
|
17
|
+
export const REMEMBER_SCOPES = Object.freeze(['once', 'agent', 'always']);
|
|
18
|
+
export const SECRET_REQUEST_TIMEOUT_MS = 120_000;
|
|
19
|
+
|
|
20
|
+
const RESPONSES_BY_KIND = Object.freeze({
|
|
21
|
+
approval: ['approve', 'deny'],
|
|
22
|
+
outbound: ['approve', 'edit-and-approve', 'deny'],
|
|
23
|
+
secret: ['provide-secret', 'skip'],
|
|
24
|
+
takeover: ['done', 'deny'],
|
|
25
|
+
permission: ['approve', 'deny'],
|
|
26
|
+
});
|
|
27
|
+
const GRANTING_RESPONSES = new Set(['approve', 'edit-and-approve', 'provide-secret', 'done']);
|
|
28
|
+
const TEXT_LIMIT = 200;
|
|
29
|
+
/** An outbound card's extra lines: mail headers, the payment, the delete, the
|
|
30
|
+
* trash card's message list (gate.mjs describeEmails) and its remainder. */
|
|
31
|
+
const DETAIL_FIELDS = [
|
|
32
|
+
'to',
|
|
33
|
+
'cc',
|
|
34
|
+
'subject',
|
|
35
|
+
'merchant',
|
|
36
|
+
'amount',
|
|
37
|
+
'currency',
|
|
38
|
+
'recurrence',
|
|
39
|
+
'count',
|
|
40
|
+
'size',
|
|
41
|
+
'messages',
|
|
42
|
+
'more',
|
|
43
|
+
];
|
|
44
|
+
const DETAIL_LIMITS = { messages: 1_000 };
|
|
45
|
+
const PAYLOAD_LIMIT = 40_000;
|
|
46
|
+
|
|
47
|
+
const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
48
|
+
const text = (value, limit = TEXT_LIMIT) => (typeof value === 'string' ? value.trim().slice(0, limit) : '');
|
|
49
|
+
|
|
50
|
+
/** The human kind of a request; anything else (ask_user's 'question', a
|
|
51
|
+
* hook's bare ask) is an ordinary approval for responses. */
|
|
52
|
+
export function humanRequestKind(request) {
|
|
53
|
+
return HUMAN_REQUEST_KINDS.includes(request?.kind) ? request.kind : 'approval';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** A login takeover's sign-in page: https, or http on loopback only (a local
|
|
57
|
+
* site); never embedded credentials. `{ url, origin }`, or null. */
|
|
58
|
+
export function loginPageUrl(value) {
|
|
59
|
+
if (typeof value !== 'string' || !value.trim() || value.length > 2048) return null;
|
|
60
|
+
let parsed;
|
|
61
|
+
try {
|
|
62
|
+
parsed = new URL(value.trim());
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const host = parsed.hostname.replace(/^\[|\]$/g, '').toLowerCase();
|
|
67
|
+
const loopback =
|
|
68
|
+
host === 'localhost' || host.endsWith('.localhost') || host === '::1' || /^127(?:\.\d{1,3}){3}$/.test(host);
|
|
69
|
+
if (parsed.protocol !== 'https:' && !(parsed.protocol === 'http:' && loopback)) return null;
|
|
70
|
+
if (parsed.username || parsed.password) return null;
|
|
71
|
+
return { url: parsed.href, origin: parsed.origin };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function rememberScopes(value) {
|
|
75
|
+
const listed = Array.isArray(value) ? value.filter((scope) => REMEMBER_SCOPES.includes(scope)) : [];
|
|
76
|
+
return ['once', ...new Set(listed.filter((scope) => scope !== 'once'))];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The kind-specific fields of a request, whitelisted. Spread onto the
|
|
80
|
+
* presented request; `args` is replaced for a secret so no value rides it. */
|
|
81
|
+
export function humanRequestFields(input = {}) {
|
|
82
|
+
const kind = input?.kind;
|
|
83
|
+
if (!HUMAN_REQUEST_KINDS.includes(kind)) return {};
|
|
84
|
+
const fields = { remember: rememberScopes(input.remember) };
|
|
85
|
+
// The agent the request acts for (its name on the card and the remembered grant).
|
|
86
|
+
if (text(input.agentId)) fields.agentId = text(input.agentId);
|
|
87
|
+
if (kind === 'outbound' && isRecord(input.outbound)) {
|
|
88
|
+
const outbound = input.outbound;
|
|
89
|
+
const details = isRecord(outbound.details) ? outbound.details : {};
|
|
90
|
+
fields.outbound = {
|
|
91
|
+
category: text(outbound.category),
|
|
92
|
+
target: text(outbound.target),
|
|
93
|
+
account: text(outbound.account),
|
|
94
|
+
payload: typeof outbound.payload === 'string' ? outbound.payload.slice(0, PAYLOAD_LIMIT) : '',
|
|
95
|
+
editable: Array.isArray(outbound.editable) ? outbound.editable.filter((name) => typeof name === 'string') : [],
|
|
96
|
+
details: Object.fromEntries(
|
|
97
|
+
DETAIL_FIELDS.filter((name) => text(details[name])).map((name) => [
|
|
98
|
+
name,
|
|
99
|
+
text(details[name], DETAIL_LIMITS[name]),
|
|
100
|
+
])
|
|
101
|
+
),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (kind === 'secret') {
|
|
105
|
+
const secret = isRecord(input.secret) ? input.secret : {};
|
|
106
|
+
fields.secret = {
|
|
107
|
+
requestId: text(secret.requestId),
|
|
108
|
+
surface: secret.surface === 'computer' ? 'computer' : 'browser',
|
|
109
|
+
target: text(secret.target),
|
|
110
|
+
field: text(secret.field),
|
|
111
|
+
};
|
|
112
|
+
fields.args = { surface: fields.secret.surface, target: fields.secret.target, field: fields.secret.field };
|
|
113
|
+
fields.remember = ['once'];
|
|
114
|
+
}
|
|
115
|
+
if (kind === 'takeover') {
|
|
116
|
+
const takeover = isRecord(input.takeover) ? input.takeover : {};
|
|
117
|
+
const surface = takeover.surface === 'computer' ? 'computer' : 'browser';
|
|
118
|
+
// The window it is about (ask-user-tool-defs.mjs handoffIdentity): a
|
|
119
|
+
// browser page ID, or a computer window id and app, so the card can bring
|
|
120
|
+
// exactly that window forward on the user's click.
|
|
121
|
+
const token = (value, limit) => (/^[\w.:#@-]+$/.test(text(value, limit)) ? text(value, limit) : '');
|
|
122
|
+
const identity =
|
|
123
|
+
surface === 'browser'
|
|
124
|
+
? { ...(token(takeover.tab, 64) ? { tab: token(takeover.tab, 64) } : {}) }
|
|
125
|
+
: {
|
|
126
|
+
...(token(takeover.windowId, 128) ? { windowId: token(takeover.windowId, 128) } : {}),
|
|
127
|
+
...(text(takeover.app, 120) ? { app: text(takeover.app, 120) } : {}),
|
|
128
|
+
};
|
|
129
|
+
// A login takeover (purpose 'login') opens the desktop's sign-in window on
|
|
130
|
+
// its validated page instead of handing over the side panel.
|
|
131
|
+
const login = surface === 'browser' && takeover.purpose === 'login' ? loginPageUrl(takeover.url) : null;
|
|
132
|
+
fields.takeover = {
|
|
133
|
+
surface,
|
|
134
|
+
instructions: text(takeover.instructions, 2_000),
|
|
135
|
+
...(text(takeover.target) ? { target: text(takeover.target) } : {}),
|
|
136
|
+
...identity,
|
|
137
|
+
...(login ? { purpose: 'login', url: login.url, origin: login.origin } : {}),
|
|
138
|
+
};
|
|
139
|
+
fields.remember = ['once'];
|
|
140
|
+
}
|
|
141
|
+
if (kind === 'permission') {
|
|
142
|
+
const scopes = Array.isArray(input.permission?.scopes) ? input.permission.scopes : [];
|
|
143
|
+
fields.permission = {
|
|
144
|
+
scopes: scopes
|
|
145
|
+
.filter((scope) => isRecord(scope) && text(scope.id))
|
|
146
|
+
.map((scope) => ({ id: text(scope.id), label: text(scope.label) || text(scope.id) })),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return fields;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Only `editable` string fields of `editedArgs`; {} when nothing applies. */
|
|
153
|
+
function editableArgs(editedArgs, editable) {
|
|
154
|
+
if (!isRecord(editedArgs)) return {};
|
|
155
|
+
const out = {};
|
|
156
|
+
for (const name of editable || []) {
|
|
157
|
+
if (typeof editedArgs[name] === 'string') out[name] = editedArgs[name].slice(0, PAYLOAD_LIMIT);
|
|
158
|
+
}
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* The canonical response to `request` from a decision: `approved` (the card's
|
|
164
|
+
* polarity) plus optional `{ response, editedArgs, remember, scope }`. An
|
|
165
|
+
* unknown or contradicting response falls back to the polarity's default;
|
|
166
|
+
* edits survive only on an outbound request and only for its editable fields;
|
|
167
|
+
* `remember` only when the request allows it and the call was granted.
|
|
168
|
+
*/
|
|
169
|
+
export function normalizeHumanResponse(request, approved, extra = {}) {
|
|
170
|
+
const kind = humanRequestKind(request);
|
|
171
|
+
const allowed = RESPONSES_BY_KIND[kind];
|
|
172
|
+
const polarity = approved === true;
|
|
173
|
+
const fallback = polarity ? allowed[0] : allowed[allowed.length - 1];
|
|
174
|
+
const asked = isRecord(extra) && allowed.includes(extra.response) ? extra.response : '';
|
|
175
|
+
let response = asked && GRANTING_RESPONSES.has(asked) === polarity ? asked : fallback;
|
|
176
|
+
const result = { approved: polarity, response };
|
|
177
|
+
if (response === 'edit-and-approve') {
|
|
178
|
+
const edits = editableArgs(extra.editedArgs, request?.outbound?.editable);
|
|
179
|
+
if (Object.keys(edits).length) result.editedArgs = edits;
|
|
180
|
+
else response = result.response = 'approve';
|
|
181
|
+
}
|
|
182
|
+
const scopes = Array.isArray(request?.remember) ? request.remember : ['once'];
|
|
183
|
+
result.remember = polarity && scopes.includes(extra?.remember) ? extra.remember : 'once';
|
|
184
|
+
if (kind === 'permission' && polarity) {
|
|
185
|
+
const ids = (request?.permission?.scopes || []).map((scope) => scope.id);
|
|
186
|
+
if (ids.includes(extra?.scope)) result.scope = extra.scope;
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** `args` with the card's edited fields in place of the model's. */
|
|
192
|
+
export function applyEditedArgs(args, editedArgs, editable) {
|
|
193
|
+
const edits = editableArgs(editedArgs, editable);
|
|
194
|
+
return Object.keys(edits).length ? { ...(isRecord(args) ? args : {}), ...edits } : args;
|
|
195
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// session/human-gate/store.mjs
|
|
2
|
+
// Per-agent permissions and the decision audit, both under the plugin data dir.
|
|
3
|
+
// A grant is keyed by agent + action kind (outbound-policy.mjs ACTION_KINDS)
|
|
4
|
+
// and says `allow` (never ask: "다시 묻지 않기") or `block` (deny without a
|
|
5
|
+
// card); no grant means ask. `agent` scope names the agent, `always` stands for
|
|
6
|
+
// every agent ('*'), and an agent's own grant wins over an every-agent one;
|
|
7
|
+
// `once` is never stored. Payments and deletes are never allowed. Grants are
|
|
8
|
+
// listed and revoked by id. The audit is one JSONL line per decision with
|
|
9
|
+
// agent, kind, action, tool, target, decision, deciding device and time —
|
|
10
|
+
// never a value, an argument or a payload — read back newest first.
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { appendFile, mkdir, readFile } from 'node:fs/promises';
|
|
13
|
+
import { dirname, join } from 'node:path';
|
|
14
|
+
import { parseJsonText, updateJsonAtomic } from '../../../../shared/atomic-file.mjs';
|
|
15
|
+
import { ACTION_KINDS, isRememberableAction } from './outbound-policy.mjs';
|
|
16
|
+
|
|
17
|
+
const ANY_AGENT = '*';
|
|
18
|
+
const FIELD_LIMIT = 200;
|
|
19
|
+
const AUDIT_KEYS = ['agentId', 'kind', 'action', 'tool', 'target', 'decision', 'device'];
|
|
20
|
+
export const PERMISSION_MODES = Object.freeze(['ask', 'allow', 'block']);
|
|
21
|
+
|
|
22
|
+
const field = (value) => String(value ?? '').slice(0, FIELD_LIMIT);
|
|
23
|
+
const grantId = (agentId, action) =>
|
|
24
|
+
`grant_${createHash('sha256').update(`${agentId}\n${action}`).digest('hex').slice(0, 24)}`;
|
|
25
|
+
const isGrant = (row) => ACTION_KINDS.includes(row?.action) && (row.mode === 'allow' || row.mode === 'block');
|
|
26
|
+
|
|
27
|
+
export function createHumanGateStore(directory) {
|
|
28
|
+
const grantsFile = join(directory, 'grants.json');
|
|
29
|
+
const auditFile = join(directory, 'audit.jsonl');
|
|
30
|
+
const grantsOf = (doc) => (Array.isArray(doc?.grants) ? doc.grants.filter(isGrant) : []);
|
|
31
|
+
async function readGrants() {
|
|
32
|
+
try {
|
|
33
|
+
return grantsOf(parseJsonText(await readFile(grantsFile, 'utf8')));
|
|
34
|
+
} catch (error) {
|
|
35
|
+
if (error?.code === 'ENOENT') return [];
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function updateGrants(mutate) {
|
|
40
|
+
await mkdir(directory, { recursive: true });
|
|
41
|
+
let result;
|
|
42
|
+
await updateJsonAtomic(grantsFile, (doc) => {
|
|
43
|
+
const out = mutate(grantsOf(doc));
|
|
44
|
+
if (!out) return undefined;
|
|
45
|
+
result = out.result;
|
|
46
|
+
return { grants: out.grants };
|
|
47
|
+
});
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
/** Set `agentId`'s mode for `action`; `ask` removes its grant. Returns the
|
|
51
|
+
* grant, or null for `ask` and for an `allow` that may not exist. */
|
|
52
|
+
async function setMode({ agentId, action, mode, device = '' }) {
|
|
53
|
+
if (!ACTION_KINDS.includes(action) || !PERMISSION_MODES.includes(mode)) return null;
|
|
54
|
+
if (mode === 'allow' && !isRememberableAction(action)) return null;
|
|
55
|
+
const owner = field(agentId);
|
|
56
|
+
const id = grantId(owner, action);
|
|
57
|
+
const grant = mode === 'ask' ? null : { id, agentId: owner, action, mode, device: field(device), at: Date.now() };
|
|
58
|
+
await updateGrants((grants) => ({
|
|
59
|
+
grants: [...grants.filter((row) => row.id !== id), ...(grant ? [grant] : [])],
|
|
60
|
+
result: grant,
|
|
61
|
+
}));
|
|
62
|
+
return grant;
|
|
63
|
+
}
|
|
64
|
+
/** `allow`, `block` or `ask` for `agentId` + `action`; the agent's own grant wins. */
|
|
65
|
+
async function modeFor({ agentId, action }) {
|
|
66
|
+
const grants = (await readGrants()).filter((grant) => grant.action === action);
|
|
67
|
+
const own =
|
|
68
|
+
grants.find((grant) => grant.agentId === agentId) || grants.find((grant) => grant.agentId === ANY_AGENT);
|
|
69
|
+
if (own?.mode === 'allow' && !isRememberableAction(action)) return 'ask';
|
|
70
|
+
return own?.mode || 'ask';
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
setMode,
|
|
74
|
+
modeFor,
|
|
75
|
+
/** Stores an `allow` for `agent`/`always` scope; `once` stores nothing. Returns the grant or null. */
|
|
76
|
+
async grant({ agentId, action, scope, device = '' }) {
|
|
77
|
+
if (scope !== 'agent' && scope !== 'always') return null;
|
|
78
|
+
return setMode({ agentId: scope === 'always' ? ANY_AGENT : agentId, action, mode: 'allow', device });
|
|
79
|
+
},
|
|
80
|
+
/** Every action kind with `agentId`'s mode, for the profile's permission table. */
|
|
81
|
+
async permissions(agentId) {
|
|
82
|
+
const out = [];
|
|
83
|
+
for (const action of ACTION_KINDS) {
|
|
84
|
+
out.push({ action, mode: await modeFor({ agentId, action }), rememberable: isRememberableAction(action) });
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
},
|
|
88
|
+
/** Grants that apply to `agentId` (its own and every-agent ones); all when omitted. */
|
|
89
|
+
async listGrants({ agentId } = {}) {
|
|
90
|
+
const grants = await readGrants();
|
|
91
|
+
return agentId ? grants.filter((grant) => grant.agentId === agentId || grant.agentId === ANY_AGENT) : grants;
|
|
92
|
+
},
|
|
93
|
+
async revokeGrant(id) {
|
|
94
|
+
return (
|
|
95
|
+
(await updateGrants((grants) => {
|
|
96
|
+
const rest = grants.filter((grant) => grant.id !== id);
|
|
97
|
+
return rest.length === grants.length ? null : { grants: rest, result: true };
|
|
98
|
+
})) === true
|
|
99
|
+
);
|
|
100
|
+
},
|
|
101
|
+
async recordAudit(entry) {
|
|
102
|
+
const line = { at: Number.isFinite(entry?.at) ? entry.at : Date.now() };
|
|
103
|
+
for (const key of AUDIT_KEYS) line[key] = field(entry?.[key]);
|
|
104
|
+
await mkdir(dirname(auditFile), { recursive: true });
|
|
105
|
+
await appendFile(auditFile, `${JSON.stringify(line)}\n`, 'utf8');
|
|
106
|
+
return line;
|
|
107
|
+
},
|
|
108
|
+
/** Newest first; `agentId` filters to one agent. */
|
|
109
|
+
async readAudit({ agentId = '', limit = 100 } = {}) {
|
|
110
|
+
let raw = '';
|
|
111
|
+
try {
|
|
112
|
+
raw = await readFile(auditFile, 'utf8');
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if (error?.code === 'ENOENT') return [];
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
const rows = [];
|
|
118
|
+
for (const line of raw.split('\n').reverse()) {
|
|
119
|
+
if (!line) continue;
|
|
120
|
+
try {
|
|
121
|
+
const row = JSON.parse(line);
|
|
122
|
+
if (!agentId || row.agentId === agentId) rows.push(row);
|
|
123
|
+
} catch {}
|
|
124
|
+
if (rows.length >= limit) break;
|
|
125
|
+
}
|
|
126
|
+
return rows;
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let processStore = null;
|
|
132
|
+
/** The process store under the plugin data dir; built on first use. */
|
|
133
|
+
export async function humanGateStore() {
|
|
134
|
+
if (!processStore) {
|
|
135
|
+
const { getPluginData } = await import('../../config.mjs');
|
|
136
|
+
processStore = createHumanGateStore(join(getPluginData(), 'human-gate'));
|
|
137
|
+
}
|
|
138
|
+
return processStore;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function requiredAgentId(agentId) {
|
|
142
|
+
if (typeof agentId !== 'string' || !agentId.trim() || agentId.length > FIELD_LIMIT || agentId === ANY_AGENT) {
|
|
143
|
+
throw new Error('agent id is invalid');
|
|
144
|
+
}
|
|
145
|
+
return agentId;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** The profile's "권한" table for `agentId` (capability getAgentPermissions). */
|
|
149
|
+
export async function agentPermissions(agentId) {
|
|
150
|
+
return (await humanGateStore()).permissions(requiredAgentId(agentId));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Set one row of that table (capability setAgentPermission); returns the table. */
|
|
154
|
+
export async function setAgentPermission(agentId, action, mode) {
|
|
155
|
+
const agent = requiredAgentId(agentId);
|
|
156
|
+
if (!ACTION_KINDS.includes(action)) throw new Error(`action must be one of ${ACTION_KINDS.join(', ')}`);
|
|
157
|
+
if (!PERMISSION_MODES.includes(mode)) throw new Error(`mode must be one of ${PERMISSION_MODES.join(', ')}`);
|
|
158
|
+
if (mode === 'allow' && !isRememberableAction(action)) throw new Error(`${action} always asks; it cannot be allowed`);
|
|
159
|
+
const store = await humanGateStore();
|
|
160
|
+
await store.setMode({ agentId: agent, action, mode });
|
|
161
|
+
return store.permissions(agent);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Replace the process store (tests); null restores the default. */
|
|
165
|
+
export function setHumanGateStore(store) {
|
|
166
|
+
processStore = store || null;
|
|
167
|
+
}
|
|
@@ -189,6 +189,15 @@ export function readTopLevelLifecycleRecord(raw) {
|
|
|
189
189
|
// — for EVERY top-level key, since consumers reserialize and act on the
|
|
190
190
|
// whole record, not only on the lifecycle three.
|
|
191
191
|
if (!hasUniqueTopLevelKeys(raw)) return LIFECYCLE_SCAN_CONFLICT;
|
|
192
|
+
return lifecycleRecordOf(doc);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Step 3 alone, for a reader that has already proven `doc` is the complete,
|
|
197
|
+
* well-formed, duplicate-free top-level object of its document (see
|
|
198
|
+
* store-record-strict-scan.mjs): the record, or LIFECYCLE_SCAN_CONFLICT.
|
|
199
|
+
*/
|
|
200
|
+
export function lifecycleRecordOf(doc) {
|
|
192
201
|
const has = (key) => Object.hasOwn(doc, key);
|
|
193
202
|
const record = { doc, id: undefined, closed: undefined, generation: undefined };
|
|
194
203
|
if (has('id')) {
|
|
@@ -17,6 +17,7 @@ import { HANDOFF_TIMEOUT_MAX_MS } from '../compact/constants.mjs';
|
|
|
17
17
|
import { envFlag, envPositiveInt } from '../../../../shared/env.mjs';
|
|
18
18
|
import { positiveInt } from '../../../../shared/numbers.mjs';
|
|
19
19
|
import { isAgentOwner } from '../../agent-owner.mjs';
|
|
20
|
+
import { isAgentModeSession } from '../agent-mode.mjs';
|
|
20
21
|
import { providerInputExcludesCache, providerNativePdf } from '../../providers/registry.mjs';
|
|
21
22
|
import { contentMediaBytes, contentMediaCount } from '../../providers/media-normalization.mjs';
|
|
22
23
|
import { splitProtectedContext } from '../compact/messages.mjs';
|
|
@@ -133,7 +134,8 @@ function effectiveContextWindowPercent(sessionRef, cfg) {
|
|
|
133
134
|
export function resolveWorkerCompactPolicy(sessionRef, tools) {
|
|
134
135
|
if (!sessionRef) return null;
|
|
135
136
|
const cfg = sessionRef.compaction || {};
|
|
136
|
-
|
|
137
|
+
// Agent mode always compacts on its own: the user is never asked to.
|
|
138
|
+
const auto = (cfg.auto !== false || isAgentModeSession(sessionRef)) && envFlag('MIXDOG_AGENT_COMPACT_AUTO', true);
|
|
137
139
|
if (!auto) return { auto: false };
|
|
138
140
|
const { contextWindow, boundaryTokens } = compactBoundaryFor(sessionRef, cfg);
|
|
139
141
|
if (!boundaryTokens) return null;
|