mixdog 1.3.4 → 1.3.5
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/oh-my-pi-MIT.txt +23 -0
- package/NOTICE.md +15 -0
- package/README.md +11 -0
- package/package.json +2 -1
- package/scripts/embed-google-oauth-client.mjs +49 -0
- package/scripts/lib/test-spawn-ledger.mjs +46 -1
- package/scripts/test.mjs +5 -0
- package/src/defaults/shipped-history.json +8 -0
- package/src/defaults/skills/browser-use/SKILL.md +21 -9
- package/src/defaults/skills/setup/SKILL.md +7 -2
- package/src/defaults/skills/setup/references/actions.md +82 -27
- package/src/defaults/skills/setup/references/surfaces.md +67 -34
- package/src/defaults/skills/setup-guide/SKILL.md +3 -3
- package/src/lib/keychain-cjs.cjs +359 -29
- package/src/rules/agent-mode/AGENT_MODE.md +10 -2
- package/src/rules/agent-mode/MIXY.md +12 -0
- package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +193 -0
- package/src/runtime/agent/orchestrator/config.mjs +18 -0
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +2 -2
- package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +68 -23
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +22 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -3
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +52 -8
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +19 -2
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
- package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
- package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +17 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
- 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-error-contract.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/wire-protobuf-codec.mjs +368 -0
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +50 -2
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/message-ids.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
- package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +0 -2
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
- package/src/runtime/agent/orchestrator/session/store-agent-worker-header-cache.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +125 -12
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +7 -1
- package/src/runtime/channels/lib/schedule-errors.mjs +51 -0
- package/src/runtime/channels/lib/scheduler.mjs +109 -14
- package/src/runtime/channels/lib/schedules-db.mjs +49 -0
- package/src/runtime/channels/lib/tool-dispatch.mjs +13 -0
- package/src/runtime/channels/lib/worker-main.mjs +9 -0
- package/src/runtime/office/com/com-adapter.mjs +17 -1
- package/src/runtime/office/com/office-com-host.ps1 +51 -1
- package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
- package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
- package/src/runtime/office/pdf/document-preview.mjs +326 -8
- package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
- package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
- package/src/runtime/office/portable/portable-soffice.mjs +45 -5
- package/src/runtime/shared/bot-hops.mjs +62 -2
- package/src/runtime/shared/config.mjs +49 -22
- package/src/runtime/shared/connector-catalog.d.mts +4 -2
- package/src/runtime/shared/connector-catalog.mjs +16 -8
- package/src/runtime/shared/developer-options.mjs +32 -1
- package/src/runtime/shared/google-oauth-client.generated.json +4 -0
- package/src/runtime/shared/google-oauth-client.mjs +34 -9
- package/src/runtime/shared/llm/anthropic-betas.mjs +7 -0
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
- package/src/runtime/shared/llm/well-formed.mjs +66 -0
- package/src/runtime/shared/provider-accounts.mjs +224 -58
- package/src/runtime/shared/provider-api-key.mjs +19 -8
- package/src/runtime/shared/routine-trigger.mjs +42 -0
- package/src/runtime/shared/tool-execution-contract.mjs +2 -0
- package/src/runtime/shared/transcript-metadata.mjs +38 -0
- package/src/runtime/shared/user-data-guard.mjs +30 -2
- package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
- package/src/session-runtime/agent-home-delivery.mjs +57 -13
- package/src/session-runtime/agent-room-delivery.mjs +28 -1
- package/src/session-runtime/agent-task-sessions.mjs +292 -79
- package/src/session-runtime/boot/begin.mjs +3 -2
- package/src/session-runtime/boot/tools.mjs +2 -0
- package/src/session-runtime/bot-chain.mjs +32 -0
- package/src/session-runtime/bot-status.mjs +7 -4
- package/src/session-runtime/channel-config-api.mjs +63 -17
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +45 -0
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
- package/src/session-runtime/internal-tool-executor.mjs +4 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +7 -1
- package/src/session-runtime/mixy-heartbeat.mjs +807 -0
- package/src/session-runtime/model-route/route-tuning.mjs +10 -6
- package/src/session-runtime/owned-automation-run.mjs +33 -12
- package/src/session-runtime/provider-auth/login.mjs +7 -0
- package/src/session-runtime/provider-models/row-hydration.mjs +13 -2
- package/src/session-runtime/routine-home-turn.mjs +33 -6
- package/src/session-runtime/schedule-session-run.mjs +7 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
- package/src/session-runtime/services/channel-admin.mjs +66 -18
- package/src/session-runtime/services/channel-worker.mjs +1 -1
- package/src/session-runtime/services/provider-admin.mjs +128 -25
- package/src/session-runtime/services/schedule-access.mjs +14 -0
- package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
- package/src/session-runtime/session-create/session-options.mjs +7 -4
- package/src/session-runtime/settings-system-api.mjs +16 -1
- package/src/session-runtime/setup-tool/executor.mjs +49 -14
- package/src/session-runtime/setup-tool/extended-actions.mjs +29 -3
- package/src/session-runtime/setup-tool/settings-contract.mjs +65 -4
- package/src/session-runtime/setup-tool/tool-defs.mjs +30 -3
- package/src/session-runtime/task-session-route.mjs +99 -0
- package/src/session-runtime/tool-policy/policy-stage.mjs +5 -2
- package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
- package/src/session-runtime/tool-surface.mjs +4 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
- package/src/session-runtime/workspace/transitions.mjs +10 -2
- package/src/standalone/daemon-session-control.mjs +88 -20
- package/src/standalone/daemon.mjs +8 -0
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
- package/src/standalone/session-service/session-calls/session-turns.mjs +6 -0
- package/src/standalone/session-service.mjs +13 -0
- package/src/standalone/session-tool-output.mjs +8 -5
- package/src/tui/app/model-options.mjs +2 -0
- package/src/tui/dist/index.mjs +24 -2
- package/src/tui/session/notice-surface.mjs +17 -1
- package/src/tui/session/session-api/integrations.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +8 -0
- package/src/tui/session/session-api/settings.mjs +14 -2
- package/src/tui/session/turn-stream.mjs +17 -1
- package/src/tui/session/turn.mjs +22 -2
|
@@ -35,6 +35,7 @@ const {
|
|
|
35
35
|
setSecret: _setSecret,
|
|
36
36
|
deleteSecret: _deleteSecret,
|
|
37
37
|
hasSecret: _hasSecret,
|
|
38
|
+
hasFallbackSecret: _hasFallbackSecret,
|
|
38
39
|
setSecretAsync: _setSecretAsyncImpl,
|
|
39
40
|
deleteSecretAsync: _deleteSecretAsyncImpl,
|
|
40
41
|
keychainStatus: _keychainStatus,
|
|
@@ -523,6 +524,18 @@ export function readSection(section) {
|
|
|
523
524
|
return stripGeneratedMarker(readAll()[section] ?? null) ?? {};
|
|
524
525
|
}
|
|
525
526
|
|
|
527
|
+
/**
|
|
528
|
+
* One section straight from the file, read-only: never served from the read
|
|
529
|
+
* cache, restored from a backup, quarantined or written. A missing, unreadable
|
|
530
|
+
* or malformed config throws. For checks that must fail closed, where a stale
|
|
531
|
+
* value restored from a backup must not count (developerOptionEnabledStrict).
|
|
532
|
+
*/
|
|
533
|
+
export function readSectionStrict(section) {
|
|
534
|
+
const parsed = parseJsonText(readFileSync(configPath(), 'utf8'));
|
|
535
|
+
if (!isPlainObject(parsed)) throw new SyntaxError('config root must be a JSON object');
|
|
536
|
+
return stripGeneratedMarker(parsed[section] ?? null) ?? {};
|
|
537
|
+
}
|
|
538
|
+
|
|
526
539
|
export function readConfig() {
|
|
527
540
|
return stripGeneratedMarker(readAll()) ?? {};
|
|
528
541
|
}
|
|
@@ -641,14 +654,17 @@ export function updateSectionAsync(section, updater) {
|
|
|
641
654
|
}
|
|
642
655
|
|
|
643
656
|
// ── Secret account names ─────────────────────────────────────────────────────
|
|
644
|
-
// Canonical account strings stored in the OS keychain
|
|
657
|
+
// Canonical account strings stored in the OS keychain (or, on a Linux host with
|
|
658
|
+
// no usable keychain provider, in the private secrets file behind the same
|
|
659
|
+
// get/set/delete calls: keychain-cjs.cjs "Linux fallback file").
|
|
645
660
|
export const SECRET_ACCOUNTS = Object.freeze({
|
|
646
661
|
agentApiKey: (provider) => `agent.${provider}.apiKey`,
|
|
647
662
|
openaiUsageSessionKey: 'agent.openai.usageSessionKey',
|
|
648
663
|
});
|
|
649
664
|
|
|
650
665
|
// ── Secret-aware getters ─────────────────────────────────────────────────────
|
|
651
|
-
// Read order: ENV MIXDOG_<UPPER_SNAKE> → OS keychain →
|
|
666
|
+
// Read order: ENV MIXDOG_<UPPER_SNAKE> → OS keychain → Linux fallback secrets
|
|
667
|
+
// file (read by _getSecret when the keychain has nothing) → null.
|
|
652
668
|
|
|
653
669
|
function _envKey(account) {
|
|
654
670
|
// 'agent.openai.apiKey' → 'MIXDOG_AGENT_OPENAI_APIKEY'
|
|
@@ -676,7 +692,9 @@ export function getOpenAIUsageSessionKey() {
|
|
|
676
692
|
}
|
|
677
693
|
|
|
678
694
|
/**
|
|
679
|
-
* Persist a secret to the OS keychain
|
|
695
|
+
* Persist a secret to the OS keychain; on a Linux host with no keychain provider
|
|
696
|
+
* (secret-tool/libsecret missing, no Secret Service) to the owner-only secrets
|
|
697
|
+
* file in the data dir instead. Throws on failure.
|
|
680
698
|
* Never writes to mixdog-config.json.
|
|
681
699
|
*/
|
|
682
700
|
export function saveSecret(account, value) {
|
|
@@ -697,25 +715,25 @@ export async function saveSecretAsync(account, value) {
|
|
|
697
715
|
}
|
|
698
716
|
|
|
699
717
|
function saveSecretError(account, err) {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
}
|
|
718
|
+
// Reached for a locked keyring, a non-Linux keychain failure, or a Linux host
|
|
719
|
+
// with no keychain provider whose fallback secrets file could not be written
|
|
720
|
+
// (keychain-cjs.cjs). Surface an actionable message that points at the
|
|
721
|
+
// env-var read path the getters already honor, instead of silently writing
|
|
722
|
+
// the plaintext secret to mixdog-config.json. The fallback is a separate
|
|
723
|
+
// owner-only file, never the config.
|
|
724
|
+
const envKey = _envKey(account);
|
|
725
|
+
const agentMatch = String(account || '').match(/^agent\.([^.]+)\.apiKey$/);
|
|
726
|
+
const stdEnv = agentMatch ? AGENT_PROVIDER_ENV[agentMatch[1]] : null;
|
|
727
|
+
const envHint = stdEnv ? `${stdEnv} (or ${envKey})` : envKey;
|
|
728
|
+
const e = new Error(
|
|
729
|
+
`[config] could not save secret to the OS keychain: ${err?.message ? err.message : err}\n` +
|
|
730
|
+
` Set the ${envHint} environment variable instead — the runtime reads it directly.`
|
|
731
|
+
);
|
|
732
|
+
e.cause = err;
|
|
733
|
+
return e;
|
|
717
734
|
}
|
|
718
735
|
|
|
736
|
+
/** Remove a secret from the OS keychain (if present) and the Linux fallback file. */
|
|
719
737
|
export function deleteSecret(account) {
|
|
720
738
|
_deleteSecret(account);
|
|
721
739
|
}
|
|
@@ -741,13 +759,16 @@ export function onKeychainRecovered(listener) {
|
|
|
741
759
|
return typeof _onKeychainRecovered === 'function' ? _onKeychainRecovered(listener) : () => {};
|
|
742
760
|
}
|
|
743
761
|
|
|
744
|
-
/** Keyring health for the UI: { state: ok|locked|missing|error|unknown, message }.
|
|
762
|
+
/** Keyring health for the UI: { state: ok|locked|missing|unreachable|error|unknown, message, fallback }.
|
|
763
|
+
* `fallback` is true when no keychain provider exists on this Linux host and
|
|
764
|
+
* secrets live in the private secrets file: working storage, not a failure. */
|
|
745
765
|
export function getKeychainStatus() {
|
|
746
766
|
return typeof _keychainStatus === 'function' ? _keychainStatus() : { state: 'unknown', message: '' };
|
|
747
767
|
}
|
|
748
768
|
|
|
749
769
|
/**
|
|
750
|
-
* Whether a secret is stored in the OS keychain
|
|
770
|
+
* Whether a secret is stored in the OS keychain (or Linux fallback file) for
|
|
771
|
+
* `account` (ignores env).
|
|
751
772
|
* Lets the setup UI show "Set" WITHOUT ever sending the secret value to the
|
|
752
773
|
* browser.
|
|
753
774
|
*/
|
|
@@ -760,4 +781,10 @@ export function hasStoredSecret(account) {
|
|
|
760
781
|
}
|
|
761
782
|
}
|
|
762
783
|
|
|
784
|
+
/** Whether `account`'s stored secret currently lives in the Linux fallback file
|
|
785
|
+
* (never true on Windows/macOS). Lets the UI label where a key is kept. */
|
|
786
|
+
export function isFallbackSecret(account) {
|
|
787
|
+
return typeof _hasFallbackSecret === 'function' ? !!_hasFallbackSecret(account) : false;
|
|
788
|
+
}
|
|
789
|
+
|
|
763
790
|
export { configPath };
|
|
@@ -25,10 +25,10 @@ export interface ConnectorCatalogEntry {
|
|
|
25
25
|
id: string;
|
|
26
26
|
name: string;
|
|
27
27
|
backend: ConnectorBackend;
|
|
28
|
-
/** Offered only after the user enters their own Google OAuth client. */
|
|
29
|
-
ownKey?: boolean;
|
|
30
28
|
/** Curated deferred-tool manifest line (connector-triggers.mjs). */
|
|
31
29
|
trigger: string;
|
|
30
|
+
/** New connections go by app password only (Gmail). */
|
|
31
|
+
appPasswordOnly?: boolean;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export const CONNECTOR_CATALOG: readonly ConnectorCatalogEntry[];
|
|
@@ -43,6 +43,8 @@ export function connectorServerInput(
|
|
|
43
43
|
key?: string,
|
|
44
44
|
options?: { extraAccount?: boolean }
|
|
45
45
|
): Record<string, unknown>;
|
|
46
|
+
export function connectorAppPasswordOnly(entry: ConnectorCatalogEntry | null | undefined): boolean;
|
|
47
|
+
export function connectorUsesGoogleClient(entry: ConnectorCatalogEntry | null | undefined): boolean;
|
|
46
48
|
export function connectorMultiAccount(entry: ConnectorCatalogEntry | null | undefined): boolean;
|
|
47
49
|
export const GMAIL_APP_PASSWORD: Readonly<{ url: string; accountHeader: string; helpUrl: string }>;
|
|
48
50
|
export function gmailAddress(value: unknown): string;
|
|
@@ -53,20 +53,18 @@ export const CONNECTOR_CATALOG = Object.freeze(
|
|
|
53
53
|
id: 'gmail',
|
|
54
54
|
name: 'Gmail',
|
|
55
55
|
backend: google('gmail', GOOGLE_SCOPES.gmail, ['send_email']),
|
|
56
|
+
// New Gmail connections use an app password only (GMAIL_APP_PASSWORD);
|
|
57
|
+
// a Gmail server already on the Google sign-in keeps working.
|
|
58
|
+
appPasswordOnly: true,
|
|
56
59
|
},
|
|
57
|
-
// Calendar and Drive are offered only to a user who entered their own
|
|
58
|
-
// Google OAuth client (Connectors → add custom → 내 Google 키): `ownKey`.
|
|
59
|
-
// Existing connections keep working; Mixy and the chat cards never offer them.
|
|
60
60
|
{
|
|
61
61
|
id: 'google-calendar',
|
|
62
62
|
name: 'Google Calendar',
|
|
63
|
-
ownKey: true,
|
|
64
63
|
backend: google('calendar', GOOGLE_SCOPES.calendar, ['delete_event']),
|
|
65
64
|
},
|
|
66
65
|
{
|
|
67
66
|
id: 'google-drive',
|
|
68
67
|
name: 'Google Drive',
|
|
69
|
-
ownKey: true,
|
|
70
68
|
backend: google('drive', GOOGLE_SCOPES.drive, []),
|
|
71
69
|
},
|
|
72
70
|
{
|
|
@@ -113,9 +111,8 @@ export const CONNECTOR_CATALOG = Object.freeze(
|
|
|
113
111
|
].map((entry) => Object.freeze({ ...entry, trigger: connectorTrigger(entry.id) }))
|
|
114
112
|
);
|
|
115
113
|
|
|
116
|
-
/** The ids
|
|
117
|
-
|
|
118
|
-
export const CONNECTOR_IDS = Object.freeze(CONNECTOR_CATALOG.filter((entry) => !entry.ownKey).map((entry) => entry.id));
|
|
114
|
+
/** The ids the setup tool's `connect_connector` offers: the whole catalog. */
|
|
115
|
+
export const CONNECTOR_IDS = Object.freeze(CONNECTOR_CATALOG.map((entry) => entry.id));
|
|
119
116
|
|
|
120
117
|
/** The catalog entry for `id`, or null. */
|
|
121
118
|
export function connectorById(id) {
|
|
@@ -193,6 +190,17 @@ export function connectorMultiAccount(entry) {
|
|
|
193
190
|
return entry?.backend?.kind === 'oauth' && entry.backend.oauthClient === 'google';
|
|
194
191
|
}
|
|
195
192
|
|
|
193
|
+
/** Whether a new connection of `entry` goes by app password only (Gmail). */
|
|
194
|
+
export function connectorAppPasswordOnly(entry) {
|
|
195
|
+
return entry?.appPasswordOnly === true;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Whether `entry` signs in with Mixdog's built-in Google client (or the
|
|
199
|
+
* user's own Google client in its place). */
|
|
200
|
+
export function connectorUsesGoogleClient(entry) {
|
|
201
|
+
return entry?.backend?.kind === 'oauth' && entry.backend.oauthClient === 'google';
|
|
202
|
+
}
|
|
203
|
+
|
|
196
204
|
/** The MCP server input that connects catalog entry `entry` under `name`
|
|
197
205
|
* (oauth / apiKey); `key` fills an apiKey backend; `extraAccount`
|
|
198
206
|
* makes it one more account of a multi-account connector. */
|
|
@@ -5,12 +5,25 @@
|
|
|
5
5
|
// `developer.<optionId>` is true. Default off. An option with a `warning`
|
|
6
6
|
// turns on only after the user confirms that warning; an option with a
|
|
7
7
|
// `provider` gates that dev-only OAuth provider.
|
|
8
|
-
import { readSection } from './config.mjs';
|
|
8
|
+
import { readSection, readSectionStrict } from './config.mjs';
|
|
9
9
|
|
|
10
10
|
const OAUTH_RISK_WARNING =
|
|
11
11
|
'Using this provider through OAuth carries a high risk of penalties such as account restrictions.';
|
|
12
12
|
|
|
13
13
|
export const DEVELOPER_SECTIONS = Object.freeze([
|
|
14
|
+
Object.freeze({
|
|
15
|
+
id: 'approvals',
|
|
16
|
+
label: 'Approvals',
|
|
17
|
+
options: Object.freeze([
|
|
18
|
+
Object.freeze({
|
|
19
|
+
id: 'allowAllActions',
|
|
20
|
+
label: 'Allow all actions',
|
|
21
|
+
description: 'Skips the approval cards for every action except payments and permanent deletes.',
|
|
22
|
+
warning:
|
|
23
|
+
'Turning this on lets agents act without asking you first, except for payments and permanent deletes. Use it only if you accept that risk.',
|
|
24
|
+
}),
|
|
25
|
+
]),
|
|
26
|
+
}),
|
|
14
27
|
Object.freeze({
|
|
15
28
|
id: 'providers',
|
|
16
29
|
label: 'Providers',
|
|
@@ -30,6 +43,13 @@ export const DEVELOPER_SECTIONS = Object.freeze([
|
|
|
30
43
|
warning: OAUTH_RISK_WARNING,
|
|
31
44
|
provider: 'cursor-oauth',
|
|
32
45
|
}),
|
|
46
|
+
Object.freeze({
|
|
47
|
+
id: 'devinOAuth',
|
|
48
|
+
label: 'Devin',
|
|
49
|
+
description: 'Show Devin OAuth in Providers and the model picker.',
|
|
50
|
+
warning: OAUTH_RISK_WARNING,
|
|
51
|
+
provider: 'devin-oauth',
|
|
52
|
+
}),
|
|
33
53
|
Object.freeze({
|
|
34
54
|
id: 'mimoOAuth',
|
|
35
55
|
label: 'MiMo',
|
|
@@ -74,6 +94,17 @@ export function developerOptionEnabled(id, stored = storedDeveloperConfig()) {
|
|
|
74
94
|
return developerOption(id) !== null && normalizeDeveloperConfig(stored)[id] === true;
|
|
75
95
|
}
|
|
76
96
|
|
|
97
|
+
/** `developerOptionEnabled` for a safety bypass: fail-closed. Read straight
|
|
98
|
+
* from the config file, so a missing or malformed config is never restored
|
|
99
|
+
* from a backup (which may hold a stale `true`); any error means off. */
|
|
100
|
+
export function developerOptionEnabledStrict(id) {
|
|
101
|
+
try {
|
|
102
|
+
return developerOption(id) !== null && normalizeDeveloperConfig(readSectionStrict('agent').developer)[id] === true;
|
|
103
|
+
} catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
77
108
|
/** Settings view of every section; `stored` defaults to the on-disk values. */
|
|
78
109
|
export function developerSettingsView(stored = storedDeveloperConfig()) {
|
|
79
110
|
const values = normalizeDeveloperConfig(stored);
|
|
@@ -6,18 +6,43 @@
|
|
|
6
6
|
// uses PKCE (S256), state and a loopback redirect
|
|
7
7
|
// (developers.google.com/identity/protocols/oauth2/native-app).
|
|
8
8
|
//
|
|
9
|
-
// The values come
|
|
10
|
-
//
|
|
11
|
-
//
|
|
9
|
+
// The source ships no client. The values come from the environment first
|
|
10
|
+
// (MIXDOG_GOOGLE_OAUTH_CLIENT_ID / _SECRET: a developer's override, and what
|
|
11
|
+
// `npm run dev:isolated` passes through), then from the generated, gitignored
|
|
12
|
+
// google-oauth-client.generated.json beside this file. Release packaging
|
|
13
|
+
// writes that file from the repository secrets
|
|
14
|
+
// (scripts/embed-google-oauth-client.mjs) before the npm package and every
|
|
15
|
+
// desktop runtime.asar are built, so each shipped build carries it. A build
|
|
16
|
+
// with neither offers no built-in Google sign-in (the user's own Google
|
|
17
|
+
// client still works).
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
import { readFileSync } from 'node:fs';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
|
|
22
|
+
/** The generated file release packaging writes (see the header). */
|
|
23
|
+
export const GOOGLE_OAUTH_CLIENT_FILE = fileURLToPath(new URL('./google-oauth-client.generated.json', import.meta.url));
|
|
24
|
+
|
|
25
|
+
const text = (value) => String(value || '').trim();
|
|
26
|
+
|
|
27
|
+
function embeddedClient(file) {
|
|
28
|
+
let source;
|
|
29
|
+
try {
|
|
30
|
+
source = readFileSync(file, 'utf8');
|
|
31
|
+
} catch (error) {
|
|
32
|
+
if (error?.code === 'ENOENT') return null;
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
const { clientId, clientSecret } = JSON.parse(source);
|
|
36
|
+
return text(clientId) ? { clientId: text(clientId), clientSecret: text(clientSecret) } : null;
|
|
37
|
+
}
|
|
14
38
|
|
|
15
39
|
/** `{ clientId, clientSecret }` of Mixdog's Google client, or null when this
|
|
16
|
-
* build has none.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return { clientId, clientSecret:
|
|
40
|
+
* build has none. The environment wins over the generated file as a whole:
|
|
41
|
+
* the two are never mixed. */
|
|
42
|
+
export function googleOAuthClient({ env = process.env, file = GOOGLE_OAUTH_CLIENT_FILE } = {}) {
|
|
43
|
+
const clientId = text(env.MIXDOG_GOOGLE_OAUTH_CLIENT_ID);
|
|
44
|
+
if (clientId) return { clientId, clientSecret: text(env.MIXDOG_GOOGLE_OAUTH_CLIENT_SECRET) };
|
|
45
|
+
return embeddedClient(file);
|
|
21
46
|
}
|
|
22
47
|
|
|
23
48
|
/** Google issues a refresh token only for `access_type=offline`. */
|
|
@@ -7,6 +7,9 @@ const FAST_MODE_BETA_HEADER = 'fast-mode-2026-02-01';
|
|
|
7
7
|
const TOOL_SEARCH_BETA_HEADER = 'advanced-tool-use-2025-11-20';
|
|
8
8
|
const THINKING_DISPLAY_UPDATES_BETA_HEADER = 'thinking-display-updates-2026-08-18';
|
|
9
9
|
export const SERVER_SIDE_FALLBACK_BETA_HEADER = 'server-side-fallback-2026-07-01';
|
|
10
|
+
// Turn-scoped mid-conversation system messages (clear_at), sent only when the
|
|
11
|
+
// request body carries one.
|
|
12
|
+
export const TURN_SCOPED_SYSTEM_BETA_HEADER = 'mid-conversation-system-clear-at-2026-08-21';
|
|
10
13
|
|
|
11
14
|
// Fast mode ships on Opus 5.5, Opus 5 and Opus 4.8 only. Opus 4.7 rejects
|
|
12
15
|
// `speed: "fast"` and Opus 4.6 silently runs at standard speed.
|
|
@@ -28,6 +31,7 @@ export function buildAnthropicBetaHeaders({
|
|
|
28
31
|
effort = false,
|
|
29
32
|
serverFallback = false,
|
|
30
33
|
thinkingDisplayUpdates = false,
|
|
34
|
+
turnScopedSystem = false,
|
|
31
35
|
} = {}) {
|
|
32
36
|
const headers = String(base || '')
|
|
33
37
|
.split(',')
|
|
@@ -48,5 +52,8 @@ export function buildAnthropicBetaHeaders({
|
|
|
48
52
|
if (thinkingDisplayUpdates && !headers.includes(THINKING_DISPLAY_UPDATES_BETA_HEADER)) {
|
|
49
53
|
headers.push(THINKING_DISPLAY_UPDATES_BETA_HEADER);
|
|
50
54
|
}
|
|
55
|
+
if (turnScopedSystem && !headers.includes(TURN_SCOPED_SYSTEM_BETA_HEADER)) {
|
|
56
|
+
headers.push(TURN_SCOPED_SYSTEM_BETA_HEADER);
|
|
57
|
+
}
|
|
51
58
|
return headers.join(',');
|
|
52
59
|
}
|
|
@@ -63,3 +63,15 @@ export function emitsAnthropicProgressUpdates(model) {
|
|
|
63
63
|
const id = normalizeClaudeModelId(model);
|
|
64
64
|
return /^claude-(?:opus-5-5|sonnet-5-5|fable-5-1|mythos-5-1|fable-5)(?:-\d{8})?$/.test(id);
|
|
65
65
|
}
|
|
66
|
+
|
|
67
|
+
// Models that accept turn-scoped mid-conversation system messages
|
|
68
|
+
// ({role:'system', clear_at:'next_user_message'}, beta
|
|
69
|
+
// mid-conversation-system-clear-at-2026-08-21). An id list for the same
|
|
70
|
+
// reason as above: a wrong "yes" is a 400 on every request, a wrong "no" only
|
|
71
|
+
// keeps the legacy tail-reminder layout — so unknown ids stay off.
|
|
72
|
+
export function supportsAnthropicTurnScopedSystemMessages(model) {
|
|
73
|
+
const id = normalizeClaudeModelId(model);
|
|
74
|
+
return /^claude-(?:fable-5-1|mythos-5-1|fable-5|mythos-5|opus-5-5|opus-5|opus-4-8|sonnet-5-5|haiku-5-5)(?:-\d{8})?$/.test(
|
|
75
|
+
id
|
|
76
|
+
);
|
|
77
|
+
}
|
|
@@ -92,6 +92,7 @@ const PROVIDER_CATALOGS = Object.freeze({
|
|
|
92
92
|
rosterLimitsAuthoritative: true,
|
|
93
93
|
},
|
|
94
94
|
'cursor-oauth': { relay: true },
|
|
95
|
+
'devin-oauth': { relay: true },
|
|
95
96
|
'cursor-api': { relay: true },
|
|
96
97
|
// The models.dev listing id of the Go gateway: a relay catalog, not a
|
|
97
98
|
// selectable provider (the model lookup needs it flagged as a relay).
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outgoing-request surrogate sanitizer.
|
|
3
|
+
*
|
|
4
|
+
* A lone UTF-16 surrogate (half of an emoji left by a char-count cut, or
|
|
5
|
+
* carried by tool output / file content) is serialized by JSON.stringify as a
|
|
6
|
+
* `\ud83d` escape that provider APIs reject ("not valid JSON"). This rewrites
|
|
7
|
+
* every string value and every object key to well-formed text (lone surrogate
|
|
8
|
+
* -> U+FFFD) in the request that is about to be sent.
|
|
9
|
+
*
|
|
10
|
+
* Copy-on-write: a request that is already well-formed is returned as the very
|
|
11
|
+
* same object (no allocation, identity kept for caches keyed on messages or
|
|
12
|
+
* tool lists). Only the containers on the path to a bad string are copied; the
|
|
13
|
+
* stored transcript is never mutated. Only arrays and plain objects are
|
|
14
|
+
* walked: Buffer / Uint8Array / ArrayBuffer and any other class instance are
|
|
15
|
+
* binary or opaque payloads and are returned untouched. Own symbol properties
|
|
16
|
+
* (e.g. the provider-native tool prefix count on a tool list) survive a copy.
|
|
17
|
+
*/
|
|
18
|
+
function copySymbols(target, source) {
|
|
19
|
+
for (const symbol of Object.getOwnPropertySymbols(source)) {
|
|
20
|
+
Object.defineProperty(target, symbol, Object.getOwnPropertyDescriptor(source, symbol));
|
|
21
|
+
}
|
|
22
|
+
return target;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function setOwn(target, key, value) {
|
|
26
|
+
Object.defineProperty(target, key, { value, enumerable: true, writable: true, configurable: true });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function walk(value, active) {
|
|
30
|
+
if (typeof value === 'string') return value.isWellFormed() ? value : value.toWellFormed();
|
|
31
|
+
if (value === null || typeof value !== 'object' || active.has(value)) return value;
|
|
32
|
+
if (Array.isArray(value)) {
|
|
33
|
+
active.add(value);
|
|
34
|
+
let out = null;
|
|
35
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
36
|
+
const next = walk(value[i], active);
|
|
37
|
+
if (!out && next !== value[i]) out = value.slice();
|
|
38
|
+
if (out) out[i] = next;
|
|
39
|
+
}
|
|
40
|
+
active.delete(value);
|
|
41
|
+
return out ? copySymbols(out, value) : value;
|
|
42
|
+
}
|
|
43
|
+
const proto = Object.getPrototypeOf(value);
|
|
44
|
+
if (proto !== Object.prototype && proto !== null) return value;
|
|
45
|
+
active.add(value);
|
|
46
|
+
const keys = Object.keys(value);
|
|
47
|
+
let out = null;
|
|
48
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
49
|
+
const key = keys[i];
|
|
50
|
+
const entry = value[key];
|
|
51
|
+
const nextKey = key.isWellFormed() ? key : key.toWellFormed();
|
|
52
|
+
const nextEntry = walk(entry, active);
|
|
53
|
+
if (!out && (nextKey !== key || nextEntry !== entry)) {
|
|
54
|
+
out = Object.create(proto);
|
|
55
|
+
for (let j = 0; j < i; j += 1) setOwn(out, keys[j], value[keys[j]]);
|
|
56
|
+
}
|
|
57
|
+
if (out) setOwn(out, nextKey, nextEntry);
|
|
58
|
+
}
|
|
59
|
+
active.delete(value);
|
|
60
|
+
return out ? copySymbols(out, value) : value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** `value` with every string and object key made well-formed; `value` itself when it already is. */
|
|
64
|
+
export function sanitizeSurrogates(value) {
|
|
65
|
+
return walk(value, new WeakSet());
|
|
66
|
+
}
|