mixdog 1.1.0 → 1.1.2
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/README.md +13 -6
- package/package.json +1 -2
- package/scripts/latest-guard.mjs +63 -0
- package/scripts/lib/run-node-tests.mjs +103 -27
- package/scripts/lib/test-failure-summary.mjs +7 -2
- package/scripts/merge-mac-update-feed.mjs +107 -0
- package/scripts/mobile-release.mjs +210 -0
- package/scripts/post-release-check.mjs +353 -0
- package/scripts/publish-asset-release.mjs +43 -0
- package/scripts/release-guard.mjs +63 -0
- package/scripts/release-paths.mjs +39 -2
- package/scripts/test.mjs +29 -7
- package/src/defaults/shipped-history.json +2 -0
- package/src/defaults/skills/computer-use/SKILL.md +1 -1
- package/src/defaults/skills/setup/references/actions.md +1 -0
- package/src/headless-role.mjs +2 -2
- package/src/lib/keychain-cjs.cjs +582 -17
- package/src/lib/rules-builder.cjs +0 -23
- package/src/rules/lead/LEAD.md +2 -2
- package/src/runtime/agent/orchestrator/config-storage.mjs +32 -4
- package/src/runtime/agent/orchestrator/config.mjs +18 -0
- package/src/runtime/agent/orchestrator/context/instruction-files.mjs +130 -0
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/lib/open-login-url.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +254 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +218 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +239 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +233 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth-login.mjs +247 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +225 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +542 -0
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +25 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +14 -6
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +99 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +4 -8
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +2 -7
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -0
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +15 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +1 -5
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +12 -14
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +11 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-call-ids.mjs +90 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +19 -11
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +1 -5
- package/src/runtime/agent/orchestrator/session/read-dedup.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/turn-effort.mjs +18 -0
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +11 -8
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +9 -4
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +245 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +13 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +49 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +9 -7
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +61 -8
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +28 -3
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +73 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +17 -6
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +23 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +93 -43
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +32 -6
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +9 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +12 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +124 -91
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +19 -4
- package/src/runtime/channels/index.mjs +1 -5
- package/src/runtime/channels/lib/runtime-paths.mjs +8 -23
- package/src/runtime/channels/lib/tool-dispatch.mjs +1 -13
- package/src/runtime/channels/lib/worker-ipc.mjs +2 -2
- package/src/runtime/channels/lib/worker-main.mjs +4 -34
- package/src/runtime/computer-bridge/client.mjs +25 -1
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +84 -0
- package/src/runtime/computer-bridge/linux-readiness.d.mts +52 -0
- package/src/runtime/computer-bridge/linux-readiness.mjs +411 -0
- package/src/runtime/computer-bridge/test-linux-display.mjs +5 -0
- package/src/runtime/effort-judge/compact-tokenizer.mjs +13 -8
- package/src/runtime/effort-judge/judge-input.mjs +5 -2
- package/src/runtime/effort-judge/model-install.mjs +9 -3
- package/src/runtime/effort-judge/model-manifest.json +7 -7
- package/src/runtime/memory/lib/embedding-worker.mjs +9 -3
- package/src/runtime/memory/lib/pg/supervisor.mjs +3 -0
- package/src/runtime/shared/config.mjs +50 -2
- package/src/runtime/shared/developer-options.mjs +7 -0
- package/src/runtime/shared/instruction-files-mode.mjs +9 -0
- package/src/runtime/shared/llm/model-catalog.mjs +2 -1
- package/src/runtime/shared/llm/openai-daybreak.mjs +79 -0
- package/src/runtime/shared/pristine-execution-contract.json +9 -0
- package/src/runtime/shared/pristine-execution.mjs +1 -1
- package/src/runtime/shared/provider-accounts.mjs +2 -0
- package/src/runtime/shared/resource-admission.mjs +10 -3
- package/src/runtime/shared/schedule-model-ref.mjs +11 -0
- package/src/runtime/shared/semver.d.mts +1 -0
- package/src/runtime/shared/semver.mjs +57 -0
- package/src/runtime/shared/session-approval-wait.mjs +35 -0
- package/src/runtime/shared/shell-display.mjs +4 -2
- package/src/runtime/shared/tool-surface.mjs +2 -2
- package/src/runtime/shared/turn-worktree-snapshot.mjs +11 -10
- package/src/runtime/shared/update-checker.mjs +2 -31
- package/src/session-runtime/boot/apis.mjs +5 -0
- package/src/session-runtime/boot/begin.mjs +0 -2
- package/src/session-runtime/boot/tools.mjs +5 -4
- package/src/session-runtime/model-recency.mjs +3 -0
- package/src/session-runtime/provider-auth/login.mjs +10 -10
- package/src/session-runtime/provider-auth/setup.mjs +22 -2
- package/src/session-runtime/provider-models/row-hydration.mjs +12 -4
- package/src/session-runtime/provider-readiness.mjs +4 -0
- package/src/session-runtime/resource-mcp-api.mjs +7 -3
- package/src/session-runtime/runtime-bootstrap.mjs +0 -4
- package/src/session-runtime/runtime-facade.mjs +5 -0
- package/src/session-runtime/runtime-paths.mjs +0 -1
- package/src/session-runtime/schedule-session-run.mjs +3 -1
- package/src/session-runtime/services/agent-tool/index-write-queue.mjs +55 -14
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +15 -3
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +2 -0
- package/src/session-runtime/services/agent-tool/worker-index/approval-wait.mjs +97 -0
- package/src/session-runtime/services/agent-tool/worker-index/mutation-batch.mjs +4 -2
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -2
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +3 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +58 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +69 -15
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +2 -0
- package/src/session-runtime/services/channel-admin.mjs +4 -2
- package/src/session-runtime/services/channel-worker.mjs +1 -1
- package/src/session-runtime/services/provider-admin.mjs +80 -17
- package/src/session-runtime/services/seeds.mjs +7 -10
- package/src/session-runtime/services/usage-dashboard-model.mjs +6 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +15 -0
- package/src/session-runtime/settings-profile-api.mjs +27 -2
- package/src/session-runtime/setup-tool/executor.mjs +5 -0
- package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
- package/src/session-runtime/starter-guide-state.mjs +62 -0
- package/src/session-runtime/tool-policy-refresh.mjs +3 -0
- package/src/session-runtime/webhook-session-run.mjs +3 -1
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -2
- package/src/standalone/channel-binding.mjs +1 -2
- package/src/standalone/channel-transport/call-dispatch.mjs +4 -10
- package/src/standalone/daemon-channels-loader.mjs +2 -3
- package/src/standalone/local-session-runtime.mjs +2 -78
- package/src/standalone/session-protocol.mjs +2 -0
- package/src/tui/app/model-options.mjs +13 -1
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +10 -4
- package/src/tui/app/provider-setup/oauth-actions.mjs +5 -0
- package/src/tui/dist/index.mjs +84 -34
- package/src/tui/session/context-state.mjs +2 -0
- package/src/tui/session/live-share/owner.mjs +17 -0
- package/src/tui/session/oauth-flows.mjs +2 -0
- package/src/tui/session/session-api/extensions.mjs +12 -8
- package/src/tui/session/session-api/integrations.mjs +9 -8
- package/src/tui/session/session-api/routes.mjs +2 -2
- package/src/tui/session/session-api/settings.mjs +1 -0
- package/src/tui/session/session-api/shared.mjs +10 -6
- package/src/tui/session/tool-card-results/grouped-result.mjs +11 -2
- package/src/tui/session/transcript-spill/spill-dir.mjs +22 -6
- package/src/tui/spinner-meta.mjs +26 -10
- package/src/runtime/channels/tool-defs.mjs +0 -17
|
@@ -11,16 +11,30 @@ import { resolve } from 'node:path';
|
|
|
11
11
|
import { WORKER_INDEX_FILE } from './tool-def.mjs';
|
|
12
12
|
import { clean, positiveInt, registerExitFlush, rowMatchesContext } from './helpers.mjs';
|
|
13
13
|
import { applyWorkerRowUpsert, recoverTagTombstoneOwner, workerRowKey } from './worker-rows.mjs';
|
|
14
|
+
import {
|
|
15
|
+
applyAwaitingUser,
|
|
16
|
+
awaitingUserWouldChange,
|
|
17
|
+
clearAwaitingUser,
|
|
18
|
+
registerApprovalWaitWriter,
|
|
19
|
+
} from './worker-index/approval-wait.mjs';
|
|
14
20
|
import { createMutationBatch } from './worker-index/mutation-batch.mjs';
|
|
15
|
-
import { createRowLiveness, isActiveWorkerRow } from './worker-index/row-liveness.mjs';
|
|
21
|
+
import { createRowLiveness, isActiveWorkerRow, isStaleApprovalWait } from './worker-index/row-liveness.mjs';
|
|
16
22
|
import { normalizeWorkerRows, workerRowFromSession } from './worker-index/row-shape.mjs';
|
|
17
|
-
import {
|
|
23
|
+
import { acquireWorkerRowStore } from './worker-index/row-store.mjs';
|
|
18
24
|
import { findTagTombstone, tagTombstoneKey, tombstoneBlocksWork } from '../../../runtime/shared/agent-reap-state.mjs';
|
|
19
25
|
|
|
20
26
|
export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCwds }) {
|
|
21
27
|
const file = dataDir ? resolve(dataDir, WORKER_INDEX_FILE) : null;
|
|
22
|
-
|
|
23
|
-
const
|
|
28
|
+
// Shared with every other worker index of this process over the same file.
|
|
29
|
+
const { store, release: releaseStore } = acquireWorkerRowStore(file);
|
|
30
|
+
// Sessions whose deferred rows still wait in the batch; reconciled once the
|
|
31
|
+
// batch lands in the store.
|
|
32
|
+
const unreconciled = new Set();
|
|
33
|
+
const batch = createMutationBatch(store.write, () => {
|
|
34
|
+
const ids = [...unreconciled];
|
|
35
|
+
unreconciled.clear();
|
|
36
|
+
for (const id of ids) reconcileAwaitingUser(id);
|
|
37
|
+
});
|
|
24
38
|
const liveness = createRowLiveness({ dataDir, cfgMod });
|
|
25
39
|
// Rows this process marked active; settled to idle on exit so a crash of
|
|
26
40
|
// the host never leaves them "running" forever.
|
|
@@ -62,10 +76,15 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
|
|
|
62
76
|
if (isActiveWorkerRow(normalized)) activeWorkerKeys.add(key);
|
|
63
77
|
else activeWorkerKeys.delete(key);
|
|
64
78
|
bindTag(normalized);
|
|
65
|
-
if (defer)
|
|
79
|
+
if (defer) {
|
|
80
|
+
if (!file) return false;
|
|
81
|
+
unreconciled.add(normalized.sessionId);
|
|
82
|
+
return batch.queue((byKey) => applyWorkerRowUpsert(byKey, normalized));
|
|
83
|
+
}
|
|
66
84
|
store.write((byKey) => {
|
|
67
85
|
applyWorkerRowUpsert(byKey, normalized);
|
|
68
86
|
});
|
|
87
|
+
reconcileAwaitingUser(normalized.sessionId);
|
|
69
88
|
return true;
|
|
70
89
|
}
|
|
71
90
|
|
|
@@ -85,6 +104,31 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
|
|
|
85
104
|
});
|
|
86
105
|
}
|
|
87
106
|
|
|
107
|
+
/** Persist (or clear) a worker's approval wait as a field update fenced to
|
|
108
|
+
* the session and its turn (`turnAt`, ms): a row whose turn started later is
|
|
109
|
+
* left alone. Writes only when a row of that session exists and would
|
|
110
|
+
* change, so a Lead's own approvals cost nothing; a row that is not in the
|
|
111
|
+
* store yet takes the wait when it lands (reconcileAwaitingUser). */
|
|
112
|
+
function setAwaitingUser(sessionId, awaitingUser, { turnAt = 0 } = {}) {
|
|
113
|
+
const fence = {
|
|
114
|
+
sessionId: clean(sessionId),
|
|
115
|
+
awaitingUser: awaitingUser === 'approval' ? 'approval' : null,
|
|
116
|
+
turnAt: Number(turnAt) || 0,
|
|
117
|
+
};
|
|
118
|
+
if (!fence.sessionId || !awaitingUserWouldChange(store.readAll(), fence)) return false;
|
|
119
|
+
store.update((byKey) => applyAwaitingUser(byKey, fence));
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** The runtime of a session this process runs is the authority on its
|
|
124
|
+
* approval wait (the runtime-liveness counter behind `awaitingUser`): every
|
|
125
|
+
* row it creates or refreshes takes that state, so a missed or stale
|
|
126
|
+
* transition heals on the next write. No runtime here: not ours to judge. */
|
|
127
|
+
function reconcileAwaitingUser(sessionId) {
|
|
128
|
+
const runtime = mgr.getSessionRuntime?.(sessionId);
|
|
129
|
+
if (runtime) setAwaitingUser(sessionId, runtime.awaitingUser, { turnAt: runtime.askStartedAt });
|
|
130
|
+
}
|
|
131
|
+
|
|
88
132
|
function refreshTagsFromIndex(context = {}) {
|
|
89
133
|
const rows = readWorkerRows(context);
|
|
90
134
|
for (const row of rows) bindTag(row);
|
|
@@ -105,18 +149,24 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
|
|
|
105
149
|
});
|
|
106
150
|
}
|
|
107
151
|
|
|
152
|
+
// Startup recovery: stale active rows settle to idle, and an approval wait
|
|
153
|
+
// left behind by a runtime that is gone (daemon restart) is cleared.
|
|
108
154
|
function recoverStaleWorkerRows() {
|
|
109
155
|
const now = Date.now();
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
156
|
+
const rows = store.readAll();
|
|
157
|
+
const staleActive = rows.filter((row) => liveness.isStaleActive(row, now));
|
|
158
|
+
const staleWaits = rows.some(isStaleApprovalWait);
|
|
159
|
+
if (!staleActive.length && !staleWaits) return false;
|
|
160
|
+
if (staleActive.length) {
|
|
161
|
+
store.write((byKey) => {
|
|
162
|
+
for (const row of staleActive) {
|
|
163
|
+
const key = workerRowKey(row);
|
|
164
|
+
const current = byKey.get(key);
|
|
165
|
+
if (current && liveness.isStaleActive(current, now)) byKey.set(key, liveness.idleRow(current, now));
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (staleWaits) store.update((byKey) => clearAwaitingUser(byKey, isStaleApprovalWait));
|
|
120
170
|
return true;
|
|
121
171
|
}
|
|
122
172
|
|
|
@@ -129,6 +179,7 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
|
|
|
129
179
|
|
|
130
180
|
recoverStaleWorkerRows();
|
|
131
181
|
const unregisterExitFlush = registerExitFlush(flushWorkerIndexOnExit);
|
|
182
|
+
const unregisterApprovalWaits = registerApprovalWaitWriter(file, setAwaitingUser);
|
|
132
183
|
let disposed = false;
|
|
133
184
|
|
|
134
185
|
/** Persist queued rows, then release the exit registration. Active rows are
|
|
@@ -142,6 +193,8 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
|
|
|
142
193
|
store.flushSync();
|
|
143
194
|
} finally {
|
|
144
195
|
unregisterExitFlush();
|
|
196
|
+
unregisterApprovalWaits();
|
|
197
|
+
releaseStore();
|
|
145
198
|
}
|
|
146
199
|
}
|
|
147
200
|
|
|
@@ -168,6 +221,7 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
|
|
|
168
221
|
upsertWorkerSessionDeferred: (session, fallbackTag = '', extra = {}) =>
|
|
169
222
|
upsertWorkerRow(rowFromSession(session, fallbackTag, extra), { defer: true }),
|
|
170
223
|
removeWorkerRow,
|
|
224
|
+
setAwaitingUser,
|
|
171
225
|
refreshTagsFromIndex,
|
|
172
226
|
flushActiveWorkerRows,
|
|
173
227
|
flushWorkerIndexOnExit,
|
|
@@ -112,6 +112,8 @@ export function applyWorkerRowUpsert(byKey, normalized) {
|
|
|
112
112
|
merged[field] = prev[field];
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
+
// `awaitingUser` is not decided here: the worker row store keeps the current
|
|
116
|
+
// row's flag across every whole-row write and drops it once the row settles.
|
|
115
117
|
byKey.set(key, {
|
|
116
118
|
...merged,
|
|
117
119
|
createdAt: normalized.createdAt || prev.createdAt || new Date().toISOString(),
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
setEndpointEnabled as dbSetEndpointEnabled,
|
|
24
24
|
} from '../../runtime/channels/lib/webhooks-db.mjs';
|
|
25
25
|
import { normalizeAutomationAttachments } from '../../runtime/shared/automation-attachments.mjs';
|
|
26
|
+
import { migrateCodexModelRef } from '../../runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs';
|
|
26
27
|
import { hasEnabledAutomation } from '../../runtime/shared/automation-presence.mjs';
|
|
27
28
|
import { resolveScheduleTimezone, validateScheduleCron } from '../../runtime/shared/schedule-time.mjs';
|
|
28
29
|
import { readHookPublicBase } from '../../runtime/channels/lib/webhook/relay-tunnel.mjs';
|
|
@@ -192,7 +193,8 @@ function scheduleToDisplay(s) {
|
|
|
192
193
|
whenAt: s.whenAt || undefined,
|
|
193
194
|
whenCron: s.whenCron || undefined,
|
|
194
195
|
timezone: s.timezone || undefined,
|
|
195
|
-
|
|
196
|
+
// Shown (and re-saved by the editor) on the catalog successor of a superseded model.
|
|
197
|
+
model: s.model ? migrateCodexModelRef(s.model) : undefined,
|
|
196
198
|
cwd: s.cwd || undefined,
|
|
197
199
|
workflow: s.workflow || undefined,
|
|
198
200
|
attachments: s.attachments || undefined,
|
|
@@ -287,7 +289,7 @@ async function listWebhooks() {
|
|
|
287
289
|
name: ep.name,
|
|
288
290
|
description: ep.description || '',
|
|
289
291
|
parser: ep.parser || 'github',
|
|
290
|
-
...(ep.model ? { model: ep.model } : {}),
|
|
292
|
+
...(ep.model ? { model: migrateCodexModelRef(ep.model) } : {}),
|
|
291
293
|
...(ep.cwd ? { cwd: ep.cwd } : {}),
|
|
292
294
|
...(ep.workflow ? { workflow: ep.workflow } : {}),
|
|
293
295
|
...(ep.attachments ? { attachments: ep.attachments } : {}),
|
|
@@ -18,7 +18,7 @@ import { daemonEnv, spawnDaemonCandidate } from './channel-worker/daemon-spawn.m
|
|
|
18
18
|
|
|
19
19
|
export { pruneStaleChannelClientHeartbeats };
|
|
20
20
|
|
|
21
|
-
const CHANNEL_TOOLS = new Set(['activate_channel_bridge', 'reload_config'
|
|
21
|
+
const CHANNEL_TOOLS = new Set(['activate_channel_bridge', 'reload_config']);
|
|
22
22
|
const CALL_RETRIES = 3;
|
|
23
23
|
|
|
24
24
|
function logLine(path, line) {
|
|
@@ -4,10 +4,11 @@ import { sameAccountIdentity } from '../../runtime/agent/orchestrator/providers/
|
|
|
4
4
|
import {
|
|
5
5
|
AGENT_PROVIDER_ENV,
|
|
6
6
|
SECRET_ACCOUNTS,
|
|
7
|
-
|
|
7
|
+
deleteSecretAsync,
|
|
8
8
|
getAgentApiKey,
|
|
9
|
+
getKeychainStatus,
|
|
9
10
|
hasStoredSecret,
|
|
10
|
-
|
|
11
|
+
saveSecretAsync,
|
|
11
12
|
} from '../../runtime/shared/config.mjs';
|
|
12
13
|
import {
|
|
13
14
|
beginOAuthLogin as beginAnthropicOAuthLogin,
|
|
@@ -35,6 +36,24 @@ import {
|
|
|
35
36
|
beginOAuthLogin as beginGrokOAuthLogin,
|
|
36
37
|
loginOAuth as loginGrokOAuth,
|
|
37
38
|
} from '../../runtime/agent/orchestrator/providers/grok-oauth-login.mjs';
|
|
39
|
+
import {
|
|
40
|
+
describeMimoOAuthCredentials,
|
|
41
|
+
forgetMimoOAuthCredentials,
|
|
42
|
+
hasMimoOAuthCredentials,
|
|
43
|
+
} from '../../runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs';
|
|
44
|
+
import {
|
|
45
|
+
beginOAuthLogin as beginMimoOAuthLogin,
|
|
46
|
+
loginOAuth as loginMimoOAuth,
|
|
47
|
+
} from '../../runtime/agent/orchestrator/providers/mimo-oauth-login.mjs';
|
|
48
|
+
import {
|
|
49
|
+
describeMuseCodeOAuthCredentials,
|
|
50
|
+
forgetMuseCodeOAuthCredentials,
|
|
51
|
+
hasMuseCodeOAuthCredentials,
|
|
52
|
+
} from '../../runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs';
|
|
53
|
+
import {
|
|
54
|
+
beginOAuthLogin as beginMuseCodeOAuthLogin,
|
|
55
|
+
loginOAuth as loginMuseCodeOAuth,
|
|
56
|
+
} from '../../runtime/agent/orchestrator/providers/muse-code-oauth-login.mjs';
|
|
38
57
|
import {
|
|
39
58
|
beginCursorOAuthLogin,
|
|
40
59
|
describeCursorOAuthCredentials,
|
|
@@ -125,6 +144,26 @@ const OAUTH_PROVIDERS = Object.freeze([
|
|
|
125
144
|
begin: beginGrokOAuthLogin,
|
|
126
145
|
login: loginGrokOAuth,
|
|
127
146
|
}),
|
|
147
|
+
Object.freeze({
|
|
148
|
+
id: 'muse-code-oauth',
|
|
149
|
+
name: 'Muse Code',
|
|
150
|
+
desc: 'Sign in with your Meta account (Muse Code subscription)',
|
|
151
|
+
has: hasMuseCodeOAuthCredentials,
|
|
152
|
+
describe: describeMuseCodeOAuthCredentials,
|
|
153
|
+
forget: forgetMuseCodeOAuthCredentials,
|
|
154
|
+
begin: beginMuseCodeOAuthLogin,
|
|
155
|
+
login: loginMuseCodeOAuth,
|
|
156
|
+
}),
|
|
157
|
+
Object.freeze({
|
|
158
|
+
id: 'mimo-oauth',
|
|
159
|
+
name: 'MiMo',
|
|
160
|
+
desc: 'Sign in with your Xiaomi MiMo account',
|
|
161
|
+
has: hasMimoOAuthCredentials,
|
|
162
|
+
describe: describeMimoOAuthCredentials,
|
|
163
|
+
forget: forgetMimoOAuthCredentials,
|
|
164
|
+
begin: beginMimoOAuthLogin,
|
|
165
|
+
login: loginMimoOAuth,
|
|
166
|
+
}),
|
|
128
167
|
Object.freeze({
|
|
129
168
|
id: 'cursor-oauth',
|
|
130
169
|
name: 'Cursor OAuth',
|
|
@@ -152,7 +191,7 @@ const BUILTIN_PROVIDER_IDS = new Set(['mixdog-local']);
|
|
|
152
191
|
const API_PROVIDER_IDS = new Set(API_PROVIDERS.map((p) => p.id));
|
|
153
192
|
const OAUTH_BY_ID = new Map(OAUTH_PROVIDERS.map((p) => [p.id, p]));
|
|
154
193
|
|
|
155
|
-
// Dev-only entries (cursor-oauth, antigravity-oauth) are unknown to
|
|
194
|
+
// Dev-only entries (cursor-oauth, antigravity-oauth, mimo-oauth) are unknown to
|
|
156
195
|
// settings/login while the Developer → Providers option is off. Filtered per
|
|
157
196
|
// call, so toggling the option takes effect without a restart.
|
|
158
197
|
function availableOAuthProviders() {
|
|
@@ -230,6 +269,24 @@ function describeOAuthProvider(p, { detail = false } = {}) {
|
|
|
230
269
|
return { authenticated, status: authenticated ? 'Set' : 'Not Set', ...(detail ? { detail: p.desc } : {}) };
|
|
231
270
|
}
|
|
232
271
|
|
|
272
|
+
// When the OS keyring is locked/missing a stored key reads as absent; say so
|
|
273
|
+
// (the UI shows the unlock / install hint) instead of a bare "No Key".
|
|
274
|
+
// Fixed, translatable hints keyed by keyring state; internal error text never
|
|
275
|
+
// reaches the UI.
|
|
276
|
+
const KEYCHAIN_HINTS = Object.freeze({
|
|
277
|
+
unreachable: 'The keyring is not reachable — make sure it is running, then press Unlock keyring.',
|
|
278
|
+
locked: 'Keyring is locked — unlock it (log in again or open Passwords and Keys).',
|
|
279
|
+
missing: 'Install libsecret-tools (sudo apt install libsecret-tools) to use the system keyring.',
|
|
280
|
+
error: 'The system keyring could not be read — check that it is running and unlocked.',
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
export function keychainIssueFor(checkSecrets) {
|
|
284
|
+
if (!checkSecrets) return null;
|
|
285
|
+
const { state } = getKeychainStatus();
|
|
286
|
+
const message = KEYCHAIN_HINTS[state];
|
|
287
|
+
return message ? { state, message } : null;
|
|
288
|
+
}
|
|
289
|
+
|
|
233
290
|
function apiProviderSetup(p, providers, checkSecrets) {
|
|
234
291
|
const configured = providers[p.id] || {};
|
|
235
292
|
const envName = AGENT_PROVIDER_ENV[p.id] || p.env;
|
|
@@ -245,8 +302,11 @@ function apiProviderSetup(p, providers, checkSecrets) {
|
|
|
245
302
|
if (stored) detail = 'stored in keychain';
|
|
246
303
|
else if (env) detail = envName;
|
|
247
304
|
else if (authenticated) detail = 'runtime credential';
|
|
305
|
+
const keychainIssue = authenticated ? null : keychainIssueFor(checkSecrets);
|
|
306
|
+
if (keychainIssue) detail = keychainIssue.message;
|
|
248
307
|
return {
|
|
249
308
|
...p,
|
|
309
|
+
...(keychainIssue ? { keychainIssue } : {}),
|
|
250
310
|
group: 'api',
|
|
251
311
|
type: 'api-key',
|
|
252
312
|
enabled: configuredEnabled || authenticated,
|
|
@@ -406,7 +466,9 @@ function customProviderRows(providers, checkSecrets) {
|
|
|
406
466
|
export async function providerSetup(config = {}, options = {}) {
|
|
407
467
|
const providers = config.providers || {};
|
|
408
468
|
const checkSecrets = options?.checkSecrets !== false;
|
|
469
|
+
const keychain = checkSecrets ? keychainIssueFor(true) : null;
|
|
409
470
|
return {
|
|
471
|
+
...(keychain ? { keychain } : {}),
|
|
410
472
|
api: [
|
|
411
473
|
...API_PROVIDERS.map((p) => apiProviderSetup(p, providers, checkSecrets)),
|
|
412
474
|
...customProviderRows(providers, checkSecrets),
|
|
@@ -500,7 +562,7 @@ export async function authenticateProvider(provider, secret) {
|
|
|
500
562
|
}
|
|
501
563
|
const value = String(secret || '').trim();
|
|
502
564
|
if (!value) throw new Error(`API key is required for ${id}`);
|
|
503
|
-
|
|
565
|
+
await saveSecretAsync(SECRET_ACCOUNTS.agentApiKey(id), value);
|
|
504
566
|
return { provider: id, type: 'api-key', authenticated: true };
|
|
505
567
|
}
|
|
506
568
|
|
|
@@ -638,6 +700,7 @@ export async function beginOAuthProviderLogin(cfgMod, provider, options = {}) {
|
|
|
638
700
|
type: 'oauth',
|
|
639
701
|
url: started.url,
|
|
640
702
|
manualUrl: started.manualUrl || null,
|
|
703
|
+
userCode: started.userCode || null,
|
|
641
704
|
waitForCallback: started.waitForCallback?.then(finish),
|
|
642
705
|
cancel: () => {
|
|
643
706
|
cancelled = true;
|
|
@@ -704,12 +767,12 @@ export function updateProviderAccounts(provider, change) {
|
|
|
704
767
|
return listProviderAccounts(provider);
|
|
705
768
|
}
|
|
706
769
|
|
|
707
|
-
export function saveProviderApiKey(cfgMod, provider, secret) {
|
|
770
|
+
export async function saveProviderApiKey(cfgMod, provider, secret) {
|
|
708
771
|
const id = String(provider || '').trim();
|
|
709
772
|
if (!API_PROVIDER_IDS.has(id)) throw new Error(`unknown API-key provider "${id}"`);
|
|
710
773
|
const value = String(secret || '').trim();
|
|
711
774
|
if (!value) throw new Error(`API key is required for ${id}`);
|
|
712
|
-
|
|
775
|
+
await saveSecretAsync(SECRET_ACCOUNTS.agentApiKey(id), value);
|
|
713
776
|
updateConfigProvider(cfgMod, id, { enabled: true });
|
|
714
777
|
return { provider: id, type: 'api-key', authenticated: true };
|
|
715
778
|
}
|
|
@@ -813,7 +876,7 @@ export async function saveCustomProvider(cfgMod, rawInput) {
|
|
|
813
876
|
const entry = { ...config, type: 'custom', enabled: config.enabled !== false };
|
|
814
877
|
const account = SECRET_ACCOUNTS.agentApiKey(id);
|
|
815
878
|
const previousKey = typed && existingId ? getAgentApiKey(id) : null;
|
|
816
|
-
if (typed)
|
|
879
|
+
if (typed) await saveSecretAsync(account, typed);
|
|
817
880
|
try {
|
|
818
881
|
const current = cfgMod.loadConfig();
|
|
819
882
|
cfgMod.saveConfig(
|
|
@@ -822,8 +885,8 @@ export async function saveCustomProvider(cfgMod, rawInput) {
|
|
|
822
885
|
);
|
|
823
886
|
} catch (error) {
|
|
824
887
|
if (typed) {
|
|
825
|
-
if (previousKey)
|
|
826
|
-
else
|
|
888
|
+
if (previousKey) await saveSecretAsync(account, previousKey);
|
|
889
|
+
else await deleteSecretAsync(account);
|
|
827
890
|
}
|
|
828
891
|
throw error;
|
|
829
892
|
}
|
|
@@ -912,13 +975,13 @@ export async function updateCustomProviderModel(cfgMod, rawId, rawModelId, patch
|
|
|
912
975
|
return customProviderRow(id, saved);
|
|
913
976
|
}
|
|
914
977
|
|
|
915
|
-
export function removeCustomProvider(cfgMod, rawId) {
|
|
978
|
+
export async function removeCustomProvider(cfgMod, rawId) {
|
|
916
979
|
const id = String(rawId || '').trim();
|
|
917
980
|
existingCustomEntry(cfgMod, id);
|
|
918
981
|
const current = cfgMod.loadConfig();
|
|
919
982
|
const { [id]: _removed, ...providers } = current.providers || {};
|
|
920
983
|
cfgMod.saveConfig({ ...current, providers }, { baseConfig: current });
|
|
921
|
-
|
|
984
|
+
await deleteSecretAsync(SECRET_ACCOUNTS.agentApiKey(id));
|
|
922
985
|
return { provider: id, type: 'custom', removed: true };
|
|
923
986
|
}
|
|
924
987
|
|
|
@@ -977,15 +1040,15 @@ function discoveryErrorView(error, apiKey) {
|
|
|
977
1040
|
};
|
|
978
1041
|
}
|
|
979
1042
|
|
|
980
|
-
export function saveOpenAIUsageSessionKey(cfgMod, secret) {
|
|
1043
|
+
export async function saveOpenAIUsageSessionKey(cfgMod, secret) {
|
|
981
1044
|
const value = String(secret || '').trim();
|
|
982
1045
|
if (!value) throw new Error('OpenAI usage session key is required for credit lookup');
|
|
983
|
-
|
|
1046
|
+
await saveSecretAsync(SECRET_ACCOUNTS.openaiUsageSessionKey, value);
|
|
984
1047
|
updateConfigProvider(cfgMod, 'openai', { enabled: true });
|
|
985
1048
|
return { provider: 'openai', type: 'usage-auth', authenticated: true };
|
|
986
1049
|
}
|
|
987
1050
|
|
|
988
|
-
export function saveOpenCodeGoUsageAuth(cfgMod, { apiKey } = {}) {
|
|
1051
|
+
export async function saveOpenCodeGoUsageAuth(cfgMod, { apiKey } = {}) {
|
|
989
1052
|
const secret = String(apiKey || '').trim();
|
|
990
1053
|
if (!secret) throw new Error('OpenCode console API key is required for usage lookup');
|
|
991
1054
|
// Subscription meters are read with a console service-account key holding the
|
|
@@ -993,7 +1056,7 @@ export function saveOpenCodeGoUsageAuth(cfgMod, { apiKey } = {}) {
|
|
|
993
1056
|
// rejecting anything else here keeps unusable auth out of the keychain.
|
|
994
1057
|
if (!/^(?:oc_sk_|sk-)/.test(secret))
|
|
995
1058
|
throw new Error('OpenCode usage auth must be a console API key (oc_sk_… or sk-…) with all permissions');
|
|
996
|
-
|
|
1059
|
+
await saveSecretAsync(SECRET_ACCOUNTS.opencodeGoConsoleKey, secret);
|
|
997
1060
|
// Usage auth may be a different key from the inference key. Only flip the
|
|
998
1061
|
// model provider on when a model key actually exists; otherwise usage-only
|
|
999
1062
|
// setups get routed to the provider with apiKey 'no-key' and fail with 401s.
|
|
@@ -1001,7 +1064,7 @@ export function saveOpenCodeGoUsageAuth(cfgMod, { apiKey } = {}) {
|
|
|
1001
1064
|
return { provider: 'opencode-go', type: 'usage-auth', authenticated: true };
|
|
1002
1065
|
}
|
|
1003
1066
|
|
|
1004
|
-
export function forgetProviderAuth(cfgModOrProvider, maybeProvider, requestedAccountId) {
|
|
1067
|
+
export async function forgetProviderAuth(cfgModOrProvider, maybeProvider, requestedAccountId) {
|
|
1005
1068
|
const cfgMod = maybeProvider === undefined ? null : cfgModOrProvider;
|
|
1006
1069
|
const id = String(maybeProvider === undefined ? cfgModOrProvider : maybeProvider || '').trim();
|
|
1007
1070
|
const oauth = availableOAuthProvider(id);
|
|
@@ -1022,7 +1085,7 @@ export function forgetProviderAuth(cfgModOrProvider, maybeProvider, requestedAcc
|
|
|
1022
1085
|
if (!API_PROVIDER_IDS.has(id)) {
|
|
1023
1086
|
throw new Error(`unknown provider "${id}"`);
|
|
1024
1087
|
}
|
|
1025
|
-
|
|
1088
|
+
await deleteSecretAsync(SECRET_ACCOUNTS.agentApiKey(id));
|
|
1026
1089
|
if (cfgMod) updateConfigProvider(cfgMod, id, { enabled: false });
|
|
1027
1090
|
return { provider: id, type: 'api-key', forgotten: true };
|
|
1028
1091
|
}
|
|
@@ -59,16 +59,13 @@ function cleanupRetiredChannelSecrets(dataDir) {
|
|
|
59
59
|
const marker = join(dataDir, '.retired-channel-secrets-cleaned');
|
|
60
60
|
if (existsSync(marker)) return;
|
|
61
61
|
void import('../../runtime/shared/config.mjs')
|
|
62
|
-
.then(({
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
deleteSecret('telegram.token');
|
|
70
|
-
} catch {
|
|
71
|
-
/* best-effort */
|
|
62
|
+
.then(async ({ deleteSecretAsync }) => {
|
|
63
|
+
for (const account of ['discord.token', 'telegram.token']) {
|
|
64
|
+
try {
|
|
65
|
+
await deleteSecretAsync(account);
|
|
66
|
+
} catch {
|
|
67
|
+
/* best-effort */
|
|
68
|
+
}
|
|
72
69
|
}
|
|
73
70
|
try {
|
|
74
71
|
writeFileSync(marker, `${new Date().toISOString()}\n`);
|
|
@@ -234,6 +234,10 @@ function providerDescription(id, group) {
|
|
|
234
234
|
return 'Anthropic OAuth subscription quota';
|
|
235
235
|
case 'grok-oauth':
|
|
236
236
|
return 'Grok Build subscription quota';
|
|
237
|
+
case 'muse-code-oauth':
|
|
238
|
+
return 'Muse Code subscription quota';
|
|
239
|
+
case 'mimo-oauth':
|
|
240
|
+
return 'MiMo Token Plan subscription quota';
|
|
237
241
|
case 'antigravity-oauth':
|
|
238
242
|
return 'Antigravity subscription quota';
|
|
239
243
|
case 'opencode-go':
|
|
@@ -338,6 +342,8 @@ const PROVIDER_RANKS = {
|
|
|
338
342
|
'openai-oauth': 10,
|
|
339
343
|
'anthropic-oauth': 20,
|
|
340
344
|
'grok-oauth': 30,
|
|
345
|
+
'muse-code-oauth': 33,
|
|
346
|
+
'mimo-oauth': 34,
|
|
341
347
|
'cursor-oauth': 35,
|
|
342
348
|
'antigravity-oauth': 36,
|
|
343
349
|
'opencode-go': 40,
|
|
@@ -8,6 +8,10 @@ import {
|
|
|
8
8
|
setBuiltinInstalledInConfig,
|
|
9
9
|
} from '../runtime/agent/orchestrator/runtime-core/builtin-features.mjs';
|
|
10
10
|
import { LOCAL_PROVIDER_ID } from '../runtime/local-provider/managed-runtime.mjs';
|
|
11
|
+
import {
|
|
12
|
+
INSTRUCTION_FILES_MODES,
|
|
13
|
+
normalizeInstructionFilesMode,
|
|
14
|
+
} from '../runtime/shared/instruction-files-mode.mjs';
|
|
11
15
|
import { getEmbeddingInfo } from '../runtime/memory/lib/embedding-provider.mjs';
|
|
12
16
|
import { onnxRuntimeSupported } from '../runtime/shared/onnx-runtime-support.mjs';
|
|
13
17
|
import {
|
|
@@ -79,6 +83,7 @@ export function createBuiltinToolSettings(
|
|
|
79
83
|
const localProvider = getLocalProviderStatus?.() || {};
|
|
80
84
|
const localProviderRuntimeInstalled = localProvider?.runtime?.installed === true;
|
|
81
85
|
return {
|
|
86
|
+
instructionFiles: normalizeInstructionFilesMode(config?.instructionFiles),
|
|
82
87
|
webSearch: { enabled: webSearchEnabled() },
|
|
83
88
|
memory: {
|
|
84
89
|
enabled: memoryToolsEnabledFn(),
|
|
@@ -118,6 +123,16 @@ export function createBuiltinToolSettings(
|
|
|
118
123
|
await refreshEmptySessionToolPolicy?.();
|
|
119
124
|
return this.getToolModuleSettings();
|
|
120
125
|
},
|
|
126
|
+
/** Which user instruction files (AGENTS.md / CLAUDE.md) new sessions load:
|
|
127
|
+
* 'all' | 'agents' | 'claude' | 'off'. The empty session rebuilds now. */
|
|
128
|
+
async setInstructionFiles(mode) {
|
|
129
|
+
if (!INSTRUCTION_FILES_MODES.includes(mode)) {
|
|
130
|
+
throw new TypeError(`Instruction files must be one of ${INSTRUCTION_FILES_MODES.join(', ')}.`);
|
|
131
|
+
}
|
|
132
|
+
saveConfigAndAdopt({ ...getConfig(), instructionFiles: mode });
|
|
133
|
+
await refreshEmptySessionToolPolicy?.();
|
|
134
|
+
return this.getToolModuleSettings();
|
|
135
|
+
},
|
|
121
136
|
async setMemoryToolsEnabled(enabled) {
|
|
122
137
|
const config = getConfig();
|
|
123
138
|
const memoryEnabled = enabled !== false;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
// Onboarding, the user profile (/profile) and the disabled-skill list. Methods
|
|
2
2
|
// reference `this.*` so cross-member calls resolve against the facade object
|
|
3
3
|
// these are spread into.
|
|
4
|
+
import {
|
|
5
|
+
mergeStarterGuide,
|
|
6
|
+
requiredStarterGuideState,
|
|
7
|
+
storedStarterGuide,
|
|
8
|
+
withStarterGuideOnCompletion,
|
|
9
|
+
} from './starter-guide-state.mjs';
|
|
10
|
+
|
|
4
11
|
export function createProfileSettings({
|
|
5
12
|
getConfig,
|
|
6
13
|
adoptConfig,
|
|
@@ -19,21 +26,39 @@ export function createProfileSettings({
|
|
|
19
26
|
version: nextConfig?.onboarding?.version || 0,
|
|
20
27
|
default: nextConfig?.default || null,
|
|
21
28
|
workflowRoutes: summarizeWorkflowRoutes(nextConfig),
|
|
29
|
+
starterGuide: storedStarterGuide(nextConfig?.onboarding?.starterGuide),
|
|
22
30
|
};
|
|
23
31
|
},
|
|
32
|
+
// Persist the desktop "Getting started" guide state beside the onboarding
|
|
33
|
+
// flags so it survives a lost renderer localStorage. Malformed input is
|
|
34
|
+
// rejected; a valid save merges forward, so a stale one cannot reopen a
|
|
35
|
+
// closed guide or forget a visited step.
|
|
36
|
+
saveStarterGuideState(state) {
|
|
37
|
+
const next = requiredStarterGuideState(state);
|
|
38
|
+
const config = getConfig();
|
|
39
|
+
const onboarding = config.onboarding || {};
|
|
40
|
+
saveConfigAndAdopt({
|
|
41
|
+
...config,
|
|
42
|
+
onboarding: {
|
|
43
|
+
...onboarding,
|
|
44
|
+
starterGuide: mergeStarterGuide(storedStarterGuide(onboarding.starterGuide), next),
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
return this.getOnboardingStatus();
|
|
48
|
+
},
|
|
24
49
|
// Mark onboarding as done WITHOUT touching routes/agents/provider. Used by
|
|
25
50
|
// the TUI "skip" (Esc) path so the wizard doesn't reappear next launch,
|
|
26
51
|
// while leaving any existing config routes untouched.
|
|
27
52
|
skipOnboarding() {
|
|
28
53
|
const config = getConfig();
|
|
29
54
|
const nextConfig = { ...config };
|
|
30
|
-
nextConfig.onboarding = {
|
|
55
|
+
nextConfig.onboarding = withStarterGuideOnCompletion(config.onboarding, {
|
|
31
56
|
...(nextConfig.onboarding || {}),
|
|
32
57
|
completed: true,
|
|
33
58
|
version: ONBOARDING_VERSION,
|
|
34
59
|
completedAt: new Date().toISOString(),
|
|
35
60
|
skipped: true,
|
|
36
|
-
};
|
|
61
|
+
});
|
|
37
62
|
saveConfigAndAdopt(nextConfig);
|
|
38
63
|
return this.getOnboardingStatus();
|
|
39
64
|
},
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* registers the tool executor before it finishes assembling the API object. */
|
|
6
6
|
import { builtinFeatureActive } from '../../runtime/agent/orchestrator/runtime-core/builtin-features.mjs';
|
|
7
7
|
import { ORCHESTRATION_MODES } from '../../runtime/shared/orchestration.mjs';
|
|
8
|
+
import { INSTRUCTION_FILES_MODES } from '../../runtime/shared/instruction-files-mode.mjs';
|
|
8
9
|
import { MEDIA_KINDS } from '../../runtime/media/tool-defs.mjs';
|
|
9
10
|
import { SETUP_DESKTOP_DOMAINS, SETUP_HANDOFFS } from './settings-contract.mjs';
|
|
10
11
|
import { executeExtendedSetupAction, publicAutomation, publicHookRule, validateMcpInput } from './extended-actions.mjs';
|
|
@@ -205,6 +206,8 @@ async function featureStatus(rt, getConfig) {
|
|
|
205
206
|
return {
|
|
206
207
|
...Object.fromEntries(
|
|
207
208
|
Object.entries(rt.getToolModuleSettings?.() || {}).map(([name, settings]) => {
|
|
209
|
+
// Scalar settings (instructionFiles mode) pass through as-is.
|
|
210
|
+
if (!settings || typeof settings !== 'object') return [name, settings];
|
|
208
211
|
const keys = [...FEATURE_STATUS_KEYS, ...(FEATURE_EXTRA_STATUS_KEYS[name] || [])];
|
|
209
212
|
return [name, Object.fromEntries(Object.entries(settings).filter(([key]) => keys.includes(key)))];
|
|
210
213
|
})
|
|
@@ -448,6 +451,8 @@ const SETUP_ACTION_HANDLERS = {
|
|
|
448
451
|
set_memory_enabled: (rt, args) => rt.setMemoryToolsEnabled(requireBoolean(args.enabled)),
|
|
449
452
|
set_recap_enabled: (rt, args) => rt.setRecapEnabled(requireBoolean(args.enabled)),
|
|
450
453
|
set_web_search_enabled: (rt, args) => rt.setWebSearchEnabled(requireBoolean(args.enabled)),
|
|
454
|
+
set_instruction_files: (rt, args) =>
|
|
455
|
+
rt.setInstructionFiles(requireEnum(args.instructionFiles, INSTRUCTION_FILES_MODES, 'instructionFiles')),
|
|
451
456
|
set_builtin_enabled: (rt, args, { requestDesktop }) => {
|
|
452
457
|
const name = requireEnum(args.name, SETUP_BUILTIN_TOGGLE_FEATURES, 'name');
|
|
453
458
|
if (DESKTOP_HOSTED_FEATURES.includes(name)) return requestDesktop(args);
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
SETUP_MCP_SCHEMA,
|
|
6
6
|
} from './settings-contract.mjs';
|
|
7
7
|
import { MEDIA_KINDS } from '../../runtime/media/tool-defs.mjs';
|
|
8
|
+
import { INSTRUCTION_FILES_MODES } from '../../runtime/shared/instruction-files-mode.mjs';
|
|
8
9
|
|
|
9
10
|
/** Built-in `setup` tool: the model's handle on a Mixdog user's persisted
|
|
10
11
|
* configuration. The description is a contract only; how to use each action
|
|
@@ -78,6 +79,7 @@ export const SETUP_ACTION_FIELDS = Object.freeze({
|
|
|
78
79
|
set_memory_enabled: 'enabled',
|
|
79
80
|
set_recap_enabled: 'enabled',
|
|
80
81
|
set_web_search_enabled: 'enabled',
|
|
82
|
+
set_instruction_files: 'instructionFiles',
|
|
81
83
|
set_builtin_enabled: 'name enabled',
|
|
82
84
|
install_builtin: 'name',
|
|
83
85
|
install_local_model: 'modelId',
|
|
@@ -212,6 +214,12 @@ export const SETUP_TOOL_DEFS = Object.freeze([
|
|
|
212
214
|
description:
|
|
213
215
|
'Boolean setters (set_*_enabled, set_compaction, set_auto_update, set_mcp_enabled, set_plugin_enabled).',
|
|
214
216
|
},
|
|
217
|
+
instructionFiles: {
|
|
218
|
+
type: 'string',
|
|
219
|
+
enum: [...INSTRUCTION_FILES_MODES],
|
|
220
|
+
description:
|
|
221
|
+
'set_instruction_files: which user instruction files new sessions load (global ~/.codex/AGENTS.md, ~/.claude/CLAUDE.md, then the Project root\'s AGENTS.md/CLAUDE.md).',
|
|
222
|
+
},
|
|
215
223
|
name: {
|
|
216
224
|
type: 'string',
|
|
217
225
|
description: `set_builtin_enabled: ${SETUP_BUILTIN_TOGGLE_FEATURES.join('|')}; install_builtin also accepts memory. Memory toggles use set_memory_enabled. revoke_linked_device: client id from status connection, not its display name; set_developer_option: option id from status developer; read_definition/delete_definition: the definition id; else MCP/plugin/provider id.`,
|