mixdog 1.2.6 → 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/isolated-test-env.mjs +16 -0
- package/src/agents/reviewer/AGENT.md +4 -2
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +7 -0
- package/src/defaults/skills/browser-use/SKILL.md +5 -0
- 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/lib/rules-builder.cjs +55 -6
- package/src/rules/agent/AGENT.md +4 -0
- 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 +7 -3
- package/src/rules/shared/70-delivery.md +3 -0
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -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 +4 -2
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +215 -0
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -4
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +115 -11
- package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
- 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/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +10 -3
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +96 -1
- 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 +12 -0
- 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-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/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/loop/compact-policy.mjs +3 -1
- 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 +74 -15
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +9 -1
- 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 +3 -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/pending-lifecycle-epoch.mjs +0 -8
- 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/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/mixy-name.mjs +24 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
- 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/store/sweep/sweep-row.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +28 -9
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +16 -2
- 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-visibility.mjs +0 -4
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +44 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +25 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +3 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +75 -57
- 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/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/tool-call-handler.mjs +2 -0
- package/src/runtime/memory/tool-defs.mjs +5 -0
- 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 +14 -1
- package/src/runtime/shared/config.mjs +8 -1
- 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/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/plain-preview.d.mts +1 -0
- package/src/runtime/shared/plain-preview.mjs +28 -0
- 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/schedule-model-ref.mjs +9 -10
- package/src/runtime/shared/slow-span.mjs +4 -12
- package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
- 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 +114 -36
- 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/resume.mjs +4 -0
- package/src/session-runtime/lifecycle/shared.mjs +6 -0
- 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/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/helpers.mjs +10 -0
- 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/channel-admin.mjs +93 -24
- package/src/session-runtime/services/memory-access.mjs +37 -0
- package/src/session-runtime/services/provider-admin.mjs +74 -39
- package/src/session-runtime/services/schedule-access.mjs +91 -0
- 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 +8 -1
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +10 -2
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +3 -0
- 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/daemon-agent-control.mjs +1 -8
- package/src/standalone/daemon-session-control.mjs +11 -2
- package/src/standalone/daemon.mjs +18 -4
- package/src/standalone/session-protocol.mjs +27 -0
- package/src/standalone/session-service/session-calls/session-turns.mjs +9 -0
- package/src/standalone/session-service.mjs +19 -0
- package/src/tui/app/slash-commands.mjs +20 -0
- package/src/tui/dist/index.mjs +164 -86
- package/src/tui/session/context-state.mjs +6 -1
- package/src/tui/session/notice-surface.mjs +35 -4
- 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 +5 -0
- package/src/tui/session/session-api/integrations.mjs +8 -0
- 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 +12 -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 +58 -24
- 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.mjs +22 -6
- package/src/session-runtime/automation-agents.mjs +0 -94
- package/src/session-runtime/automation-workflow.mjs +0 -59
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
// The Mixdog mascot: a blocky pixel creature on a 16x12 grid, painted from the
|
|
2
|
+
// string layers in agent-avatar-sprites.mjs (design/mockups/mixy-art). Every
|
|
3
|
+
// look is the same body block; the species (ears, marks, tail, legs), an
|
|
4
|
+
// accessory, the expression and the colour vary. An agent's `agent.json`
|
|
5
|
+
// stores its pick as `avatar: { kind: 'mascot', species, accessory,
|
|
6
|
+
// expression, color }` (an older `variant` reads as its mapped look), or its
|
|
7
|
+
// own images per motion state as `avatar: { kind: 'custom', states: { idle,
|
|
8
|
+
// typing?, message? } }`. An agent without one gets a stable look from its id.
|
|
9
|
+
import { MIXY_AGENT_ID } from '../agent/orchestrator/session/agent-home.mjs';
|
|
10
|
+
import { MASCOT_SPRITES } from './agent-avatar-sprites.mjs';
|
|
11
|
+
|
|
12
|
+
/** The palette an avatar colour is chosen from. */
|
|
13
|
+
export const AGENT_AVATAR_COLORS = Object.freeze([
|
|
14
|
+
'#e6e6e6',
|
|
15
|
+
'#9a9a9a',
|
|
16
|
+
'#f06a5f',
|
|
17
|
+
'#f59a42',
|
|
18
|
+
'#f2c94c',
|
|
19
|
+
'#5cc98a',
|
|
20
|
+
'#3fc1c9',
|
|
21
|
+
'#5b9bff',
|
|
22
|
+
'#9b7bff',
|
|
23
|
+
'#ef6fb0',
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
/** Every species a user can pick: the six dogs. Mixy's own (`mixy`) is not one of them. */
|
|
27
|
+
export const MASCOT_SPECIES = Object.freeze(['labrador', 'shepherd', 'terrier', 'corgi', 'husky', 'shiba']);
|
|
28
|
+
export const MASCOT_ACCESSORIES = Object.freeze(['none', 'collar', 'glasses', 'beanie', 'scarf', 'bow']);
|
|
29
|
+
/** Picks that were removed, read as their nearest remaining option. */
|
|
30
|
+
const RETIRED_SPECIES = { dalmatian: 'labrador', cat: 'labrador', bird: 'labrador', robot: 'labrador' };
|
|
31
|
+
const RETIRED_ACCESSORIES = { headset: 'glasses' };
|
|
32
|
+
export const MASCOT_EXPRESSIONS = Object.freeze(['calm', 'happy', 'wink', 'sleepy']);
|
|
33
|
+
|
|
34
|
+
/** Mixy, the primary assistant: its own silver pup with one ear up and a
|
|
35
|
+
* slate collar with the gold star medal. Never offered in the picker. */
|
|
36
|
+
export const MIXY_AVATAR = Object.freeze({
|
|
37
|
+
kind: 'mascot',
|
|
38
|
+
species: 'mixy',
|
|
39
|
+
accessory: 'none',
|
|
40
|
+
expression: 'calm',
|
|
41
|
+
color: '#e6e6e6',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/** The fixed inks a sprite letter names; B, D, L and E depend on the look. */
|
|
45
|
+
export const MASCOT_INKS = Object.freeze({
|
|
46
|
+
K: '#141414',
|
|
47
|
+
G: '#f2c94c',
|
|
48
|
+
R: '#e5534b',
|
|
49
|
+
O: '#f59a42',
|
|
50
|
+
W: '#f4f4f4',
|
|
51
|
+
C: '#3fc1c9',
|
|
52
|
+
M: '#8a8a90',
|
|
53
|
+
S: '#2a2b30',
|
|
54
|
+
P: '#ef8fb4',
|
|
55
|
+
N: '#f06a5f',
|
|
56
|
+
n: '#c4544c',
|
|
57
|
+
r: '#b94039',
|
|
58
|
+
F: '#ef6fb0',
|
|
59
|
+
f: '#b8497f',
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
/** `hex` with every channel scaled by `k`. */
|
|
63
|
+
export function shadeHex(hex, k) {
|
|
64
|
+
const n = Number.parseInt(hex.slice(1), 16);
|
|
65
|
+
const channel = (shift) =>
|
|
66
|
+
Math.round(((n >> shift) & 255) * k)
|
|
67
|
+
.toString(16)
|
|
68
|
+
.padStart(2, '0');
|
|
69
|
+
return `#${channel(16)}${channel(8)}${channel(0)}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** `hex` mixed `k` of the way to white. */
|
|
73
|
+
function liftHex(hex, k) {
|
|
74
|
+
const n = Number.parseInt(hex.slice(1), 16);
|
|
75
|
+
const channel = (shift) => {
|
|
76
|
+
const value = (n >> shift) & 255;
|
|
77
|
+
return Math.round(value + (255 - value) * k)
|
|
78
|
+
.toString(16)
|
|
79
|
+
.padStart(2, '0');
|
|
80
|
+
};
|
|
81
|
+
return `#${channel(16)}${channel(8)}${channel(0)}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// The 12 looks before species existed, `<ears>-<expression>-<plain|collar>`:
|
|
85
|
+
// each reads as the species with those ears, the collar as an accessory.
|
|
86
|
+
const LEGACY_EARS = { floppy: 'labrador', perky: 'shepherd', folded: 'terrier' };
|
|
87
|
+
const LEGACY_VARIANTS = Object.keys(LEGACY_EARS).flatMap((ears) =>
|
|
88
|
+
['calm', 'happy'].flatMap((expression) => ['plain', 'collar'].map((extra) => `${ears}-${expression}-${extra}`))
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
/** An older `variant` as its species, accessory and expression; null if unknown. */
|
|
92
|
+
export function mascotFromVariant(variant) {
|
|
93
|
+
if (!LEGACY_VARIANTS.includes(variant)) return null;
|
|
94
|
+
const [ears, expression, extra] = variant.split('-');
|
|
95
|
+
return { species: LEGACY_EARS[ears], accessory: extra === 'collar' ? 'collar' : 'none', expression };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** `species-accessory-expression`: a look's key (data attributes, tests). */
|
|
99
|
+
export const mascotLook = (avatar) => `${avatar.species}-${avatar.accessory}-${avatar.expression}`;
|
|
100
|
+
|
|
101
|
+
function layerCells(rows, color, eye) {
|
|
102
|
+
if (!rows) return [];
|
|
103
|
+
const ink = (key) => {
|
|
104
|
+
if (key === 'B') return color;
|
|
105
|
+
if (key === 'D') return shadeHex(color, 0.7);
|
|
106
|
+
if (key === 'L') return liftHex(color, 0.35);
|
|
107
|
+
return MASCOT_INKS[key === 'E' ? eye : key];
|
|
108
|
+
};
|
|
109
|
+
const cells = [];
|
|
110
|
+
rows.forEach((row, y) => {
|
|
111
|
+
for (let x = 0; x < row.length; x += 1) if (row[x] !== '.') cells.push({ x, y, fill: ink(row[x]) });
|
|
112
|
+
});
|
|
113
|
+
return cells;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** A look's cells by part, in paint order — the groups the renderer draws
|
|
117
|
+
* (tail, legs, then the bobbing body with its ears, marks, eyes and
|
|
118
|
+
* accessory). `blink` is the closed eyes an idle blink shows. Null for an
|
|
119
|
+
* unknown species. */
|
|
120
|
+
export function mascotParts(avatar) {
|
|
121
|
+
const species = MASCOT_SPRITES.species[avatar.species];
|
|
122
|
+
if (!species) return null;
|
|
123
|
+
const paint = (rows) => layerCells(rows, avatar.color, species.eye);
|
|
124
|
+
return {
|
|
125
|
+
tail: paint(species.tail && MASCOT_SPRITES.tails[species.tail]),
|
|
126
|
+
legs: paint(MASCOT_SPRITES.legs[species.legs]),
|
|
127
|
+
body: paint(MASCOT_SPRITES.body),
|
|
128
|
+
ear: paint(species.ears),
|
|
129
|
+
marks: paint(species.marks),
|
|
130
|
+
eyes: paint(MASCOT_SPRITES.eyes[avatar.expression]),
|
|
131
|
+
blink: paint(MASCOT_SPRITES.eyes.sleepy),
|
|
132
|
+
accessory: paint(MASCOT_SPRITES.accessories[avatar.accessory]),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The look as one still frame: each cell's final fill. [] when unknown. */
|
|
137
|
+
export function mascotCells(avatar) {
|
|
138
|
+
const parts = mascotParts(avatar);
|
|
139
|
+
if (!parts) return [];
|
|
140
|
+
const cells = new Map();
|
|
141
|
+
for (const part of ['tail', 'legs', 'body', 'ear', 'marks', 'eyes', 'accessory']) {
|
|
142
|
+
for (const cell of parts[part]) cells.set(`${cell.y},${cell.x}`, cell);
|
|
143
|
+
}
|
|
144
|
+
return [...cells.values()];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Cells as one SVG path per fill, each row's run one rectangle. */
|
|
148
|
+
export function cellPaths(cells) {
|
|
149
|
+
const byFill = new Map();
|
|
150
|
+
for (const { x, y, fill } of cells) {
|
|
151
|
+
const rows = byFill.get(fill) ?? new Map();
|
|
152
|
+
byFill.set(fill, rows);
|
|
153
|
+
rows.set(y, [...(rows.get(y) ?? []), x]);
|
|
154
|
+
}
|
|
155
|
+
return [...byFill].map(([fill, rows]) => {
|
|
156
|
+
let d = '';
|
|
157
|
+
for (const [y, xs] of [...rows].sort(([a], [b]) => a - b)) {
|
|
158
|
+
const sorted = [...new Set(xs)].sort((a, b) => a - b);
|
|
159
|
+
for (let i = 0; i < sorted.length; ) {
|
|
160
|
+
let j = i;
|
|
161
|
+
while (j + 1 < sorted.length && sorted[j + 1] === sorted[j] + 1) j += 1;
|
|
162
|
+
const run = j - i + 1;
|
|
163
|
+
d += `M${sorted[i]} ${y}h${run}v1h-${run}z`;
|
|
164
|
+
i = j + 1;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return { fill, d };
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** The motion states an avatar shows today, `idle` first (a custom avatar's
|
|
172
|
+
* one required image, and every missing state's fallback). */
|
|
173
|
+
export const AGENT_AVATAR_STATES = Object.freeze(['idle', 'typing', 'message']);
|
|
174
|
+
|
|
175
|
+
/** The single image avatar before per-state images: a PNG beside AGENT.md
|
|
176
|
+
* under a content-hash name. Still read, as a custom avatar's idle image. */
|
|
177
|
+
export const AGENT_AVATAR_IMAGE_FILE = /^avatar-[0-9a-f]{12}\.png$/;
|
|
178
|
+
/** One state's image in `agents/<id>/avatar/`, under a content-hash name (a
|
|
179
|
+
* new upload is a new name, so caches by name never go stale). An animated
|
|
180
|
+
* one keeps its still first frame beside it (avatarPosterFile). */
|
|
181
|
+
export const AGENT_AVATAR_STATE_FILE = /^(idle|typing|message)-[0-9a-f]{12}\.(png|gif|webp)$/;
|
|
182
|
+
export const AGENT_AVATAR_DIR = 'avatar';
|
|
183
|
+
/** The largest image upload accepted, and the largest side of an animation. */
|
|
184
|
+
export const AGENT_AVATAR_IMAGE_MAX_BYTES = 1024 * 1024;
|
|
185
|
+
export const AGENT_AVATAR_IMAGE_MAX_SIDE = 512;
|
|
186
|
+
|
|
187
|
+
/** A state image's path under the agent's folder ('/'-separated). */
|
|
188
|
+
export const agentAvatarStatePath = (file) =>
|
|
189
|
+
AGENT_AVATAR_IMAGE_FILE.test(file) ? file : `${AGENT_AVATAR_DIR}/${file}`;
|
|
190
|
+
/** The still first frame stored beside an animated state image. */
|
|
191
|
+
export const avatarPosterFile = (file) => file.replace(/\.(png|gif|webp)$/, '.poster.png');
|
|
192
|
+
/** The image a custom avatar shows in `state`: its own, else idle's. */
|
|
193
|
+
export const customAvatarStateFile = (avatar, state) => avatar.states[state] ?? avatar.states.idle;
|
|
194
|
+
|
|
195
|
+
const u16le = (bytes, at) => bytes[at] | (bytes[at + 1] << 8);
|
|
196
|
+
const u24le = (bytes, at) => bytes[at] | (bytes[at + 1] << 8) | (bytes[at + 2] << 16);
|
|
197
|
+
const u32be = (bytes, at) => ((bytes[at] << 24) | (bytes[at + 1] << 16) | (bytes[at + 2] << 8) | bytes[at + 3]) >>> 0;
|
|
198
|
+
const ascii = (bytes, at, length) => String.fromCharCode(...bytes.subarray(at, at + length));
|
|
199
|
+
|
|
200
|
+
/** An upload's format and size, read from its header bytes: a PNG (an APNG
|
|
201
|
+
* counts as animated), a GIF (always treated as animated) or a WebP; null
|
|
202
|
+
* for anything else — SVG and every other markup included. */
|
|
203
|
+
export function avatarImageInfo(bytes) {
|
|
204
|
+
if (!(bytes instanceof Uint8Array) || bytes.length < 30) return null;
|
|
205
|
+
if (u32be(bytes, 0) === 0x89504e47 && u32be(bytes, 4) === 0x0d0a1a0a && ascii(bytes, 12, 4) === 'IHDR') {
|
|
206
|
+
let animated = false;
|
|
207
|
+
for (let at = 8; at + 8 <= bytes.length; at += 12 + u32be(bytes, at)) {
|
|
208
|
+
const type = ascii(bytes, at + 4, 4);
|
|
209
|
+
if (type === 'acTL') animated = true;
|
|
210
|
+
if (type === 'IDAT' || type === 'IEND') break;
|
|
211
|
+
}
|
|
212
|
+
return { format: 'png', width: u32be(bytes, 16), height: u32be(bytes, 20), animated };
|
|
213
|
+
}
|
|
214
|
+
if (ascii(bytes, 0, 6) === 'GIF87a' || ascii(bytes, 0, 6) === 'GIF89a') {
|
|
215
|
+
return { format: 'gif', width: u16le(bytes, 6), height: u16le(bytes, 8), animated: true };
|
|
216
|
+
}
|
|
217
|
+
if (ascii(bytes, 0, 4) === 'RIFF' && ascii(bytes, 8, 4) === 'WEBP') {
|
|
218
|
+
const chunk = ascii(bytes, 12, 4);
|
|
219
|
+
if (chunk === 'VP8X') {
|
|
220
|
+
const animated = (bytes[20] & 0x02) !== 0;
|
|
221
|
+
return { format: 'webp', width: u24le(bytes, 24) + 1, height: u24le(bytes, 27) + 1, animated };
|
|
222
|
+
}
|
|
223
|
+
if (chunk === 'VP8 ') {
|
|
224
|
+
return { format: 'webp', width: u16le(bytes, 26) & 0x3fff, height: u16le(bytes, 28) & 0x3fff, animated: false };
|
|
225
|
+
}
|
|
226
|
+
if (chunk === 'VP8L') {
|
|
227
|
+
const bits = (bytes[21] | (bytes[22] << 8) | (bytes[23] << 16) | (bytes[24] << 24)) >>> 0;
|
|
228
|
+
return { format: 'webp', width: (bits & 0x3fff) + 1, height: ((bits >>> 14) & 0x3fff) + 1, animated: false };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** Why bytes cannot be a state image ('' when they can): not a PNG, GIF or
|
|
235
|
+
* WebP, over 1 MB, not square, or over 512px. */
|
|
236
|
+
export function agentAvatarImageProblem(bytes) {
|
|
237
|
+
const info = avatarImageInfo(bytes);
|
|
238
|
+
if (!info) return 'must be a PNG, GIF or WebP image';
|
|
239
|
+
if (bytes.length > AGENT_AVATAR_IMAGE_MAX_BYTES) return 'is larger than 1 MB';
|
|
240
|
+
if (!info.width || info.width !== info.height) return 'must be square';
|
|
241
|
+
if (info.width > AGENT_AVATAR_IMAGE_MAX_SIDE) return 'must be 512px or smaller';
|
|
242
|
+
return '';
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function normalizeCustom(states) {
|
|
246
|
+
if (!states || typeof states !== 'object') return null;
|
|
247
|
+
const kept = {};
|
|
248
|
+
for (const state of AGENT_AVATAR_STATES) {
|
|
249
|
+
const file = states[state];
|
|
250
|
+
if (file == null) continue;
|
|
251
|
+
const own = typeof file === 'string' && AGENT_AVATAR_STATE_FILE.test(file) && file.startsWith(`${state}-`);
|
|
252
|
+
const legacy = state === 'idle' && typeof file === 'string' && AGENT_AVATAR_IMAGE_FILE.test(file);
|
|
253
|
+
if (!own && !legacy) return null;
|
|
254
|
+
kept[state] = file;
|
|
255
|
+
}
|
|
256
|
+
return kept.idle ? { kind: 'custom', states: kept } : null;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const pick = (value, list, fallback) => (value == null ? fallback : list.includes(value) ? value : null);
|
|
260
|
+
|
|
261
|
+
/** A stored avatar as the app understands it, or null when it is not one. An
|
|
262
|
+
* older single image reads as a custom avatar with only its idle image; an
|
|
263
|
+
* older mascot `variant` as its mapped species, accessory and expression. */
|
|
264
|
+
export function normalizeAgentAvatar(value) {
|
|
265
|
+
if (!value || typeof value !== 'object') return null;
|
|
266
|
+
if (value.kind === 'image') {
|
|
267
|
+
return typeof value.file === 'string' && AGENT_AVATAR_IMAGE_FILE.test(value.file)
|
|
268
|
+
? { kind: 'custom', states: { idle: value.file } }
|
|
269
|
+
: null;
|
|
270
|
+
}
|
|
271
|
+
if (value.kind === 'custom') return normalizeCustom(value.states);
|
|
272
|
+
if (value.kind !== 'mascot') return null;
|
|
273
|
+
const color = typeof value.color === 'string' ? value.color.toLowerCase() : '';
|
|
274
|
+
if (!AGENT_AVATAR_COLORS.includes(color)) return null;
|
|
275
|
+
const look =
|
|
276
|
+
value.species == null && typeof value.variant === 'string'
|
|
277
|
+
? mascotFromVariant(value.variant)
|
|
278
|
+
: {
|
|
279
|
+
species: pick(
|
|
280
|
+
RETIRED_SPECIES[value.species] ?? value.species,
|
|
281
|
+
[...MASCOT_SPECIES, MIXY_AVATAR.species],
|
|
282
|
+
null
|
|
283
|
+
),
|
|
284
|
+
accessory: pick(RETIRED_ACCESSORIES[value.accessory] ?? value.accessory, MASCOT_ACCESSORIES, 'none'),
|
|
285
|
+
expression: pick(value.expression, MASCOT_EXPRESSIONS, 'calm'),
|
|
286
|
+
};
|
|
287
|
+
if (!look?.species || !look.accessory || !look.expression) return null;
|
|
288
|
+
return { kind: 'mascot', ...look, color };
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// FNV-1a: a small stable string hash, the same on every platform.
|
|
292
|
+
function hashId(id) {
|
|
293
|
+
let hash = 0x811c9dc5;
|
|
294
|
+
for (const char of String(id)) {
|
|
295
|
+
hash ^= char.codePointAt(0);
|
|
296
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
297
|
+
}
|
|
298
|
+
return hash;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** The look of an agent that never picked one: fixed by its id — the
|
|
302
|
+
* species, accessory and colour it had before species existed (its old
|
|
303
|
+
* variant, mapped), with the neutral face every default wears. */
|
|
304
|
+
export function defaultAgentAvatar(id) {
|
|
305
|
+
const hash = hashId(id);
|
|
306
|
+
return {
|
|
307
|
+
kind: 'mascot',
|
|
308
|
+
...mascotFromVariant(LEGACY_VARIANTS[hash % LEGACY_VARIANTS.length]),
|
|
309
|
+
expression: 'calm',
|
|
310
|
+
color: AGENT_AVATAR_COLORS[Math.floor(hash / LEGACY_VARIANTS.length) % AGENT_AVATAR_COLORS.length],
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** What an agent shows: its own images, else Mixy's fixed look (for Mixy),
|
|
315
|
+
* its own mascot pick, or its id default. */
|
|
316
|
+
export function agentAvatar(id, stored) {
|
|
317
|
+
const own = normalizeAgentAvatar(stored);
|
|
318
|
+
if (id === MIXY_AGENT_ID) return own ?? { ...MIXY_AVATAR };
|
|
319
|
+
return own ?? defaultAgentAvatar(id);
|
|
320
|
+
}
|
|
@@ -16,6 +16,22 @@ export const DEFAULT_DISABLED_AGENT_IDS = Object.freeze([
|
|
|
16
16
|
// runs only once the user turns it on and picks its model.
|
|
17
17
|
export const DEFAULT_DISABLED_AGENT_ROSTER = Object.freeze([...DEFAULT_DISABLED_AGENT_IDS, 'maintainer']);
|
|
18
18
|
|
|
19
|
+
/** The AGENT.md frontmatter `kind` the Workflows page writes when it creates
|
|
20
|
+
* an agent: a workflow delegation role, never a contact (봇). */
|
|
21
|
+
export const WORKFLOW_AGENT_KIND = 'agent';
|
|
22
|
+
|
|
23
|
+
/** A contact agent (a 봇): one the user made — not Mixy ('lead'), not a
|
|
24
|
+
* shipped role (the starter sub-agents Worker, Reviewer, … and the
|
|
25
|
+
* Maintainer), and not marked `kind: agent` (made on the Workflows page).
|
|
26
|
+
* `kind` is the definition's frontmatter `kind`; an unmarked custom agent
|
|
27
|
+
* stays a contact. The one rule for the runtime (delegation, agent catalogs)
|
|
28
|
+
* and the desktop (contacts, agent lists). */
|
|
29
|
+
export function isContactAgentId(value, kind) {
|
|
30
|
+
const id = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
31
|
+
const marked = typeof kind === 'string' && kind.trim().toLowerCase() === WORKFLOW_AGENT_KIND;
|
|
32
|
+
return Boolean(id) && id !== 'lead' && !DEFAULT_DISABLED_AGENT_ROSTER.includes(id) && !marked;
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
function record(value) {
|
|
20
36
|
return isPlainObject(value) ? value : {};
|
|
21
37
|
}
|
|
@@ -19,7 +19,8 @@ import {
|
|
|
19
19
|
unlink as unlinkAsync,
|
|
20
20
|
writeFile as writeFileAsync,
|
|
21
21
|
} from 'node:fs/promises';
|
|
22
|
-
import {
|
|
22
|
+
import { tmpdir } from 'node:os';
|
|
23
|
+
import { dirname, basename, join, relative, isAbsolute, resolve } from 'node:path';
|
|
23
24
|
import { randomBytes } from 'node:crypto';
|
|
24
25
|
import { DEFAULT_BACKOFFS_MS, recordLockTiming, withFileLock, withFileLockSync } from './file-lock.mjs';
|
|
25
26
|
import {
|
|
@@ -164,7 +165,18 @@ async function fsyncPathAsync(path, tolerated) {
|
|
|
164
165
|
}
|
|
165
166
|
}
|
|
166
167
|
|
|
168
|
+
// Node sets NODE_TEST_CONTEXT in every `--test` process. A secret (credential)
|
|
169
|
+
// write from a test must land under the temp dir; anything else is a fixture
|
|
170
|
+
// about to overwrite a real profile, so fail loudly instead.
|
|
171
|
+
function assertTestSecretWriteSafe(filePath, opts) {
|
|
172
|
+
if (opts.secret !== true || !process.env.NODE_TEST_CONTEXT) return;
|
|
173
|
+
const rel = relative(resolve(tmpdir()).toLowerCase(), resolve(filePath).toLowerCase());
|
|
174
|
+
if (rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))) return;
|
|
175
|
+
throw new Error(`refusing to write a secret outside the temp dir under node --test: ${filePath}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
167
178
|
export function writeFileAtomicSync(filePath, data, opts = {}) {
|
|
179
|
+
assertTestSecretWriteSafe(filePath, opts);
|
|
168
180
|
const run = () => {
|
|
169
181
|
const dir = dirname(filePath);
|
|
170
182
|
mkdirSync(dir, { recursive: true });
|
|
@@ -289,6 +301,7 @@ export function updateJsonAtomicSync(filePath, mutator, opts = {}) {
|
|
|
289
301
|
// block the host event loop on read/write/fsync/rename.
|
|
290
302
|
// Async writes retain atomic rename publication; truncate recovery is sync-only.
|
|
291
303
|
export async function writeFileAtomicAsync(filePath, data, opts = {}) {
|
|
304
|
+
assertTestSecretWriteSafe(filePath, opts);
|
|
292
305
|
const run = async () => {
|
|
293
306
|
const dir = dirname(filePath);
|
|
294
307
|
await mkdirAsync(dir, { recursive: true });
|
|
@@ -328,7 +328,14 @@ function readAll() {
|
|
|
328
328
|
// marker yet) is a recovery case too; without a verifiable backup reads stay
|
|
329
329
|
// empty and RMW writes refuse (see readAllForRmW).
|
|
330
330
|
if (isUserDataRecoveryExpected(resolvePluginData())) {
|
|
331
|
-
|
|
331
|
+
let restored = null;
|
|
332
|
+
try {
|
|
333
|
+
restored = loadLatestMixdogConfigFromBackup(resolvePluginData());
|
|
334
|
+
} catch (err) {
|
|
335
|
+
// A transient backup read failure: this read stays empty and the next
|
|
336
|
+
// one retries (an RMW write refuses instead).
|
|
337
|
+
process.stderr.write(`[config] backup restore lookup failed: ${err.message}\n`);
|
|
338
|
+
}
|
|
332
339
|
if (restored && isPlainObject(restored)) {
|
|
333
340
|
const config = canonicalizeUnifiedConfig(restored);
|
|
334
341
|
persistRestoredConfig(config);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// What a multi-account connector server tells the model about itself (MCP
|
|
2
|
+
// `instructions`): the account it acts for, and to ask which one when the
|
|
3
|
+
// user did not say and several are connected. The deferred-tool manifest
|
|
4
|
+
// (context/deferred-tools.mjs) reads the leading "Account: <address>" back.
|
|
5
|
+
|
|
6
|
+
/** The MCP instructions of a `service` server acting for `account` ('' when unknown). */
|
|
7
|
+
export function accountInstructions(service, account) {
|
|
8
|
+
if (!account) return undefined;
|
|
9
|
+
return `Account: ${account}. This server acts only for this ${service} account; other ${service} accounts are separate servers. If several are connected and the user did not name one, ask which account before acting.`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** The account a server's instructions name, or ''. */
|
|
13
|
+
export function accountOfInstructions(instructions) {
|
|
14
|
+
return /^Account: (\S+?)\. /.exec(String(instructions || ''))?.[1] || '';
|
|
15
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type ConnectorBackend =
|
|
2
|
+
| {
|
|
3
|
+
kind: 'oauth';
|
|
4
|
+
url: string;
|
|
5
|
+
/** A pre-registered client the runtime supplies instead of registration. */
|
|
6
|
+
oauthClient?: 'google';
|
|
7
|
+
scopes?: readonly string[];
|
|
8
|
+
askTools?: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
| {
|
|
11
|
+
kind: 'apiKey';
|
|
12
|
+
url?: string;
|
|
13
|
+
header?: string;
|
|
14
|
+
prefix?: string;
|
|
15
|
+
command?: string;
|
|
16
|
+
args?: readonly string[];
|
|
17
|
+
env?: string;
|
|
18
|
+
keyUrl: string;
|
|
19
|
+
placeholder?: string;
|
|
20
|
+
/** Tools that ask before they run unless the agent set them. */
|
|
21
|
+
askTools?: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
| { kind: 'builtin'; feature: string };
|
|
24
|
+
|
|
25
|
+
export interface ConnectorCatalogEntry {
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
backend: ConnectorBackend;
|
|
29
|
+
/** Offered only after the user enters their own Google OAuth client. */
|
|
30
|
+
ownKey?: boolean;
|
|
31
|
+
/** Curated deferred-tool manifest line (connector-triggers.mjs). */
|
|
32
|
+
trigger: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const CONNECTOR_CATALOG: readonly ConnectorCatalogEntry[];
|
|
36
|
+
export const GOOGLE_SCOPES: Readonly<Record<'gmail' | 'calendar' | 'drive', readonly string[]>>;
|
|
37
|
+
export const CONNECTOR_IDS: readonly string[];
|
|
38
|
+
export function connectorById(id: unknown): ConnectorCatalogEntry | null;
|
|
39
|
+
export function connectorOfServer(cfg: unknown): string;
|
|
40
|
+
export function connectorToolDefault(connectorId: string, tool: string): 'auto' | 'needs_approval';
|
|
41
|
+
export function connectorServerInput(
|
|
42
|
+
entry: ConnectorCatalogEntry,
|
|
43
|
+
name: string,
|
|
44
|
+
key?: string,
|
|
45
|
+
options?: { extraAccount?: boolean }
|
|
46
|
+
): Record<string, unknown>;
|
|
47
|
+
export function connectorMultiAccount(entry: ConnectorCatalogEntry | null | undefined): boolean;
|
|
48
|
+
export const GMAIL_APP_PASSWORD: Readonly<{ url: string; accountHeader: string; helpUrl: string }>;
|
|
49
|
+
export function gmailAddress(value: unknown): string;
|
|
50
|
+
export function gmailAppPasswordValue(value: unknown): string;
|
|
51
|
+
export function gmailAppPasswordAccount(cfg: unknown): string;
|
|
52
|
+
export function gmailAppPasswordServerInput(name: string, email: string, password: string): Record<string, unknown>;
|