mixdog 1.2.0 → 1.2.1
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 +7 -5
- package/package.json +1 -1
- package/src/defaults/shipped-history.json +4 -0
- package/src/defaults/skills/pptx/SKILL.md +6 -6
- package/src/defaults/skills/pptx/references/review.md +6 -4
- package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
- package/src/defaults/skills/setup/references/actions.md +13 -3
- package/src/defaults/skills/visualize/SKILL.md +12 -9
- package/src/rules/shared/60-verification.md +3 -1
- package/src/rules/shared/70-delivery.md +4 -2
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
- package/src/runtime/agent/orchestrator/config.mjs +10 -4
- package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +86 -8
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +5 -1
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +65 -7
- package/src/runtime/agent/orchestrator/mcp/client.mjs +128 -44
- package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
- package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +108 -17
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +19 -11
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +444 -0
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +41 -28
- package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +15 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +35 -0
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +9 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/registry.mjs +35 -9
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
- package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +267 -84
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +268 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
- package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +6 -4
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +20 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +17 -4
- package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +817 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +19 -12
- package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +183 -374
- package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +21 -2
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +38 -17
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +173 -22
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +15 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
- package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
- package/src/runtime/attachments/store.d.mts +3 -0
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
- package/src/runtime/channels/lib/worker-main.mjs +17 -14
- package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
- package/src/runtime/effort-judge/judge-client.mjs +56 -18
- package/src/runtime/memory/lib/memory.mjs +1 -1
- package/src/runtime/memory/lib/session-ingest.mjs +2 -2
- package/src/runtime/shared/atomic-file.mjs +25 -4
- package/src/runtime/shared/extension-scopes.mjs +5 -3
- package/src/runtime/shared/file-lock.mjs +37 -11
- package/src/runtime/shared/llm/anthropic-effort.mjs +14 -0
- package/src/runtime/shared/llm/model-catalog.mjs +0 -12
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +6 -0
- package/src/runtime/shared/plugin-manifest.mjs +18 -9
- package/src/runtime/shared/pristine-execution-contract.json +9 -2
- package/src/runtime/shared/pristine-execution.mjs +28 -4
- package/src/runtime/shared/provider-accounts.mjs +124 -20
- package/src/runtime/shared/provider-api-key.mjs +12 -0
- package/src/runtime/shared/shell-display.mjs +9 -3
- package/src/runtime/shared/skill-mentions.d.mts +10 -0
- package/src/runtime/shared/skill-mentions.mjs +133 -0
- package/src/runtime/shared/skill-script-runtime.mjs +264 -0
- package/src/runtime/shared/tool-primitives.mjs +35 -2
- package/src/runtime/shared/turn-worktree-snapshot.mjs +25 -5
- package/src/runtime/shared/worker-requests.mjs +15 -2
- package/src/session-runtime/automation-agents.mjs +8 -2
- package/src/session-runtime/boot/apis.mjs +55 -0
- package/src/session-runtime/boot/config.mjs +5 -2
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +29 -18
- package/src/session-runtime/conversation-import/discovery.mjs +698 -0
- package/src/session-runtime/conversation-import/service.mjs +369 -0
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +10 -5
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
- package/src/session-runtime/mcp-glue/connect.mjs +57 -10
- package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +115 -30
- package/src/session-runtime/mcp-glue.mjs +22 -2
- package/src/session-runtime/new-session-config.mjs +3 -2
- package/src/session-runtime/notification-bus.mjs +9 -2
- package/src/session-runtime/provider-auth/accounts.mjs +33 -15
- package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
- package/src/session-runtime/provider-readiness.mjs +16 -10
- package/src/session-runtime/resource-extension-sync.mjs +20 -5
- package/src/session-runtime/resource-mcp-api.mjs +101 -77
- package/src/session-runtime/resource-plugins-api.mjs +29 -41
- package/src/session-runtime/resource-scope-decorate.mjs +6 -8
- package/src/session-runtime/resource-skills-api.mjs +23 -2
- package/src/session-runtime/schedule-session-run.mjs +1 -1
- package/src/session-runtime/services/channel-session-router.mjs +4 -1
- package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
- package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
- package/src/session-runtime/services/provider-admin.mjs +64 -18
- package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
- package/src/session-runtime/setup-tool/executor.mjs +12 -1
- package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +1 -0
- package/src/session-runtime/setup-tool/tool-defs.mjs +7 -1
- package/src/session-runtime/skills-api.mjs +7 -3
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/webhook-session-run.mjs +16 -4
- package/src/skill-script-entry.mjs +36 -0
- package/src/standalone/daemon-stored-session-views.mjs +11 -3
- package/src/standalone/daemon.mjs +41 -4
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +6 -1
- package/src/tui/App.jsx +9 -1
- package/src/tui/app/app-view/floating-panel.jsx +9 -1
- package/src/tui/app/app-view.jsx +6 -0
- package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
- package/src/tui/app/model-options.mjs +2 -0
- package/src/tui/app/skill-mention-palette.mjs +88 -0
- package/src/tui/app/slash-palette.mjs +23 -7
- package/src/tui/app/transcript-row-estimate.mjs +11 -3
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
- package/src/tui/app/use-prompt-state.mjs +5 -0
- package/src/tui/components/Message.jsx +22 -1
- package/src/tui/components/PromptInput.jsx +21 -3
- package/src/tui/components/SlashCommandPalette.jsx +12 -3
- package/src/tui/components/TranscriptItem.jsx +9 -1
- package/src/tui/components/prompt-input/key-handler.mjs +21 -8
- package/src/tui/components/user-message-skills.mjs +38 -0
- package/src/tui/dist/index.mjs +507 -171
- package/src/tui/session/queue-helpers.mjs +7 -2
- package/src/tui/session/session-api/extensions.mjs +4 -2
- package/src/tui/session/session-api/settings.mjs +7 -0
- package/src/tui/session/session-flow/drain.mjs +14 -4
- package/src/tui/session/tui-steering-persist.mjs +25 -9
- package/src/tui/session/turn.mjs +17 -0
- package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
- package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
|
@@ -54,6 +54,15 @@ import {
|
|
|
54
54
|
beginOAuthLogin as beginMuseCodeOAuthLogin,
|
|
55
55
|
loginOAuth as loginMuseCodeOAuth,
|
|
56
56
|
} from '../../runtime/agent/orchestrator/providers/muse-code-oauth-login.mjs';
|
|
57
|
+
import {
|
|
58
|
+
describeCommandCodeOAuthCredentials,
|
|
59
|
+
forgetCommandCodeOAuthCredentials,
|
|
60
|
+
hasCommandCodeOAuthCredentials,
|
|
61
|
+
} from '../../runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs';
|
|
62
|
+
import {
|
|
63
|
+
beginOAuthLogin as beginCommandCodeOAuthLogin,
|
|
64
|
+
loginOAuth as loginCommandCodeOAuth,
|
|
65
|
+
} from '../../runtime/agent/orchestrator/providers/command-code-oauth-login.mjs';
|
|
57
66
|
import {
|
|
58
67
|
beginCursorOAuthLogin,
|
|
59
68
|
describeCursorOAuthCredentials,
|
|
@@ -80,6 +89,7 @@ import {
|
|
|
80
89
|
changeProviderAccounts,
|
|
81
90
|
removeProviderAccount,
|
|
82
91
|
clearProviderAccountQuotaState,
|
|
92
|
+
providerAccountLimit,
|
|
83
93
|
ACCOUNT_PROVIDERS,
|
|
84
94
|
} from '../../runtime/shared/provider-accounts.mjs';
|
|
85
95
|
import { currentProviderAccountId, withProviderAccount } from '../../runtime/shared/provider-auth-binding.mjs';
|
|
@@ -154,6 +164,16 @@ const OAUTH_PROVIDERS = Object.freeze([
|
|
|
154
164
|
begin: beginMuseCodeOAuthLogin,
|
|
155
165
|
login: loginMuseCodeOAuth,
|
|
156
166
|
}),
|
|
167
|
+
Object.freeze({
|
|
168
|
+
id: 'command-code-oauth',
|
|
169
|
+
name: 'Command Code',
|
|
170
|
+
desc: 'Sign in with your Command Code account',
|
|
171
|
+
has: hasCommandCodeOAuthCredentials,
|
|
172
|
+
describe: describeCommandCodeOAuthCredentials,
|
|
173
|
+
forget: forgetCommandCodeOAuthCredentials,
|
|
174
|
+
begin: beginCommandCodeOAuthLogin,
|
|
175
|
+
login: loginCommandCodeOAuth,
|
|
176
|
+
}),
|
|
157
177
|
Object.freeze({
|
|
158
178
|
id: 'mimo-oauth',
|
|
159
179
|
name: 'MiMo',
|
|
@@ -421,6 +441,12 @@ function customProviderRow(id, entry, checkSecrets = true) {
|
|
|
421
441
|
const keyless = (config?.auth ?? entry.auth) === 'none';
|
|
422
442
|
const stored = checkSecrets ? hasStoredSecret(SECRET_ACCOUNTS.agentApiKey(id)) : false;
|
|
423
443
|
const unstoredStatus = configuredEnabled ? 'No Key' : 'Off';
|
|
444
|
+
let status = stored ? 'Set' : unstoredStatus;
|
|
445
|
+
let detail = stored ? 'stored in keychain' : 'custom endpoint';
|
|
446
|
+
if (keyless) {
|
|
447
|
+
status = configuredEnabled ? 'Keyless' : 'Off';
|
|
448
|
+
detail = 'no API key required';
|
|
449
|
+
}
|
|
424
450
|
const row = {
|
|
425
451
|
id,
|
|
426
452
|
name: entry.name,
|
|
@@ -431,12 +457,12 @@ function customProviderRow(id, entry, checkSecrets = true) {
|
|
|
431
457
|
group: 'api',
|
|
432
458
|
type: 'api-key',
|
|
433
459
|
enabled: configuredEnabled,
|
|
434
|
-
authenticated: keyless
|
|
460
|
+
authenticated: keyless || (checkSecrets ? stored : configuredEnabled),
|
|
435
461
|
stored,
|
|
436
462
|
env: false,
|
|
437
463
|
envName: null,
|
|
438
|
-
status
|
|
439
|
-
detail
|
|
464
|
+
status,
|
|
465
|
+
detail,
|
|
440
466
|
};
|
|
441
467
|
row.schemaVersion = config?.schemaVersion ?? entry.schemaVersion;
|
|
442
468
|
row.auth = keyless ? 'none' : 'key';
|
|
@@ -584,7 +610,7 @@ export async function loginOAuthProvider(cfgMod, provider) {
|
|
|
584
610
|
updateConfigProvider(cfgMod, id, { enabled: true });
|
|
585
611
|
// Same reason as the interactive add-account flow: a fresh credential says
|
|
586
612
|
// nothing about the quota the previous one exhausted.
|
|
587
|
-
if (ACCOUNT_PROVIDERS.includes(id)) clearProviderAccountQuotaState(id, currentProviderAccountId(id));
|
|
613
|
+
if (ACCOUNT_PROVIDERS.includes(id)) await clearProviderAccountQuotaState(id, currentProviderAccountId(id));
|
|
588
614
|
}
|
|
589
615
|
return { provider: id, type: 'oauth', authenticated: Boolean(auth.authenticated), status: auth.status || null };
|
|
590
616
|
}
|
|
@@ -621,7 +647,7 @@ function rosterAccountForIdentity(id, oauth, newAccountId, auth) {
|
|
|
621
647
|
return match?.id || null;
|
|
622
648
|
}
|
|
623
649
|
|
|
624
|
-
function settleOAuthLogin(
|
|
650
|
+
async function settleOAuthLogin(
|
|
625
651
|
{ cfgMod, id, accountId: signedInId, addAccount, includeDefault, label, inAccount, oauth },
|
|
626
652
|
result
|
|
627
653
|
) {
|
|
@@ -635,11 +661,11 @@ function settleOAuthLogin(
|
|
|
635
661
|
renameSync(providerAccountPath(id, signedInId), providerAccountPath(id, existingId));
|
|
636
662
|
accountId = existingId;
|
|
637
663
|
}
|
|
638
|
-
registerProviderAccount(id, accountId, { includeDefault, label });
|
|
664
|
+
await registerProviderAccount(id, accountId, { includeDefault, label });
|
|
639
665
|
// A re-connect can follow a re-created subscription under the same
|
|
640
666
|
// account id: start it from no recorded quota rather than from the
|
|
641
667
|
// exhausted window the previous credential earned.
|
|
642
|
-
clearProviderAccountQuotaState(id, accountId);
|
|
668
|
+
await clearProviderAccountQuotaState(id, accountId);
|
|
643
669
|
updateConfigProvider(cfgMod, id, { enabled: true });
|
|
644
670
|
}
|
|
645
671
|
return {
|
|
@@ -688,12 +714,20 @@ export async function beginOAuthProviderLogin(cfgMod, provider, options = {}) {
|
|
|
688
714
|
// The callback and a pasted code can both deliver the same sign-in; it must
|
|
689
715
|
// settle once, because settling may move the credential to an existing id.
|
|
690
716
|
let settled = null;
|
|
717
|
+
let settling = null;
|
|
691
718
|
const finish = async (result) => {
|
|
692
719
|
if (!result || cancelled) return null;
|
|
693
720
|
if (settled) return settled;
|
|
694
|
-
|
|
695
|
-
if (
|
|
696
|
-
|
|
721
|
+
// Settling is async now: a second delivery arriving mid-write shares it.
|
|
722
|
+
if (settling) return settling;
|
|
723
|
+
settling = settleOAuthLogin(login, result);
|
|
724
|
+
try {
|
|
725
|
+
const outcome = await settling;
|
|
726
|
+
if (outcome.authenticated) settled = outcome;
|
|
727
|
+
return outcome;
|
|
728
|
+
} finally {
|
|
729
|
+
settling = null;
|
|
730
|
+
}
|
|
697
731
|
};
|
|
698
732
|
return {
|
|
699
733
|
provider: id,
|
|
@@ -721,9 +755,11 @@ export function listProviderAccounts(provider) {
|
|
|
721
755
|
if (!oauth) throw new TypeError('Unknown OAuth provider.');
|
|
722
756
|
const pool = readProviderAccountPool(provider);
|
|
723
757
|
const accounts = pool.accounts.length ? pool.accounts : defaultAccountRows(provider, oauth);
|
|
758
|
+
const now = Date.now();
|
|
724
759
|
return {
|
|
725
760
|
provider,
|
|
726
761
|
auto: pool.auto !== false,
|
|
762
|
+
policy: pool.policy,
|
|
727
763
|
useCredits: pool.useCredits === true,
|
|
728
764
|
selectedId: pool.selectedId || accounts[0]?.id || null,
|
|
729
765
|
accounts: accounts.map((row) => {
|
|
@@ -740,6 +776,9 @@ export function listProviderAccounts(provider) {
|
|
|
740
776
|
reauthRequired: auth.reauthRequired === true,
|
|
741
777
|
usage: row.usage || null,
|
|
742
778
|
blockedUntil: row.blockedUntil || null,
|
|
779
|
+
// The limit holding the account now: account-wide, or only for one
|
|
780
|
+
// model family ("7D Fable") while other models still run.
|
|
781
|
+
limit: providerAccountLimit(row, now, { useCredits: pool.useCredits === true }),
|
|
743
782
|
...(identity ? { identity } : {}),
|
|
744
783
|
...(typeof auth.email === 'string' && auth.email.trim() ? { email: auth.email.trim() } : {}),
|
|
745
784
|
};
|
|
@@ -753,17 +792,23 @@ function defaultAccountRows(provider, oauth) {
|
|
|
753
792
|
return authenticated ? [{ id: 'default', label: 'Account 1' }] : [];
|
|
754
793
|
}
|
|
755
794
|
|
|
756
|
-
|
|
795
|
+
// Store the implicit signed-in `default` account in the roster, so a change or
|
|
796
|
+
// a usage measurement has a row to land on. Returns the current roster view.
|
|
797
|
+
export async function materializeProviderAccounts(provider) {
|
|
757
798
|
const current = listProviderAccounts(provider);
|
|
758
|
-
if (
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
799
|
+
if (readProviderAccountPool(provider).accounts.length || !current.accounts.length) return current;
|
|
800
|
+
await registerProviderAccount(provider, 'default', { label: 'Account 1' });
|
|
801
|
+
return listProviderAccounts(provider);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
export async function updateProviderAccounts(provider, change) {
|
|
805
|
+
await materializeProviderAccounts(provider);
|
|
806
|
+
await changeProviderAccounts(provider, change);
|
|
762
807
|
// Picking an account by hand is a decision to use it NOW, so the refusal
|
|
763
808
|
// window and meter stored against it — both describing the state the user
|
|
764
809
|
// just changed — are dropped here. Never in the pool's own fallback commit,
|
|
765
810
|
// where clearing them would send the request back to a spent account.
|
|
766
|
-
if (change?.selectedId !== undefined) clearProviderAccountQuotaState(provider, change.selectedId);
|
|
811
|
+
if (change?.selectedId !== undefined) await clearProviderAccountQuotaState(provider, change.selectedId);
|
|
767
812
|
return listProviderAccounts(provider);
|
|
768
813
|
}
|
|
769
814
|
|
|
@@ -859,7 +904,8 @@ async function resolveCustomInput(cfgMod, rawInput, options) {
|
|
|
859
904
|
const config = normalizeCustomProviderConfig(input, options);
|
|
860
905
|
const typed = typeof input.apiKey === 'string' ? input.apiKey.trim() : '';
|
|
861
906
|
const keyless = config.auth === 'none';
|
|
862
|
-
|
|
907
|
+
let apiKey = '';
|
|
908
|
+
if (!keyless) apiKey = typed || (id ? getAgentApiKey(id) || '' : '');
|
|
863
909
|
return { id, config, typed: keyless ? '' : typed, apiKey, keyless };
|
|
864
910
|
}
|
|
865
911
|
|
|
@@ -1078,7 +1124,7 @@ export async function forgetProviderAuth(cfgModOrProvider, maybeProvider, reques
|
|
|
1078
1124
|
throw new TypeError('Account is no longer connected.');
|
|
1079
1125
|
}
|
|
1080
1126
|
const result = withProviderAccount(id, accountId, () => oauth.forget());
|
|
1081
|
-
const pool = removeProviderAccount(id, accountId);
|
|
1127
|
+
const pool = await removeProviderAccount(id, accountId);
|
|
1082
1128
|
if (cfgMod) updateConfigProvider(cfgMod, id, { enabled: pool.accounts.length > 0 });
|
|
1083
1129
|
return { provider: id, type: 'oauth', forgotten: true, removed: Boolean(result?.removed) };
|
|
1084
1130
|
}
|
|
@@ -236,6 +236,8 @@ function providerDescription(id, group) {
|
|
|
236
236
|
return 'Grok Build subscription quota';
|
|
237
237
|
case 'muse-code-oauth':
|
|
238
238
|
return 'Muse Code subscription quota';
|
|
239
|
+
case 'command-code-oauth':
|
|
240
|
+
return 'Command Code subscription quota';
|
|
239
241
|
case 'mimo-oauth':
|
|
240
242
|
return 'MiMo Token Plan subscription quota';
|
|
241
243
|
case 'antigravity-oauth':
|
|
@@ -343,6 +345,7 @@ const PROVIDER_RANKS = {
|
|
|
343
345
|
'anthropic-oauth': 20,
|
|
344
346
|
'grok-oauth': 30,
|
|
345
347
|
'muse-code-oauth': 33,
|
|
348
|
+
'command-code-oauth': 33.5,
|
|
346
349
|
'mimo-oauth': 34,
|
|
347
350
|
'cursor-oauth': 35,
|
|
348
351
|
'antigravity-oauth': 36,
|
|
@@ -146,6 +146,7 @@ function publicAccounts(pool) {
|
|
|
146
146
|
return {
|
|
147
147
|
selectedId: pool.selectedId,
|
|
148
148
|
auto: pool.auto,
|
|
149
|
+
...(pool.policy ? { policy: pool.policy } : {}),
|
|
149
150
|
useCredits: pool.useCredits === true,
|
|
150
151
|
accounts: pool.accounts.map(({ id, label, authenticated, reauthRequired }) => ({
|
|
151
152
|
id,
|
|
@@ -166,9 +167,15 @@ function mcpRows(status) {
|
|
|
166
167
|
transport: server.transport || server.type || '',
|
|
167
168
|
toolCount: Number(server.toolCount || 0),
|
|
168
169
|
source: server.source || '',
|
|
170
|
+
...(server.owner?.kind === 'plugin'
|
|
171
|
+
? { plugin: server.owner.id, pluginServer: server.owner.key, disabledReason: server.disabledReason || null }
|
|
172
|
+
: {}),
|
|
169
173
|
error: server.error || null,
|
|
174
|
+
...(server.warnings?.length ? { warnings: server.warnings } : {}),
|
|
170
175
|
scope: Array.isArray(server.scope) ? server.scope : null,
|
|
171
176
|
})),
|
|
177
|
+
...(status?.warnings?.length ? { warnings: status.warnings } : {}),
|
|
178
|
+
...(status?.declarationErrors?.length ? { declarationErrors: status.declarationErrors } : {}),
|
|
172
179
|
};
|
|
173
180
|
}
|
|
174
181
|
|
|
@@ -577,7 +584,11 @@ const SETUP_ACTION_HANDLERS = {
|
|
|
577
584
|
const plugin = ((await rt.pluginsStatus())?.plugins || []).find((row) => row.name === name || row.id === name);
|
|
578
585
|
if (!plugin) throw new Error(`plugin "${name}" not found`);
|
|
579
586
|
const result = await rt.enablePluginMcp(plugin);
|
|
580
|
-
return {
|
|
587
|
+
return {
|
|
588
|
+
serverName: result.serverName,
|
|
589
|
+
...(result.serverNames ? { serverNames: result.serverNames } : {}),
|
|
590
|
+
mcp: mcpRows(result.status),
|
|
591
|
+
};
|
|
581
592
|
},
|
|
582
593
|
};
|
|
583
594
|
|
|
@@ -34,6 +34,7 @@ function publicMcpConfig(row) {
|
|
|
34
34
|
return {
|
|
35
35
|
name: row.name,
|
|
36
36
|
source: row.source,
|
|
37
|
+
...(row.owner?.kind === 'plugin' ? { plugin: row.owner.id, pluginServer: row.owner.key, readOnly: true } : {}),
|
|
37
38
|
enabled: row.enabled !== false,
|
|
38
39
|
type: config.type || 'stdio',
|
|
39
40
|
cwd: config.cwd || '',
|
|
@@ -196,6 +196,7 @@ export const SETUP_EXTENDED_PROPERTIES = Object.freeze({
|
|
|
196
196
|
runInBackground: boolean,
|
|
197
197
|
turnNotifications: boolean,
|
|
198
198
|
usagePinned: boolean,
|
|
199
|
+
usageRailShortLong: boolean,
|
|
199
200
|
computerObserveOnly: boolean,
|
|
200
201
|
notificationVolume: {
|
|
201
202
|
type: 'integer',
|
|
@@ -227,7 +227,7 @@ export const SETUP_TOOL_DEFS = Object.freeze([
|
|
|
227
227
|
type: 'string',
|
|
228
228
|
enum: [...INSTRUCTION_FILES_MODES],
|
|
229
229
|
description:
|
|
230
|
-
|
|
230
|
+
"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).",
|
|
231
231
|
},
|
|
232
232
|
name: {
|
|
233
233
|
type: 'string',
|
|
@@ -244,6 +244,12 @@ export const SETUP_TOOL_DEFS = Object.freeze([
|
|
|
244
244
|
properties: {
|
|
245
245
|
selectedId: { type: 'string', description: 'Account to use now.' },
|
|
246
246
|
auto: { type: 'boolean', description: 'Automatic switching to another account when one is exhausted.' },
|
|
247
|
+
policy: {
|
|
248
|
+
type: 'string',
|
|
249
|
+
enum: ['manual', 'limit', 'headroom'],
|
|
250
|
+
description:
|
|
251
|
+
'Account switching: manual = selected account only; limit = switch when it reaches a limit; headroom = each new session starts on the account with the most headroom.',
|
|
252
|
+
},
|
|
247
253
|
useCredits: { type: 'boolean', description: 'Allow paid credits once plan limits are reached.' },
|
|
248
254
|
order: {
|
|
249
255
|
type: 'array',
|
|
@@ -24,8 +24,8 @@ const DEFAULT_SKILL_BODY = '# Instructions\n\nDescribe how to use this skill.';
|
|
|
24
24
|
export function createSkillsApi({ contextMod, getCwd, getTools = () => [] }) {
|
|
25
25
|
const globalSkillsRoot = () => resolve(resolvePluginData(), 'skills');
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
/** `cwd` overrides the session's folder (already validated by the caller). */
|
|
28
|
+
function skillsStatus({ cwd = getCwd() } = {}) {
|
|
29
29
|
const skills = typeof contextMod.collectSkillsCached === 'function' ? contextMod.collectSkillsCached(cwd) : [];
|
|
30
30
|
const norm = (value) =>
|
|
31
31
|
String(value || '')
|
|
@@ -54,7 +54,10 @@ export function createSkillsApi({ contextMod, getCwd, getTools = () => [] }) {
|
|
|
54
54
|
const source = sourceForSkill(skill);
|
|
55
55
|
return {
|
|
56
56
|
name: skill.name,
|
|
57
|
-
enabled: !(
|
|
57
|
+
enabled: !(
|
|
58
|
+
contextMod.isSkillDisabled?.(skill.name, null, skills) ||
|
|
59
|
+
contextMod.skillMissingFeature?.(skill.name, null, skills)
|
|
60
|
+
),
|
|
58
61
|
description: skill.description || '',
|
|
59
62
|
whenToUse: skill.whenToUse || '',
|
|
60
63
|
filePath: skill.filePath || null,
|
|
@@ -90,6 +93,7 @@ export function createSkillsApi({ contextMod, getCwd, getTools = () => [] }) {
|
|
|
90
93
|
if (typeof contextMod.isSkillDisabled === 'function' && contextMod.isSkillDisabled(skillName)) {
|
|
91
94
|
return `Error: skill "${skillName}" is disabled`;
|
|
92
95
|
}
|
|
96
|
+
if (contextMod.skillOutsideScope?.(skillName, getCwd())) return contextMod.skillOutsideScopeError(skillName);
|
|
93
97
|
const skill = skillContent(skillName);
|
|
94
98
|
// The general tool envelope keeps the main/Lead session identical to agent
|
|
95
99
|
// loops: the model-visible tool_result is the short stub and the SKILL.md
|
|
@@ -91,6 +91,7 @@ export function createAskCallbacks({ transcript, notifyFnForSession, scheduleSea
|
|
|
91
91
|
onStreamDelta: streamDelta(turn, options),
|
|
92
92
|
drainSteering: options.drainSteering,
|
|
93
93
|
onSteerMessage: options.onSteerMessage,
|
|
94
|
+
onSkillsApplied: options.onSkillsApplied,
|
|
94
95
|
notifyFn: notifyFnForSession(session0.id),
|
|
95
96
|
signal: turn.signal,
|
|
96
97
|
};
|
|
@@ -35,6 +35,10 @@ export async function runWebhookSession({
|
|
|
35
35
|
workflow = null,
|
|
36
36
|
attachments = null,
|
|
37
37
|
signal = null,
|
|
38
|
+
// Endpoint-authored instructions: the run's ONLY skill-selection input.
|
|
39
|
+
// `prompt` also carries the fenced external payload, which must never
|
|
40
|
+
// select a skill; absent means nothing selects.
|
|
41
|
+
skillSelection = '',
|
|
38
42
|
}) {
|
|
39
43
|
const endpoint = String(name || '').trim();
|
|
40
44
|
const body = String(prompt || '').trim();
|
|
@@ -63,9 +67,17 @@ export async function runWebhookSession({
|
|
|
63
67
|
// askOpts.signal is the parent-abort link: it is cascaded onto the turn
|
|
64
68
|
// controller, so aborting it stops the in-flight provider/tool work instead
|
|
65
69
|
// of leaving a timed-out delivery's session running with live side effects.
|
|
66
|
-
const ask = (turnContent) =>
|
|
67
|
-
askSession(session.id, turnContent, null, null, projectCwd || undefined, undefined,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
const ask = (turnContent, askOpts) =>
|
|
71
|
+
askSession(session.id, turnContent, null, null, projectCwd || undefined, undefined, {
|
|
72
|
+
...askOpts,
|
|
73
|
+
...(signal ? { signal } : {}),
|
|
74
|
+
});
|
|
75
|
+
// Agents the run delegates to report back; each result is the next turn
|
|
76
|
+
// (runAutomationTurns marks those turns as task notifications).
|
|
77
|
+
const result = await runAutomationTurns(
|
|
78
|
+
session.id,
|
|
79
|
+
() => ask(content, { skillSelection: String(skillSelection ?? '') }),
|
|
80
|
+
ask
|
|
81
|
+
);
|
|
70
82
|
return { sessionId: session.id, result: String(result?.content || '') };
|
|
71
83
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Entry the skill-script launcher runs (src/runtime/shared/skill-script-runtime.mjs):
|
|
3
|
+
// <runtime executable> skill-script-entry.mjs <script.mjs> [args...]
|
|
4
|
+
// The script then sees itself as the main module, exactly as under
|
|
5
|
+
// `node <script.mjs> [args...]`, and its exit code is the process's.
|
|
6
|
+
|
|
7
|
+
// Before anything can import sharp: Electron on Linux must use its wasm build.
|
|
8
|
+
await import('./runtime/shared/sharp-electron-linux.mjs');
|
|
9
|
+
// Node mode belongs to this process only; whatever the script starts is a
|
|
10
|
+
// normal child again.
|
|
11
|
+
delete process.env.ELECTRON_RUN_AS_NODE;
|
|
12
|
+
|
|
13
|
+
const { pathToFileURL } = await import('node:url');
|
|
14
|
+
const { canonicalSkillScriptPath, decodeSkillArgv, SKILL_ARGV_ENV } = await import(
|
|
15
|
+
'./runtime/shared/skill-script-runtime.mjs'
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
// The PowerShell `mixdog-skill-node` function passes its arguments in the
|
|
19
|
+
// environment (see renderPowerShellSkillFunction); the script never sees them.
|
|
20
|
+
const envArgv = process.argv.length === 2 ? decodeSkillArgv(process.env[SKILL_ARGV_ENV]) : null;
|
|
21
|
+
delete process.env[SKILL_ARGV_ENV];
|
|
22
|
+
const [execPath, , target, ...args] = envArgv ? [process.argv[0], process.argv[1], ...envArgv] : process.argv;
|
|
23
|
+
if (!target) {
|
|
24
|
+
console.error('Usage: <skill launcher> <script.mjs> [args...]');
|
|
25
|
+
process.exitCode = 2;
|
|
26
|
+
} else {
|
|
27
|
+
const script = canonicalSkillScriptPath(target);
|
|
28
|
+
// The scripts' main check compares import.meta.url with argv[1].
|
|
29
|
+
process.argv = [execPath, script, ...args];
|
|
30
|
+
try {
|
|
31
|
+
await import(pathToFileURL(script).href);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error(error?.stack || String(error));
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -78,9 +78,17 @@ export function createStoredSessionViews({ desktopRuntime, dataDir }) {
|
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
const store = await desktopRuntime.loadSessionStore();
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
81
|
+
const refreshFromStorage = options.refreshFromStorage === true;
|
|
82
|
+
// Paged ordinary catalog ({ sessions, nextCursor }) only on the explicit
|
|
83
|
+
// `page: { limit, cursor }` option (`limit` alone keeps its old meaning:
|
|
84
|
+
// ignored, full array). An authoritative refresh is never paged.
|
|
85
|
+
const page = options.page && typeof options.page === 'object' ? options.page : null;
|
|
86
|
+
if (page && !refreshFromStorage && store.listStoredSessionSummaryPage) {
|
|
87
|
+
return store.listStoredSessionSummaryPage({ limit: page.limit, cursor: page.cursor });
|
|
88
|
+
}
|
|
89
|
+
// The async listing may answer from the session catalog DB.
|
|
90
|
+
if (store.listStoredSessionSummariesAsync) return store.listStoredSessionSummariesAsync({ refreshFromStorage });
|
|
91
|
+
return store.listStoredSessionSummaries({ refreshFromStorage });
|
|
84
92
|
},
|
|
85
93
|
};
|
|
86
94
|
}
|
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
startOwnerLivenessListener,
|
|
50
50
|
} from './daemon-owner.mjs';
|
|
51
51
|
import { remoteIntentPath } from '../runtime/shared/remote-intent.mjs';
|
|
52
|
+
import { modelProxyClientMode } from '../runtime/shared/model-proxy-mode.mjs';
|
|
52
53
|
import { setChannelNotifySink } from '../runtime/channels/lib/parent-bridge.mjs';
|
|
53
54
|
import { setOwnerContext } from '../runtime/channels/lib/runtime-paths.mjs';
|
|
54
55
|
import { safeIpcSend } from '../runtime/shared/safe-ipc-send.mjs';
|
|
@@ -144,6 +145,11 @@ let ownerLiveness = null;
|
|
|
144
145
|
// The endpoints daemon.json carries once published; a heartbeat re-publishes
|
|
145
146
|
// them when the file goes missing (TEMP cleanup).
|
|
146
147
|
let publishedEndpoints = null;
|
|
148
|
+
// Remote mode only: the loopback relay that lets headless runs started from
|
|
149
|
+
// model shells (skill scripts) reach the PC behind this daemon's model proxy
|
|
150
|
+
// channel (providers/model-proxy-bridge.mjs), and its running-call count.
|
|
151
|
+
let modelProxyBridge = null;
|
|
152
|
+
let modelProxyBridgeActive = 0;
|
|
147
153
|
const eventLoopDelay = monitorEventLoopDelay({ resolution: 20 });
|
|
148
154
|
eventLoopDelay.enable();
|
|
149
155
|
let idleGc = null;
|
|
@@ -218,6 +224,13 @@ async function shutdown(reason, code = 0) {
|
|
|
218
224
|
try {
|
|
219
225
|
setChannelNotifySink(null);
|
|
220
226
|
} catch {}
|
|
227
|
+
// Abort every relayed model call, close the bridge sockets and wait for the
|
|
228
|
+
// calls to settle before anything they depend on goes away.
|
|
229
|
+
try {
|
|
230
|
+
await modelProxyBridge?.close(`daemon shutdown: ${reason}`);
|
|
231
|
+
} catch (e) {
|
|
232
|
+
log(`model proxy bridge stop failed: ${e?.message || e}`);
|
|
233
|
+
}
|
|
221
234
|
try {
|
|
222
235
|
await sessionService?.stop?.(reason);
|
|
223
236
|
} catch (e) {
|
|
@@ -292,7 +305,7 @@ async function shutdown(reason, code = 0) {
|
|
|
292
305
|
* asks whether this process may exit; idle GC asks whether a pause is safe. */
|
|
293
306
|
function inFlightWork() {
|
|
294
307
|
return {
|
|
295
|
-
activeCalls: (transport?.activeCount ?? 0) + (sessionTransport?.activeCount ?? 0),
|
|
308
|
+
activeCalls: (transport?.activeCount ?? 0) + (sessionTransport?.activeCount ?? 0) + modelProxyBridgeActive,
|
|
296
309
|
queuedCalls: (transport?.queuedCount ?? 0) + (sessionTransport?.queuedCount ?? 0),
|
|
297
310
|
busySessions: sessionService?.busyCount ?? 0,
|
|
298
311
|
busyMemoryAgents: agentDispatchBroker?.snapshot?.().inFlight ?? 0,
|
|
@@ -562,9 +575,9 @@ function daemonStatusSnapshot() {
|
|
|
562
575
|
|
|
563
576
|
/** The file every attacher reads to find this daemon: wire identity plus both
|
|
564
577
|
* loopback endpoints and their privileged tokens. */
|
|
565
|
-
function publishDaemonDiscovery({ channel, session }) {
|
|
578
|
+
function publishDaemonDiscovery({ channel, session, modelProxy = null }) {
|
|
566
579
|
// A re-publish keeps the first publication's startedAt.
|
|
567
|
-
publishedEndpoints = { channel, session, startedAt: publishedEndpoints?.startedAt ?? Date.now() };
|
|
580
|
+
publishedEndpoints = { channel, session, modelProxy, startedAt: publishedEndpoints?.startedAt ?? Date.now() };
|
|
568
581
|
writeJsonAtomicSync(
|
|
569
582
|
DAEMON_DISCOVERY_PATH,
|
|
570
583
|
{
|
|
@@ -577,12 +590,34 @@ function publishDaemonDiscovery({ channel, session }) {
|
|
|
577
590
|
endpoints: {
|
|
578
591
|
channel: { port: channel.port, token: channel.token },
|
|
579
592
|
session: { port: session.port, token: session.token },
|
|
593
|
+
...(modelProxy ? { modelProxy: { port: modelProxy.port, token: modelProxy.token } } : {}),
|
|
580
594
|
},
|
|
581
595
|
},
|
|
582
596
|
{ compact: true, secret: true }
|
|
583
597
|
);
|
|
584
598
|
}
|
|
585
599
|
|
|
600
|
+
/** Remote mode only: the model proxy bridge endpoint to publish, or null. */
|
|
601
|
+
async function startModelProxyBridge(bootPhases) {
|
|
602
|
+
if (!modelProxyClientMode()) return null;
|
|
603
|
+
const [{ createModelProxyBridgeServer }, { getModelProxyChannel }] = await Promise.all([
|
|
604
|
+
import('../runtime/agent/orchestrator/providers/model-proxy-bridge.mjs'),
|
|
605
|
+
import('../runtime/agent/orchestrator/providers/model-proxy-channel.mjs'),
|
|
606
|
+
]);
|
|
607
|
+
modelProxyBridge = createModelProxyBridgeServer({
|
|
608
|
+
channel: getModelProxyChannel(),
|
|
609
|
+
// Fenced or shutting down: no new relayed call.
|
|
610
|
+
admit: () => !shuttingDown && admitOwnerWork(),
|
|
611
|
+
trackWork: (active) => {
|
|
612
|
+
modelProxyBridgeActive = active;
|
|
613
|
+
},
|
|
614
|
+
log,
|
|
615
|
+
});
|
|
616
|
+
const endpoint = await bootPhases.measure('model-proxy-bridge-start', () => modelProxyBridge.start());
|
|
617
|
+
log(`model proxy bridge on 127.0.0.1:${endpoint.port}`);
|
|
618
|
+
return endpoint;
|
|
619
|
+
}
|
|
620
|
+
|
|
586
621
|
/** Asked by both front doors before every register/call: an expired lease
|
|
587
622
|
* fences here (answered 503), and after an event-loop stall nothing is
|
|
588
623
|
* served until the record is re-verified as ours. */
|
|
@@ -598,6 +633,7 @@ function fenceDaemon(reason) {
|
|
|
598
633
|
log(`${reason} — refusing new work and stopping so only one daemon serves`);
|
|
599
634
|
sessionTransport?.commitDrain?.(reason);
|
|
600
635
|
transport?.commitDrain?.(reason);
|
|
636
|
+
modelProxyBridge?.abortAll(reason);
|
|
601
637
|
try {
|
|
602
638
|
if (discoveryPid(DAEMON_DISCOVERY_PATH) === process.pid) rmSync(DAEMON_DISCOVERY_PATH, { force: true });
|
|
603
639
|
} catch (e) {
|
|
@@ -890,6 +926,7 @@ async function main() {
|
|
|
890
926
|
admitWork: admitOwnerWork,
|
|
891
927
|
});
|
|
892
928
|
const sessionEndpoint = await bootPhases.measure('session-transport-start', () => sessionTransport.start());
|
|
929
|
+
const modelProxyEndpoint = await startModelProxyBridge(bootPhases);
|
|
893
930
|
// A boot whose holder stopped answering may have been superseded by a
|
|
894
931
|
// contender between beats; never publish over the winner's endpoint. An
|
|
895
932
|
// unreadable record (an antivirus lock) is not a takeover.
|
|
@@ -900,7 +937,7 @@ async function main() {
|
|
|
900
937
|
exitRecorder.setReason(`owner claim superseded by pid=${ownerPid} before publish`, 0);
|
|
901
938
|
process.exit(0);
|
|
902
939
|
}
|
|
903
|
-
publishDaemonDiscovery({ channel: { port, token }, session: sessionEndpoint });
|
|
940
|
+
publishDaemonDiscovery({ channel: { port, token }, session: sessionEndpoint, modelProxy: modelProxyEndpoint });
|
|
904
941
|
bootPhases.mark('discovery-published');
|
|
905
942
|
log(`session front door on 127.0.0.1:${sessionEndpoint.port}`);
|
|
906
943
|
|
|
@@ -13,6 +13,7 @@ export const SESSION_READ_ACTIONS = Object.freeze([
|
|
|
13
13
|
'getChannelSetup',
|
|
14
14
|
'getChannelWorkerStatus',
|
|
15
15
|
'getCompactionSettings',
|
|
16
|
+
'getConversationImportJobs',
|
|
16
17
|
'getDeveloperSettings',
|
|
17
18
|
'getDisabledSkills',
|
|
18
19
|
'getMediaDefault',
|
|
@@ -57,6 +58,7 @@ export const SESSION_READ_ACTIONS = Object.freeze([
|
|
|
57
58
|
'hooksStatus',
|
|
58
59
|
'inheritancePreflight',
|
|
59
60
|
'listAgents',
|
|
61
|
+
'listImportableConversations',
|
|
60
62
|
'listMediaAssets',
|
|
61
63
|
'listMediaLanes',
|
|
62
64
|
'listOutputStyles',
|
|
@@ -87,6 +89,7 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
|
|
|
87
89
|
'cacheMediaThumbnail',
|
|
88
90
|
'cancelMediaJob',
|
|
89
91
|
'cancelOAuthProviderLogin',
|
|
92
|
+
'cancelConversationImport',
|
|
90
93
|
'checkForUpdate',
|
|
91
94
|
'clear',
|
|
92
95
|
'compact',
|
|
@@ -118,6 +121,7 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
|
|
|
118
121
|
'pushNotice',
|
|
119
122
|
'recall',
|
|
120
123
|
'reconnectMcp',
|
|
124
|
+
'registerConversationImportFile',
|
|
121
125
|
'reloadPlugins',
|
|
122
126
|
'reloadSkills',
|
|
123
127
|
'rememberPromptHistory',
|
|
@@ -198,6 +202,7 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
|
|
|
198
202
|
'setOrchestrationMode',
|
|
199
203
|
'saveStarterGuideState',
|
|
200
204
|
'skipOnboarding',
|
|
205
|
+
'startConversationImport',
|
|
201
206
|
'startMediaJob',
|
|
202
207
|
'stopShellJob',
|
|
203
208
|
'switchContext',
|
|
@@ -101,15 +101,20 @@ export function createSessionActionCalls(ctx) {
|
|
|
101
101
|
if (typeof listSessions !== 'function') {
|
|
102
102
|
throw new Error('session catalog is unavailable');
|
|
103
103
|
}
|
|
104
|
-
const
|
|
104
|
+
const listed = await listSessions({
|
|
105
105
|
...(options || {}),
|
|
106
106
|
// Agent-only records are an internal ancestry/reuse source, never part
|
|
107
107
|
// of the ordinary session catalog returned over the public transport.
|
|
108
108
|
includeAgentOnly: false,
|
|
109
109
|
});
|
|
110
|
+
// A `page: { limit, cursor }` request answers one page: { sessions, nextCursor }.
|
|
111
|
+
const page = listed && !Array.isArray(listed) && Array.isArray(listed.sessions) ? listed : null;
|
|
112
|
+
const sessions = page ? page.sessions : listed;
|
|
110
113
|
const remoteSession = typeof getRemoteSessionState === 'function' ? await getRemoteSessionState() : null;
|
|
114
|
+
const nextCursor = typeof page?.nextCursor === 'string' ? page.nextCursor : null;
|
|
111
115
|
return {
|
|
112
116
|
sessions: sanitizeForWire(Array.isArray(sessions) ? sessions : []),
|
|
117
|
+
...(page ? { nextCursor } : {}),
|
|
113
118
|
remoteSession: sanitizeForWire(remoteSession) ?? null,
|
|
114
119
|
};
|
|
115
120
|
}
|
package/src/tui/App.jsx
CHANGED
|
@@ -21,6 +21,7 @@ import { useApp, useStdin, useStdout } from 'ink';
|
|
|
21
21
|
import { useSession } from './hooks/useSession.mjs';
|
|
22
22
|
import { pickFolder } from '../standalone/folder-dialog.mjs';
|
|
23
23
|
import { deriveSlashPalette } from './app/slash-palette.mjs';
|
|
24
|
+
import { skillMentionQuery, useSkillMentionSkills } from './app/skill-mention-palette.mjs';
|
|
24
25
|
import { shouldSupersedePanelEpoch, supersedePanelEpoch } from './app/panel-epoch.mjs';
|
|
25
26
|
import { createPanelSurface } from './app/panel-surface.mjs';
|
|
26
27
|
import { resolvePickerState } from './app/picker-index-mode.mjs';
|
|
@@ -215,6 +216,8 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
215
216
|
setPromptDraft,
|
|
216
217
|
promptDraftOverride,
|
|
217
218
|
setPromptDraftOverride,
|
|
219
|
+
promptCaret,
|
|
220
|
+
setPromptCaret,
|
|
218
221
|
promptLayoutValueRef,
|
|
219
222
|
setPromptLayoutRows,
|
|
220
223
|
textEntryLayoutRows,
|
|
@@ -625,7 +628,8 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
625
628
|
pastedTextsRef,
|
|
626
629
|
});
|
|
627
630
|
|
|
628
|
-
const
|
|
631
|
+
const mentionSkills = useSkillMentionSkills(store, skillMentionQuery(promptDraft, promptCaret) !== null);
|
|
632
|
+
const { activeSlashQuery, slashCommands, slashPaletteOpen, paletteKind } = deriveSlashPalette({
|
|
629
633
|
providerPrompt,
|
|
630
634
|
settingsPrompt,
|
|
631
635
|
toolApproval,
|
|
@@ -636,6 +640,8 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
636
640
|
commandBusy: state.commandBusy,
|
|
637
641
|
promptDraft,
|
|
638
642
|
slashDismissedFor,
|
|
643
|
+
skills: mentionSkills,
|
|
644
|
+
promptCaret,
|
|
639
645
|
});
|
|
640
646
|
slashPaletteRef.current = { open: slashPaletteOpen, count: slashCommands.length };
|
|
641
647
|
scrollFocusRef.current = {
|
|
@@ -833,10 +839,12 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
833
839
|
hasUserMessages,
|
|
834
840
|
initialStatusLine,
|
|
835
841
|
onPromptDraftChange,
|
|
842
|
+
onPromptCaretChange: setPromptCaret,
|
|
836
843
|
onSubmit,
|
|
837
844
|
overlayHintAttachItemIndex,
|
|
838
845
|
overlayHintFallbackRow,
|
|
839
846
|
overlayHintOnLastItem,
|
|
847
|
+
paletteKind,
|
|
840
848
|
panelInkMaskEpoch,
|
|
841
849
|
panelTransitionEpoch,
|
|
842
850
|
picker,
|