@songsid/agend 2.2.0-beta.2 → 2.2.0-beta.20
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 +40 -24
- package/README.zh-TW.md +40 -24
- package/dist/agent-cli-instructions.md +6 -2
- package/dist/agent-cli.js +15 -7
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +3 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-whats-new.js +16 -4
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.d.ts +3 -1
- package/dist/auth-api.js +17 -1
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/antigravity.d.ts +33 -0
- package/dist/backend/antigravity.js +126 -18
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-carry.d.ts +22 -0
- package/dist/backend/claude-carry.js +170 -0
- package/dist/backend/claude-carry.js.map +1 -0
- package/dist/backend/claude-code.d.ts +65 -2
- package/dist/backend/claude-code.js +226 -33
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-metadata.d.ts +33 -0
- package/dist/backend/codex-metadata.js +122 -18
- package/dist/backend/codex-metadata.js.map +1 -1
- package/dist/backend/codex.d.ts +3 -0
- package/dist/backend/codex.js +17 -1
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/credential-profile.d.ts +40 -3
- package/dist/backend/credential-profile.js +113 -5
- package/dist/backend/credential-profile.js.map +1 -1
- package/dist/backend/effort-metadata.d.ts +37 -1
- package/dist/backend/effort-metadata.js +86 -15
- package/dist/backend/effort-metadata.js.map +1 -1
- package/dist/backend/grok.d.ts +4 -0
- package/dist/backend/grok.js +14 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +27 -1
- package/dist/backend/kiro.js +63 -10
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/launch-effort.d.ts +61 -0
- package/dist/backend/launch-effort.js +170 -0
- package/dist/backend/launch-effort.js.map +1 -0
- package/dist/backend/muse.d.ts +84 -0
- package/dist/backend/muse.js +449 -53
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +48 -2
- package/dist/backend/types.js +12 -1
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-command.d.ts +91 -0
- package/dist/backend-command.js +122 -0
- package/dist/backend-command.js.map +1 -0
- package/dist/background-work-ended.d.ts +18 -0
- package/dist/background-work-ended.js +30 -0
- package/dist/background-work-ended.js.map +1 -0
- package/dist/cache-service.d.ts +2 -0
- package/dist/cache-service.js +2 -1
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +26 -1
- package/dist/channel/adapters/discord.js +103 -3
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +35 -3
- package/dist/channel/adapters/telegram.js +122 -23
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +5 -3
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/message-edit-errors.d.ts +5 -0
- package/dist/channel/message-edit-errors.js +24 -0
- package/dist/channel/message-edit-errors.js.map +1 -0
- package/dist/channel/telegram-markdown.d.ts +6 -0
- package/dist/channel/telegram-markdown.js +104 -0
- package/dist/channel/telegram-markdown.js.map +1 -0
- package/dist/channel/tool-router.d.ts +2 -0
- package/dist/channel/tool-router.js +6 -5
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/channel/types.d.ts +46 -4
- package/dist/cli.js +184 -34
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +2 -2
- package/dist/command-table.js +5 -2
- package/dist/command-table.js.map +1 -1
- package/dist/compact-watch.d.ts +86 -0
- package/dist/compact-watch.js +288 -0
- package/dist/compact-watch.js.map +1 -0
- package/dist/config-validator.js +55 -5
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/cross-instance-envelope.js +2 -0
- package/dist/cross-instance-envelope.js.map +1 -1
- package/dist/daemon.d.ts +129 -1
- package/dist/daemon.js +754 -94
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +64 -8
- package/dist/delivery-outbox.js +315 -24
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-reconciliation.d.ts +18 -1
- package/dist/delivery-reconciliation.js +67 -2
- package/dist/delivery-reconciliation.js.map +1 -1
- package/dist/doctor.js +7 -0
- package/dist/doctor.js.map +1 -1
- package/dist/fleet-context.d.ts +12 -1
- package/dist/fleet-manager.d.ts +392 -19
- package/dist/fleet-manager.js +2030 -275
- package/dist/fleet-manager.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +4 -3
- package/dist/forged-envelope-scan.js +4 -3
- package/dist/forged-envelope-scan.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +84 -16
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +16 -1
- package/dist/general-knowledge/skills/model-discovery/SKILL.md +4 -1
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +4 -0
- package/dist/host-memory.d.ts +10 -0
- package/dist/host-memory.js +33 -1
- package/dist/host-memory.js.map +1 -1
- package/dist/human-delivery-receipts.d.ts +83 -0
- package/dist/human-delivery-receipts.js +194 -0
- package/dist/human-delivery-receipts.js.map +1 -0
- package/dist/install-lock.d.ts +18 -1
- package/dist/install-lock.js +30 -3
- package/dist/install-lock.js.map +1 -1
- package/dist/instance-avatar.d.ts +5 -4
- package/dist/instance-avatar.js +12 -8
- package/dist/instance-avatar.js.map +1 -1
- package/dist/instance-config-impact.js +1 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +25 -6
- package/dist/instance-lifecycle.js +76 -27
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.js +3 -3
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-compact-pane.d.ts +38 -0
- package/dist/kiro-compact-pane.js +57 -0
- package/dist/kiro-compact-pane.js.map +1 -0
- package/dist/kiro-log-gate.d.ts +42 -0
- package/dist/kiro-log-gate.js +39 -0
- package/dist/kiro-log-gate.js.map +1 -0
- package/dist/launchd-handoff.d.ts +43 -0
- package/dist/launchd-handoff.js +56 -0
- package/dist/launchd-handoff.js.map +1 -0
- package/dist/locale.js +268 -42
- package/dist/locale.js.map +1 -1
- package/dist/log-service.d.ts +99 -0
- package/dist/log-service.js +243 -0
- package/dist/log-service.js.map +1 -0
- package/dist/log-steps.d.ts +169 -0
- package/dist/log-steps.js +858 -0
- package/dist/log-steps.js.map +1 -0
- package/dist/login-controller.d.ts +20 -3
- package/dist/login-controller.js +71 -19
- package/dist/login-controller.js.map +1 -1
- package/dist/login-flows.d.ts +5 -2
- package/dist/login-flows.js +5 -4
- package/dist/login-flows.js.map +1 -1
- package/dist/login-shell.d.ts +21 -0
- package/dist/login-shell.js +98 -0
- package/dist/login-shell.js.map +1 -0
- package/dist/memory-pressure.d.ts +13 -1
- package/dist/memory-pressure.js +50 -10
- package/dist/memory-pressure.js.map +1 -1
- package/dist/needs-you-hub.js +2 -0
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you-live.d.ts +6 -0
- package/dist/needs-you-live.js +23 -3
- package/dist/needs-you-live.js.map +1 -1
- package/dist/outbound-handlers.d.ts +100 -0
- package/dist/outbound-handlers.js +277 -93
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +30 -15
- package/dist/outbound-schemas.js +23 -5
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/provider-probe.d.ts +29 -0
- package/dist/provider-probe.js +198 -2
- package/dist/provider-probe.js.map +1 -1
- package/dist/public-link-progress.d.ts +1 -1
- package/dist/public-link-progress.js +8 -2
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-preview.d.ts +101 -0
- package/dist/public-preview.js +236 -0
- package/dist/public-preview.js.map +1 -0
- package/dist/public-web-gateway.d.ts +2 -0
- package/dist/public-web-gateway.js +20 -6
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +24 -1
- package/dist/public-web-link.js +63 -9
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart-api.d.ts +1 -1
- package/dist/quickstart-api.js +8 -6
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +12 -0
- package/dist/quickstart.js +36 -6
- package/dist/quickstart.js.map +1 -1
- package/dist/reply-buttons-controller.d.ts +89 -5
- package/dist/reply-buttons-controller.js +273 -8
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/reply-buttons.d.ts +48 -3
- package/dist/reply-buttons.js +105 -10
- package/dist/reply-buttons.js.map +1 -1
- package/dist/reply-polls.d.ts +85 -0
- package/dist/reply-polls.js +154 -0
- package/dist/reply-polls.js.map +1 -0
- package/dist/restart-guard.d.ts +6 -3
- package/dist/restart-guard.js +6 -3
- package/dist/restart-guard.js.map +1 -1
- package/dist/restart-progress.d.ts +33 -2
- package/dist/restart-progress.js +30 -2
- package/dist/restart-progress.js.map +1 -1
- package/dist/sd-notify.d.ts +22 -1
- package/dist/sd-notify.js +63 -10
- package/dist/sd-notify.js.map +1 -1
- package/dist/service-activation.d.ts +15 -7
- package/dist/service-activation.js +42 -26
- package/dist/service-activation.js.map +1 -1
- package/dist/service-installer.d.ts +55 -0
- package/dist/service-installer.js +90 -3
- package/dist/service-installer.js.map +1 -1
- package/dist/service-plan.d.ts +11 -0
- package/dist/service-plan.js +23 -0
- package/dist/service-plan.js.map +1 -1
- package/dist/settings-api.js +14 -4
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +4 -2
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +2 -0
- package/dist/settings-effect.js.map +1 -1
- package/dist/spawn-gate.js +5 -1
- package/dist/spawn-gate.js.map +1 -1
- package/dist/spawn-hold-reply.d.ts +12 -0
- package/dist/spawn-hold-reply.js +39 -0
- package/dist/spawn-hold-reply.js.map +1 -0
- package/dist/systemd-peer-bus.d.ts +95 -0
- package/dist/systemd-peer-bus.js +430 -0
- package/dist/systemd-peer-bus.js.map +1 -0
- package/dist/systemd-runtime.d.ts +27 -1
- package/dist/systemd-runtime.js +69 -7
- package/dist/systemd-runtime.js.map +1 -1
- package/dist/tips.js +1 -1
- package/dist/tips.js.map +1 -1
- package/dist/tool-permissions.js +3 -3
- package/dist/tool-permissions.js.map +1 -1
- package/dist/tool-progress.js +3 -2
- package/dist/tool-progress.js.map +1 -1
- package/dist/topic-commands.d.ts +71 -4
- package/dist/topic-commands.js +167 -34
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-delta-reader.d.ts +3 -3
- package/dist/transcript-delta-reader.js +8 -8
- package/dist/transcript-delta-reader.js.map +1 -1
- package/dist/transcript-jsonl.d.ts +85 -3
- package/dist/transcript-jsonl.js +156 -13
- package/dist/transcript-jsonl.js.map +1 -1
- package/dist/transcript-monitor.d.ts +11 -0
- package/dist/transcript-monitor.js +61 -13
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-sources.d.ts +24 -0
- package/dist/transcript-sources.js +211 -56
- package/dist/transcript-sources.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +7 -15
- package/dist/tunnel/cloudflared.js +36 -1
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/purpose-lane.d.ts +5 -1
- package/dist/tunnel/purpose-lane.js +14 -7
- package/dist/tunnel/purpose-lane.js.map +1 -1
- package/dist/tunnel/types.d.ts +5 -1
- package/dist/tunnel/types.js.map +1 -1
- package/dist/turn-resume.d.ts +2 -0
- package/dist/turn-resume.js +1 -1
- package/dist/turn-resume.js.map +1 -1
- package/dist/types.d.ts +22 -0
- package/dist/ui/chat-commands.js +1 -0
- package/dist/ui/chat-mentions.js +63 -0
- package/dist/ui/chat-render.js +80 -10
- package/dist/ui/chat-store.js +70 -6
- package/dist/ui/chat-strings.js +62 -32
- package/dist/ui/chat-thread.js +199 -24
- package/dist/ui/chat-time.js +80 -0
- package/dist/ui/chat-tour.js +17 -14
- package/dist/ui/panel-chat.js +45 -21
- package/dist/ui/panel-details.js +2 -0
- package/dist/ui/panel-fleet.js +213 -58
- package/dist/ui/panel-log.js +428 -0
- package/dist/ui/panel-needs.js +14 -10
- package/dist/ui/panel-settings.js +82 -17
- package/dist/ui/preview-panel.js +55 -15
- package/dist/ui/preview-status.js +28 -0
- package/dist/ui/preview.js +44 -3
- package/dist/ui/settings-dialogs.js +11 -6
- package/dist/ui/settings-model.js +3 -1
- package/dist/ui/settings-strings.js +32 -12
- package/dist/ui/settings-token.js +8 -1
- package/dist/ui/settings-wizard.js +5 -3
- package/dist/ui/shared/app-i18n.js +41 -15
- package/dist/ui/shared/app-prefs.js +250 -0
- package/dist/ui/shared/app-route.js +6 -1
- package/dist/ui/shared/app-shell.js +165 -8
- package/dist/ui/shared/app-store.js +5 -1
- package/dist/ui/shared/app-stream.js +26 -5
- package/dist/ui/shared/app.css +170 -30
- package/dist/ui/shared/app.js +11 -1
- package/dist/ui/shared/fonts/README.md +1 -1
- package/dist/ui/shared/header-tools.js +83 -13
- package/dist/ui/shared/instance-nav.js +178 -51
- package/dist/ui/shared/instance-switch.js +8 -5
- package/dist/ui/shared/panel-view.js +21 -4
- package/dist/ui/shared/signin.js +15 -9
- package/dist/ui/shared/theme.js +39 -7
- package/dist/ui/shared/tokens.css +1 -1
- package/dist/ui/shared/ui-icons.js +2 -0
- package/dist/ui/shared/usage-dialog.js +23 -5
- package/dist/ui/shared/view-strings.js +40 -4
- package/dist/ui/signin.html +8 -3
- package/dist/unrecognised-prompt.d.ts +23 -0
- package/dist/unrecognised-prompt.js +74 -0
- package/dist/unrecognised-prompt.js.map +1 -0
- package/dist/update-check.d.ts +31 -0
- package/dist/update-check.js +47 -0
- package/dist/update-check.js.map +1 -1
- package/dist/update-install.d.ts +13 -1
- package/dist/update-install.js +16 -4
- package/dist/update-install.js.map +1 -1
- package/dist/update-launch.d.ts +48 -1
- package/dist/update-launch.js +159 -5
- package/dist/update-launch.js.map +1 -1
- package/dist/update-marker.d.ts +51 -0
- package/dist/update-marker.js +61 -0
- package/dist/update-marker.js.map +1 -1
- package/dist/usage/i18n-keys.d.ts +1 -1
- package/dist/usage/i18n-keys.js +1 -1
- package/dist/usage/i18n-keys.js.map +1 -1
- package/dist/usage/providers.d.ts +62 -13
- package/dist/usage/providers.js +256 -68
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/statusline-usage.d.ts +6 -2
- package/dist/usage/statusline-usage.js +10 -4
- package/dist/usage/statusline-usage.js.map +1 -1
- package/dist/view-api.js +31 -9
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +82 -4
- package/dist/web-api.js +632 -88
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +5 -2
- package/dist/web-auth.js.map +1 -1
- package/dist/web-chat-history.d.ts +26 -1
- package/dist/web-chat-history.js +47 -8
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +41 -5
- package/dist/web-commands.js +25 -7
- package/dist/web-commands.js.map +1 -1
- package/dist/web-login.d.ts +14 -0
- package/dist/web-login.js +4 -2
- package/dist/web-login.js.map +1 -1
- package/dist/web-mentions.d.ts +44 -0
- package/dist/web-mentions.js +75 -0
- package/dist/web-mentions.js.map +1 -0
- package/dist/web-prefs.d.ts +81 -0
- package/dist/web-prefs.js +297 -0
- package/dist/web-prefs.js.map +1 -0
- package/dist/web-preview.d.ts +14 -1
- package/dist/web-preview.js +35 -13
- package/dist/web-preview.js.map +1 -1
- package/dist/web-profile.d.ts +32 -0
- package/dist/web-profile.js +132 -0
- package/dist/web-profile.js.map +1 -0
- package/dist/web-reply-files.d.ts +45 -0
- package/dist/web-reply-files.js +223 -0
- package/dist/web-reply-files.js.map +1 -0
- package/dist/web-schedules.d.ts +12 -0
- package/dist/web-schedules.js +34 -0
- package/dist/web-schedules.js.map +1 -0
- package/dist/web-server-drain.d.ts +10 -0
- package/dist/web-server-drain.js +50 -0
- package/dist/web-server-drain.js.map +1 -0
- package/dist/web-session.d.ts +14 -0
- package/dist/web-session.js +11 -1
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +3 -1
- package/dist/web-settings-patch.js +4 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-shell-routes.d.ts +4 -0
- package/dist/web-shell-routes.js +9 -0
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/web-upload.d.ts +135 -7
- package/dist/web-upload.js +315 -51
- package/dist/web-upload.js.map +1 -1
- package/launcher/install-admission.cjs +61 -6
- package/package.json +3 -3
- package/templates/launchd.plist.ejs +3 -1
- package/templates/systemd.service.ejs +2 -1
package/dist/usage/providers.js
CHANGED
|
@@ -20,13 +20,15 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { readFile, writeFile, access, constants } from "node:fs/promises";
|
|
22
22
|
import { readFileSync, readdirSync } from "node:fs";
|
|
23
|
-
import { join } from "node:path";
|
|
23
|
+
import { join, resolve, sep } from "node:path";
|
|
24
|
+
import { execFile } from "node:child_process";
|
|
24
25
|
import { getAgendHome } from "../paths.js";
|
|
25
26
|
import { loadFleetConfig } from "../config.js";
|
|
26
27
|
import { classicProfile, profileName, readClassicBindings } from "../classic-bindings.js";
|
|
27
|
-
import { credentialHomeSpec, credentialProfileStoreHome, instanceCredentialProfile, } from "../backend/credential-profile.js";
|
|
28
|
+
import { CHAT_PROFILE_LOGIN_BACKENDS, credentialHomeSpec, credentialProfileLoginCommand, credentialProfileStoreHome, instanceCredentialProfile, } from "../backend/credential-profile.js";
|
|
29
|
+
import { claudeKeychainService } from "../backend/claude-code.js";
|
|
28
30
|
import { readKiroAuthTokens } from "../backend/kiro-auth-store.js";
|
|
29
|
-
import { homedir } from "node:os";
|
|
31
|
+
import { homedir, userInfo } from "node:os";
|
|
30
32
|
import { getProviderRateLimit } from "./provider-alerts.js";
|
|
31
33
|
import { MUSE_USAGE_STALE_MS, readMuseUsageSnapshot } from "../muse-usage-relay.js";
|
|
32
34
|
import { readStatuslineRateLimits, } from "./statusline-usage.js";
|
|
@@ -216,43 +218,163 @@ export function statuslineUsage(reading, plan, now = Date.now()) {
|
|
|
216
218
|
metrics,
|
|
217
219
|
};
|
|
218
220
|
}
|
|
221
|
+
/** `claudeAiOauth` of a credentials document (the `.credentials.json` file, or the same JSON in a Keychain item). */
|
|
222
|
+
function claudeOAuthOf(json) {
|
|
223
|
+
try {
|
|
224
|
+
const value = JSON.parse(json)?.claudeAiOauth;
|
|
225
|
+
return value && typeof value === "object" ? value : null;
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async function readClaudeCredentialsFile(dir) {
|
|
232
|
+
try {
|
|
233
|
+
return claudeOAuthOf(await readFile(join(dir, ".credentials.json"), "utf8"));
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const readKeychainItem = (service, account) => new Promise(done => {
|
|
240
|
+
execFile("security", ["find-generic-password", "-a", account, "-w", "-s", service], { timeout: 5_000 }, (err, stdout) => {
|
|
241
|
+
done(err ? null : String(stdout).trim() || null);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
const defaultKeychain = () => ({ platform: process.platform, read: readKeychainItem, username: () => userInfo().username });
|
|
245
|
+
let claudeKeychain = defaultKeychain();
|
|
246
|
+
/** Test seam (#1699): the platform, the Keychain read and the OS user name; null restores all three. */
|
|
247
|
+
export function setClaudeKeychainForTests(seam) {
|
|
248
|
+
claudeKeychain = seam ? { ...claudeKeychain, ...seam } : defaultKeychain();
|
|
249
|
+
}
|
|
219
250
|
/**
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* CLAUDE_CODE_OAUTH_TOKEN → shell rc. Null when nothing usable exists.
|
|
251
|
+
* The account claude files its Keychain item under (2.1.296, as Prism read it from the official darwin bundle, #1713
|
|
252
|
+
* review): `$USER`, else the OS user name; one that cannot be read or is not `[a-zA-Z0-9._-]+` is "claude-code-user".
|
|
223
253
|
*/
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
let file;
|
|
254
|
+
function claudeKeychainAccount() {
|
|
255
|
+
let name;
|
|
227
256
|
try {
|
|
228
|
-
|
|
257
|
+
name = process.env.USER || claudeKeychain.username();
|
|
229
258
|
}
|
|
230
259
|
catch {
|
|
231
|
-
|
|
260
|
+
name = undefined;
|
|
232
261
|
}
|
|
233
|
-
|
|
234
|
-
return auth && "token" in auth ? auth.token : null;
|
|
262
|
+
return name && /^[a-zA-Z0-9._-]+$/.test(name) ? name : "claude-code-user";
|
|
235
263
|
}
|
|
236
|
-
/**
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
264
|
+
/**
|
|
265
|
+
* A credential profile's own Claude login (#1699) — and nothing else: on macOS the Keychain item claude keeps for
|
|
266
|
+
* exactly this config dir (claudeKeychainService; the account is $USER, as claude names it), else — or when that has
|
|
267
|
+
* none — the dir's `.credentials.json`. Never the shared login, `CLAUDE_CODE_OAUTH_TOKEN` or a shell rc: those are
|
|
268
|
+
* another account's, and their numbers on this row would be a lie about this subscription.
|
|
269
|
+
*/
|
|
270
|
+
async function readClaudeProfileLogin(configDir) {
|
|
271
|
+
if (claudeKeychain.platform === "darwin") {
|
|
272
|
+
// As claude: a credentials document in the Keychain is THE login — one with no OAuth in it (say only MCP
|
|
273
|
+
// logins) means no OAuth login, and an older `.credentials.json` beside it is not consulted (#1713 review).
|
|
274
|
+
const secret = await claudeKeychain.read(claudeKeychainService(configDir), claudeKeychainAccount());
|
|
275
|
+
const document = secret ? credentialsDocument(secret) : null;
|
|
276
|
+
if (document)
|
|
277
|
+
return claudeOAuthOf(secret);
|
|
278
|
+
}
|
|
279
|
+
return readClaudeCredentialsFile(configDir);
|
|
280
|
+
}
|
|
281
|
+
/** A credentials document (any JSON object), or null — unparseable is no document, as claude reads its storage. */
|
|
282
|
+
function credentialsDocument(json) {
|
|
240
283
|
try {
|
|
241
|
-
|
|
284
|
+
const v = JSON.parse(json);
|
|
285
|
+
return v && typeof v === "object" ? v : null;
|
|
242
286
|
}
|
|
243
287
|
catch {
|
|
244
|
-
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Whether a token the profile's own login does not control can reach claude in a profile's pane: AgEnD sets only
|
|
293
|
+
* `CLAUDE_CONFIG_DIR` for a profile, so `CLAUDE_CODE_OAUTH_TOKEN` from the fleet's environment, or set in a shell rc
|
|
294
|
+
* the pane's shell reads, still signs it in — and outranks the stored login (#1713 review).
|
|
295
|
+
*/
|
|
296
|
+
function envTokenReachesClaude() {
|
|
297
|
+
return !!process.env.CLAUDE_CODE_OAUTH_TOKEN?.trim() || shellRcSetsClaudeToken((path) => readFileSync(path, "utf-8"));
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Whether a shell rc sets `CLAUDE_CODE_OAUTH_TOKEN` at all — any assignment, export or declaration that is not a
|
|
301
|
+
* comment, whatever its value: `"$OTHER"` or `${OTHER}` is a token once the pane's shell expands it, so unlike
|
|
302
|
+
* tokenFromShellRc (which must hand the API a literal bearer) this never discounts one it cannot read (#1713 review).
|
|
303
|
+
* Files those rcs `source` are not followed.
|
|
304
|
+
*/
|
|
305
|
+
export function shellRcSetsClaudeToken(read, home = homedir(), files = SHELL_RC_FILES) {
|
|
306
|
+
const sets = [
|
|
307
|
+
/^[ \t]*(?:(?:export|readonly|local|declare|typeset)(?:[ \t]+-[a-zA-Z]+)*[ \t]+(?:[^#\n]*[ \t])?)?CLAUDE_CODE_OAUTH_TOKEN[ \t]*=/m,
|
|
308
|
+
/^[ \t]*(?:export|declare[ \t]+-[a-zA-Z]*x[a-zA-Z]*|typeset[ \t]+-[a-zA-Z]*x[a-zA-Z]*)[ \t]+(?:[^#\n]*[ \t])?CLAUDE_CODE_OAUTH_TOKEN\b/m,
|
|
309
|
+
/^[ \t]*setenv[ \t]+CLAUDE_CODE_OAUTH_TOKEN\b/m,
|
|
310
|
+
];
|
|
311
|
+
for (const file of files) {
|
|
312
|
+
let content;
|
|
313
|
+
try {
|
|
314
|
+
content = read(join(home, file));
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (sets.some((re) => re.test(content)))
|
|
320
|
+
return true;
|
|
245
321
|
}
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
/** `path` is `dir` or inside it. */
|
|
325
|
+
const isWithin = (path, dir) => { const p = resolve(path); return p === dir || p.startsWith(dir + sep); };
|
|
326
|
+
/**
|
|
327
|
+
* Best-effort OAuth access token for direct Anthropic API calls (the /model
|
|
328
|
+
* catalog probe). Same resolution order as the usage panel: credentials file →
|
|
329
|
+
* CLAUDE_CODE_OAUTH_TOKEN → shell rc. Null when nothing usable exists. With
|
|
330
|
+
* `storeHome` (a credential profile's config dir, #1699): that profile's login only.
|
|
331
|
+
*/
|
|
332
|
+
export async function getClaudeOAuthToken(storeHome) {
|
|
333
|
+
const auth = storeHome !== undefined
|
|
334
|
+
? resolveClaudeAuth(await readClaudeProfileLogin(storeHome), {}, () => null)
|
|
335
|
+
: resolveClaudeAuth(await readClaudeCredentialsFile(process.env.CLAUDE_HOME || join(homedir(), ".claude")));
|
|
336
|
+
return auth && "token" in auth ? auth.token : null;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Exported for tests — the statusline/API preference order is the subject.
|
|
340
|
+
*
|
|
341
|
+
* `storeHome` (#1699): a credential profile's config dir — the row reads that profile's login and only the rate
|
|
342
|
+
* limits its own instances wrote (their conversations are under its `projects/`); a profile with no login says so,
|
|
343
|
+
* with the line that signs it in, and never shows the shared account's numbers. Without it: the shared login as
|
|
344
|
+
* always; beside profiles (`besideProfiles`), its statusline fallback leaves the profiles' instances out.
|
|
345
|
+
*/
|
|
346
|
+
export async function fetchClaudeUsage(storeHome, scope = {}) {
|
|
347
|
+
const profileHome = storeHome !== undefined ? resolve(storeHome) : null;
|
|
348
|
+
const file = profileHome !== null
|
|
349
|
+
? await readClaudeProfileLogin(profileHome)
|
|
350
|
+
: await readClaudeCredentialsFile(process.env.CLAUDE_HOME || join(homedir(), ".claude"));
|
|
246
351
|
// Read before anything else: it costs one stat per instance, needs no token,
|
|
247
352
|
// and it is what keeps the panel useful when the API path cannot run at all.
|
|
248
|
-
|
|
249
|
-
|
|
353
|
+
// A profile's: only readings written under its own `projects/` — and only when nothing but its own login can
|
|
354
|
+
// have signed those instances in. Where the conversation is says which config dir, not whose subscription: with
|
|
355
|
+
// a token in the environment the readings may be another account's, so none is this row's (#1713 review).
|
|
356
|
+
const profilesRoot = resolve(getAgendHome(), "credential-profiles", "claude-code");
|
|
357
|
+
const statusline = profileHome !== null
|
|
358
|
+
? (envTokenReachesClaude() ? null : readStatuslineRateLimits(undefined, undefined, (path) => path !== null && isWithin(path, join(profileHome, "projects"))))
|
|
359
|
+
: readStatuslineRateLimits(undefined, undefined, scope.besideProfiles ? (path) => path === null || !isWithin(path, profilesRoot) : undefined);
|
|
360
|
+
const auth = profileHome !== null ? resolveClaudeAuth(file, {}, () => null) : resolveClaudeAuth(file);
|
|
250
361
|
if (auth === null) {
|
|
251
362
|
// No token anywhere — but the CLI itself is logged in somehow (including an
|
|
252
363
|
// API key, which the usage endpoint rejects outright), and it wrote its
|
|
253
364
|
// limits down. This is the case the whole statusline source exists for.
|
|
254
365
|
if (statusline)
|
|
255
366
|
return statuslineUsage(statusline, null);
|
|
367
|
+
if (profileHome !== null) {
|
|
368
|
+
// On screen (`ok`, as kiro's signed-out row), with what signs this profile in — never a fallback: from chat
|
|
369
|
+
// (`/login claude-code <profile>`, #1699 part 2), or the exact line on the host — the same words as the auth alert.
|
|
370
|
+
const host = (scope.profile && credentialProfileLoginCommand(getAgendHome(), "claude-code", scope.profile))
|
|
371
|
+
|| `CLAUDE_CONFIG_DIR=${JSON.stringify(profileHome)} claude auth login`;
|
|
372
|
+
if (scope.profile && CHAT_PROFILE_LOGIN_BACKENDS.has("claude-code")) {
|
|
373
|
+
const chat = `/login claude-code ${scope.profile}`;
|
|
374
|
+
return { status: "ok", hint: `Not logged in — sign in with \`${chat}\` (or run \`${host}\` on the host).`, hintI18n: i18n("usage.hint.claude_profile_signed_out_chat", chat, host), metrics: [] };
|
|
375
|
+
}
|
|
376
|
+
return { status: "ok", hint: `Not logged in — sign in with: ${host}`, hintI18n: i18n("usage.hint.claude_profile_signed_out", host), metrics: [] };
|
|
377
|
+
}
|
|
256
378
|
const hint = process.env.ANTHROPIC_API_KEY
|
|
257
379
|
? "API-key login has no subscription usage. Use `claude /login` or set CLAUDE_CODE_OAUTH_TOKEN (from `claude setup-token`)."
|
|
258
380
|
: "Log in with the Claude Code CLI (`claude`).";
|
|
@@ -427,42 +549,96 @@ function agyOAuthClient(env = process.env) {
|
|
|
427
549
|
/** Refreshed bearer, cached until shortly before expiry. The CLI's token file is
|
|
428
550
|
* never written back — it belongs to agy; refresh tokens are reusable. */
|
|
429
551
|
let agyTokenCache = null;
|
|
552
|
+
/** The summary's buckets, each tagged with its group's name. The top-level list (deprecated in the proto) only counts
|
|
553
|
+
* when no group carries any bucket. */
|
|
554
|
+
export function agyQuotaBuckets(body) {
|
|
555
|
+
const grouped = (body.groups ?? []).flatMap(g => (g.buckets ?? []).map(b => ({ ...b, group: g.displayName?.trim() || undefined })));
|
|
556
|
+
return grouped.length ? grouped : (body.buckets ?? []);
|
|
557
|
+
}
|
|
558
|
+
const AGY_POOLED = {
|
|
559
|
+
"gemini-5h": { pool: "Gemini", window: "session" },
|
|
560
|
+
"gemini-weekly": { pool: "Gemini", window: "weekly" },
|
|
561
|
+
"3p-5h": { pool: "Claude & others", window: "session" },
|
|
562
|
+
"3p-weekly": { pool: "Claude & others", window: "weekly" },
|
|
563
|
+
};
|
|
564
|
+
/** The pool a bucket belongs to: its group when the summary names one (#1898), else a guess from the bucket id. */
|
|
565
|
+
function agyPool(b, id) {
|
|
566
|
+
const pooled = AGY_POOLED[id];
|
|
567
|
+
if (pooled)
|
|
568
|
+
return pooled.pool;
|
|
569
|
+
const group = b.group;
|
|
570
|
+
if (group) {
|
|
571
|
+
if (/gemini/i.test(group))
|
|
572
|
+
return "Gemini";
|
|
573
|
+
if (/claude|gpt|third.?party|\b3p\b/i.test(group))
|
|
574
|
+
return "Claude & others";
|
|
575
|
+
return group;
|
|
576
|
+
}
|
|
577
|
+
return id.startsWith("gemini") ? "Gemini" : "Claude & others";
|
|
578
|
+
}
|
|
579
|
+
/** The limit a bucket counts against ("Five Hour Limit", window "5h" …), or null for a per-model bucket. */
|
|
580
|
+
function agyWindow(b, id) {
|
|
581
|
+
const pooled = AGY_POOLED[id];
|
|
582
|
+
if (pooled)
|
|
583
|
+
return pooled.window;
|
|
584
|
+
// One source at a time, the most specific first: the bucket's own window, then its id, then — only inside a named
|
|
585
|
+
// group, where a per-model name ("Gemini 2.5 High") cannot occur — its display name. A word that merely appears in an
|
|
586
|
+
// opaque id never overrides a window the bucket states.
|
|
587
|
+
for (const text of [b.window, id, b.group ? b.displayName : undefined]) {
|
|
588
|
+
const window = text ? agyWindowOf(text) : null;
|
|
589
|
+
if (window)
|
|
590
|
+
return window;
|
|
591
|
+
}
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
594
|
+
/** "5h", "5 h", "5-hour", "5_hours", "Five Hour Limit", "session" → session; "weekly", "7d", "7 days" → weekly. */
|
|
595
|
+
function agyWindowOf(text) {
|
|
596
|
+
if (/(^|[^0-9.])5[\s_-]*h(ours?|rs?)?\b|five[\s_-]*h(ours?|rs?)\b|\bsession\b/i.test(text))
|
|
597
|
+
return "session";
|
|
598
|
+
if (/week|(^|[^0-9.])7[\s_-]*d(ays?)?\b|seven[\s_-]*days?\b/i.test(text))
|
|
599
|
+
return "weekly";
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
function agyLabel(pool, window) {
|
|
603
|
+
if (pool === "Claude & others") {
|
|
604
|
+
return window === "session" ? { text: "Claude & others (session)", i18n: i18n("usage.metric.agy_claude_others_session") }
|
|
605
|
+
: window === "weekly" ? { text: "Claude & others (weekly)", i18n: i18n("usage.metric.agy_claude_others_weekly") }
|
|
606
|
+
: { text: pool, i18n: i18n("usage.metric.agy_claude_others") };
|
|
607
|
+
}
|
|
608
|
+
return window === "session" ? { text: `${pool} (session)`, i18n: i18n("usage.metric.named_session", pool) }
|
|
609
|
+
: window === "weekly" ? { text: `${pool} (weekly)`, i18n: i18n("usage.metric.named_weekly", pool) }
|
|
610
|
+
: { text: pool, i18n: i18n("usage.metric.named", pool) };
|
|
611
|
+
}
|
|
430
612
|
/**
|
|
431
|
-
* Pool the summary's buckets into
|
|
613
|
+
* Pool the summary's buckets into one metric per pool and limit.
|
|
432
614
|
*
|
|
433
|
-
*
|
|
434
|
-
* `gemini-weekly`, `3p-5h`, `3p-weekly`), which map 1:1
|
|
435
|
-
*
|
|
436
|
-
*
|
|
437
|
-
* Gemini
|
|
438
|
-
*
|
|
439
|
-
*
|
|
615
|
+
* Three payload shapes exist:
|
|
616
|
+
* - pooled ids (`gemini-5h`, `gemini-weekly`, `3p-5h`, `3p-weekly`), which map 1:1;
|
|
617
|
+
* - PER-MODEL buckets (`gemini-3.6-flash-high`, `claude-sonnet-4-6`, …), aggregated into a Gemini pool and an
|
|
618
|
+
* everything-else pool;
|
|
619
|
+
* - (#1898, agy 2026-10) named groups ("Gemini Models", "Claude and GPT Models") whose buckets are the group's
|
|
620
|
+
* five-hour and weekly limits. The group decides the pool; the bucket's window, id or name decides the limit.
|
|
621
|
+
*
|
|
622
|
+
* Every metric keeps the WORST remaining fraction of its buckets, because the binding constraint is the one that runs
|
|
623
|
+
* out first. Within one pool a bucket with a known limit is authoritative over per-model buckets; one pool never hides
|
|
624
|
+
* another. Disabled buckets (agy dims them, no number) are left out.
|
|
440
625
|
*/
|
|
441
626
|
export function agyPoolMetrics(buckets) {
|
|
442
|
-
const
|
|
443
|
-
"gemini-5h": { text: "Gemini (session)", i18n: i18n("usage.metric.named_session", "Gemini") },
|
|
444
|
-
"gemini-weekly": { text: "Gemini (weekly)", i18n: i18n("usage.metric.named_weekly", "Gemini") },
|
|
445
|
-
"3p-5h": { text: "Claude & others (session)", i18n: i18n("usage.metric.agy_claude_others_session") },
|
|
446
|
-
"3p-weekly": { text: "Claude & others (weekly)", i18n: i18n("usage.metric.agy_claude_others_weekly") },
|
|
447
|
-
};
|
|
448
|
-
const direct = [];
|
|
449
|
-
const pools = new Map();
|
|
627
|
+
const entries = new Map();
|
|
450
628
|
for (const b of buckets) {
|
|
451
|
-
|
|
629
|
+
const id = b.bucketId?.trim() || (b.group ? b.displayName?.trim() : undefined);
|
|
630
|
+
if (!id || b.disabled === true || typeof b.remainingFraction !== "number" || !Number.isFinite(b.remainingFraction))
|
|
452
631
|
continue;
|
|
632
|
+
const pool = agyPool(b, id);
|
|
633
|
+
const window = agyWindow(b, id);
|
|
634
|
+
const key = `${pool}\u0000${window ?? ""}`;
|
|
453
635
|
const reset = b.resetTime ?? null;
|
|
454
|
-
const
|
|
455
|
-
if (pooledLabel) {
|
|
456
|
-
direct.push({ label: pooledLabel.text, labelI18n: pooledLabel.i18n, type: "percent", used: (1 - b.remainingFraction) * 100, resetsAt: reset });
|
|
457
|
-
continue;
|
|
458
|
-
}
|
|
459
|
-
const pool = b.bucketId.startsWith("gemini") ? "Gemini" : "Claude & others";
|
|
460
|
-
const existing = pools.get(pool);
|
|
636
|
+
const existing = entries.get(key);
|
|
461
637
|
if (!existing) {
|
|
462
|
-
|
|
638
|
+
entries.set(key, { pool, window, fraction: b.remainingFraction, resetsAt: reset, models: 1 });
|
|
463
639
|
continue;
|
|
464
640
|
}
|
|
465
|
-
// Count every
|
|
641
|
+
// Count every bucket in the entry; track the worst separately. Replacing the
|
|
466
642
|
// whole entry on a new worst would restart the count at that bucket.
|
|
467
643
|
existing.models += 1;
|
|
468
644
|
if (b.remainingFraction < existing.fraction) {
|
|
@@ -470,22 +646,24 @@ export function agyPoolMetrics(buckets) {
|
|
|
470
646
|
existing.resetsAt = reset;
|
|
471
647
|
}
|
|
472
648
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
used: (1 -
|
|
482
|
-
resetsAt: p.resetsAt,
|
|
649
|
+
const limited = new Set([...entries.values()].filter(e => e.window).map(e => e.pool));
|
|
650
|
+
const order = (w) => (w === "session" ? 0 : w === "weekly" ? 1 : 2);
|
|
651
|
+
const pools = [...new Set([...entries.values()].map(e => e.pool))];
|
|
652
|
+
return [...entries.values()]
|
|
653
|
+
.filter(e => e.window || !limited.has(e.pool))
|
|
654
|
+
.sort((a, b) => pools.indexOf(a.pool) - pools.indexOf(b.pool) || order(a.window) - order(b.window))
|
|
655
|
+
.map(e => {
|
|
656
|
+
const label = agyLabel(e.pool, e.window);
|
|
657
|
+
const metric = { label: label.text, labelI18n: label.i18n, type: "percent", used: (1 - e.fraction) * 100, resetsAt: e.resetsAt };
|
|
483
658
|
// Which number this is: the highest usage across the pool's models. Without
|
|
484
659
|
// it a flat 0% right after a weekly rollover is indistinguishable from a
|
|
485
660
|
// broken reading — which is exactly how it was reported.
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
661
|
+
if (!e.window || e.models > 1) {
|
|
662
|
+
metric.note = `busiest of ${e.models} model${e.models === 1 ? "" : "s"}`;
|
|
663
|
+
metric.noteI18n = i18n(e.models === 1 ? "usage.note.busiest_model" : "usage.note.busiest_models", e.models);
|
|
664
|
+
}
|
|
665
|
+
return metric;
|
|
666
|
+
});
|
|
489
667
|
}
|
|
490
668
|
/**
|
|
491
669
|
* agy's token file, in either shape.
|
|
@@ -613,8 +791,7 @@ async function fetchAntigravityUsage() {
|
|
|
613
791
|
catch {
|
|
614
792
|
continue;
|
|
615
793
|
}
|
|
616
|
-
const
|
|
617
|
-
const metrics = agyPoolMetrics(buckets);
|
|
794
|
+
const metrics = agyPoolMetrics(agyQuotaBuckets(body ?? {}));
|
|
618
795
|
return metrics.length
|
|
619
796
|
? { status: "ok", plan: null, metrics }
|
|
620
797
|
: { status: "ok", plan: null, hint: "No quota information reported for this account.", hintI18n: i18n("usage.hint.no_quota"), metrics: [] };
|
|
@@ -1274,13 +1451,14 @@ export function providersForConfig(config, base = DEFAULT_PROVIDERS) {
|
|
|
1274
1451
|
rows.push({
|
|
1275
1452
|
id: provider.id,
|
|
1276
1453
|
name: provider.id === "codex" ? `${provider.name} (default)` : provider.name,
|
|
1277
|
-
|
|
1454
|
+
// Claude's shared row keeps its statusline fallback to the shared instances (#1699); others ignore the scope.
|
|
1455
|
+
fetch: () => provider.fetch(undefined, { besideProfiles: true }),
|
|
1278
1456
|
});
|
|
1279
1457
|
}
|
|
1280
1458
|
rows.push(...profiles.map(profile => ({
|
|
1281
1459
|
id: `${provider.id}:${profile}`,
|
|
1282
1460
|
name: `${provider.name} (${profile})`,
|
|
1283
|
-
fetch: () => provider.fetch(credentialProfileStoreHome(getAgendHome(), backendName, profile)),
|
|
1461
|
+
fetch: () => provider.fetch(credentialProfileStoreHome(getAgendHome(), backendName, profile), { profile }),
|
|
1284
1462
|
})));
|
|
1285
1463
|
return rows;
|
|
1286
1464
|
});
|
|
@@ -1302,7 +1480,7 @@ function hasEffectiveSharedBinding(config, backendName) {
|
|
|
1302
1480
|
const instances = config.instances ?? {};
|
|
1303
1481
|
let sawEffectiveBinding = false;
|
|
1304
1482
|
for (const instance of Object.values(instances)) {
|
|
1305
|
-
const backend = instance.backend ?? defaults
|
|
1483
|
+
const backend = instance.backend ?? defaultBackend(defaults);
|
|
1306
1484
|
if (backend !== backendName)
|
|
1307
1485
|
continue;
|
|
1308
1486
|
sawEffectiveBinding = true;
|
|
@@ -1313,12 +1491,20 @@ function hasEffectiveSharedBinding(config, backendName) {
|
|
|
1313
1491
|
// backend is this provider and no profile was configured. With no known
|
|
1314
1492
|
// binding at all, preserve the pre-profile shared-provider behaviour.
|
|
1315
1493
|
if (!sawEffectiveBinding) {
|
|
1316
|
-
if (defaults
|
|
1494
|
+
if (defaultBackend(defaults) === backendName && !instanceCredentialProfile(undefined, defaults, backendName))
|
|
1317
1495
|
return true;
|
|
1318
1496
|
return Object.keys(instances).length === 0;
|
|
1319
1497
|
}
|
|
1320
1498
|
return false;
|
|
1321
1499
|
}
|
|
1500
|
+
/**
|
|
1501
|
+
* The backend an instance without one runs: the fleet default, else Claude Code — as the fleet launches it
|
|
1502
|
+
* (fleet-manager's bindings). Claude Code is the backend instances most often leave unnamed, so without this a
|
|
1503
|
+
* Claude profile on such an instance had no row of its own (#1699).
|
|
1504
|
+
*/
|
|
1505
|
+
function defaultBackend(defaults) {
|
|
1506
|
+
return defaults?.backend ?? "claude-code";
|
|
1507
|
+
}
|
|
1322
1508
|
/** Profiles on effective bindings only (not dormant backend_options on another backend). */
|
|
1323
1509
|
function effectiveCredentialProfiles(config, backendName) {
|
|
1324
1510
|
if (!config)
|
|
@@ -1326,14 +1512,14 @@ function effectiveCredentialProfiles(config, backendName) {
|
|
|
1326
1512
|
const found = new Set();
|
|
1327
1513
|
const defaults = config.defaults;
|
|
1328
1514
|
for (const instance of Object.values(config.instances ?? {})) {
|
|
1329
|
-
const backend = instance.backend ?? defaults
|
|
1515
|
+
const backend = instance.backend ?? defaultBackend(defaults);
|
|
1330
1516
|
if (backend !== backendName)
|
|
1331
1517
|
continue;
|
|
1332
1518
|
const profile = bindingProfile(instance, defaults, backendName);
|
|
1333
1519
|
if (profile)
|
|
1334
1520
|
found.add(profile);
|
|
1335
1521
|
}
|
|
1336
|
-
if (Object.keys(config.instances ?? {}).length === 0 && defaults
|
|
1522
|
+
if (Object.keys(config.instances ?? {}).length === 0 && defaultBackend(defaults) === backendName) {
|
|
1337
1523
|
const profile = instanceCredentialProfile(undefined, defaults, backendName);
|
|
1338
1524
|
if (profile)
|
|
1339
1525
|
found.add(profile);
|
|
@@ -1387,6 +1573,8 @@ function usageBackendForProviderId(id) {
|
|
|
1387
1573
|
return "kiro-cli";
|
|
1388
1574
|
if (id === "codex")
|
|
1389
1575
|
return "codex";
|
|
1576
|
+
if (id === "claude")
|
|
1577
|
+
return "claude-code";
|
|
1390
1578
|
return null;
|
|
1391
1579
|
}
|
|
1392
1580
|
let PROVIDERS = DEFAULT_PROVIDERS;
|