charness 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +3 -6
- package/DEVELOPMENT.md +15 -0
- package/README.md +111 -38
- package/SETUP.md +121 -16
- package/dist/adapters/adapterEventRouting.d.ts +2 -1
- package/dist/adapters/adapterEventRouting.d.ts.map +1 -1
- package/dist/adapters/adapterEventRouting.js +3 -0
- package/dist/adapters/adapterEventRouting.js.map +1 -1
- package/dist/adapters/adapterNames.d.ts +13 -0
- package/dist/adapters/adapterNames.d.ts.map +1 -1
- package/dist/adapters/adapterNames.js +16 -0
- package/dist/adapters/adapterNames.js.map +1 -1
- package/dist/adapters/backendUnavailableError.d.ts +11 -0
- package/dist/adapters/backendUnavailableError.d.ts.map +1 -0
- package/dist/adapters/backendUnavailableError.js +19 -0
- package/dist/adapters/backendUnavailableError.js.map +1 -0
- package/dist/adapters/claudeCliAdapter.d.ts +29 -6
- package/dist/adapters/claudeCliAdapter.d.ts.map +1 -1
- package/dist/adapters/claudeCliAdapter.js +70 -16
- package/dist/adapters/claudeCliAdapter.js.map +1 -1
- package/dist/adapters/claudeJsonStreamAdapter.d.ts +36 -3
- package/dist/adapters/claudeJsonStreamAdapter.d.ts.map +1 -1
- package/dist/adapters/claudeJsonStreamAdapter.js +93 -30
- package/dist/adapters/claudeJsonStreamAdapter.js.map +1 -1
- package/dist/adapters/createAdapter.d.ts +3 -14
- package/dist/adapters/createAdapter.d.ts.map +1 -1
- package/dist/adapters/createAdapter.js +9 -19
- package/dist/adapters/createAdapter.js.map +1 -1
- package/dist/adapters/openCodeAdapter.d.ts +140 -12
- package/dist/adapters/openCodeAdapter.d.ts.map +1 -1
- package/dist/adapters/openCodeAdapter.js +385 -119
- package/dist/adapters/openCodeAdapter.js.map +1 -1
- package/dist/apiErrorRetry.d.ts +70 -6
- package/dist/apiErrorRetry.d.ts.map +1 -1
- package/dist/apiErrorRetry.js +312 -34
- package/dist/apiErrorRetry.js.map +1 -1
- package/dist/apiRetryKick.d.ts +26 -1
- package/dist/apiRetryKick.d.ts.map +1 -1
- package/dist/apiRetryKick.js +41 -2
- package/dist/apiRetryKick.js.map +1 -1
- package/dist/bot.d.ts +2 -1
- package/dist/bot.d.ts.map +1 -1
- package/dist/bot.js +736 -184
- package/dist/bot.js.map +1 -1
- package/dist/cli/claudeProfiles.d.ts +1 -1
- package/dist/cli/claudeProfiles.js +1 -1
- package/dist/cli/hot.d.ts +7 -1
- package/dist/cli/hot.d.ts.map +1 -1
- package/dist/cli/hot.js +29 -3
- package/dist/cli/hot.js.map +1 -1
- package/dist/configDirFile.d.ts +73 -0
- package/dist/configDirFile.d.ts.map +1 -0
- package/dist/configDirFile.js +216 -0
- package/dist/configDirFile.js.map +1 -0
- package/dist/connectors/telegram/commands/autoContinueLimits.d.ts +2 -2
- package/dist/connectors/telegram/commands/autoContinueLimits.d.ts.map +1 -1
- package/dist/connectors/telegram/commands/autoContinueLimits.js +4 -4
- package/dist/connectors/telegram/commands/autoContinueLimits.js.map +1 -1
- package/dist/connectors/telegram/commands/backendSwitch.d.ts +25 -0
- package/dist/connectors/telegram/commands/backendSwitch.d.ts.map +1 -0
- package/dist/connectors/telegram/commands/backendSwitch.js +104 -0
- package/dist/connectors/telegram/commands/backendSwitch.js.map +1 -0
- package/dist/connectors/telegram/commands/callbackMessage.d.ts +12 -0
- package/dist/connectors/telegram/commands/callbackMessage.d.ts.map +1 -1
- package/dist/connectors/telegram/commands/callbackMessage.js +24 -0
- package/dist/connectors/telegram/commands/callbackMessage.js.map +1 -1
- package/dist/connectors/telegram/commands/callbackToast.d.ts +36 -0
- package/dist/connectors/telegram/commands/callbackToast.d.ts.map +1 -0
- package/dist/connectors/telegram/commands/callbackToast.js +83 -0
- package/dist/connectors/telegram/commands/callbackToast.js.map +1 -0
- package/dist/connectors/telegram/commands/claudeAccounts.d.ts +18 -0
- package/dist/connectors/telegram/commands/claudeAccounts.d.ts.map +1 -1
- package/dist/connectors/telegram/commands/claudeAccounts.js +220 -66
- package/dist/connectors/telegram/commands/claudeAccounts.js.map +1 -1
- package/dist/connectors/telegram/commands/displayModes.d.ts.map +1 -1
- package/dist/connectors/telegram/commands/displayModes.js +4 -2
- package/dist/connectors/telegram/commands/displayModes.js.map +1 -1
- package/dist/connectors/telegram/commands/fallbackChain.d.ts +5 -8
- package/dist/connectors/telegram/commands/fallbackChain.d.ts.map +1 -1
- package/dist/connectors/telegram/commands/fallbackChain.js +183 -193
- package/dist/connectors/telegram/commands/fallbackChain.js.map +1 -1
- package/dist/connectors/telegram/commands/limitsBoard.d.ts +40 -0
- package/dist/connectors/telegram/commands/limitsBoard.d.ts.map +1 -0
- package/dist/connectors/telegram/commands/limitsBoard.js +281 -0
- package/dist/connectors/telegram/commands/limitsBoard.js.map +1 -0
- package/dist/connectors/telegram/commands/modelPage.d.ts +130 -0
- package/dist/connectors/telegram/commands/modelPage.d.ts.map +1 -0
- package/dist/connectors/telegram/commands/modelPage.js +120 -0
- package/dist/connectors/telegram/commands/modelPage.js.map +1 -0
- package/dist/connectors/telegram/commands/modelProviders.d.ts +9 -1
- package/dist/connectors/telegram/commands/modelProviders.d.ts.map +1 -1
- package/dist/connectors/telegram/commands/modelProviders.js +203 -111
- package/dist/connectors/telegram/commands/modelProviders.js.map +1 -1
- package/dist/connectors/telegram/commands/stt.d.ts +32 -0
- package/dist/connectors/telegram/commands/stt.d.ts.map +1 -0
- package/dist/connectors/telegram/commands/stt.js +460 -0
- package/dist/connectors/telegram/commands/stt.js.map +1 -0
- package/dist/effortLevels.d.ts +57 -7
- package/dist/effortLevels.d.ts.map +1 -1
- package/dist/effortLevels.js +65 -9
- package/dist/effortLevels.js.map +1 -1
- package/dist/i18n/de.d.ts.map +1 -1
- package/dist/i18n/de.js +160 -17
- package/dist/i18n/de.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +160 -17
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +160 -17
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/fr.d.ts.map +1 -1
- package/dist/i18n/fr.js +160 -17
- package/dist/i18n/fr.js.map +1 -1
- package/dist/i18n/hi.d.ts.map +1 -1
- package/dist/i18n/hi.js +160 -17
- package/dist/i18n/hi.js.map +1 -1
- package/dist/i18n/ja.d.ts.map +1 -1
- package/dist/i18n/ja.js +160 -17
- package/dist/i18n/ja.js.map +1 -1
- package/dist/i18n/ka.d.ts.map +1 -1
- package/dist/i18n/ka.js +160 -17
- package/dist/i18n/ka.js.map +1 -1
- package/dist/i18n/pt.d.ts.map +1 -1
- package/dist/i18n/pt.js +160 -17
- package/dist/i18n/pt.js.map +1 -1
- package/dist/i18n/ru.d.ts.map +1 -1
- package/dist/i18n/ru.js +160 -17
- package/dist/i18n/ru.js.map +1 -1
- package/dist/i18n/uk.d.ts.map +1 -1
- package/dist/i18n/uk.js +160 -17
- package/dist/i18n/uk.js.map +1 -1
- package/dist/i18n/uz.d.ts.map +1 -1
- package/dist/i18n/uz.js +160 -17
- package/dist/i18n/uz.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +160 -17
- package/dist/i18n/zh.js.map +1 -1
- package/dist/installManager.d.ts +20 -4
- package/dist/installManager.d.ts.map +1 -1
- package/dist/installManager.js +82 -14
- package/dist/installManager.js.map +1 -1
- package/dist/instanceSettings.d.ts +52 -0
- package/dist/instanceSettings.d.ts.map +1 -0
- package/dist/instanceSettings.js +136 -0
- package/dist/instanceSettings.js.map +1 -0
- package/dist/pinnedStatus.d.ts +7 -1
- package/dist/pinnedStatus.d.ts.map +1 -1
- package/dist/pinnedStatus.js +1 -1
- package/dist/pinnedStatus.js.map +1 -1
- package/dist/requests/requestLedger.d.ts +8 -0
- package/dist/requests/requestLedger.d.ts.map +1 -1
- package/dist/requests/requestLedger.js +19 -1
- package/dist/requests/requestLedger.js.map +1 -1
- package/dist/scheduler/mcpSurface.js +4 -4
- package/dist/scheduler/mcpSurface.js.map +1 -1
- package/dist/shutdown.d.ts +14 -0
- package/dist/shutdown.d.ts.map +1 -1
- package/dist/shutdown.js +16 -0
- package/dist/shutdown.js.map +1 -1
- package/dist/state.d.ts +54 -2
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +62 -1
- package/dist/state.js.map +1 -1
- package/dist/stt/sttAutoInstall.d.ts +39 -0
- package/dist/stt/sttAutoInstall.d.ts.map +1 -0
- package/dist/stt/sttAutoInstall.js +158 -0
- package/dist/stt/sttAutoInstall.js.map +1 -0
- package/dist/stt/sttChildEnv.d.ts +11 -0
- package/dist/stt/sttChildEnv.d.ts.map +1 -0
- package/dist/stt/sttChildEnv.js +30 -0
- package/dist/stt/sttChildEnv.js.map +1 -0
- package/dist/stt/sttConfigEdit.d.ts +71 -0
- package/dist/stt/sttConfigEdit.d.ts.map +1 -0
- package/dist/stt/sttConfigEdit.js +144 -0
- package/dist/stt/sttConfigEdit.js.map +1 -0
- package/dist/stt/sttInstall.d.ts +147 -0
- package/dist/stt/sttInstall.d.ts.map +1 -0
- package/dist/stt/sttInstall.js +491 -0
- package/dist/stt/sttInstall.js.map +1 -0
- package/dist/stt/sttInstallEntry.d.ts +2 -0
- package/dist/stt/sttInstallEntry.d.ts.map +1 -0
- package/dist/stt/sttInstallEntry.js +31 -0
- package/dist/stt/sttInstallEntry.js.map +1 -0
- package/dist/stt/sttInstallReporter.d.ts +45 -0
- package/dist/stt/sttInstallReporter.d.ts.map +1 -0
- package/dist/stt/sttInstallReporter.js +57 -0
- package/dist/stt/sttInstallReporter.js.map +1 -0
- package/dist/stt/sttRuntime.d.ts +35 -0
- package/dist/stt/sttRuntime.d.ts.map +1 -0
- package/dist/stt/sttRuntime.js +73 -0
- package/dist/stt/sttRuntime.js.map +1 -0
- package/dist/stt/sttScreenPlan.d.ts +193 -0
- package/dist/stt/sttScreenPlan.d.ts.map +1 -0
- package/dist/stt/sttScreenPlan.js +541 -0
- package/dist/stt/sttScreenPlan.js.map +1 -0
- package/dist/stt/sttSettings.d.ts +201 -0
- package/dist/stt/sttSettings.d.ts.map +1 -0
- package/dist/stt/sttSettings.js +387 -0
- package/dist/stt/sttSettings.js.map +1 -0
- package/dist/stt/sttSidecarOwner.d.ts +115 -0
- package/dist/stt/sttSidecarOwner.d.ts.map +1 -0
- package/dist/stt/sttSidecarOwner.js +475 -0
- package/dist/stt/sttSidecarOwner.js.map +1 -0
- package/dist/stt/transcribeChain.d.ts +36 -0
- package/dist/stt/transcribeChain.d.ts.map +1 -0
- package/dist/stt/transcribeChain.js +42 -0
- package/dist/stt/transcribeChain.js.map +1 -0
- package/dist/types.d.ts +77 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/adapterSwitchSessionIds.d.ts +32 -0
- package/dist/utils/adapterSwitchSessionIds.d.ts.map +1 -0
- package/dist/utils/adapterSwitchSessionIds.js +44 -0
- package/dist/utils/adapterSwitchSessionIds.js.map +1 -0
- package/dist/utils/backendSwitchPlan.d.ts +63 -0
- package/dist/utils/backendSwitchPlan.d.ts.map +1 -0
- package/dist/utils/backendSwitchPlan.js +73 -0
- package/dist/utils/backendSwitchPlan.js.map +1 -0
- package/dist/utils/claudeAccountPickerPlan.d.ts +12 -1
- package/dist/utils/claudeAccountPickerPlan.d.ts.map +1 -1
- package/dist/utils/claudeAccountPickerPlan.js +20 -1
- package/dist/utils/claudeAccountPickerPlan.js.map +1 -1
- package/dist/utils/claudeTranscriptContent.d.ts +24 -0
- package/dist/utils/claudeTranscriptContent.d.ts.map +1 -0
- package/dist/utils/claudeTranscriptContent.js +107 -0
- package/dist/utils/claudeTranscriptContent.js.map +1 -0
- package/dist/utils/claudeUsage.d.ts +47 -8
- package/dist/utils/claudeUsage.d.ts.map +1 -1
- package/dist/utils/claudeUsage.js +76 -14
- package/dist/utils/claudeUsage.js.map +1 -1
- package/dist/utils/claudeUsageRefresher.d.ts +8 -1
- package/dist/utils/claudeUsageRefresher.d.ts.map +1 -1
- package/dist/utils/claudeUsageRefresher.js +9 -4
- package/dist/utils/claudeUsageRefresher.js.map +1 -1
- package/dist/utils/effortPickerPlan.d.ts +54 -0
- package/dist/utils/effortPickerPlan.d.ts.map +1 -0
- package/dist/utils/effortPickerPlan.js +56 -0
- package/dist/utils/effortPickerPlan.js.map +1 -0
- package/dist/utils/ensureSessionPlan.d.ts +20 -4
- package/dist/utils/ensureSessionPlan.d.ts.map +1 -1
- package/dist/utils/ensureSessionPlan.js +17 -4
- package/dist/utils/ensureSessionPlan.js.map +1 -1
- package/dist/utils/fallbackBridge.d.ts +6 -2
- package/dist/utils/fallbackBridge.d.ts.map +1 -1
- package/dist/utils/fallbackBridge.js +10 -3
- package/dist/utils/fallbackBridge.js.map +1 -1
- package/dist/utils/fallbackChain.d.ts +36 -0
- package/dist/utils/fallbackChain.d.ts.map +1 -1
- package/dist/utils/fallbackChain.js +65 -1
- package/dist/utils/fallbackChain.js.map +1 -1
- package/dist/utils/fallbackSwitchNotice.d.ts +41 -0
- package/dist/utils/fallbackSwitchNotice.d.ts.map +1 -0
- package/dist/utils/fallbackSwitchNotice.js +75 -0
- package/dist/utils/fallbackSwitchNotice.js.map +1 -0
- package/dist/utils/fileSendService.d.ts +33 -10
- package/dist/utils/fileSendService.d.ts.map +1 -1
- package/dist/utils/fileSendService.js +78 -27
- package/dist/utils/fileSendService.js.map +1 -1
- package/dist/utils/jsonStreamHost.d.ts +39 -0
- package/dist/utils/jsonStreamHost.d.ts.map +1 -1
- package/dist/utils/jsonStreamHost.js +60 -1
- package/dist/utils/jsonStreamHost.js.map +1 -1
- package/dist/utils/limitEpisodeRecovery.d.ts +16 -2
- package/dist/utils/limitEpisodeRecovery.d.ts.map +1 -1
- package/dist/utils/limitEpisodeRecovery.js +44 -3
- package/dist/utils/limitEpisodeRecovery.js.map +1 -1
- package/dist/utils/limitSettings.d.ts +25 -0
- package/dist/utils/limitSettings.d.ts.map +1 -0
- package/dist/utils/limitSettings.js +31 -0
- package/dist/utils/limitSettings.js.map +1 -0
- package/dist/utils/limitsBoardPlan.d.ts +52 -0
- package/dist/utils/limitsBoardPlan.d.ts.map +1 -0
- package/dist/utils/limitsBoardPlan.js +93 -0
- package/dist/utils/limitsBoardPlan.js.map +1 -0
- package/dist/utils/openCodeUsage.d.ts +93 -0
- package/dist/utils/openCodeUsage.d.ts.map +1 -0
- package/dist/utils/openCodeUsage.js +248 -0
- package/dist/utils/openCodeUsage.js.map +1 -0
- package/dist/utils/operatorSwitchPlan.d.ts +61 -0
- package/dist/utils/operatorSwitchPlan.d.ts.map +1 -0
- package/dist/utils/operatorSwitchPlan.js +32 -0
- package/dist/utils/operatorSwitchPlan.js.map +1 -0
- package/dist/utils/promptDelivery.d.ts +40 -0
- package/dist/utils/promptDelivery.d.ts.map +1 -1
- package/dist/utils/promptDelivery.js +31 -0
- package/dist/utils/promptDelivery.js.map +1 -1
- package/dist/utils/recvPreviewRedaction.d.ts +14 -4
- package/dist/utils/recvPreviewRedaction.d.ts.map +1 -1
- package/dist/utils/recvPreviewRedaction.js +19 -7
- package/dist/utils/recvPreviewRedaction.js.map +1 -1
- package/dist/utils/startupReadiness.d.ts +3 -3
- package/dist/utils/startupReadiness.d.ts.map +1 -1
- package/dist/utils/startupReadiness.js +2 -2
- package/dist/utils/startupReadiness.js.map +1 -1
- package/dist/utils/threadStatusReport.d.ts +3 -1
- package/dist/utils/threadStatusReport.d.ts.map +1 -1
- package/dist/utils/threadStatusReport.js +4 -3
- package/dist/utils/threadStatusReport.js.map +1 -1
- package/dist/utils/timezone.d.ts +23 -0
- package/dist/utils/timezone.d.ts.map +1 -1
- package/dist/utils/timezone.js +38 -0
- package/dist/utils/timezone.js.map +1 -1
- package/dist/utils/transcribeAudio.d.ts +25 -12
- package/dist/utils/transcribeAudio.d.ts.map +1 -1
- package/dist/utils/transcribeAudio.js +39 -21
- package/dist/utils/transcribeAudio.js.map +1 -1
- package/dist/utils/usageRefreshBudget.d.ts +9 -0
- package/dist/utils/usageRefreshBudget.d.ts.map +1 -0
- package/dist/utils/usageRefreshBudget.js +27 -0
- package/dist/utils/usageRefreshBudget.js.map +1 -0
- package/examples/.env.example +7 -3
- package/examples/docker-compose.yml +9 -7
- package/package.json +2 -1
- package/stt/gigaam_sidecar.py +800 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @description The USAGE of OpenCode providers signed in through a SUBSCRIPTION — what `/limits` and `/accounts` print
|
|
4
|
+
* beside an OpenCode provider the way they print a Claude account's windows. v1 knows one provider: `openai` signed in
|
|
5
|
+
* with a ChatGPT subscription (an `oauth` record in OpenCode's `auth.json`), read off
|
|
6
|
+
* `GET https://chatgpt.com/backend-api/wham/usage` — the endpoint the Codex CLI and ChatGPT's own settings page use. It
|
|
7
|
+
* has no published schema; the field names below (`rate_limit.primary_window` / `secondary_window`, each with
|
|
8
|
+
* `used_percent`, `limit_window_seconds`, `reset_after_seconds`, `reset_at`) come from third-party documentation of it
|
|
9
|
+
* (the codex-lb proxy's API reference), so the parser is tolerant and an unknown shape yields no windows — the row just
|
|
10
|
+
* has no usage. API-key providers and other subscriptions have no reader: they show their auth kind only.
|
|
11
|
+
*
|
|
12
|
+
* Like a Claude profile's usage (`claudeUsage.ts`): the stored token is used as is and NEVER refreshed here (OpenCode
|
|
13
|
+
* renews it; a bot-side refresh would race it) — a token past its expiry is not sent and marks the snapshot stale; the
|
|
14
|
+
* token is never logged. Snapshots reuse the Claude shape (`ClaudeUsageSnapshot`: the primary window is `session`, the
|
|
15
|
+
* secondary `weekly_all`), so `formatClaudeProfileUsageLines` renders them unchanged. Pure except
|
|
16
|
+
* {@link readOpenCodeCredentials} (one file read) and the injectable fetch.
|
|
17
|
+
*/
|
|
18
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
21
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
22
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
23
|
+
}
|
|
24
|
+
Object.defineProperty(o, k2, desc);
|
|
25
|
+
}) : (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
o[k2] = m[k];
|
|
28
|
+
}));
|
|
29
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
30
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
31
|
+
}) : function(o, v) {
|
|
32
|
+
o["default"] = v;
|
|
33
|
+
});
|
|
34
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
35
|
+
var ownKeys = function(o) {
|
|
36
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
37
|
+
var ar = [];
|
|
38
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
39
|
+
return ar;
|
|
40
|
+
};
|
|
41
|
+
return ownKeys(o);
|
|
42
|
+
};
|
|
43
|
+
return function (mod) {
|
|
44
|
+
if (mod && mod.__esModule) return mod;
|
|
45
|
+
var result = {};
|
|
46
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
47
|
+
__setModuleDefault(result, mod);
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
})();
|
|
51
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
+
exports.openCodeUsageReaders = exports.chatGptProviderId = exports.chatGptUsageEndpoint = void 0;
|
|
53
|
+
exports.parseOpenCodeCredentials = parseOpenCodeCredentials;
|
|
54
|
+
exports.readOpenCodeCredentials = readOpenCodeCredentials;
|
|
55
|
+
exports.parseChatGptUsageResponse = parseChatGptUsageResponse;
|
|
56
|
+
exports.fetchChatGptUsage = fetchChatGptUsage;
|
|
57
|
+
exports.createOpenCodeUsagePoller = createOpenCodeUsagePoller;
|
|
58
|
+
const fs = __importStar(require("fs"));
|
|
59
|
+
const claudeUsage_1 = require("./claudeUsage");
|
|
60
|
+
exports.chatGptUsageEndpoint = 'https://chatgpt.com/backend-api/wham/usage';
|
|
61
|
+
/** The OpenCode provider a ChatGPT subscription signs in to. */
|
|
62
|
+
exports.chatGptProviderId = 'openai';
|
|
63
|
+
/** A window up to this long counts as the short (5-hour) one, a longer window as the weekly one. */
|
|
64
|
+
const shortWindowMaxSeconds = 24 * 3600;
|
|
65
|
+
function checkIsRecord(value) {
|
|
66
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
67
|
+
}
|
|
68
|
+
function readAuthKind(type) {
|
|
69
|
+
if (type === 'oauth')
|
|
70
|
+
return 'subscription';
|
|
71
|
+
if (type === 'api')
|
|
72
|
+
return 'apiKey';
|
|
73
|
+
return 'unknown';
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* @description The providers of a parsed `auth.json` with their credential kind; a malformed entry is skipped, never
|
|
77
|
+
* thrown on. `null` when the document is not an object.
|
|
78
|
+
*/
|
|
79
|
+
function parseOpenCodeCredentials(authJson) {
|
|
80
|
+
if (!checkIsRecord(authJson))
|
|
81
|
+
return null;
|
|
82
|
+
const credentials = {};
|
|
83
|
+
for (const [providerId, entry] of Object.entries(authJson)) {
|
|
84
|
+
if (!checkIsRecord(entry))
|
|
85
|
+
continue;
|
|
86
|
+
credentials[providerId] = {
|
|
87
|
+
kind: readAuthKind(entry.type),
|
|
88
|
+
accessToken: typeof entry.access === 'string' && entry.access !== '' ? entry.access : null,
|
|
89
|
+
expiresAtMs: typeof entry.expires === 'number' ? entry.expires : null,
|
|
90
|
+
accountId: typeof entry.accountId === 'string' && entry.accountId !== '' ? entry.accountId : null,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return credentials;
|
|
94
|
+
}
|
|
95
|
+
/** @description {@link parseOpenCodeCredentials} of the file at `authFilePath`; `null` when it is missing or unreadable. */
|
|
96
|
+
function readOpenCodeCredentials(authFilePath) {
|
|
97
|
+
try {
|
|
98
|
+
return parseOpenCodeCredentials(JSON.parse(fs.readFileSync(authFilePath, 'utf8')));
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// ── the ChatGPT reader ──
|
|
105
|
+
/** The account id inside a ChatGPT access token (a JWT): the claim `chatgpt_account_id` under `https://api.openai.com/auth`. */
|
|
106
|
+
function readAccountIdFromJwt(accessToken) {
|
|
107
|
+
const payload = accessToken.split('.')[1];
|
|
108
|
+
if (payload === undefined)
|
|
109
|
+
return null;
|
|
110
|
+
try {
|
|
111
|
+
const claims = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
|
|
112
|
+
const auth = checkIsRecord(claims) ? claims['https://api.openai.com/auth'] : null;
|
|
113
|
+
return checkIsRecord(auth) && typeof auth.chatgpt_account_id === 'string' ? auth.chatgpt_account_id : null;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function clampPercent(value) {
|
|
120
|
+
return Math.max(0, Math.min(100, Math.round(value)));
|
|
121
|
+
}
|
|
122
|
+
/** A window's reset as an ISO instant: its own `reset_at` (Unix seconds), else `reset_after_seconds` from now. */
|
|
123
|
+
function readResetsAt(window, nowMs) {
|
|
124
|
+
if (typeof window.reset_at === 'number')
|
|
125
|
+
return new Date(window.reset_at * 1000).toISOString();
|
|
126
|
+
if (typeof window.reset_after_seconds === 'number')
|
|
127
|
+
return new Date(nowMs + window.reset_after_seconds * 1000).toISOString();
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* @description The windows of a ChatGPT usage response as Claude-shaped buckets. A window is the 5-hour `session` when
|
|
132
|
+
* its length (`limit_window_seconds`) is a day or less, else the weekly one; a window that names no length is read by
|
|
133
|
+
* its place (primary = 5-hour, secondary = weekly). An account with one window only (a weekly-only plan) yields that
|
|
134
|
+
* bucket. A body of another shape yields none.
|
|
135
|
+
*/
|
|
136
|
+
function parseChatGptUsageResponse(body, nowMs) {
|
|
137
|
+
const rateLimit = checkIsRecord(body) ? body.rate_limit : null;
|
|
138
|
+
if (!checkIsRecord(rateLimit))
|
|
139
|
+
return [];
|
|
140
|
+
const buckets = [];
|
|
141
|
+
for (const [field, placeKind] of [['primary_window', 'session'], ['secondary_window', 'weekly_all']]) {
|
|
142
|
+
const window = rateLimit[field];
|
|
143
|
+
if (!checkIsRecord(window) || typeof window.used_percent !== 'number')
|
|
144
|
+
continue;
|
|
145
|
+
const length = window.limit_window_seconds;
|
|
146
|
+
const kind = typeof length === 'number' ? (length <= shortWindowMaxSeconds ? 'session' : 'weekly_all') : placeKind;
|
|
147
|
+
if (buckets.some((bucket) => bucket.kind === kind))
|
|
148
|
+
continue;
|
|
149
|
+
buckets.push({ kind, percent: clampPercent(window.used_percent), resetsAt: readResetsAt(window, nowMs), scopeModel: null });
|
|
150
|
+
}
|
|
151
|
+
return buckets;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* @description One GET of the ChatGPT usage endpoint with the subscription's token and account id (the id off the record,
|
|
155
|
+
* else off the token). Never throws; the token never appears in the result.
|
|
156
|
+
*/
|
|
157
|
+
function fetchChatGptUsage(credential, options = {}) {
|
|
158
|
+
const accessToken = credential.accessToken ?? '';
|
|
159
|
+
const accountId = credential.accountId ?? readAccountIdFromJwt(accessToken);
|
|
160
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
161
|
+
return (0, claudeUsage_1.fetchUsageBuckets)({
|
|
162
|
+
url: exports.chatGptUsageEndpoint,
|
|
163
|
+
headers: {
|
|
164
|
+
Authorization: `Bearer ${accessToken}`,
|
|
165
|
+
Accept: 'application/json',
|
|
166
|
+
...(accountId === null ? {} : { 'ChatGPT-Account-Id': accountId }),
|
|
167
|
+
},
|
|
168
|
+
parse: (body) => parseChatGptUsageResponse(body, nowMs),
|
|
169
|
+
fetchImpl: options.fetchImpl,
|
|
170
|
+
timeoutMs: options.timeoutMs,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/** The subscription usage readers by provider id; a provider not here shows only its auth kind. */
|
|
174
|
+
exports.openCodeUsageReaders = {
|
|
175
|
+
[exports.chatGptProviderId]: (credential) => fetchChatGptUsage(credential),
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* @description The poller of OpenCode providers' usage. For each provider in `auth.json`: an API key or an unknown record
|
|
179
|
+
* is stored as its kind alone (no usage); a subscription with a reader is polled — an expired token is not sent and marks
|
|
180
|
+
* the snapshot stale, a failed poll keeps the last figures marked stale. A provider `auth.json` does not list (one
|
|
181
|
+
* enabled by an environment variable) is left as it is. A failure is logged once per change of its reason — a poll every
|
|
182
|
+
* ten minutes must not fill the log — and never reported to error tracking (nothing for us to fix).
|
|
183
|
+
*/
|
|
184
|
+
function createOpenCodeUsagePoller(deps) {
|
|
185
|
+
const now = deps.now ?? (() => Date.now());
|
|
186
|
+
const log = deps.log ?? ((line) => console.log(line));
|
|
187
|
+
const readers = deps.readers ?? exports.openCodeUsageReaders;
|
|
188
|
+
function saveIfChanged(providerId, previous, next) {
|
|
189
|
+
if (JSON.stringify(previous) !== JSON.stringify(next))
|
|
190
|
+
deps.saveRecord(providerId, next);
|
|
191
|
+
}
|
|
192
|
+
function logFailureOnce(providerId, previous, reason) {
|
|
193
|
+
if (previous?.usage?.isStale && previous.usage.error === reason)
|
|
194
|
+
return;
|
|
195
|
+
log(`[usage] OpenCode ${providerId}: usage unavailable (${reason})`);
|
|
196
|
+
}
|
|
197
|
+
async function pollSubscription(providerId, credential, previous) {
|
|
198
|
+
const reader = readers[providerId];
|
|
199
|
+
if (reader === undefined) {
|
|
200
|
+
saveIfChanged(providerId, previous, { authKind: 'subscription' });
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const markStale = (reason) => {
|
|
204
|
+
logFailureOnce(providerId, previous, reason);
|
|
205
|
+
saveIfChanged(providerId, previous, { authKind: 'subscription', usage: (0, claudeUsage_1.markClaudeUsageSnapshotStale)(previous?.usage, reason, now()) });
|
|
206
|
+
};
|
|
207
|
+
if (credential.accessToken === null) {
|
|
208
|
+
markStale('not signed in');
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (credential.expiresAtMs !== null && credential.expiresAtMs <= now()) {
|
|
212
|
+
markStale('token expired');
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const result = await reader(credential);
|
|
216
|
+
if (!result.ok) {
|
|
217
|
+
markStale(result.error);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
deps.saveRecord(providerId, { authKind: 'subscription', usage: (0, claudeUsage_1.mergeClaudeUsageSnapshot)(previous?.usage, result.buckets, 'api', now()) });
|
|
221
|
+
}
|
|
222
|
+
function checkNeedsPoll(previous, maxAgeMs) {
|
|
223
|
+
if (maxAgeMs === undefined || !previous?.usage || previous.usage.isStale)
|
|
224
|
+
return true;
|
|
225
|
+
return now() - Date.parse(previous.usage.fetchedAt) >= maxAgeMs;
|
|
226
|
+
}
|
|
227
|
+
async function refreshAll(options = {}) {
|
|
228
|
+
const credentials = deps.readCredentials();
|
|
229
|
+
if (credentials === null)
|
|
230
|
+
return;
|
|
231
|
+
await Promise.all(Object.entries(credentials).map(async ([providerId, credential]) => {
|
|
232
|
+
const previous = deps.getRecord(providerId);
|
|
233
|
+
try {
|
|
234
|
+
if (credential.kind !== 'subscription') {
|
|
235
|
+
saveIfChanged(providerId, previous, { authKind: credential.kind });
|
|
236
|
+
}
|
|
237
|
+
else if (checkNeedsPoll(previous, options.maxAgeMs)) {
|
|
238
|
+
await pollSubscription(providerId, credential, previous);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch (e) {
|
|
242
|
+
log(`[usage] OpenCode ${providerId}: usage poll threw: ${e instanceof Error ? e.message : String(e)}`);
|
|
243
|
+
}
|
|
244
|
+
}));
|
|
245
|
+
}
|
|
246
|
+
return { refreshAll };
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=openCodeUsage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openCodeUsage.js","sourceRoot":"","sources":["../../src/utils/openCodeUsage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description The pure decision behind the ONE switch path the operator's own picks share — a row of `/limits` or
|
|
3
|
+
* `/accounts`, a model page, `/accounts use`: given where the topic runs and where it was told to go, WHICH kind of
|
|
4
|
+
* move it is. `bot.ts` (`switchTopicByOperator`) makes the move; the screens only ask for it and word their toast
|
|
5
|
+
* from the outcome.
|
|
6
|
+
*/
|
|
7
|
+
import type { FallbackChainEntry } from './fallbackChain';
|
|
8
|
+
import type { BackendFamily } from './backendSwitchPlan';
|
|
9
|
+
/**
|
|
10
|
+
* How the topic gets to the picked rung:
|
|
11
|
+
* - `limitMove` — a usage-limit wait is armed: the pick is the limit move (the wait is dropped, the work continues,
|
|
12
|
+
* a conversation is handed over without the question);
|
|
13
|
+
* - `sameFamily` — the topic stays on the backend it runs (or has none, and a Claude account is only recorded for
|
|
14
|
+
* its next start): a Claude pick changes the account, an OpenCode pick the model — the conversation is kept;
|
|
15
|
+
* - `askFirst` — the other backend, with a conversation to hand over: the operator is asked first;
|
|
16
|
+
* - `switchNow` — the other backend with nothing to carry (or no agent yet): the target is started at once.
|
|
17
|
+
*/
|
|
18
|
+
export type OperatorSwitchRoute = 'limitMove' | 'sameFamily' | 'askFirst' | 'switchNow';
|
|
19
|
+
/**
|
|
20
|
+
* What a screen is told about a pick. `switched` carries the bot's own confirmation line (`text`) and where the topic runs now
|
|
21
|
+
* in words (`label`: `Claude «work» (sonnet)`, `OpenCode openai/gpt-5`), from which a screen words its short toast; `asked` means
|
|
22
|
+
* the hand-over question is already in the topic and nothing more is to be said; `refused` carries why nothing moved.
|
|
23
|
+
*/
|
|
24
|
+
export type OperatorSwitchOutcome = {
|
|
25
|
+
kind: 'switched';
|
|
26
|
+
text: string;
|
|
27
|
+
label: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'asked';
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'refused';
|
|
32
|
+
text: string;
|
|
33
|
+
};
|
|
34
|
+
export interface OperatorSwitchInput {
|
|
35
|
+
/** A usage-limit wait is armed for the topic. */
|
|
36
|
+
isUsageLimitWaitArmed: boolean;
|
|
37
|
+
/** The rung the topic runs on now; `null` for no agent, a shell, or an OpenCode on the server's default model. */
|
|
38
|
+
from: FallbackChainEntry | null;
|
|
39
|
+
to: FallbackChainEntry;
|
|
40
|
+
/** The backend family the topic's agent runs on; `null` for no agent or a shell. */
|
|
41
|
+
currentFamily: BackendFamily | null;
|
|
42
|
+
/** Whether the agent being left holds a conversation to hand over (only read when the families differ). */
|
|
43
|
+
hasConversation: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* The pick names another model of the SAME Claude account and that model is clear of the exhausted window (a Fable-only
|
|
46
|
+
* weekly limit does not stop `sonnet`): the work can continue on it, so with a wait armed the pick is the limit move.
|
|
47
|
+
*/
|
|
48
|
+
isPickBeyondLimit?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* @description The route of a pick, in this order:
|
|
52
|
+
* 1. a wait is armed and the pick leaves the account (Claude) / model (OpenCode) that hit the limit, or names a model of the
|
|
53
|
+
* same Claude account that the limit does not cover → `limitMove`; a pick still inside the limit's scope (another model
|
|
54
|
+
* under the same exhausted window) only changes the model and the wait stays;
|
|
55
|
+
* 2. the topic runs no agent of a family (nothing, a shell): a Claude pick is recorded for the next start
|
|
56
|
+
* (`sameFamily`), an OpenCode pick starts OpenCode on it (`switchNow`);
|
|
57
|
+
* 3. the topic runs the picked family → `sameFamily`;
|
|
58
|
+
* 4. otherwise the other backend: `askFirst` with a conversation, `switchNow` without.
|
|
59
|
+
*/
|
|
60
|
+
export declare function decideOperatorSwitch(input: OperatorSwitchInput): OperatorSwitchRoute;
|
|
61
|
+
//# sourceMappingURL=operatorSwitchPlan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operatorSwitchPlan.d.ts","sourceRoot":"","sources":["../../src/utils/operatorSwitchPlan.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;AAExF;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kHAAkH;IAClH,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAChC,EAAE,EAAE,kBAAkB,CAAC;IACvB,oFAAoF;IACpF,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IACpC,2GAA2G;IAC3G,eAAe,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,GAAG,mBAAmB,CAOpF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @description The pure decision behind the ONE switch path the operator's own picks share — a row of `/limits` or
|
|
4
|
+
* `/accounts`, a model page, `/accounts use`: given where the topic runs and where it was told to go, WHICH kind of
|
|
5
|
+
* move it is. `bot.ts` (`switchTopicByOperator`) makes the move; the screens only ask for it and word their toast
|
|
6
|
+
* from the outcome.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.decideOperatorSwitch = decideOperatorSwitch;
|
|
10
|
+
const fallbackChain_1 = require("./fallbackChain");
|
|
11
|
+
/**
|
|
12
|
+
* @description The route of a pick, in this order:
|
|
13
|
+
* 1. a wait is armed and the pick leaves the account (Claude) / model (OpenCode) that hit the limit, or names a model of the
|
|
14
|
+
* same Claude account that the limit does not cover → `limitMove`; a pick still inside the limit's scope (another model
|
|
15
|
+
* under the same exhausted window) only changes the model and the wait stays;
|
|
16
|
+
* 2. the topic runs no agent of a family (nothing, a shell): a Claude pick is recorded for the next start
|
|
17
|
+
* (`sameFamily`), an OpenCode pick starts OpenCode on it (`switchNow`);
|
|
18
|
+
* 3. the topic runs the picked family → `sameFamily`;
|
|
19
|
+
* 4. otherwise the other backend: `askFirst` with a conversation, `switchNow` without.
|
|
20
|
+
*/
|
|
21
|
+
function decideOperatorSwitch(input) {
|
|
22
|
+
const { from, to, currentFamily } = input;
|
|
23
|
+
const isLeavingLimitedRung = from === null || !(0, fallbackChain_1.checkIsSameFallbackAccount)(from, to);
|
|
24
|
+
if (input.isUsageLimitWaitArmed && currentFamily !== null && (isLeavingLimitedRung || input.isPickBeyondLimit === true))
|
|
25
|
+
return 'limitMove';
|
|
26
|
+
if (currentFamily === null)
|
|
27
|
+
return to.backend === 'claude' ? 'sameFamily' : 'switchNow';
|
|
28
|
+
if (currentFamily === to.backend)
|
|
29
|
+
return 'sameFamily';
|
|
30
|
+
return input.hasConversation ? 'askFirst' : 'switchNow';
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=operatorSwitchPlan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operatorSwitchPlan.js","sourceRoot":"","sources":["../../src/utils/operatorSwitchPlan.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAsDH,oDAOC;AA1DD,mDAA6D;AAyC7D;;;;;;;;;GASG;AACH,SAAgB,oBAAoB,CAAC,KAA0B;IAC7D,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAC1C,MAAM,oBAAoB,GAAG,IAAI,KAAK,IAAI,IAAI,CAAC,IAAA,0CAA0B,EAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACpF,IAAI,KAAK,CAAC,qBAAqB,IAAI,aAAa,KAAK,IAAI,IAAI,CAAC,oBAAoB,IAAI,KAAK,CAAC,iBAAiB,KAAK,IAAI,CAAC;QAAE,OAAO,WAAW,CAAC;IAC5I,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC;IACxF,IAAI,aAAa,KAAK,EAAE,CAAC,OAAO;QAAE,OAAO,YAAY,CAAC;IACtD,OAAO,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC;AAC1D,CAAC"}
|
|
@@ -43,4 +43,44 @@ export type PromptDelivery = 'forwarded' | 'buffered';
|
|
|
43
43
|
* buffered before the notice went out.
|
|
44
44
|
*/
|
|
45
45
|
export declare function deliverPromptOrBuffer(deps: PromptDeliveryDeps, key: SessionKey, text: string, isStarting: boolean, onBufferedSettled?: BufferedPromptSettled): Promise<PromptDelivery>;
|
|
46
|
+
/**
|
|
47
|
+
* @name LatePromptRoute
|
|
48
|
+
* @description How a prompt decided on when it ARRIVED is delivered once its handler is ready to forward it:
|
|
49
|
+
* `buffer` — a start or the idle stop is under way (its window is open: the prompt waits there, and the stop resumes the
|
|
50
|
+
* session for it); `wake` — the process is gone meanwhile (the conversation sleeps: wake it, then forward); `forward`.
|
|
51
|
+
*/
|
|
52
|
+
export type LatePromptRoute = 'buffer' | 'wake' | 'forward';
|
|
53
|
+
/**
|
|
54
|
+
* @description The {@link LatePromptRoute} of a prompt, read at the moment it is forwarded. The idle stop posts a
|
|
55
|
+
* re-asked question just before it stops the process, and a handler awaits between reading the session's state and the
|
|
56
|
+
* forward (the tap's toast, the request it opens): written into a process being stopped the prompt was lost, and
|
|
57
|
+
* into one already gone it was dropped.
|
|
58
|
+
*/
|
|
59
|
+
export declare function getLatePromptRoute(input: {
|
|
60
|
+
isWindowOpen: boolean;
|
|
61
|
+
isSessionActive: boolean;
|
|
62
|
+
}): LatePromptRoute;
|
|
63
|
+
/**
|
|
64
|
+
* @name LatePromptDeliveryPorts
|
|
65
|
+
* @description What {@link deliverLatePrompt} acts through, for one prompt: the session's state read NOW, and the three
|
|
66
|
+
* ways out. `reportNoSession` runs when the wake found nothing to resume (the ids released, the topic unbound, a start
|
|
67
|
+
* that failed): it tells the person, as the arrival-time paths do, and closes what the prompt opened.
|
|
68
|
+
*/
|
|
69
|
+
export interface LatePromptDeliveryPorts {
|
|
70
|
+
checkIsWindowOpen: () => boolean;
|
|
71
|
+
checkIsSessionActive: () => boolean;
|
|
72
|
+
buffer: () => Promise<void>;
|
|
73
|
+
/** Resume the sleeping conversation; `true` once a session is up to forward to. */
|
|
74
|
+
wake: () => Promise<boolean>;
|
|
75
|
+
forward: () => Promise<void>;
|
|
76
|
+
reportNoSession: () => Promise<void>;
|
|
77
|
+
}
|
|
78
|
+
/** @description Where {@link deliverLatePrompt} put the prompt; `noSession` — nowhere: nothing to deliver it to. */
|
|
79
|
+
export type LatePromptOutcome = 'buffered' | 'forwarded' | 'noSession';
|
|
80
|
+
/**
|
|
81
|
+
* @description Deliver a prompt whose handler decided, when it arrived, that the session is live — routed again by
|
|
82
|
+
* {@link getLatePromptRoute} now, after the handler's awaits. A wake that finds nothing never forwards: the forward
|
|
83
|
+
* would show the topic as working while the adapter drops the text.
|
|
84
|
+
*/
|
|
85
|
+
export declare function deliverLatePrompt(ports: LatePromptDeliveryPorts): Promise<LatePromptOutcome>;
|
|
46
86
|
//# sourceMappingURL=promptDelivery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promptDelivery.d.ts","sourceRoot":"","sources":["../../src/utils/promptDelivery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAE7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAEzF;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;IACtD,aAAa,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,cAAc,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,UAAU,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,kBAAkB,EACxB,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,OAAO,EACnB,iBAAiB,CAAC,EAAE,qBAAqB,GACxC,OAAO,CAAC,cAAc,CAAC,CAiBzB"}
|
|
1
|
+
{"version":3,"file":"promptDelivery.d.ts","sourceRoot":"","sources":["../../src/utils/promptDelivery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAE7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAEzF;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;IACtD,aAAa,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,cAAc,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,UAAU,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,kBAAkB,EACxB,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,OAAO,EACnB,iBAAiB,CAAC,EAAE,qBAAqB,GACxC,OAAO,CAAC,cAAc,CAAC,CAiBzB;AAED;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE5D;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IAAE,YAAY,EAAE,OAAO,CAAC;IAAC,eAAe,EAAE,OAAO,CAAA;CAAE,GAAG,eAAe,CAG9G;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,iBAAiB,EAAE,MAAM,OAAO,CAAC;IACjC,oBAAoB,EAAE,MAAM,OAAO,CAAC;IACpC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,mFAAmF;IACnF,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAED,oHAAoH;AACpH,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,CAAC;AAEvE;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAYlG"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.deliverPromptOrBuffer = deliverPromptOrBuffer;
|
|
4
|
+
exports.getLatePromptRoute = getLatePromptRoute;
|
|
5
|
+
exports.deliverLatePrompt = deliverLatePrompt;
|
|
4
6
|
const sessionKey_1 = require("../sessionKey");
|
|
5
7
|
const sessionKeyCodec_1 = require("../connectors/telegram/sessionKeyCodec");
|
|
6
8
|
/**
|
|
@@ -46,4 +48,33 @@ async function deliverPromptOrBuffer(deps, key, text, isStarting, onBufferedSett
|
|
|
46
48
|
}
|
|
47
49
|
return 'buffered';
|
|
48
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* @description The {@link LatePromptRoute} of a prompt, read at the moment it is forwarded. The idle stop posts a
|
|
53
|
+
* re-asked question just before it stops the process, and a handler awaits between reading the session's state and the
|
|
54
|
+
* forward (the tap's toast, the request it opens): written into a process being stopped the prompt was lost, and
|
|
55
|
+
* into one already gone it was dropped.
|
|
56
|
+
*/
|
|
57
|
+
function getLatePromptRoute(input) {
|
|
58
|
+
if (input.isWindowOpen)
|
|
59
|
+
return 'buffer';
|
|
60
|
+
return input.isSessionActive ? 'forward' : 'wake';
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* @description Deliver a prompt whose handler decided, when it arrived, that the session is live — routed again by
|
|
64
|
+
* {@link getLatePromptRoute} now, after the handler's awaits. A wake that finds nothing never forwards: the forward
|
|
65
|
+
* would show the topic as working while the adapter drops the text.
|
|
66
|
+
*/
|
|
67
|
+
async function deliverLatePrompt(ports) {
|
|
68
|
+
const route = getLatePromptRoute({ isWindowOpen: ports.checkIsWindowOpen(), isSessionActive: ports.checkIsSessionActive() });
|
|
69
|
+
if (route === 'buffer') {
|
|
70
|
+
await ports.buffer();
|
|
71
|
+
return 'buffered';
|
|
72
|
+
}
|
|
73
|
+
if (route === 'wake' && !(await ports.wake())) {
|
|
74
|
+
await ports.reportNoSession();
|
|
75
|
+
return 'noSession';
|
|
76
|
+
}
|
|
77
|
+
await ports.forward();
|
|
78
|
+
return 'forwarded';
|
|
79
|
+
}
|
|
49
80
|
//# sourceMappingURL=promptDelivery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promptDelivery.js","sourceRoot":"","sources":["../../src/utils/promptDelivery.ts"],"names":[],"mappings":";;AAgDA,sDAuBC;
|
|
1
|
+
{"version":3,"file":"promptDelivery.js","sourceRoot":"","sources":["../../src/utils/promptDelivery.ts"],"names":[],"mappings":";;AAgDA,sDAuBC;AAgBD,gDAGC;AA0BD,8CAYC;AAhID,8CAA6D;AAC7D,4EAA4E;AAuB5E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACI,KAAK,UAAU,qBAAqB,CACzC,IAAwB,EACxB,GAAe,EACf,IAAY,EACZ,UAAmB,EACnB,iBAAyC;IAEzC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACpC,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,IAAA,wBAAW,EAAC,GAAG,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC;IAChG,IAAI,eAAe,IAAI,IAAA,oCAAkB,EAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,sGAAsG;QACtG,sGAAsG;QACtG,gDAAgD;QAChD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,sCAAsC,IAAA,wBAAW,EAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAUD;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,KAA0D;IAC3F,IAAI,KAAK,CAAC,YAAY;QAAE,OAAO,QAAQ,CAAC;IACxC,OAAO,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;AACpD,CAAC;AAqBD;;;;GAIG;AACI,KAAK,UAAU,iBAAiB,CAAC,KAA8B;IACpE,MAAM,KAAK,GAAG,kBAAkB,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,iBAAiB,EAAE,EAAE,eAAe,EAAE,KAAK,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;IAC7H,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC;QACrB,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,IAAI,KAAK,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QAC9C,MAAM,KAAK,CAAC,eAAe,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;IACtB,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
/** Recorded instead of a pasted provider API key while `/connect` is pending. */
|
|
2
2
|
export declare const redactedConnectKeyPreview = "[redacted: provider API key]";
|
|
3
|
+
/** Recorded instead of a pasted speech-engine key while `/stt` waits for one. */
|
|
4
|
+
export declare const redactedSttKeyPreview = "[redacted: speech engine key]";
|
|
5
|
+
/**
|
|
6
|
+
* Recorded instead of a custom speech-engine address while `/stt` waits for one: an address may carry a login
|
|
7
|
+
* (`http://user:pass@host`), and the message is deleted from the topic for that reason.
|
|
8
|
+
*/
|
|
9
|
+
export declare const redactedSttAddressPreview = "[redacted: speech engine address]";
|
|
10
|
+
/** What `/stt` waits for as plain text: the next non-command message of the topic IS that secret-bearing input. */
|
|
11
|
+
export type SttAwaitedInputStep = 'url' | 'key';
|
|
3
12
|
/** Recorded instead of a `/connect …` invocation — its arguments may carry the key inline. */
|
|
4
13
|
export declare const redactedConnectCommandPreview = "/connect <redacted>";
|
|
5
14
|
/**
|
|
@@ -15,9 +24,10 @@ export declare function checkIsConnectCommandText(rawText: string): boolean;
|
|
|
15
24
|
* on-disk trace log. Mirrors the text handler's own routing: while the thread
|
|
16
25
|
* is in the pending `/connect` state, the next non-command text IS the pasted
|
|
17
26
|
* key → the preview is fully redacted (a command text cancels the flow instead,
|
|
18
|
-
* so it is not a secret).
|
|
19
|
-
*
|
|
20
|
-
*
|
|
27
|
+
* so it is not a secret). The same holds while `/stt` waits for a speech-engine
|
|
28
|
+
* key or for a custom server's address (it may carry a login). Independently of the pending state, an inline `/connect <key>` carries
|
|
29
|
+
* the key in its arguments → only a fixed command marker is recorded.
|
|
30
|
+
* Everything else records unchanged.
|
|
21
31
|
*/
|
|
22
|
-
export declare function getRecvTracePreview(messageText: string, isThreadPendingProviderConnect: boolean): string;
|
|
32
|
+
export declare function getRecvTracePreview(messageText: string, isThreadPendingProviderConnect: boolean, awaitedSttStep?: SttAwaitedInputStep | null): string;
|
|
23
33
|
//# sourceMappingURL=recvPreviewRedaction.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recvPreviewRedaction.d.ts","sourceRoot":"","sources":["../../src/utils/recvPreviewRedaction.ts"],"names":[],"mappings":"AAEA,iFAAiF;AACjF,eAAO,MAAM,yBAAyB,iCAAiC,CAAC;AAExE,8FAA8F;AAC9F,eAAO,MAAM,6BAA6B,wBAAwB,CAAC;AAEnE;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGlE;AAED
|
|
1
|
+
{"version":3,"file":"recvPreviewRedaction.d.ts","sourceRoot":"","sources":["../../src/utils/recvPreviewRedaction.ts"],"names":[],"mappings":"AAEA,iFAAiF;AACjF,eAAO,MAAM,yBAAyB,iCAAiC,CAAC;AAExE,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,kCAAkC,CAAC;AAErE;;;GAGG;AACH,eAAO,MAAM,yBAAyB,sCAAsC,CAAC;AAE7E,mHAAmH;AACnH,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,KAAK,CAAC;AAEhD,8FAA8F;AAC9F,eAAO,MAAM,6BAA6B,wBAAwB,CAAC;AAEnE;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGlE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,8BAA8B,EAAE,OAAO,EACvC,cAAc,GAAE,mBAAmB,GAAG,IAAW,GAChD,MAAM,CAOR"}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.redactedConnectCommandPreview = exports.redactedConnectKeyPreview = void 0;
|
|
3
|
+
exports.redactedConnectCommandPreview = exports.redactedSttAddressPreview = exports.redactedSttKeyPreview = exports.redactedConnectKeyPreview = void 0;
|
|
4
4
|
exports.checkIsConnectCommandText = checkIsConnectCommandText;
|
|
5
5
|
exports.getRecvTracePreview = getRecvTracePreview;
|
|
6
6
|
const utils_1 = require("../utils");
|
|
7
7
|
/** Recorded instead of a pasted provider API key while `/connect` is pending. */
|
|
8
8
|
exports.redactedConnectKeyPreview = '[redacted: provider API key]';
|
|
9
|
+
/** Recorded instead of a pasted speech-engine key while `/stt` waits for one. */
|
|
10
|
+
exports.redactedSttKeyPreview = '[redacted: speech engine key]';
|
|
11
|
+
/**
|
|
12
|
+
* Recorded instead of a custom speech-engine address while `/stt` waits for one: an address may carry a login
|
|
13
|
+
* (`http://user:pass@host`), and the message is deleted from the topic for that reason.
|
|
14
|
+
*/
|
|
15
|
+
exports.redactedSttAddressPreview = '[redacted: speech engine address]';
|
|
9
16
|
/** Recorded instead of a `/connect …` invocation — its arguments may carry the key inline. */
|
|
10
17
|
exports.redactedConnectCommandPreview = '/connect <redacted>';
|
|
11
18
|
/**
|
|
@@ -24,16 +31,21 @@ function checkIsConnectCommandText(rawText) {
|
|
|
24
31
|
* on-disk trace log. Mirrors the text handler's own routing: while the thread
|
|
25
32
|
* is in the pending `/connect` state, the next non-command text IS the pasted
|
|
26
33
|
* key → the preview is fully redacted (a command text cancels the flow instead,
|
|
27
|
-
* so it is not a secret).
|
|
28
|
-
*
|
|
29
|
-
*
|
|
34
|
+
* so it is not a secret). The same holds while `/stt` waits for a speech-engine
|
|
35
|
+
* key or for a custom server's address (it may carry a login). Independently of the pending state, an inline `/connect <key>` carries
|
|
36
|
+
* the key in its arguments → only a fixed command marker is recorded.
|
|
37
|
+
* Everything else records unchanged.
|
|
30
38
|
*/
|
|
31
|
-
function getRecvTracePreview(messageText, isThreadPendingProviderConnect) {
|
|
39
|
+
function getRecvTracePreview(messageText, isThreadPendingProviderConnect, awaitedSttStep = null) {
|
|
32
40
|
if (checkIsConnectCommandText(messageText))
|
|
33
41
|
return exports.redactedConnectCommandPreview;
|
|
34
|
-
|
|
42
|
+
const isPlainText = !messageText.trim().startsWith('/');
|
|
43
|
+
if (isThreadPendingProviderConnect && isPlainText)
|
|
35
44
|
return exports.redactedConnectKeyPreview;
|
|
36
|
-
|
|
45
|
+
if (awaitedSttStep === 'key' && isPlainText)
|
|
46
|
+
return exports.redactedSttKeyPreview;
|
|
47
|
+
if (awaitedSttStep === 'url' && isPlainText)
|
|
48
|
+
return exports.redactedSttAddressPreview;
|
|
37
49
|
return messageText;
|
|
38
50
|
}
|
|
39
51
|
//# sourceMappingURL=recvPreviewRedaction.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recvPreviewRedaction.js","sourceRoot":"","sources":["../../src/utils/recvPreviewRedaction.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"recvPreviewRedaction.js","sourceRoot":"","sources":["../../src/utils/recvPreviewRedaction.ts"],"names":[],"mappings":";;;AA0BA,8DAGC;AAaD,kDAWC;AArDD,oCAAkD;AAElD,iFAAiF;AACpE,QAAA,yBAAyB,GAAG,8BAA8B,CAAC;AAExE,iFAAiF;AACpE,QAAA,qBAAqB,GAAG,+BAA+B,CAAC;AAErE;;;GAGG;AACU,QAAA,yBAAyB,GAAG,mCAAmC,CAAC;AAK7E,8FAA8F;AACjF,QAAA,6BAA6B,GAAG,qBAAqB,CAAC;AAEnE;;;;;GAKG;AACH,SAAgB,yBAAyB,CAAC,OAAe;IACvD,MAAM,CAAC,WAAW,GAAG,EAAE,CAAC,GAAG,IAAA,8BAAsB,EAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAClF,OAAO,WAAW,KAAK,UAAU,CAAC;AACpC,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,mBAAmB,CACjC,WAAmB,EACnB,8BAAuC,EACvC,iBAA6C,IAAI;IAEjD,IAAI,yBAAyB,CAAC,WAAW,CAAC;QAAE,OAAO,qCAA6B,CAAC;IACjF,MAAM,WAAW,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACxD,IAAI,8BAA8B,IAAI,WAAW;QAAE,OAAO,iCAAyB,CAAC;IACpF,IAAI,cAAc,KAAK,KAAK,IAAI,WAAW;QAAE,OAAO,6BAAqB,CAAC;IAC1E,IAAI,cAAc,KAAK,KAAK,IAAI,WAAW;QAAE,OAAO,iCAAyB,CAAC;IAC9E,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -36,8 +36,8 @@ export interface ReadinessFacts {
|
|
|
36
36
|
hasBinding: boolean;
|
|
37
37
|
/** Installed agent CLIs among `claude` / `opencode` (empty ⇒ none installed). */
|
|
38
38
|
availableAgents: string[];
|
|
39
|
-
/**
|
|
40
|
-
|
|
39
|
+
/** At least one speech engine is available (optional — enables voice input). */
|
|
40
|
+
hasSpeechEngine: boolean;
|
|
41
41
|
/** `OWNER_USER_ID` is set. */
|
|
42
42
|
ownerSet: boolean;
|
|
43
43
|
/**
|
|
@@ -75,7 +75,7 @@ export declare function formatMissingRights(keys: BotRightKey[]): string;
|
|
|
75
75
|
*
|
|
76
76
|
* `isReady` is true iff NONE of the required items are unmet:
|
|
77
77
|
* groupPaired && all admin rights held && a binding exists && an agent CLI installed.
|
|
78
|
-
* The optional
|
|
78
|
+
* The optional speech-engine / owner items are informational — they populate `unmetKeys`
|
|
79
79
|
* (so they render inside a not-ready checklist) but never flip `isReady`.
|
|
80
80
|
*
|
|
81
81
|
* `grant_admin` is only unmet while a group IS paired (you cannot grant admin
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startupReadiness.d.ts","sourceRoot":"","sources":["../../src/utils/startupReadiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gFAAgF;AAChF,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE5D,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,aAAa,GACb,YAAY,GACZ,eAAe,GACf,eAAe,GACf,gBAAgB,CAAC;AAErB,yFAAyF;AACzF,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,WAAW,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;IACjC,mEAAmE;IACnE,UAAU,EAAE,OAAO,CAAC;IACpB,iFAAiF;IACjF,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,
|
|
1
|
+
{"version":3,"file":"startupReadiness.d.ts","sourceRoot":"","sources":["../../src/utils/startupReadiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gFAAgF;AAChF,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE5D,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,aAAa,GACb,YAAY,GACZ,eAAe,GACf,eAAe,GACf,gBAAgB,CAAC;AAErB,yFAAyF;AACzF,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,WAAW,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;IACjC,mEAAmE;IACnE,UAAU,EAAE,OAAO,CAAC;IACpB,iFAAiF;IACjF,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,gFAAgF;IAChF,eAAe,EAAE,OAAO,CAAC;IACzB,8BAA8B;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED,8DAA8D;AAC9D,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,OAAO,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,iFAAiF;IACjF,aAAa,EAAE,WAAW,EAAE,CAAC;CAC9B;AAoBD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAItD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,WAAW,EAAE,CAOhF;AAED,mFAAmF;AACnF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,CAE/D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,GAAG,eAAe,CAe3E;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE;IAClD,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG,OAAO,CAEV;AAED,uGAAuG;AACvG,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,OAAO,EACvB,gBAAgB,EAAE,OAAO,GACxB,aAAa,EAAE,CAQjB;AAED,0GAA0G;AAC1G,MAAM,MAAM,sBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC;AAE7F;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,sBAAsB,GAChC,MAAM,CAaR"}
|
|
@@ -69,7 +69,7 @@ function formatMissingRights(keys) {
|
|
|
69
69
|
*
|
|
70
70
|
* `isReady` is true iff NONE of the required items are unmet:
|
|
71
71
|
* groupPaired && all admin rights held && a binding exists && an agent CLI installed.
|
|
72
|
-
* The optional
|
|
72
|
+
* The optional speech-engine / owner items are informational — they populate `unmetKeys`
|
|
73
73
|
* (so they render inside a not-ready checklist) but never flip `isReady`.
|
|
74
74
|
*
|
|
75
75
|
* `grant_admin` is only unmet while a group IS paired (you cannot grant admin
|
|
@@ -86,7 +86,7 @@ function buildReadinessReport(facts) {
|
|
|
86
86
|
unmet.add('bind_topic');
|
|
87
87
|
if (facts.availableAgents.length === 0)
|
|
88
88
|
unmet.add('install_agent');
|
|
89
|
-
if (!facts.
|
|
89
|
+
if (!facts.hasSpeechEngine)
|
|
90
90
|
unmet.add('optional_groq');
|
|
91
91
|
if (!facts.ownerSet && facts.usedGeneralFallback)
|
|
92
92
|
unmet.add('optional_owner');
|