mixdog 1.3.2 → 1.3.4
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/package.json +8 -8
- package/scripts/verify-runtime-dependency-versions.mjs +158 -0
- package/src/agents/reviewer/AGENT.md +5 -7
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +4 -0
- package/src/defaults/skills/browser-use/SKILL.md +6 -3
- package/src/defaults/skills/local-provider/SKILL.md +33 -6
- package/src/rules/lead/LEAD.md +5 -8
- package/src/rules/shared/45-destructive.md +5 -1
- package/src/rules/shared/60-verification.md +6 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +38 -11
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +15 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +17 -4
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +13 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +5 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +10 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +40 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +32 -11
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +13 -0
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +68 -12
- package/src/runtime/agent/orchestrator/session/compact/continuation.mjs +15 -6
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +31 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +44 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +117 -19
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +147 -137
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +37 -74
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +0 -2
- package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +13 -7
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/empty-nudge.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +62 -13
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +22 -6
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +12 -20
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/call-prep.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/manager/agent-listing-notice.mjs +102 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +24 -15
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +32 -1
- package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +17 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +36 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -9
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +7 -5
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +7 -3
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +10 -1
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +7 -4
- package/src/runtime/agent/orchestrator/session/runtime-user-context.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +140 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +76 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +33 -1
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.d.mts +5 -0
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +37 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +1 -0
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +18 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +127 -20
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +557 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +8 -2
- package/src/runtime/attachments/legacy-office.mjs +110 -0
- package/src/runtime/attachments/prompt-restore.mjs +70 -0
- package/src/runtime/attachments/store.mjs +60 -3
- package/src/runtime/effort-judge/judge-client.mjs +61 -14
- package/src/runtime/effort-judge/model-install.mjs +34 -2
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +14 -2
- package/src/runtime/office/portable/portable-soffice.mjs +132 -30
- package/src/runtime/shared/agent-avatar-sprites.mjs +23 -8
- package/src/runtime/shared/agent-avatar.mjs +3 -2
- package/src/runtime/shared/agent-room-host.d.mts +31 -0
- package/src/runtime/shared/agent-room-host.mjs +58 -0
- package/src/runtime/shared/bot-hops.mjs +16 -11
- package/src/runtime/shared/llm/usage-rollup.mjs +4 -383
- package/src/runtime/shared/redact-directories.mjs +18 -0
- package/src/runtime/shared/remove-directory.mjs +28 -0
- package/src/runtime/shared/session-sidebar-host.d.mts +11 -2
- package/src/runtime/shared/session-sidebar-host.mjs +16 -3
- package/src/runtime/shared/tool-execution-contract.mjs +4 -0
- package/src/runtime/shared/tool-work-units.mjs +12 -9
- package/src/runtime/shared/turn-snapshot.mjs +233 -122
- package/src/runtime/shared/user-data-guard.mjs +51 -19
- package/src/runtime/shared/worktrees/activity-gate.mjs +209 -227
- package/src/runtime/shared/worktrees/contract.mjs +11 -3
- package/src/runtime/shared/worktrees/maintenance.mjs +11 -2
- package/src/runtime/shared/worktrees/manager.mjs +419 -52
- package/src/runtime/shared/worktrees/registry.mjs +3 -1
- package/src/runtime/shared/worktrees/tool-host.mjs +39 -0
- package/src/runtime/tidy/process.mjs +41 -8
- package/src/runtime/tidy/resolve.mjs +10 -7
- package/src/session-runtime/agent-home-delivery.mjs +73 -91
- package/src/session-runtime/agent-profile-changes.mjs +16 -0
- package/src/session-runtime/agent-room-delivery.mjs +2 -63
- package/src/session-runtime/agent-task-sessions.mjs +194 -64
- package/src/session-runtime/agent-tool-routing.mjs +49 -4
- package/src/session-runtime/boot/apis.mjs +3 -0
- package/src/session-runtime/boot/facade.mjs +5 -6
- package/src/session-runtime/boot/tools.mjs +23 -1
- package/src/session-runtime/held-requests.mjs +20 -25
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +5 -22
- package/src/session-runtime/model-recency.mjs +1 -0
- package/src/session-runtime/provider-models/row-hydration.mjs +8 -1
- package/src/session-runtime/quick-model-rows/model-meta.mjs +2 -0
- package/src/session-runtime/quick-model-rows/provider-rows.mjs +7 -1
- package/src/session-runtime/runtime-review-api.mjs +4 -1
- package/src/session-runtime/services/agent-tool/close-flow.mjs +14 -2
- package/src/session-runtime/services/agent-tool/execute.mjs +6 -1
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +44 -20
- package/src/session-runtime/services/agent-tool/render.mjs +3 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -0
- package/src/session-runtime/services/agent-tool/tool-def.mjs +1 -1
- package/src/session-runtime/services/provider-admin.mjs +12 -2
- package/src/session-runtime/services/worktree-access.mjs +27 -0
- package/src/session-runtime/session-hooks.mjs +9 -17
- package/src/session-runtime/settings-builtin-tools-api.mjs +2 -0
- package/src/session-runtime/setup-tool/executor.mjs +4 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +3 -0
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +98 -14
- package/src/session-runtime/tool-policy/policy-stage.mjs +23 -5
- package/src/session-runtime/tool-policy-refresh.mjs +1 -0
- package/src/session-runtime/tool-surface.mjs +9 -5
- package/src/session-runtime/turn/session-ops.mjs +8 -0
- package/src/session-runtime/turn/turn-run.mjs +5 -1
- package/src/session-runtime/usage-stats-api.mjs +1 -1
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +10 -2
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +39 -17
- package/src/session-runtime/workspace/transition-steps.mjs +1 -18
- package/src/session-runtime/workspace/transitions.mjs +279 -67
- package/src/session-runtime/workspace/worktree-tool.mjs +194 -0
- package/src/standalone/daemon-lag-profiler.mjs +3 -1
- package/src/standalone/daemon-session-control.mjs +140 -23
- package/src/standalone/daemon-telemetry.mjs +9 -0
- package/src/standalone/daemon.mjs +5 -0
- package/src/standalone/local-session-runtime.mjs +11 -2
- package/src/standalone/session-protocol.mjs +1 -0
- package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +2 -0
- package/src/standalone/session-service/agent-route-follow.mjs +69 -0
- package/src/standalone/session-service/session-calls/session-turns.mjs +33 -4
- package/src/standalone/session-service.mjs +10 -0
- package/src/standalone/session-tool-output.mjs +1 -0
- package/src/standalone/staged-import.mjs +47 -0
- package/src/tui/App.jsx +2 -0
- package/src/tui/app/message-selector.mjs +15 -2
- package/src/tui/app/model-options.mjs +16 -2
- package/src/tui/app/model-picker.mjs +2 -1
- package/src/tui/app/route-pickers.mjs +3 -1
- package/src/tui/dist/index.mjs +403 -210
- package/src/tui/paste-attachments.mjs +0 -1
- package/src/tui/paste-text-policy.mjs +4 -5
- package/src/tui/session/agent-job-feed/execution-delivery.mjs +4 -1
- package/src/tui/session/notice-surface.mjs +3 -0
- package/src/tui/session/session-api/intake/abort.mjs +33 -17
- package/src/tui/session/session-api/intake/rewind.mjs +39 -4
- package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
- package/src/tui/session/tool-approval.mjs +11 -48
- package/src/vendor/statusline/src/gateway/claude-current.mjs +0 -58
- package/src/vendor/statusline/src/gateway/route-meta.mjs +1 -361
- package/src/vendor/statusline/src/gateway/session-routes.mjs +0 -55
- package/src/session-runtime/room-member-gate.mjs +0 -61
- package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +0 -285
|
@@ -9,12 +9,6 @@ import { resolvePluginData } from '../../../../runtime/shared/plugin-paths.mjs';
|
|
|
9
9
|
import { readSection } from '../../../../runtime/shared/config.mjs';
|
|
10
10
|
import { withFileLock, withFileLockSync } from '../../../../runtime/shared/file-lock.mjs';
|
|
11
11
|
import { computeCostUsd, isInclusiveProvider } from '../../../../runtime/shared/llm/cost.mjs';
|
|
12
|
-
import { getModelMetadataSync } from '../../../../runtime/agent/orchestrator/providers/model-catalog.mjs';
|
|
13
|
-
import {
|
|
14
|
-
estimateMessagesTokens,
|
|
15
|
-
estimateRequestReserveTokens,
|
|
16
|
-
} from '../../../../runtime/agent/orchestrator/session/context-utils.mjs';
|
|
17
|
-
import { CLAUDE_CURRENT_MODE } from './claude-current.mjs';
|
|
18
12
|
|
|
19
13
|
// Legacy store: one JSON document rewritten on every flush. Current store: an
|
|
20
14
|
// append-only JSONL (one event per line) compacted off the hot path.
|
|
@@ -49,10 +43,6 @@ function round(value, digits = 6) {
|
|
|
49
43
|
return Math.round(n * scale) / scale;
|
|
50
44
|
}
|
|
51
45
|
|
|
52
|
-
function hasOwn(obj, key) {
|
|
53
|
-
return !!obj && Object.prototype.hasOwnProperty.call(obj, key);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
46
|
function readJsonFile(file) {
|
|
57
47
|
try {
|
|
58
48
|
if (!existsSync(file)) return null;
|
|
@@ -78,27 +68,11 @@ function providerSection(provider) {
|
|
|
78
68
|
: {};
|
|
79
69
|
}
|
|
80
70
|
|
|
81
|
-
function gatewayPresets() {
|
|
82
|
-
const agent = agentConfigSection();
|
|
83
|
-
return Array.isArray(agent?.presets) ? agent.presets : [];
|
|
84
|
-
}
|
|
85
|
-
|
|
86
71
|
function cleanString(value) {
|
|
87
72
|
const s = typeof value === 'string' ? value.trim() : '';
|
|
88
73
|
return s || null;
|
|
89
74
|
}
|
|
90
75
|
|
|
91
|
-
function cleanBool(value) {
|
|
92
|
-
if (value === true) return true;
|
|
93
|
-
if (value === false) return false;
|
|
94
|
-
if (typeof value === 'string') {
|
|
95
|
-
const s = value.trim().toLowerCase();
|
|
96
|
-
if (['1', 'true', 'yes', 'on', 'fast', 'priority', 'ultrafast'].includes(s)) return true;
|
|
97
|
-
if (['0', 'false', 'no', 'off', 'none'].includes(s)) return false;
|
|
98
|
-
}
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
76
|
function providerKind(provider) {
|
|
103
77
|
const p = String(provider || '').toLowerCase();
|
|
104
78
|
if (!p) return 'unknown';
|
|
@@ -107,12 +81,6 @@ function providerKind(provider) {
|
|
|
107
81
|
return 'api';
|
|
108
82
|
}
|
|
109
83
|
|
|
110
|
-
function boundedPercent(value, fallback = null) {
|
|
111
|
-
const n = Number(value);
|
|
112
|
-
if (Number.isFinite(n) && n > 0 && n <= 100) return n;
|
|
113
|
-
return fallback;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
84
|
export function defaultEffectiveContextWindowPercent(_provider) {
|
|
117
85
|
// Gateway/statusline reports the full model boundary. Trigger headroom is a
|
|
118
86
|
// Compact policy concern and must not shrink the displayed denominator.
|
|
@@ -120,60 +88,6 @@ export function defaultEffectiveContextWindowPercent(_provider) {
|
|
|
120
88
|
return 100;
|
|
121
89
|
}
|
|
122
90
|
|
|
123
|
-
function effectiveContextWindowPercent(provider, info = {}, seed = {}) {
|
|
124
|
-
return boundedPercent(
|
|
125
|
-
seed.effectiveContextWindowPercent
|
|
126
|
-
?? seed.effective_context_window_percent
|
|
127
|
-
?? info.effectiveContextWindowPercent
|
|
128
|
-
?? info.effective_context_window_percent,
|
|
129
|
-
defaultEffectiveContextWindowPercent(provider),
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function effectiveContextWindow(rawContextWindow, percent) {
|
|
134
|
-
const raw = num(rawContextWindow, 0);
|
|
135
|
-
if (!(raw > 0)) return null;
|
|
136
|
-
const pct = boundedPercent(percent, 100);
|
|
137
|
-
return Math.max(1, Math.floor(raw * pct / 100));
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function autoCompactTokenLimit(provider, rawContextWindow, contextWindow, info = {}, seed = {}) {
|
|
141
|
-
// routeInfo.autoCompactTokenLimit is an EXPLICIT auto-compaction limit only.
|
|
142
|
-
// It must NOT be derived from the effective/raw context window: the runtime
|
|
143
|
-
// (manager.mjs resolveSessionContextMeta / loop.mjs resolveWorkerCompactPolicy)
|
|
144
|
-
// treats autoCompactTokenLimit as the compaction trigger. Deriving it from the
|
|
145
|
-
// full boundary makes autoTriggerTokens == boundary, collapses the compaction
|
|
146
|
-
// buffer to 0, and auto-compaction only fires once the window is already full
|
|
147
|
-
// (where semantic compact overflows and the turn is lost). The boundary/window
|
|
148
|
-
// fallback that status + gateway env still need lives in compactBoundaryForRoute
|
|
149
|
-
// / autoCompactWindowForRoute, which read contextWindow/rawContextWindow
|
|
150
|
-
// directly. Return null when there is no explicit provider/catalog/seed limit.
|
|
151
|
-
const explicit = num(
|
|
152
|
-
seed.autoCompactTokenLimit
|
|
153
|
-
?? seed.auto_compact_token_limit
|
|
154
|
-
?? info.autoCompactTokenLimit
|
|
155
|
-
?? info.auto_compact_token_limit,
|
|
156
|
-
0,
|
|
157
|
-
);
|
|
158
|
-
if (!(explicit > 0)) return null;
|
|
159
|
-
// An explicit limit is only a real auto-compaction trigger when it sits
|
|
160
|
-
// STRICTLY BELOW the boundary/window. A legacy seed/info value equal to or
|
|
161
|
-
// above the boundary is a derived full-window artifact — returning
|
|
162
|
-
// Math.min(explicit, derived) would still surface the boundary, which the
|
|
163
|
-
// runtime then treats as the trigger and collapses the compaction buffer.
|
|
164
|
-
// Drop those to null so display + downstream fall back to the default
|
|
165
|
-
// boundary trigger.
|
|
166
|
-
const derived = num(contextWindow, 0) || num(rawContextWindow, 0);
|
|
167
|
-
if (derived > 0) return explicit < derived ? explicit : null;
|
|
168
|
-
// No boundary known: keep the positive explicit value (cannot be proven to
|
|
169
|
-
// be a full-window artifact), but never derive one.
|
|
170
|
-
return explicit;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Test-only export of the explicit-vs-derived auto-compact-limit resolver
|
|
174
|
-
// (see scripts/compact-trigger-migration-smoke.mjs).
|
|
175
|
-
export const _autoCompactTokenLimit = autoCompactTokenLimit;
|
|
176
|
-
|
|
177
91
|
function routeIdentityKey(routeInfo = {}) {
|
|
178
92
|
return [
|
|
179
93
|
routeInfo.provider || '',
|
|
@@ -198,196 +112,7 @@ function shouldTrackDollarSpend(routeInfo = {}) {
|
|
|
198
112
|
return kind === 'api' || kind === 'quota-api';
|
|
199
113
|
}
|
|
200
114
|
|
|
201
|
-
|
|
202
|
-
return cleanString(p?.name) || cleanString(p?.id) || null;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function findPresetForRoute(provider, model, gateway) {
|
|
206
|
-
const presets = gatewayPresets().filter(p => p?.provider === provider && p?.model === model);
|
|
207
|
-
if (!presets.length) return null;
|
|
208
|
-
if (cleanString(gateway?.mode) === CLAUDE_CURRENT_MODE) {
|
|
209
|
-
const effort = cleanString(gateway?.effort ?? gateway?.displayEffort);
|
|
210
|
-
const fast = cleanBool(gateway?.fast);
|
|
211
|
-
if (effort || fast !== null) {
|
|
212
|
-
const exact = presets.find(p =>
|
|
213
|
-
(!effort || cleanString(p.effort) === effort) &&
|
|
214
|
-
(fast === null || cleanBool(p.fast) === fast)
|
|
215
|
-
);
|
|
216
|
-
if (exact) return exact;
|
|
217
|
-
}
|
|
218
|
-
return presets.length === 1 ? presets[0] : null;
|
|
219
|
-
}
|
|
220
|
-
const presetId = cleanString(gateway?.presetId);
|
|
221
|
-
const presetName = cleanString(gateway?.presetName);
|
|
222
|
-
if (presetId || presetName) {
|
|
223
|
-
const exact = presets.find(p =>
|
|
224
|
-
(presetId && p.id === presetId) ||
|
|
225
|
-
(presetName && (p.name === presetName || p.id === presetName))
|
|
226
|
-
);
|
|
227
|
-
if (exact) return exact;
|
|
228
|
-
}
|
|
229
|
-
const effort = cleanString(gateway?.effort ?? gateway?.displayEffort);
|
|
230
|
-
const fast = cleanBool(gateway?.fast);
|
|
231
|
-
if (effort || fast !== null) {
|
|
232
|
-
const exact = presets.find(p =>
|
|
233
|
-
(!effort || cleanString(p.effort) === effort) &&
|
|
234
|
-
(fast === null || cleanBool(p.fast) === fast)
|
|
235
|
-
);
|
|
236
|
-
if (exact) return exact;
|
|
237
|
-
}
|
|
238
|
-
return presets.length === 1 ? presets[0] : null;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
function loadCachedModel(provider, model) {
|
|
242
|
-
const files = [
|
|
243
|
-
`${provider}-models.json`,
|
|
244
|
-
provider === 'openai-oauth' ? 'openai-oauth-models.json' : null,
|
|
245
|
-
provider === 'anthropic-oauth' ? 'anthropic-oauth-models.json' : null,
|
|
246
|
-
provider === 'grok-oauth' ? 'grok-oauth-models.json' : null,
|
|
247
|
-
].filter(Boolean);
|
|
248
|
-
const dataDir = resolvePluginData();
|
|
249
|
-
for (const name of files) {
|
|
250
|
-
const raw = readJsonFile(join(dataDir, name));
|
|
251
|
-
const models = Array.isArray(raw?.models) ? raw.models : Array.isArray(raw) ? raw : [];
|
|
252
|
-
const found = models.find(m => (m?.id || m?.name || m?.slug) === model);
|
|
253
|
-
if (found) return found;
|
|
254
|
-
}
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function modelInfoFromProvider(providerObj, model) {
|
|
259
|
-
try {
|
|
260
|
-
const info = providerObj?.getCachedModelInfo?.(model);
|
|
261
|
-
return info && typeof info === 'object' ? info : null;
|
|
262
|
-
} catch {
|
|
263
|
-
return null;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function displayForModel(provider, model, info) {
|
|
268
|
-
const display = cleanString(info?.display) || cleanString(info?.displayName) || cleanString(info?.name);
|
|
269
|
-
if (display) return display;
|
|
270
|
-
if (provider === 'anthropic-oauth') {
|
|
271
|
-
const m = String(model || '').match(/^claude-(opus|sonnet|haiku|fable)-(\d+)(?:-(\d+))?/i);
|
|
272
|
-
if (m) return `${m[1][0].toUpperCase()}${m[1].slice(1).toLowerCase()} ${m[2]}${m[3] ? `.${m[3]}` : ''}`;
|
|
273
|
-
}
|
|
274
|
-
return model || '';
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function mergeModelInfo(provider, model, providerObj) {
|
|
278
|
-
const fromProvider = modelInfoFromProvider(providerObj, model);
|
|
279
|
-
const fromCache = loadCachedModel(provider, model);
|
|
280
|
-
const fromCatalog = getModelMetadataSync(model, provider);
|
|
281
|
-
const merged = {
|
|
282
|
-
...(fromCatalog || {}),
|
|
283
|
-
...(fromCache || {}),
|
|
284
|
-
...(fromProvider || {}),
|
|
285
|
-
};
|
|
286
|
-
// Catalog/known metadata is authoritative for the context window. Spreading
|
|
287
|
-
// fromCache after fromCatalog otherwise lets a STALE cached window (e.g. Opus
|
|
288
|
-
// 4.8 cached at 272k after its window grew to the catalog's 1M) override the
|
|
289
|
-
// catalog. Only a live provider API window (context_window / max_context_window)
|
|
290
|
-
// outranks the catalog; when the provider info supplies no such window and the
|
|
291
|
-
// catalog disagrees with the merged (cached) window, prefer the catalog.
|
|
292
|
-
const providerApiWindow = num(
|
|
293
|
-
fromProvider?.context_window ?? fromProvider?.max_context_window,
|
|
294
|
-
0,
|
|
295
|
-
);
|
|
296
|
-
const catalogWindow = num(
|
|
297
|
-
fromCatalog?.contextWindow
|
|
298
|
-
?? fromCatalog?.maxContextWindow
|
|
299
|
-
?? fromCatalog?.context_window
|
|
300
|
-
?? fromCatalog?.max_context_window,
|
|
301
|
-
0,
|
|
302
|
-
);
|
|
303
|
-
const mergedWindow = num(merged?.contextWindow ?? merged?.maxContextWindow, 0);
|
|
304
|
-
if (!providerApiWindow && catalogWindow > 0 && mergedWindow !== catalogWindow) {
|
|
305
|
-
merged.contextWindow = catalogWindow;
|
|
306
|
-
merged.maxContextWindow = catalogWindow;
|
|
307
|
-
}
|
|
308
|
-
return merged;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
export function readGatewayRouteInfo(seed = {}, providerObj = null) {
|
|
312
|
-
let gateway = {};
|
|
313
|
-
try { gateway = gatewaySection(); } catch { gateway = {}; }
|
|
314
|
-
const mode = cleanString(seed.mode) || cleanString(gateway.mode);
|
|
315
|
-
const inheritClaudeCurrent = mode === CLAUDE_CURRENT_MODE;
|
|
316
|
-
const seedProvider = cleanString(seed.provider ?? seed.defaultProvider);
|
|
317
|
-
const seedModel = cleanString(seed.model ?? seed.defaultModel);
|
|
318
|
-
const provider = cleanString(process.env.MIXDOG_GATEWAY_PROVIDER)
|
|
319
|
-
|| seedProvider
|
|
320
|
-
|| cleanString(gateway.defaultProvider);
|
|
321
|
-
const model = cleanString(process.env.MIXDOG_GATEWAY_MODEL)
|
|
322
|
-
|| seedModel
|
|
323
|
-
|| cleanString(gateway.defaultModel);
|
|
324
|
-
if (!provider || !model) return { provider, model, mode };
|
|
325
|
-
|
|
326
|
-
const routeGateway = {
|
|
327
|
-
...gateway,
|
|
328
|
-
...(seed?.presetId ? { presetId: seed.presetId } : {}),
|
|
329
|
-
...(seed?.presetName ? { presetName: seed.presetName } : {}),
|
|
330
|
-
...(seed?.effort || seed?.displayEffort ? { effort: seed.effort ?? seed.displayEffort } : {}),
|
|
331
|
-
...(hasOwn(seed, 'fast') ? { fast: seed.fast } : {}),
|
|
332
|
-
};
|
|
333
|
-
const seedGateway = inheritClaudeCurrent
|
|
334
|
-
? {
|
|
335
|
-
mode,
|
|
336
|
-
effort: seed.effort ?? seed.displayEffort ?? gateway.effort ?? gateway.displayEffort,
|
|
337
|
-
fast: seed.fast ?? gateway.fast,
|
|
338
|
-
}
|
|
339
|
-
: routeGateway;
|
|
340
|
-
const preset = findPresetForRoute(provider, model, seedGateway);
|
|
341
|
-
const effort = cleanString(process.env.MIXDOG_GATEWAY_EFFORT)
|
|
342
|
-
|| cleanString(seed.effort ?? seed.displayEffort)
|
|
343
|
-
|| cleanString(gateway.effort ?? gateway.displayEffort)
|
|
344
|
-
|| cleanString(preset?.effort);
|
|
345
|
-
const fast = cleanBool(process.env.MIXDOG_GATEWAY_FAST)
|
|
346
|
-
?? cleanBool(seed.fast)
|
|
347
|
-
?? cleanBool(gateway.fast)
|
|
348
|
-
?? cleanBool(preset?.fast)
|
|
349
|
-
?? false;
|
|
350
|
-
const info = mergeModelInfo(provider, model, providerObj);
|
|
351
|
-
const rawContextWindow = num(
|
|
352
|
-
info?.context_window
|
|
353
|
-
?? info?.max_context_window
|
|
354
|
-
?? info?.contextWindow
|
|
355
|
-
?? info?.maxContextWindow
|
|
356
|
-
?? info?.max_input_tokens,
|
|
357
|
-
0,
|
|
358
|
-
)
|
|
359
|
-
|| num(seed.contextWindow, 0);
|
|
360
|
-
const effectivePercent = effectiveContextWindowPercent(provider, info, seed);
|
|
361
|
-
const contextWindow = effectiveContextWindow(rawContextWindow, effectivePercent);
|
|
362
|
-
const compactLimit = autoCompactTokenLimit(provider, rawContextWindow, contextWindow, info, seed);
|
|
363
|
-
const outputTokens = num(info?.outputTokens ?? info?.maxOutputTokens ?? info?.max_output_tokens, 0);
|
|
364
|
-
|
|
365
|
-
return {
|
|
366
|
-
mode,
|
|
367
|
-
provider,
|
|
368
|
-
model,
|
|
369
|
-
requestedModel: cleanString(seed.requestedModel) || null,
|
|
370
|
-
providerKind: providerKind(provider),
|
|
371
|
-
modelDisplay: cleanString(seed.modelDisplay) || displayForModel(provider, model, info),
|
|
372
|
-
presetId: inheritClaudeCurrent ? cleanString(preset?.id) : cleanString(seed.presetId) || cleanString(gateway.presetId) || cleanString(preset?.id),
|
|
373
|
-
presetName: inheritClaudeCurrent ? presetLabel(preset) : cleanString(seed.presetName) || cleanString(gateway.presetName) || presetLabel(preset),
|
|
374
|
-
effort,
|
|
375
|
-
fast,
|
|
376
|
-
thinkingBudgetTokens: num(seed.thinkingBudgetTokens, null),
|
|
377
|
-
contextWindow: contextWindow > 0 ? contextWindow : null,
|
|
378
|
-
rawContextWindow: rawContextWindow > 0 ? rawContextWindow : null,
|
|
379
|
-
effectiveContextWindowPercent: effectivePercent,
|
|
380
|
-
autoCompactTokenLimit: compactLimit,
|
|
381
|
-
outputTokens: outputTokens > 0 ? outputTokens : null,
|
|
382
|
-
inputCostPerM: info?.inputCostPerM ?? null,
|
|
383
|
-
outputCostPerM: info?.outputCostPerM ?? null,
|
|
384
|
-
cacheReadCostPerM: info?.cacheReadCostPerM ?? null,
|
|
385
|
-
cacheWriteCostPerM: info?.cacheWriteCostPerM ?? null,
|
|
386
|
-
serviceTier: cleanString(info?.defaultServiceTier) || null,
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Boundary denominator for status %, overflow checks, and gateway env window.
|
|
115
|
+
// Boundary denominator for status percentages and usage telemetry.
|
|
391
116
|
// Order: explicit boundary (routeInfo or compact) → contextWindow → budgetWindow
|
|
392
117
|
// → rawContextWindow. autoCompactTokenLimit / compactLimitTokens are triggers
|
|
393
118
|
// only and are never read here.
|
|
@@ -414,62 +139,6 @@ export function compactBoundaryDenominator(routeInfo = {}, compact = null) {
|
|
|
414
139
|
return rawContextWindow > 0 ? rawContextWindow : 0;
|
|
415
140
|
}
|
|
416
141
|
|
|
417
|
-
function compactBoundaryForRoute(routeInfo = {}, compact = null) {
|
|
418
|
-
return compactBoundaryDenominator(routeInfo, compact);
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// Single source of truth for the value synced to host env
|
|
422
|
-
// CLAUDE_CODE_AUTO_COMPACT_WINDOW. BOTH the --enable-time write
|
|
423
|
-
// (scripts/gateway-model.mjs) and the runtime sync (src/gateway/server.mjs)
|
|
424
|
-
// must derive the window the SAME way, or they disagree on the value written to
|
|
425
|
-
// settings.json. Denominator order: compactBoundaryTokens / boundaryTokens (route
|
|
426
|
-
// or compact) → contextWindow → budgetWindow → rawContextWindow. Never
|
|
427
|
-
// autoCompactTokenLimit or compactLimitTokens (trigger-only). Returns a positive
|
|
428
|
-
// integer, or null when unknown.
|
|
429
|
-
export function autoCompactWindowForRoute(routeInfo) {
|
|
430
|
-
const n = compactBoundaryForRoute(routeInfo);
|
|
431
|
-
return Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
export function gatewaySendOptions(routeInfo, extra = {}) {
|
|
435
|
-
const opts = {};
|
|
436
|
-
if (routeInfo?.thinkingBudgetTokens) opts.thinkingBudgetTokens = routeInfo.thinkingBudgetTokens;
|
|
437
|
-
if (routeInfo?.effort) opts.effort = routeInfo.effort;
|
|
438
|
-
if (routeInfo?.fast === true) opts.fast = true;
|
|
439
|
-
if (routeInfo?.outputTokens) opts.maxOutputTokens = routeInfo.outputTokens;
|
|
440
|
-
if (extra?.sessionId) opts.sessionId = extra.sessionId;
|
|
441
|
-
return opts;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
export function prepareGatewayMessages(messages, tools, routeInfo, _log = () => {}, opts = {}) {
|
|
445
|
-
const working = messages;
|
|
446
|
-
const contextWindow = num(routeInfo?.contextWindow, 0);
|
|
447
|
-
const compactLimit = num(routeInfo?.autoCompactTokenLimit, 0);
|
|
448
|
-
const budgetWindow = compactBoundaryForRoute(routeInfo);
|
|
449
|
-
const reserveTokens = estimateRequestReserveTokens(tools);
|
|
450
|
-
const beforeTokens = estimateMessagesTokens(working) + reserveTokens;
|
|
451
|
-
const lastPromptTokens = num(opts?.lastPromptTokens, 0);
|
|
452
|
-
const cacheCold = opts?.cacheCold === true;
|
|
453
|
-
const afterTokens = estimateMessagesTokens(working) + reserveTokens;
|
|
454
|
-
const compact = {
|
|
455
|
-
contextWindow: contextWindow > 0 ? contextWindow : null,
|
|
456
|
-
compactLimitTokens: compactLimit > 0 ? compactLimit : null,
|
|
457
|
-
budgetWindow: budgetWindow > 0 ? budgetWindow : null,
|
|
458
|
-
beforeTokens,
|
|
459
|
-
afterTokens,
|
|
460
|
-
reserveTokens,
|
|
461
|
-
lastPromptTokens: lastPromptTokens || null,
|
|
462
|
-
cacheCold,
|
|
463
|
-
method: 'none',
|
|
464
|
-
compacted: false,
|
|
465
|
-
};
|
|
466
|
-
if (budgetWindow > 0 && afterTokens > budgetWindow) compact.overflow = true;
|
|
467
|
-
return {
|
|
468
|
-
messages: working,
|
|
469
|
-
compact,
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
|
|
473
142
|
function promptFootprintTokens(provider, usage) {
|
|
474
143
|
const input = num(usage?.inputTokens, 0);
|
|
475
144
|
const cacheRead = num(usage?.cachedTokens ?? usage?.cacheReadTokens, 0);
|
|
@@ -997,32 +666,3 @@ export function buildGatewayLimits(routeInfo, providerOut = null, usageSnapshot
|
|
|
997
666
|
routeSpend: localRouteSpend(routeInfo),
|
|
998
667
|
};
|
|
999
668
|
}
|
|
1000
|
-
|
|
1001
|
-
export function gatewayAdvertFields(routeInfo, usageSummary = null, limits = null) {
|
|
1002
|
-
ensureRouteSection(routeInfo);
|
|
1003
|
-
const fields = {
|
|
1004
|
-
gateway_route_mode: routeInfo?.mode || null,
|
|
1005
|
-
gateway_provider: routeInfo?.provider || null,
|
|
1006
|
-
gateway_provider_kind: routeInfo?.providerKind || providerKind(routeInfo?.provider),
|
|
1007
|
-
gateway_model: routeInfo?.model || null,
|
|
1008
|
-
gateway_model_display: routeInfo?.modelDisplay || routeInfo?.model || null,
|
|
1009
|
-
gateway_context_window: routeInfo?.contextWindow || null,
|
|
1010
|
-
gateway_raw_context_window: routeInfo?.rawContextWindow || routeInfo?.contextWindow || null,
|
|
1011
|
-
gateway_effective_context_window_percent: routeInfo?.effectiveContextWindowPercent || null,
|
|
1012
|
-
gateway_auto_compact_token_limit: routeInfo?.autoCompactTokenLimit || null,
|
|
1013
|
-
gateway_output_tokens: routeInfo?.outputTokens || null,
|
|
1014
|
-
gateway_preset_id: routeInfo?.presetId || null,
|
|
1015
|
-
gateway_preset_name: routeInfo?.presetName || null,
|
|
1016
|
-
gateway_effort: routeInfo?.effort || null,
|
|
1017
|
-
gateway_fast: routeInfo?.fast === true,
|
|
1018
|
-
gateway_updated_at: Date.now(),
|
|
1019
|
-
};
|
|
1020
|
-
if (usageSummary) {
|
|
1021
|
-
fields.gateway_context_used_pct = usageSummary.contextUsedPct;
|
|
1022
|
-
fields.gateway_last_usage = usageSummary;
|
|
1023
|
-
}
|
|
1024
|
-
if (limits?.quotaWindows?.length) fields.gateway_quota_windows = limits.quotaWindows;
|
|
1025
|
-
if (limits?.balance) fields.gateway_balance = limits.balance;
|
|
1026
|
-
if (limits?.routeSpend) fields.gateway_route_spend = limits.routeSpend;
|
|
1027
|
-
return fields;
|
|
1028
|
-
}
|
|
@@ -221,58 +221,3 @@ export function clearGatewaySessionRoute(sessionId, options = {}) {
|
|
|
221
221
|
return false;
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
|
-
|
|
225
|
-
export function priorGatewaySessionIdForClear(active, newSessionId) {
|
|
226
|
-
const sid = normalizeGatewaySessionId(newSessionId);
|
|
227
|
-
if (!sid || !active || typeof active !== 'object') return null;
|
|
228
|
-
const transcriptPath = cleanString(active.transcriptPath);
|
|
229
|
-
const currentBase = transcriptPath ? cleanString(transcriptPath.split(/[\\/]/).pop()?.replace(/\.jsonl$/i, '')) : null;
|
|
230
|
-
if (currentBase !== sid) return null;
|
|
231
|
-
const priorTranscriptPath = cleanString(active.priorTranscriptPath);
|
|
232
|
-
const priorBase = priorTranscriptPath ? cleanString(priorTranscriptPath.split(/[\\/]/).pop()?.replace(/\.jsonl$/i, '')) : null;
|
|
233
|
-
const priorSid = normalizeGatewaySessionId(priorBase);
|
|
234
|
-
return priorSid && priorSid !== sid ? priorSid : null;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
export function gatewayConfigForSession(globalGateway = {}, sessionId = null, options = {}) {
|
|
238
|
-
const sessionRoute = readGatewaySessionRoute(sessionId, options);
|
|
239
|
-
return sessionRoute ? { ...(globalGateway || {}), ...sessionRoute } : (globalGateway || {});
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
export function gatewayConfigForSessionBoot(globalGateway = {}, sessionId = null, inheritFromSessionId = null, options = {}) {
|
|
243
|
-
const sid = normalizeGatewaySessionId(sessionId);
|
|
244
|
-
if (!sid) return globalGateway || {};
|
|
245
|
-
const pid = normalizeClientHostPid(options?.clientHostPid);
|
|
246
|
-
const routeOptions = pid ? { clientHostPid: pid } : {};
|
|
247
|
-
// 1. Session already has a stored route — use it (idempotent).
|
|
248
|
-
const sessionRoute = readGatewaySessionRoute(sid, routeOptions);
|
|
249
|
-
if (sessionRoute) return { ...(globalGateway || {}), ...sessionRoute };
|
|
250
|
-
// 2. No route yet — try to inherit from a prior session (e.g. after /clear)
|
|
251
|
-
// before falling back to the global default. This preserves a manually
|
|
252
|
-
// pinned route across session boundaries.
|
|
253
|
-
if (inheritFromSessionId) {
|
|
254
|
-
const priorSid = normalizeGatewaySessionId(inheritFromSessionId);
|
|
255
|
-
if (priorSid && priorSid !== sid) {
|
|
256
|
-
const priorRoute = readGatewaySessionRoute(priorSid, routeOptions);
|
|
257
|
-
if (priorRoute) {
|
|
258
|
-
writeGatewaySessionRoute(sid, priorRoute, routeOptions);
|
|
259
|
-
return { ...(globalGateway || {}), ...priorRoute };
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
// 3. If the host session did not provide a reliable prior transcript on /new,
|
|
264
|
-
// carry the last explicit route for this terminal only. This keeps multiple
|
|
265
|
-
// terminals isolated without falling back to the process-global default.
|
|
266
|
-
if (pid) {
|
|
267
|
-
const hostRoute = readLatestGatewayHostRoute(pid, { excludeSessionId: sid });
|
|
268
|
-
if (hostRoute) {
|
|
269
|
-
writeGatewaySessionRoute(sid, hostRoute, routeOptions);
|
|
270
|
-
return { ...(globalGateway || {}), ...hostRoute };
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
// 4. No prior route to inherit — pin the current global config.
|
|
274
|
-
const normalized = normalizeGatewayRouteSection(globalGateway || {});
|
|
275
|
-
if (!normalized) return globalGateway || {};
|
|
276
|
-
writeGatewaySessionRoute(sid, normalized, routeOptions);
|
|
277
|
-
return { ...(globalGateway || {}), ...normalized };
|
|
278
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// A group-room member's tool calls (session/agent-room.mjs). Reads run freely;
|
|
2
|
-
// anything that can change files or state asks the user through the ordinary
|
|
3
|
-
// approval flow, whatever the agent's own permission or hook rules say — even
|
|
4
|
-
// an agent that normally runs auto-approved. A hook's deny still wins.
|
|
5
|
-
// Opening a task session (`session create`) runs as freely as in the agent's
|
|
6
|
-
// home thread: it changes nothing itself, and the task session is the user's
|
|
7
|
-
// own coding Lead, whose every side effect follows its usual approval rules.
|
|
8
|
-
import { analyzeShellCommandEffects } from '../runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs';
|
|
9
|
-
|
|
10
|
-
const READ_ONLY_TOOLS = new Set([
|
|
11
|
-
'read',
|
|
12
|
-
'grep',
|
|
13
|
-
'glob',
|
|
14
|
-
'find',
|
|
15
|
-
'list',
|
|
16
|
-
'code_graph',
|
|
17
|
-
'load_tool',
|
|
18
|
-
'skill',
|
|
19
|
-
'Skill',
|
|
20
|
-
'recall',
|
|
21
|
-
'search_memories',
|
|
22
|
-
'web_search',
|
|
23
|
-
'web_fetch',
|
|
24
|
-
'local_fetch',
|
|
25
|
-
'image_fetch',
|
|
26
|
-
'ask_user',
|
|
27
|
-
]);
|
|
28
|
-
|
|
29
|
-
export const ROOM_APPROVAL_REASON = 'Group-room members need your approval before changing anything.';
|
|
30
|
-
|
|
31
|
-
/** Whether `name(args)` only reads: a read-only tool, or a shell command whose
|
|
32
|
-
* every stage the shell analysis classifies as non-mutating. */
|
|
33
|
-
export async function isReadOnlyRoomCall({ name, args, cwd }, analyze = analyzeShellCommandEffects) {
|
|
34
|
-
if (READ_ONLY_TOOLS.has(name)) return true;
|
|
35
|
-
if (name !== 'shell' || typeof args?.command !== 'string') return false;
|
|
36
|
-
try {
|
|
37
|
-
return (await analyze(args.command, cwd))?.mutationMode === 'none';
|
|
38
|
-
} catch {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Whether `name(args)` opens a task session (session create). */
|
|
44
|
-
export function isTaskSessionCreate({ name, args }) {
|
|
45
|
-
return (
|
|
46
|
-
name === 'session' &&
|
|
47
|
-
String(args?.action ?? '')
|
|
48
|
-
.trim()
|
|
49
|
-
.toLowerCase() === 'create'
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** The PreToolUse decision for a room member's call: the hook's own `decision`
|
|
54
|
-
* when it denies, the call only reads, or it opens a task session; otherwise
|
|
55
|
-
* an approval ask that keeps any rewrite the hook made. */
|
|
56
|
-
export async function roomMemberToolDecision(call, decision, analyze) {
|
|
57
|
-
const action = String(decision?.action || decision?.decision || '').toLowerCase();
|
|
58
|
-
if (action === 'deny' || action === 'block') return decision;
|
|
59
|
-
if (isTaskSessionCreate(call) || (await isReadOnlyRoomCall(call, analyze))) return decision;
|
|
60
|
-
return { ...(decision && typeof decision === 'object' ? decision : {}), action: 'ask', reason: ROOM_APPROVAL_REASON };
|
|
61
|
-
}
|