dsh-ssh-tui 0.6.2 → 0.6.4
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.en.md +67 -2
- package/README.md +56 -3
- package/lib/context-window.js +139 -0
- package/lib/context-window.js.map +1 -0
- package/lib/dialogs.js +13 -7
- package/lib/dialogs.js.map +1 -1
- package/lib/i18n/en.js +69 -3
- package/lib/i18n/en.js.map +1 -1
- package/lib/i18n/zh.js +69 -3
- package/lib/i18n/zh.js.map +1 -1
- package/lib/index.js +10 -4
- package/lib/index.js.map +1 -1
- package/lib/job-label.js +45 -0
- package/lib/job-label.js.map +1 -0
- package/lib/paint.js +3 -3
- package/lib/paint.js.map +1 -1
- package/lib/preset-label.js +73 -0
- package/lib/preset-label.js.map +1 -0
- package/lib/preset-rows.js +96 -0
- package/lib/preset-rows.js.map +1 -0
- package/lib/provider-catalog.js +12 -2
- package/lib/provider-catalog.js.map +1 -1
- package/lib/quota.js +149 -1
- package/lib/quota.js.map +1 -1
- package/lib/reasoning.js +9 -4
- package/lib/reasoning.js.map +1 -1
- package/lib/term-text.js +82 -11
- package/lib/term-text.js.map +1 -1
- package/lib/tool-present.js +14 -1
- package/lib/tool-present.js.map +1 -1
- package/lib/tui.js +363 -25
- package/lib/tui.js.map +1 -1
- package/lib/types/context-window.d.ts +46 -0
- package/lib/types/dialogs.d.ts +5 -4
- package/lib/types/job-label.d.ts +20 -0
- package/lib/types/preset-label.d.ts +38 -0
- package/lib/types/preset-rows.d.ts +47 -0
- package/lib/types/provider-catalog.d.ts +2 -0
- package/lib/types/quota.d.ts +49 -0
- package/lib/types/reasoning.d.ts +9 -4
- package/lib/types/term-text.d.ts +33 -4
- package/lib/types/tool-present.d.ts +1 -0
- package/lib/types/tui.d.ts +76 -1
- package/package.json +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route context-window sizing for hand-declared gateways.
|
|
3
|
+
*
|
|
4
|
+
* A gateway whose `GET /models` discloses no capacity leaves every model on the
|
|
5
|
+
* route at the harness default (262,144), so a long session compacts far
|
|
6
|
+
* earlier than the endpoint requires. `/setup` closes that gap from two
|
|
7
|
+
* sources, in order: the listing's own `context_length`, then the installed
|
|
8
|
+
* pi-ai catalog, which sizes 1,200-odd models under its own provider ids.
|
|
9
|
+
*
|
|
10
|
+
* A gateway id is rarely a catalog id verbatim — `gemini-claude-sonnet-4-6`
|
|
11
|
+
* proxies `claude-sonnet-4-6`, `deepseek/deepseek-v4.1-flash` is namespaced,
|
|
12
|
+
* `gemini-3.6-flash-high` names its thinking level — so the lookup normalizes
|
|
13
|
+
* before it matches, and reports nothing rather than guessing a window it
|
|
14
|
+
* never found.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-ssh-tui/context-window
|
|
17
|
+
*/
|
|
18
|
+
import type { CatalogPreset } from './provider-catalog.js';
|
|
19
|
+
/**
|
|
20
|
+
* Catalog ids to try for one gateway model id, most specific first.
|
|
21
|
+
* @param raw - the id the endpoint advertises.
|
|
22
|
+
* @returns lowercased candidates, deduplicated and order-preserving.
|
|
23
|
+
*/
|
|
24
|
+
export declare function catalogIdCandidates(raw: string): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Every catalog window, keyed by lowercased model id. The first provider to
|
|
27
|
+
* size an id wins, so a shared id keeps one stable answer.
|
|
28
|
+
* @param presets - the read catalog presets.
|
|
29
|
+
* @returns the lookup index.
|
|
30
|
+
*/
|
|
31
|
+
export declare function catalogWindowIndex(presets: readonly CatalogPreset[]): Map<string, number>;
|
|
32
|
+
/**
|
|
33
|
+
* The catalog window for one gateway model id.
|
|
34
|
+
* @param id - the id the endpoint advertises.
|
|
35
|
+
* @param index - {@link catalogWindowIndex} for the loaded catalog.
|
|
36
|
+
* @returns the window, or `undefined` when no candidate names a sized model.
|
|
37
|
+
*/
|
|
38
|
+
export declare function catalogContextWindow(id: string, index: ReadonlyMap<string, number>): number | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* The route-level default to persist: the smallest window discovered for the
|
|
41
|
+
* route's selected models. A model neither the listing nor the catalog sizes
|
|
42
|
+
* then inherits a value the route already proved it serves, never more.
|
|
43
|
+
* @param windows - the per-model windows discovered so far.
|
|
44
|
+
* @returns the window, or `undefined` when nothing was discovered.
|
|
45
|
+
*/
|
|
46
|
+
export declare function suggestedRouteContextWindow(windows: Iterable<number>): number | undefined;
|
package/lib/types/dialogs.d.ts
CHANGED
|
@@ -67,10 +67,11 @@ export type QuestionSubmit = {
|
|
|
67
67
|
kind: 'none';
|
|
68
68
|
};
|
|
69
69
|
/**
|
|
70
|
-
* What Enter means for a question dialog. A single-select list with
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
70
|
+
* What Enter means for a question dialog. A single-select list answers with the
|
|
71
|
+
* option its highlight sits on: the list opens on the first option, so Enter
|
|
72
|
+
* without arrowing answers that default instead of cancelling, and Esc stays the
|
|
73
|
+
* explicit cancel. A multi-select list may answer with an empty selection. With
|
|
74
|
+
* no options at all, the typed text is the answer.
|
|
74
75
|
*/
|
|
75
76
|
export declare function questionSubmit(dialog: QuestionDialog, input: string): QuestionSubmit;
|
|
76
77
|
/** y/n/ctrl-c/esc answers for a confirm prompt. */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Friendly display names for background jobs.
|
|
3
|
+
*
|
|
4
|
+
* `job_*` cards otherwise read as the raw tool vocabulary (`job_output`,
|
|
5
|
+
* `job_id: bash-1`), which is both untranslated and hard to talk about out
|
|
6
|
+
* loud. Each job id instead gets a two-word alias — "蔚蓝水獭", "azure otter" —
|
|
7
|
+
* derived from the id itself rather than from a random draw, so the same job
|
|
8
|
+
* keeps one name across its call card, its result card, and every later
|
|
9
|
+
* `job_output` / `job_kill` mention. The model-facing id stays authoritative;
|
|
10
|
+
* the alias is presentation only.
|
|
11
|
+
*
|
|
12
|
+
* @module dsh-ssh-tui/job-label
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* One stable alias for a background job, or `undefined` when the id is empty
|
|
16
|
+
* or the locale carries no vocabulary.
|
|
17
|
+
* @param jobId - the native job id (`bash-1`, `pwsh-2`, …).
|
|
18
|
+
* @returns the locale-formatted alias, e.g. `蔚蓝水獭` / `azure otter`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function jobAlias(jobId: string): string | undefined;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent-preset display names, and the profile row the terminal `/mode` needs.
|
|
3
|
+
*
|
|
4
|
+
* A shipped preset's name resolves through the id-keyed dictionary this module
|
|
5
|
+
* owns — the same rule `@deepseek-ai/dsh-agent-presets/display` applies on the
|
|
6
|
+
* browser surface — so `/language` reaches the picker, the banner, and
|
|
7
|
+
* `/status`. A user-authored preset keeps the name its own `preset.yml`
|
|
8
|
+
* published: that metadata is never translated.
|
|
9
|
+
*
|
|
10
|
+
* A terminal profile built on `dsh-base` composes no preset roster, and this
|
|
11
|
+
* plugin's own bundle patch may not mount one (DSH STORE accepts additive
|
|
12
|
+
* plugin-owned rows only), so the profile's user layer owns the row. When it is
|
|
13
|
+
* absent `/mode` reports the exact repair instead of a dead end.
|
|
14
|
+
* @module dsh-ssh-tui/preset-label
|
|
15
|
+
*/
|
|
16
|
+
/** Whether this id belongs to the shipped, translatable roster. */
|
|
17
|
+
export declare function isShippedPreset(id: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the name a picker, banner, or report renders for one preset.
|
|
20
|
+
*
|
|
21
|
+
* A published name equal to the id is the roster's own "no metadata" answer,
|
|
22
|
+
* not a name, so it falls through to the dictionary or back to the id.
|
|
23
|
+
* @param id - the preset id, also the last-resort label.
|
|
24
|
+
* @param name - display name the preset published, when it published one.
|
|
25
|
+
* @param trust - `user` keeps published metadata; anything else (including an
|
|
26
|
+
* unknown trust) resolves a shipped id through the dictionary.
|
|
27
|
+
* @returns the localized or published name, never empty.
|
|
28
|
+
*/
|
|
29
|
+
export declare function presetLabel(id: string, name?: string, trust?: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* The profile this process booted, from `--profile <name>` / `--profile=<name>`.
|
|
32
|
+
*
|
|
33
|
+
* The launcher passes the same arguments to the front end and to the Host it
|
|
34
|
+
* spawns (only `--resume`/`--new` are rewritten), so both report one profile.
|
|
35
|
+
* @param argv - the argument list to read.
|
|
36
|
+
* @returns the profile name, or the TUI's own default when none was named.
|
|
37
|
+
*/
|
|
38
|
+
export declare function profileFromArgv(argv?: readonly string[]): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The profile patch that mounts the agent-preset roster `/mode` needs.
|
|
3
|
+
*
|
|
4
|
+
* A terminal profile built on `dsh-base` composes no preset roster (only the
|
|
5
|
+
* Web bundle does), and this plugin's own bundle patch may not mount one: DSH
|
|
6
|
+
* STORE accepts additive rows with plugin-owned ids and no `@deepseek-ai/*`
|
|
7
|
+
* module names. The profile's user layer is the supported home for the row, so
|
|
8
|
+
* both the install script and the running TUI write the same block here — the
|
|
9
|
+
* TUI needs it because `dsh plugin add dsh-ssh-tui@latest` (the in-app update
|
|
10
|
+
* path) never runs `scripts/`, which npm installs do not ship.
|
|
11
|
+
*
|
|
12
|
+
* The roster is not cosmetic: without it `/mode` cannot switch, and the tools
|
|
13
|
+
* the shipped presets own (`ask_user_question`, `present`, PTC's presentation)
|
|
14
|
+
* are absent from the agent's catalog.
|
|
15
|
+
* @module dsh-ssh-tui/preset-rows
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* The exact profile patch block that mounts the roster and the two host
|
|
19
|
+
* services the shipped presets need. `scripts/ensure-profile-rows.sh` carries
|
|
20
|
+
* the same text; a test compares the two so they cannot drift.
|
|
21
|
+
*/
|
|
22
|
+
export declare const ROSTER_PATCH_BLOCK = "# dsh-ssh-tui /mode: the agent-preset roster (standard / minimal / PTC /\n# cordis, plus every preset under $DSH_HOME/.agent-presets) and the two host\n# services the shipped presets need. dsh-base composes no roster in a terminal\n# profile, and a third-party bundle patch may not mount an @deepseek-ai row, so\n# the profile's user layer owns them.\n- insert:\n - id: agent-presets\n name: '@deepseek-ai/dsh-agent-presets'\n config:\n default: standard\n\n - id: code-runtime\n name: '@deepseek-ai/dsh-code-runtime-worker-thread'\n\n - id: subagent-model-selection-settings\n name: '@deepseek-ai/dsh-tool-subagent/model-selection-settings'\n";
|
|
23
|
+
/** The profile patch file the roster block belongs in. */
|
|
24
|
+
export declare function rosterPatchPath(home: string, profile: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* The patch text with the roster block appended, or `undefined` when the file
|
|
27
|
+
* already names the roster row.
|
|
28
|
+
*
|
|
29
|
+
* A file that is exactly `[]` (the profile template) is replaced, so the result
|
|
30
|
+
* stays a valid top-level patch list; anything else keeps its content and the
|
|
31
|
+
* block is appended after a blank line.
|
|
32
|
+
* @param existing - the patch file's current text.
|
|
33
|
+
* @returns the new text, or `undefined` when nothing has to change.
|
|
34
|
+
*/
|
|
35
|
+
export declare function rosterPatchText(existing: string): string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Mount the roster in one profile, unless it is already composed.
|
|
38
|
+
*
|
|
39
|
+
* Idempotent: a profile whose patch already names the roster row (one bundling
|
|
40
|
+
* `@deepseek-ai/dsh-web-app`, for example) is left untouched. The write is a
|
|
41
|
+
* plain whole-file replace because the file is small and read once at boot; a
|
|
42
|
+
* half-written patch would only be seen by the next launch.
|
|
43
|
+
* @param home - the harness home carrying `profiles/`.
|
|
44
|
+
* @param profile - the profile to patch.
|
|
45
|
+
* @returns `present` when the row already exists, else `written`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function ensureRosterRows(home: string, profile: string): Promise<'present' | 'written'>;
|
|
@@ -3,6 +3,8 @@ export interface CatalogPreset {
|
|
|
3
3
|
name: string;
|
|
4
4
|
baseUrl: string;
|
|
5
5
|
modelIds: string[];
|
|
6
|
+
/** Context capacity the catalog records, by lowercased model id; absent when it sizes none. */
|
|
7
|
+
capacities?: Record<string, number>;
|
|
6
8
|
}
|
|
7
9
|
/** Filter presets by a case-insensitive substring match on id or name. */
|
|
8
10
|
export declare function filterCatalogPresets(presets: readonly CatalogPreset[], query: string): CatalogPreset[];
|
package/lib/types/quota.d.ts
CHANGED
|
@@ -27,6 +27,15 @@ export declare const OPENCODE_GO_USAGE_URL = "https://opencode.ai/zen/go/v1/usag
|
|
|
27
27
|
export declare const OPENCODE_ZEN_BASE_URL = "https://opencode.ai/zen/v1";
|
|
28
28
|
export declare const SUPERGROK_BILLING_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
|
|
29
29
|
export declare const DEEPSEEK_PUBLIC_BASE_URL = "https://api.deepseek.com";
|
|
30
|
+
/**
|
|
31
|
+
* Command Code's billing surface sits on the API root, not under the
|
|
32
|
+
* `/provider/v1` route its chat requests use, so these are fixed: a configured
|
|
33
|
+
* base URL only decides whether the canonical host is the right one to ask.
|
|
34
|
+
*/
|
|
35
|
+
export declare const COMMAND_CODE_BASE_URL = "https://api.commandcode.ai";
|
|
36
|
+
export declare const COMMAND_CODE_CREDITS_URL = "https://api.commandcode.ai/alpha/billing/credits";
|
|
37
|
+
export declare const COMMAND_CODE_SUBSCRIPTIONS_URL = "https://api.commandcode.ai/alpha/billing/subscriptions";
|
|
38
|
+
export declare const COMMAND_CODE_USAGE_URL = "https://api.commandcode.ai/alpha/usage/summary";
|
|
30
39
|
/** OpenAI-completions gateways: probe these relative to the configured base URL. */
|
|
31
40
|
export declare const OPENAI_COMPAT_BALANCE_PATHS: readonly ["/user/balance", "/dashboard/billing/credit_grants", "/v1/dashboard/billing/credit_grants", "/v1/dashboard/billing/subscription"];
|
|
32
41
|
/**
|
|
@@ -35,6 +44,23 @@ export declare const OPENAI_COMPAT_BALANCE_PATHS: readonly ["/user/balance", "/d
|
|
|
35
44
|
* routes are recognized by their `opencode.ai` base URL.
|
|
36
45
|
*/
|
|
37
46
|
export declare function openCodeSourceFor(provider: string, llmPiAiSection: unknown): OpenCodeSource | null;
|
|
47
|
+
/** A recognized Command Code route, used by the quota poller. */
|
|
48
|
+
export interface CommandCodeSource {
|
|
49
|
+
provider: string;
|
|
50
|
+
apiKeyEnv: string;
|
|
51
|
+
label: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Classify one route as Command Code's quota surface.
|
|
55
|
+
*
|
|
56
|
+
* Recognized by provider id or by a canonical base URL. The billing requests
|
|
57
|
+
* always target the canonical host, so a lookalike base URL never receives the
|
|
58
|
+
* credential even when the route keeps Command Code's provider id.
|
|
59
|
+
* @param provider - the selected provider route.
|
|
60
|
+
* @param llmPiAiSection - the `llm-pi-ai` settings section, if readable.
|
|
61
|
+
* @returns the credential reference to use, or `null` for another provider.
|
|
62
|
+
*/
|
|
63
|
+
export declare function commandCodeSourceFor(provider: string, llmPiAiSection: unknown): CommandCodeSource | null;
|
|
38
64
|
export type QuotaPeriod = 'hourly' | 'weekly' | 'monthly' | 'unknown';
|
|
39
65
|
export interface QuotaWindow {
|
|
40
66
|
label: string;
|
|
@@ -42,6 +68,8 @@ export interface QuotaWindow {
|
|
|
42
68
|
/** Remaining percent of the window (100 = unused). */
|
|
43
69
|
remainingPercent: number;
|
|
44
70
|
resetsAt?: string;
|
|
71
|
+
/** Extra human-readable fact beside the percent, e.g. remaining USD credits. */
|
|
72
|
+
detail?: string;
|
|
45
73
|
}
|
|
46
74
|
export interface QuotaSnapshot {
|
|
47
75
|
provider: string;
|
|
@@ -64,6 +92,27 @@ export declare function quotaRefreshEverySteps(window: QuotaWindow | undefined):
|
|
|
64
92
|
export declare const quotaRefreshEveryTurns: typeof quotaRefreshEverySteps;
|
|
65
93
|
export declare function parseSuperGrokBilling(payload: unknown): QuotaSnapshot;
|
|
66
94
|
export declare function parseOpenCodeGoQuota(payload: unknown, provider: string): QuotaSnapshot;
|
|
95
|
+
/** The billing-period start used to scope the spend query, when reported. */
|
|
96
|
+
export declare function commandCodePeriodStart(subscription: unknown): string | undefined;
|
|
97
|
+
export interface CommandCodeQuotaPayload {
|
|
98
|
+
/** Required `/alpha/billing/credits` reply. */
|
|
99
|
+
credits: unknown;
|
|
100
|
+
/** Optional `/alpha/billing/subscriptions` reply, for the plan and period. */
|
|
101
|
+
subscription?: unknown;
|
|
102
|
+
/** Optional `/alpha/usage/summary` reply, for period spend. */
|
|
103
|
+
summary?: unknown;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Parse Command Code's credits reply into the shared quota snapshot.
|
|
107
|
+
*
|
|
108
|
+
* The rolling five-hour and weekly windows report used/cap; the credit pool
|
|
109
|
+
* reports a remaining USD balance, which becomes a third window whose percent
|
|
110
|
+
* divides period spend by spend plus remaining balance.
|
|
111
|
+
* @param payload - the billing replies already fetched.
|
|
112
|
+
* @param provider - the route the snapshot is labeled with.
|
|
113
|
+
* @throws Error when no window could be read.
|
|
114
|
+
*/
|
|
115
|
+
export declare function parseCommandCodeQuota(payload: CommandCodeQuotaPayload, provider: string): QuotaSnapshot;
|
|
67
116
|
export declare function formatQuotaSnapshot(snapshot: QuotaSnapshot): string;
|
|
68
117
|
/** Compact `/status` quota line: tightest window first, then the rest. */
|
|
69
118
|
export declare function formatQuotaStatusLine(snapshot: QuotaSnapshot | undefined): string;
|
package/lib/types/reasoning.d.ts
CHANGED
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
* Shared reasoning-effort defaults for the SSH TUI.
|
|
3
3
|
*
|
|
4
4
|
* OpenCode / third-party (llm-pi-ai) routes carry no adapter-level reasoning
|
|
5
|
-
* default
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* needed to render the collapsible `思考中` block. This helper picks a
|
|
5
|
+
* default. Without an explicit effort the model streams its thinking as plain
|
|
6
|
+
* `text` chunks instead of `reasoning` blocks, so the TUI never receives the
|
|
7
|
+
* data needed to render the collapsible `思考中` block. This helper picks a
|
|
9
8
|
* supported default so the fold has data to show.
|
|
9
|
+
*
|
|
10
|
+
* `llm-deepseek` is not covered here: its adapter always reports a
|
|
11
|
+
* `defaultEffort`, which the LLM runtime materializes into the request on its
|
|
12
|
+
* own. Since the 0.5.1 STORE compliance trim dropped the bundle patch's
|
|
13
|
+
* `reasoningEffort: max` row override, that adapter default is `high` unless a
|
|
14
|
+
* deployment sets it (or `/effort` picks one, remembered per route).
|
|
10
15
|
*/
|
|
11
16
|
import { type LlmRuntime, type ReasoningEffortId } from '@deepseek-ai/dsh-llm';
|
|
12
17
|
/**
|
package/lib/types/term-text.d.ts
CHANGED
|
@@ -46,15 +46,44 @@ export declare function wrapWaitDetails(detail: string, width: number, maxLines?
|
|
|
46
46
|
* those ambiguous glyphs as two made `repeatToWidth('─', cols)` paint a
|
|
47
47
|
* half-width rule and parked the input cursor half a cell past the text.
|
|
48
48
|
*
|
|
49
|
-
* Emoji-bearing symbols are the exception: an emoji font draws
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* for the
|
|
49
|
+
* Emoji-bearing symbols are the exception: a terminal with an emoji font draws
|
|
50
|
+
* a symbol the monospace font lacks with a colour glyph that is wider than the
|
|
51
|
+
* cell it advances, so they are budgeted two cells. {@link pinEmojiCells} makes
|
|
52
|
+
* the terminal actually spend both: VS15 asks for the narrow text form, and a
|
|
53
|
+
* reserving space clears the second cell when the run does not already end in
|
|
54
|
+
* one. Budgeting two cells without clearing the second is what left `✖`
|
|
55
|
+
* overlapping the `|` beside it while every `▶` row came up a cell short.
|
|
53
56
|
*
|
|
54
57
|
* Overflow into the input box is handled by clipping/padding painted rows to
|
|
55
58
|
* the measured column count, not by inflating glyph width.
|
|
56
59
|
*/
|
|
57
60
|
export declare function displayWidth(text: string): number;
|
|
61
|
+
/**
|
|
62
|
+
* Make a painted row spend the two cells {@link displayWidth} budgets for every
|
|
63
|
+
* BMP emoji symbol.
|
|
64
|
+
*
|
|
65
|
+
* The monospace font of the terminal this was measured on covers `▶` but not
|
|
66
|
+
* `✖` or `ℹ`, so the two fall back to a colour emoji glyph about 1.6 cells wide
|
|
67
|
+
* while still advancing one cell: the `|` and `^` beside them were drawn under
|
|
68
|
+
* the glyph, and the row ended short because the second budgeted cell was never
|
|
69
|
+
* spent. The fix has two halves:
|
|
70
|
+
*
|
|
71
|
+
* - VS15 asks for the narrow text form (`emoji-variation-sequences.txt`,
|
|
72
|
+
* Unicode 17.0, lists `2139 FE0E` and `2716 FE0E` among 371 such sequences).
|
|
73
|
+
* Terminals that ignore it fall back to the colour glyph, which the next
|
|
74
|
+
* bullet still contains.
|
|
75
|
+
* - A reserving space supplies the second cell, always emitted even when the run
|
|
76
|
+
* already has one. That keeps the budget and the terminal in step for every
|
|
77
|
+
* shape: the table counts the symbol as two cells plus every space the text
|
|
78
|
+
* carries, and the terminal spends one cell of glyph advance, one for the
|
|
79
|
+
* reserving space, and one for each of those spaces.
|
|
80
|
+
*
|
|
81
|
+
* A symbol whose Unicode default presentation is emoji already advances two
|
|
82
|
+
* cells, so it is left untouched.
|
|
83
|
+
* @param text - one already-padded, already-clipped row.
|
|
84
|
+
* @returns the row with the text request and the second cell filled in.
|
|
85
|
+
*/
|
|
86
|
+
export declare function pinEmojiCells(text: string): string;
|
|
58
87
|
/** Pad or clip one already-sanitized line so it occupies exactly `width` cells. */
|
|
59
88
|
export declare function padToWidth(text: string, width: number): string;
|
|
60
89
|
/**
|
|
@@ -6,6 +6,7 @@ import { type TextSegment } from './term-text.js';
|
|
|
6
6
|
import type { DisplayKind, Row, ToolDiffHunk } from './transcript-types.js';
|
|
7
7
|
export declare const SHELL_TOOL_NAMES: Set<string>;
|
|
8
8
|
export declare const DIFF_TOOL_NAMES: Set<string>;
|
|
9
|
+
export declare const JOB_TOOL_NAMES: Set<string>;
|
|
9
10
|
/** Format a model list compactly: show the first few entries and an ellipsis. */
|
|
10
11
|
export declare function formatModelList(models: readonly string[], max?: number): string;
|
|
11
12
|
/** Prefer the fields a human scans for; fall back to the first scalar pairs. */
|
package/lib/types/tui.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export type { CollapsibleBlock, DisplayKind, DisconnectPolicyName, PlanTodoItem,
|
|
|
29
29
|
export { clipAnsiToWidth, cursorVisualPosition, displayWidth, foldInputView, hrefAtColumn, osc52Clipboard, osc8Enabled, paintedLinkHits, fmtElapsedCompact, padAnsiToWidth, padToWidth, renderMarkdownLines, repeatToWidth, shimmerText, truncateToWidth, visibleWidth, waitCardCopy, waitSummaryFromReasoning, wrapWaitDetails, } from './term-text.js';
|
|
30
30
|
export { captureHangupSignals, composePaintOutput, detectSshSession, formatLinkQualityChip, ignoreFurtherHangupSignals, isEscapePrefix, findCursorPositionReply, isHangupErrno, linkQualityOf, linkSignalPips, paintIntervalForRtt, paintLinkLabel, parseCursorPositionReply, pickerWindowStart, probeTerminalRttMs, releaseHangupSignals, resolvePaintIntervalMs, waitUntilIdleOrTimeout, writeBootSplash, type LinkQuality, type PaintLinkKind, } from './paint.js';
|
|
31
31
|
export { CONTEXT_IDLE_COMPACT_RATIO, CONTEXT_PRESSURE_DANGER_RATIO, CONTEXT_PRESSURE_WARN_RATIO, CONTEXT_RING_EMPTY, CONTEXT_RING_SEGMENTS, contextPressureAlertText, contextPressureRingColor, contextPressureUsedTokens, contextPressureView, describeProviderRoute, dropFooterQuotaPlanName, fitFooterStatsLine, fitFooterStatusLine, footerActivity, footerIdentityParts, footerStatsGroups, formatContextPressureChip, formatContextPressureRing, formatContextPressureStatusLine, formatDuration, formatFooterQuota, formatQuotaBar, formatStatusReport, formatTokens, formatTokensPerSecond, parseContextPressure, promptPressureTokens, providerShortCode, providerUsesLocalOAuth, shouldIdleAutoCompact, subagentRouteLabel, type ContextPressureSample, type ContextPressureView, type FooterActivityKind, type FooterStatsInput, type FooterStatusInput, type StatusReportInput, } from './footer.js';
|
|
32
|
-
export { crossedQuotaThresholds, formatAccountBalance, formatFooterBalance, formatOpenCodeGoUsage, formatQuotaSnapshot, formatQuotaStatusLine, joinUrl, openCodeSourceFor, parseDeepSeekBalance, parseOpenAiCompatibleBalance, parseOpenCodeGoQuota, parseSuperGrokBilling, quotaAlertText, quotaRefreshEverySteps, quotaRefreshEveryTurns, remainingPercentFromUsed, tightestQuotaWindow, type AccountBalanceLine, type AccountBalanceSnapshot, type OpenCodeFlavor, type OpenCodeSource, type QuotaPeriod, type QuotaSnapshot, type QuotaWindow, } from './quota.js';
|
|
32
|
+
export { commandCodePeriodStart, commandCodeSourceFor, crossedQuotaThresholds, formatAccountBalance, formatFooterBalance, formatOpenCodeGoUsage, formatQuotaSnapshot, formatQuotaStatusLine, joinUrl, openCodeSourceFor, parseCommandCodeQuota, parseDeepSeekBalance, parseOpenAiCompatibleBalance, parseOpenCodeGoQuota, parseSuperGrokBilling, quotaAlertText, quotaRefreshEverySteps, quotaRefreshEveryTurns, remainingPercentFromUsed, tightestQuotaWindow, type AccountBalanceLine, type AccountBalanceSnapshot, type CommandCodeSource, type OpenCodeFlavor, type OpenCodeSource, type QuotaPeriod, type QuotaSnapshot, type QuotaWindow, } from './quota.js';
|
|
33
33
|
export { commandAcceptsAttachments, forEachSessionEvent, isAssistantStreamEvent, isTokenDeltaChunk, listPersistenceHeaders, inspectPersistenceSession, sessionEventType, sessionEvents, settingsNamespace, streamChunkOf, streamFirstTokenTime, streamFrameAttemptId, streamFrameOwner, } from './dsh-compat.js';
|
|
34
34
|
export { applyTurnEndToPlan, askSummary, cardCategoryOf, compactionHeaderText, formatCompactCommandError, isPromptInjectionMessage, matchTranscriptRows, parseFindQuery, parsePlanTodos, planCloseNudgeText, planDockNote, planIsLive, planTitleFromMarkdown, planTurnLeftOpen, promptInjectionSources, promptInjectionTitle, subagentHeaderText, todoProgressLabel, todoSummary, type CardCategory, } from './plan.js';
|
|
35
35
|
export { buildToolHeader, canMergeToolCall, compactEditPath, compactToolBursts, compactToolGroups, countDiffAddDel, countDiffLines, countOutputLines, diffMetaDiffs, diffStatToken, friendlyJsonLines, parseExitStatus, presentToolCall, READ_TOOL_NAMES, renderToolDiff, toolBodyFitsWorkspace, toolBodyLines, toolStateColor, toolStateLabel, wrappedToolBodyLineCount, } from './tool-present.js';
|
|
@@ -63,6 +63,12 @@ export interface TuiConfig {
|
|
|
63
63
|
presetId?: string;
|
|
64
64
|
/** Display name of the active preset. */
|
|
65
65
|
presetName?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Trust of the root the active preset came from (`system`/`user`). A `user`
|
|
68
|
+
* preset keeps its own published name; a shipped one resolves through the
|
|
69
|
+
* locale dictionary.
|
|
70
|
+
*/
|
|
71
|
+
presetTrust?: string;
|
|
66
72
|
/** Notify the launcher of an explicit in-process selection change. */
|
|
67
73
|
onSelectionChanged?: (selection: ModelSelection) => void;
|
|
68
74
|
/**
|
|
@@ -88,6 +94,31 @@ export interface TuiController {
|
|
|
88
94
|
}
|
|
89
95
|
export type WorkspaceView = 'detailed' | 'compact';
|
|
90
96
|
export declare function parseDisconnectPolicy(raw: string): DisconnectPolicyName | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* The `reasoningEfforts` map `/setup` writes for a hand-declared
|
|
99
|
+
* OpenAI-compatible route.
|
|
100
|
+
*
|
|
101
|
+
* Such a route is absent from pi-ai's catalog, so `defaultReasoningEffort`
|
|
102
|
+
* resolves nothing before the profile is saved and the model would land as a
|
|
103
|
+
* bare `{ id }` entry. The Harness then reports that model as non-reasoning
|
|
104
|
+
* (`levels [off]`) and refuses every effort the TUI itself offers for an
|
|
105
|
+
* undeclared model. Declaring the offered vocabulary up front keeps the model
|
|
106
|
+
* dispatchable; no parameter is sent until an effort is selected.
|
|
107
|
+
* @returns the level-to-wire map, with `off` meaning "send no parameter".
|
|
108
|
+
*/
|
|
109
|
+
export declare function handDeclaredReasoningEfforts(): Record<string, string | null>;
|
|
110
|
+
/**
|
|
111
|
+
* The `reasoningEfforts` map `/setup` persists for one model entry.
|
|
112
|
+
*
|
|
113
|
+
* A hand-declared OpenAI-compatible completions route always receives the
|
|
114
|
+
* offered vocabulary; a catalog-backed route keeps whatever live model info
|
|
115
|
+
* resolved, preserving the existing behavior of redeclaring only the chosen
|
|
116
|
+
* default.
|
|
117
|
+
* @param providerType - the wizard template that produced the route.
|
|
118
|
+
* @param defaultEffort - the level resolved from live model info, if any.
|
|
119
|
+
* @returns the level-to-wire map, or `undefined` to declare nothing.
|
|
120
|
+
*/
|
|
121
|
+
export declare function onboardingReasoningEfforts(providerType: string, defaultEffort: string | undefined): Record<string, string | null> | undefined;
|
|
91
122
|
/** Parse `/effort high` / `/subeffort default`. Empty or unknown → undefined. */
|
|
92
123
|
export declare function parseEffortArg(raw: string): {
|
|
93
124
|
kind: 'default';
|
|
@@ -113,6 +144,8 @@ export declare class SshTui {
|
|
|
113
144
|
/** Web-aligned provider presets from the host's pi-ai catalog (undefined until loaded / when unreachable). */
|
|
114
145
|
private catalogPresets;
|
|
115
146
|
private catalogLoad;
|
|
147
|
+
/** Memoized id→window index over {@link catalogPresets}. */
|
|
148
|
+
private catalogWindows;
|
|
116
149
|
private input;
|
|
117
150
|
private cursor;
|
|
118
151
|
private inputFolded;
|
|
@@ -557,6 +590,20 @@ export declare class SshTui {
|
|
|
557
590
|
private runSubmodelCommand;
|
|
558
591
|
/** /effort: pick or set the reasoning effort for the current model. */
|
|
559
592
|
private runEffortCommand;
|
|
593
|
+
/**
|
|
594
|
+
* Persist one explicitly chosen level as a model's `reasoningEfforts`.
|
|
595
|
+
*
|
|
596
|
+
* `/effort` offers `low`…`max` for a model whose route declares nothing, but
|
|
597
|
+
* the selection alone cannot make the request legal: the Harness still
|
|
598
|
+
* resolves the model as non-reasoning and refuses it. Writing the chosen
|
|
599
|
+
* level — merged with whatever the entry already declares — keeps the
|
|
600
|
+
* selection and the declaration consistent. Only a route that explicitly
|
|
601
|
+
* speaks OpenAI Completions is amended: its dialect omits the parameter for
|
|
602
|
+
* `off` and was verified against a gateway, while another protocol may
|
|
603
|
+
* materialize an unset level as a value its endpoint refuses.
|
|
604
|
+
* @returns whether the entry now declares the level.
|
|
605
|
+
*/
|
|
606
|
+
private declareReasoningEffort;
|
|
560
607
|
private setReasoningEffort;
|
|
561
608
|
/** /subeffort: pick the reasoning effort subagent children use. */
|
|
562
609
|
private runSubeffortCommand;
|
|
@@ -568,12 +615,30 @@ export declare class SshTui {
|
|
|
568
615
|
private runDisconnectCommand;
|
|
569
616
|
/** /mode: pick an agent preset (standard / minimal / ptc / cordis / routing-suite / ...). */
|
|
570
617
|
private runModeCommand;
|
|
618
|
+
/**
|
|
619
|
+
* `/mode fix`: write the roster row into this profile's user patch layer.
|
|
620
|
+
*
|
|
621
|
+
* The write only takes effect on the next launch — the loader composes the
|
|
622
|
+
* patch tree once at boot — so the report says so instead of pretending the
|
|
623
|
+
* running session gained a roster.
|
|
624
|
+
*/
|
|
625
|
+
private repairRoster;
|
|
571
626
|
/** Current provider route selected for the running agent. */
|
|
572
627
|
private currentProvider;
|
|
573
628
|
/** Resolve one credential reference without exposing its value. */
|
|
574
629
|
private resolveCredential;
|
|
575
630
|
/** Query the OpenCode Go quota endpoint. */
|
|
576
631
|
private fetchOpenCodeGoUsage;
|
|
632
|
+
/**
|
|
633
|
+
* Command Code's quota: the rolling 5h/weekly windows and credit pool off
|
|
634
|
+
* `/alpha/billing/credits`, enriched by the subscription period and spend.
|
|
635
|
+
* Only the credits read is required; the two enrichment reads are
|
|
636
|
+
* best-effort so one failing endpoint cannot hide the windows.
|
|
637
|
+
* @param source - the recognized Command Code route.
|
|
638
|
+
*/
|
|
639
|
+
private fetchCommandCodeQuota;
|
|
640
|
+
/** Best-effort JSON read for quota enrichment; a failure leaves the field out. */
|
|
641
|
+
private tryFetchJson;
|
|
577
642
|
/** Explain Zen metered billing instead of pretending it has a quota. */
|
|
578
643
|
private zenUsageText;
|
|
579
644
|
/** /usage and /balance: remaining quota or prepaid balance for the current provider. */
|
|
@@ -600,6 +665,16 @@ export declare class SshTui {
|
|
|
600
665
|
*/
|
|
601
666
|
private mergedProviderEntries;
|
|
602
667
|
private moveProviderCursor;
|
|
668
|
+
/** The installed catalog's id→window index, built once per catalog load. */
|
|
669
|
+
private catalogWindowIndexSource;
|
|
670
|
+
/**
|
|
671
|
+
* Size the wizard's picked models from the installed catalog, filling in the
|
|
672
|
+
* capacities the endpoint's listing did not disclose and recording them on
|
|
673
|
+
* the wizard state so the saved entries carry them.
|
|
674
|
+
* @param state - the wizard state whose `models` are being sized.
|
|
675
|
+
* @returns the windows discovered for this pick, by model id.
|
|
676
|
+
*/
|
|
677
|
+
private sizeOnboardingModels;
|
|
603
678
|
private handleOnboardingChar;
|
|
604
679
|
private advanceOnboarding;
|
|
605
680
|
/** Fetch the endpoint's model list into the onboarding wizard's models step. */
|