acryl-cli-linux-x64 0.1.30 → 0.1.35
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/package.json +1 -1
- package/runtime/lib/bin.js +831 -220
- package/runtime/lib/index.js +831 -220
- package/runtime/lib/types/buildInfo.generated.d.ts +4 -0
- package/runtime/lib/types/tui/acrylMark.d.ts +14 -0
- package/runtime/lib/types/tui/actions.d.ts +8 -6
- package/runtime/lib/types/tui/auth-guidance.d.ts +0 -2
- package/runtime/lib/types/tui/login/LoginOverlay.d.ts +46 -11
- package/runtime/lib/types/tui/login/types.d.ts +5 -1
- package/runtime/lib/types/tui/modelProfile/ModelProfileOverlay.d.ts +55 -3
- package/runtime/lib/types/tui/modelProfile/types.d.ts +23 -0
- package/runtime/lib/types/tui/store.d.ts +10 -0
- package/runtime/node_modules/.modules.yaml +2 -2
- package/runtime/node_modules/.package-map.json +1 -1
- package/runtime/node_modules/@earendil-works/pi-ai/dist/auth/oauth/oauth-page.js +1 -1
- package/runtime/node_modules/acryl-control/package.json +1 -1
- package/runtime/node_modules/acryl-harness-runtime/lib/index.mjs +129 -2
- package/runtime/node_modules/acryl-harness-runtime/lib/types/acryl-home.d.ts +35 -0
- package/runtime/node_modules/acryl-harness-runtime/lib/types/index.d.ts +2 -0
- package/runtime/node_modules/acryl-harness-runtime/lib/types/session-bridge.d.ts +13 -0
- package/runtime/node_modules/acryl-harness-runtime/lib/types/session-log-exporter.d.ts +31 -0
- package/runtime/node_modules/acryl-harness-runtime/package.json +1 -1
- package/runtime/node_modules/acryl-harness-runtime/src/acryl-home.ts +50 -0
- package/runtime/node_modules/acryl-harness-runtime/src/index.ts +16 -0
- package/runtime/node_modules/acryl-harness-runtime/src/session-bridge.ts +24 -1
- package/runtime/node_modules/acryl-harness-runtime/src/session-log-exporter.ts +69 -0
- package/runtime/package.json +3 -1
- package/runtime/receipt.json +2 -2
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The compact ACRYL wordmark shown in the fixed header, next to the pet.
|
|
3
|
+
*
|
|
4
|
+
* This is the real pixelized brand wordmark (`assets/pixelized/`), rendered
|
|
5
|
+
* natively as half-block characters (each terminal row packs 2 pixel rows
|
|
6
|
+
* via \u2580/\u2584/\u2588) instead of downsampled or replaced with a different mark \u2014 54
|
|
7
|
+
* columns wide at the artwork's own resolution, not simplified. Generated
|
|
8
|
+
* from the SVG's rect grid and verified by printing it before wiring into
|
|
9
|
+
* the header \u2014 same proven-before-embedding convention as
|
|
10
|
+
* `yly/compile-sprites.mjs`.
|
|
11
|
+
* @module @tomowave/dsh-tui/tui/acrylMark
|
|
12
|
+
*/
|
|
13
|
+
/** The plain (uncolored) rows of the ACRYL mark \u2014 11 lines, 54 columns. */
|
|
14
|
+
export declare const ACRYL_MARK_ROWS: readonly string[];
|
|
@@ -42,26 +42,28 @@ export interface TuiActions {
|
|
|
42
42
|
logout(): void;
|
|
43
43
|
/** Close the `/login` overlay. */
|
|
44
44
|
closeLogin(): void;
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
/** Run the authorization flow for the selected provider (pi-ai OAuth). */
|
|
48
|
-
beginAuthorization(key: string): void;
|
|
45
|
+
/** Run the authorization flow for the selected provider (pi-ai OAuth). `method` defaults to the flow's first (its preferred) method when omitted. */
|
|
46
|
+
beginAuthorization(key: string, method?: string): void;
|
|
49
47
|
/** Answer the in-flight authorization prompt (typed text/secret, or a chosen option id). */
|
|
50
48
|
answerAuthorizationPrompt(value: string): void;
|
|
51
49
|
/** Close the `/model` overlay, discarding any in-progress edit. */
|
|
52
50
|
closeModelProfile(): void;
|
|
53
51
|
/** Return from the add/edit form to the provider list without saving. */
|
|
54
52
|
backToProviderList(): void;
|
|
55
|
-
/** Move the provider list's selection cursor. */
|
|
56
|
-
selectProvider(index: number): void;
|
|
57
53
|
/** Open a blank draft for a new custom provider. */
|
|
58
54
|
createProvider(): void;
|
|
55
|
+
/** Switch to `/model`'s custom-provider form directly, from wherever the caller is (e.g. `/login`'s provider list, which offers no custom-provider path of its own). */
|
|
56
|
+
addCustomProvider(): void;
|
|
59
57
|
/** Open an existing provider's stored profile for editing. */
|
|
60
58
|
editProvider(route: string): void;
|
|
59
|
+
/** Open `/model` and jump straight to editing this provider — the entry point `/login`'s provider list uses for an already-configured route, since it offers no edit/models path of its own. */
|
|
60
|
+
openProviderEditor(route: string): void;
|
|
61
61
|
/** Persist a draft via `ctx.settings`/`ctx.credentials`, then reload the list. */
|
|
62
62
|
saveProvider(draft: ProviderDraft): void;
|
|
63
63
|
/** Remove a provider's settings section and credential. */
|
|
64
64
|
deleteProvider(row: ProviderRow): void;
|
|
65
|
+
/** Remove only a draft's stored credential (both the `apiKeyEnv` reference and any `/login` record), keeping its settings profile (baseURL/api/models) intact. */
|
|
66
|
+
clearApiKey(draft: ProviderDraft): void;
|
|
65
67
|
/** Probe a draft's endpoint via `ctx.llm.discoverModels`. */
|
|
66
68
|
discoverModelsForDraft(draft: ProviderDraft): void;
|
|
67
69
|
/** Save `{provider, model}` as the Agent's default model selection. */
|
|
@@ -1,27 +1,62 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `/login` overlay:
|
|
3
|
-
* OpenAI Codex, GitHub Copilot, …)
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
2
|
+
* `/login` overlay: a pi.dev-style two-step sign-in flow over the
|
|
3
|
+
* `ctx.authorization` flows (Anthropic, OpenAI Codex, GitHub Copilot, …)
|
|
4
|
+
* registered by `dsh-llm-pi-ai`. Step one asks "sign in with an account"
|
|
5
|
+
* (OAuth) vs "sign in with an API key"; step two shows the fuzzy-searchable
|
|
6
|
+
* provider list for that method, filtered from the same flow list step one
|
|
7
|
+
* partitioned. If every registered flow only offers one of the two method
|
|
8
|
+
* types, step one is skipped automatically (there's nothing to choose).
|
|
9
|
+
* Selecting a provider and pressing enter runs its flow through
|
|
10
|
+
* `ctx.authorization.begin`, which drives pi-ai's own OAuth/API-key
|
|
11
|
+
* strategies and persists the grant. While a flow is running it may ask a
|
|
12
|
+
* question (a `select` account picker, a `secret` API-key field, or a
|
|
13
|
+
* `text` manual-code field) — the overlay renders that prompt inline and
|
|
14
|
+
* routes keystrokes to it until the flow settles.
|
|
9
15
|
* @module @tomowang/dsh-tui/tui/login/LoginOverlay
|
|
10
16
|
*/
|
|
11
|
-
import type { Component } from '@earendil-works/pi-tui';
|
|
17
|
+
import type { Component, TUI } from '@earendil-works/pi-tui';
|
|
12
18
|
import type { TuiActions } from '../actions.js';
|
|
13
19
|
import type { TuiStore } from '../store.js';
|
|
20
|
+
/** A non-secret reminder that replacing an API-key prompt will overwrite an existing stored key. */
|
|
21
|
+
export declare function formatStoredApiKeyHint(preview: string | undefined): string | undefined;
|
|
14
22
|
export declare class LoginOverlay implements Component {
|
|
23
|
+
private readonly tui;
|
|
15
24
|
private readonly store;
|
|
16
25
|
private readonly actions;
|
|
26
|
+
private step;
|
|
27
|
+
private authType;
|
|
28
|
+
private authTypeCursor;
|
|
29
|
+
private chooserSkipped;
|
|
30
|
+
private autoSkipChecked;
|
|
31
|
+
private listCursor;
|
|
32
|
+
private searchQuery;
|
|
17
33
|
private promptField;
|
|
18
34
|
private promptCursor;
|
|
19
|
-
constructor(store: TuiStore, actions: TuiActions);
|
|
35
|
+
constructor(tui: TUI, store: TuiStore, actions: TuiActions);
|
|
20
36
|
invalidate(): void;
|
|
21
|
-
|
|
37
|
+
/** See `ModelProfileOverlay.listWindow` — same overflow bug, same fix: a long provider list (~35 catalog entries) must never push the key-legend hint line past the bottom of the terminal. */
|
|
38
|
+
private listWindow;
|
|
39
|
+
/** The `[start, end)` slice of `count` items to show so `selected` stays visible within `maxVisible` rows, biased to keep it centered. */
|
|
40
|
+
private visibleRange;
|
|
41
|
+
/**
|
|
42
|
+
* The global one-line notice (`store.setNotice`), rendered inline here.
|
|
43
|
+
* `/login` runs as a full-screen overlay that paints over the whole
|
|
44
|
+
* terminal, so the notice dock underneath — where sign-in progress,
|
|
45
|
+
* success ("Signed in to X."), and failure text otherwise land — is
|
|
46
|
+
* completely hidden for as long as this overlay stays open. Surfacing it
|
|
47
|
+
* here is what makes an OAuth callback's result actually visible instead
|
|
48
|
+
* of the screen appearing to do nothing once the browser redirects back.
|
|
49
|
+
*/
|
|
50
|
+
private noticeLines;
|
|
51
|
+
/** Partition the loaded flows by method type, once, the first time they arrive; auto-advances past the chooser if only one type is on offer. */
|
|
52
|
+
private maybeAutoSkipChooser;
|
|
53
|
+
private filteredFlows;
|
|
54
|
+
private renderAuthTypeChooser;
|
|
55
|
+
private renderProviderList;
|
|
22
56
|
private renderPrompt;
|
|
23
57
|
render(_width: number): string[];
|
|
24
58
|
handleInput(data: string): void;
|
|
25
59
|
private handlePromptInput;
|
|
26
|
-
private
|
|
60
|
+
private handleAuthTypeChooserInput;
|
|
61
|
+
private handleProviderListInput;
|
|
27
62
|
}
|
|
@@ -18,6 +18,10 @@ export interface AuthorizationFlowRow {
|
|
|
18
18
|
readonly methods: readonly AuthorizationMethodRow[];
|
|
19
19
|
/** Whether an attempt is already running for this key. */
|
|
20
20
|
readonly inFlight: boolean;
|
|
21
|
+
/** Whether a credential is already stored for this flow's key — signed in and ready to use. */
|
|
22
|
+
readonly configured: boolean;
|
|
23
|
+
/** How the stored credential was obtained, or `undefined` when `configured` is false. */
|
|
24
|
+
readonly authMethod: 'oauth' | 'api-key' | undefined;
|
|
21
25
|
}
|
|
22
26
|
/** One choice offered by a `select` authorization prompt. */
|
|
23
27
|
export interface LoginPromptOption {
|
|
@@ -34,6 +38,7 @@ export type LoginPromptState = {
|
|
|
34
38
|
readonly kind: 'secret';
|
|
35
39
|
readonly message: string;
|
|
36
40
|
readonly placeholder?: string;
|
|
41
|
+
readonly storedApiKeyPreview?: string;
|
|
37
42
|
} | {
|
|
38
43
|
readonly kind: 'select';
|
|
39
44
|
readonly message: string;
|
|
@@ -43,7 +48,6 @@ export type LoginPromptState = {
|
|
|
43
48
|
export interface LoginOverlayState {
|
|
44
49
|
/** Joined flow list; `undefined` until the first load settles. */
|
|
45
50
|
readonly flows: readonly AuthorizationFlowRow[] | undefined;
|
|
46
|
-
readonly selected: number;
|
|
47
51
|
/** The flow being signed into right now (spinner), or undefined. */
|
|
48
52
|
readonly signingIn: string | undefined;
|
|
49
53
|
/** The prompt the running flow is waiting on, or undefined outside a flow. */
|
|
@@ -11,13 +11,20 @@
|
|
|
11
11
|
* — the direct equivalent of the old remount, just explicit.
|
|
12
12
|
* @module @tomowang/dsh-tui/tui/modelProfile/ModelProfileOverlay
|
|
13
13
|
*/
|
|
14
|
-
import type { Component } from '@earendil-works/pi-tui';
|
|
14
|
+
import type { Component, TUI } from '@earendil-works/pi-tui';
|
|
15
15
|
import type { TuiActions } from '../actions.js';
|
|
16
16
|
import type { TuiStore } from '../store.js';
|
|
17
17
|
export declare class ModelProfileOverlay implements Component {
|
|
18
|
+
private readonly tui;
|
|
18
19
|
private readonly store;
|
|
19
20
|
private readonly actions;
|
|
21
|
+
private mode;
|
|
22
|
+
private modelSearch;
|
|
23
|
+
private modelPickerCursor;
|
|
24
|
+
private providerSearch;
|
|
25
|
+
private providerCursor;
|
|
20
26
|
private confirmDelete;
|
|
27
|
+
private pendingShowModels;
|
|
21
28
|
private formKeySeen;
|
|
22
29
|
private route;
|
|
23
30
|
private displayName;
|
|
@@ -29,18 +36,63 @@ export declare class ModelProfileOverlay implements Component {
|
|
|
29
36
|
private focused;
|
|
30
37
|
private modelDraftId;
|
|
31
38
|
private modelSelected;
|
|
32
|
-
|
|
33
|
-
constructor(store: TuiStore, actions: TuiActions);
|
|
39
|
+
constructor(tui: TUI, store: TuiStore, actions: TuiActions);
|
|
34
40
|
invalidate(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Rows available for a scrollable list body: terminal height minus the
|
|
43
|
+
* lines every such screen spends on chrome (header/hint/notice/search —
|
|
44
|
+
* `chrome` lines, caller-counted since it varies by screen). Long catalogs
|
|
45
|
+
* (~35 providers, matching that many models) previously rendered every row
|
|
46
|
+
* unconditionally, pushing the key-legend hint line — the only place a
|
|
47
|
+
* shortcut is documented — past the bottom of the terminal, invisible
|
|
48
|
+
* without scrolling back. Every list-shaped view here windows around the
|
|
49
|
+
* current selection instead, so the hint line is always the last line
|
|
50
|
+
* printed and always fits on screen.
|
|
51
|
+
*/
|
|
52
|
+
private listWindow;
|
|
53
|
+
/** The `[start, end)` slice of `count` items to show so `selected` stays visible within `maxVisible` rows, biased to keep it centered. */
|
|
54
|
+
private visibleRange;
|
|
55
|
+
/**
|
|
56
|
+
* The global one-line notice (`store.setNotice`), rendered inline here.
|
|
57
|
+
* `/model` runs as a full-screen overlay that paints over the whole
|
|
58
|
+
* terminal, so the notice dock underneath — where "Saved X."/"Active model
|
|
59
|
+
* set to X." otherwise lands — is invisible for as long as this overlay
|
|
60
|
+
* stays open (e.g. right after `saveProvider` returns to the list view
|
|
61
|
+
* without closing the overlay). Surfacing it here is what makes a save
|
|
62
|
+
* actually visible as "done" instead of the screen looking unchanged.
|
|
63
|
+
*/
|
|
64
|
+
private noticeLines;
|
|
35
65
|
private textFields;
|
|
36
66
|
/** Reinitialize form-local state from the store's draft when `formKey` changes — the equivalent of the old `key={formKey}` remount. */
|
|
37
67
|
private syncFormState;
|
|
38
68
|
private buildDraft;
|
|
39
69
|
render(_width: number): string[];
|
|
70
|
+
private pickerItems;
|
|
71
|
+
private filteredPickerItems;
|
|
72
|
+
/**
|
|
73
|
+
* pi.dev's `/model` picker (see Image #45): a flat, fuzzy-searchable list of
|
|
74
|
+
* every model on a live (actually usable) route, not a per-provider drill-down.
|
|
75
|
+
* Provider add/edit/delete moves to a secondary `p` mode instead of being the
|
|
76
|
+
* default, since picking a model to make active is the far more common action.
|
|
77
|
+
*/
|
|
78
|
+
private renderModelPicker;
|
|
79
|
+
private handleModelPickerInput;
|
|
80
|
+
private filteredProviders;
|
|
40
81
|
private renderList;
|
|
41
82
|
private handleListInput;
|
|
42
83
|
private renderForm;
|
|
43
84
|
private handleFormInput;
|
|
85
|
+
/**
|
|
86
|
+
* No Tab-toggled focus, on purpose: a hidden "which of two things am I
|
|
87
|
+
* typing into right now" mode with no visible indicator (the earlier
|
|
88
|
+
* design) is exactly the kind of invisible-state bug already fixed
|
|
89
|
+
* elsewhere in this file. Instead the "Add id" field is *always* live —
|
|
90
|
+
* every printable key, paste, and left/right/backspace/delete/home/end
|
|
91
|
+
* goes there, full stop, since ↑/↓ are the only keys `miniTextFieldInput`
|
|
92
|
+
* never claims. That leaves ↑/↓ free to always drive the list selection
|
|
93
|
+
* (for removal) at the same time, with no mode switch and no key that can
|
|
94
|
+
* ever mean two different things depending on invisible state.
|
|
95
|
+
*/
|
|
44
96
|
private renderModelListEditor;
|
|
45
97
|
private addModel;
|
|
46
98
|
private handleModelListEditorInput;
|
|
@@ -5,6 +5,23 @@
|
|
|
5
5
|
* draft one add/edit form works with before a save round-trips it back.
|
|
6
6
|
* @module @tomowang/dsh-tui/tui/modelProfile/types
|
|
7
7
|
*/
|
|
8
|
+
/**
|
|
9
|
+
* The `apiKeyEnv` reference a provider route falls back to when its settings
|
|
10
|
+
* profile names none, e.g. `my-proxy` -> `MY_PROXY_API_KEY`. Shared between
|
|
11
|
+
* the overlay (recomputing it for a just-typed custom route before save) and
|
|
12
|
+
* the host wiring (deriving it for every already-configured row), so the
|
|
13
|
+
* naming rule lives in exactly one place.
|
|
14
|
+
*/
|
|
15
|
+
export declare function deriveApiKeyRef(route: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* A short, identifying (never full) preview of a stored secret — first 4 and
|
|
18
|
+
* last 4 characters, so the API-key field isn't blank-looking when a key is
|
|
19
|
+
* already set and the user can tell *which* key it is without ever seeing
|
|
20
|
+
* enough of it to be usable on its own. Short values (<= 10 chars, where that
|
|
21
|
+
* split would show most of the string anyway) mask everything but the first
|
|
22
|
+
* and last single character instead.
|
|
23
|
+
*/
|
|
24
|
+
export declare function maskKeyPreview(value: string): string;
|
|
8
25
|
/** One model entry within a provider's catalog. */
|
|
9
26
|
export interface ModelEntry {
|
|
10
27
|
readonly id: string;
|
|
@@ -41,6 +58,8 @@ export interface ProviderRow {
|
|
|
41
58
|
readonly baseURL: string | undefined;
|
|
42
59
|
readonly apiKeyRef: string;
|
|
43
60
|
readonly apiKeyConfigured: boolean;
|
|
61
|
+
/** How the credential behind `apiKeyConfigured` was obtained, or `undefined` when none is configured. */
|
|
62
|
+
readonly authMethod: 'oauth' | 'api-key' | undefined;
|
|
44
63
|
readonly models: readonly ModelEntry[];
|
|
45
64
|
/** Settings revision this row was read at; replayed as `expectedRevision` on write. */
|
|
46
65
|
readonly revision: number | undefined;
|
|
@@ -56,8 +75,12 @@ export interface ProviderDraft {
|
|
|
56
75
|
readonly baseURL: string;
|
|
57
76
|
readonly apiKeyRef: string;
|
|
58
77
|
readonly apiKeyConfigured: boolean;
|
|
78
|
+
/** How the credential behind `apiKeyConfigured` was obtained, or `undefined` when none is configured. */
|
|
79
|
+
readonly authMethod: 'oauth' | 'api-key' | undefined;
|
|
59
80
|
/** Local-only plaintext key entered in this session; empty means "keep current". */
|
|
60
81
|
readonly apiKeyDraft: string;
|
|
82
|
+
/** First/last few characters of the currently-stored key (e.g. `sk-p…9sZ4`), so the field isn't blank-looking when one is already set; `undefined` when none is configured. */
|
|
83
|
+
readonly apiKeyPreview: string | undefined;
|
|
61
84
|
readonly models: readonly ModelEntry[];
|
|
62
85
|
readonly revision: number | undefined;
|
|
63
86
|
}
|
|
@@ -151,6 +151,11 @@ export interface TuiState {
|
|
|
151
151
|
readonly stats: StatsSnapshot;
|
|
152
152
|
/** Current agent preset, or `undefined` when `ctx.agentPresets` isn't composed in this profile. */
|
|
153
153
|
readonly preset: PresetState | undefined;
|
|
154
|
+
/** Live override of the session's active provider/model set via `/model`; `undefined` until the first switch, so the status bar falls back to the mount-time default. */
|
|
155
|
+
readonly activeModel: {
|
|
156
|
+
readonly provider: string;
|
|
157
|
+
readonly model: string;
|
|
158
|
+
} | undefined;
|
|
154
159
|
/** The in-flight step's accumulated text, or `undefined` when nothing is currently streaming. */
|
|
155
160
|
readonly streaming: StreamingState | undefined;
|
|
156
161
|
/** Tool calls sent but not yet resolved by a `tool/result`, in call order. */
|
|
@@ -205,6 +210,11 @@ export declare class TuiStore {
|
|
|
205
210
|
setTitle(title: string | null | undefined): void;
|
|
206
211
|
setStats(stats: StatsSnapshot): void;
|
|
207
212
|
setPreset(preset: PresetState | undefined): void;
|
|
213
|
+
/** Record a live `/model` switch so the status bar reflects it immediately. */
|
|
214
|
+
setActiveModel(activeModel: {
|
|
215
|
+
provider: string;
|
|
216
|
+
model: string;
|
|
217
|
+
}): void;
|
|
208
218
|
private shellRunSeq;
|
|
209
219
|
/** Begin one local shell-escape run; its output accumulates via `appendShellOutput` until `finishShellRun` settles it into the transcript. */
|
|
210
220
|
startShellRun(command: string): number;
|
|
@@ -660,7 +660,7 @@
|
|
|
660
660
|
"eventsource-parser@3.1.1": {
|
|
661
661
|
"eventsource-parser": "private"
|
|
662
662
|
},
|
|
663
|
-
"@earendil-works/pi-ai@0.82.1(zod@4.4.3)": {
|
|
663
|
+
"@earendil-works/pi-ai@0.82.1(patch_hash=ef7e0dd0e86a1b21c8e64ec36c432a2a1512afb9819470c32a4cd19c322bdffe)(zod@4.4.3)": {
|
|
664
664
|
"@earendil-works/pi-ai": "private"
|
|
665
665
|
},
|
|
666
666
|
"@modelcontextprotocol/sdk@1.30.0(zod@4.4.3)": {
|
|
@@ -1699,7 +1699,7 @@
|
|
|
1699
1699
|
"packageManager": "pnpm@11.8.0",
|
|
1700
1700
|
"pendingBuilds": [],
|
|
1701
1701
|
"publicHoistPattern": [],
|
|
1702
|
-
"prunedAt": "
|
|
1702
|
+
"prunedAt": "Tue, 08 Sep 2026 14:35:40 GMT",
|
|
1703
1703
|
"registries": {
|
|
1704
1704
|
"default": "https://registry.npmjs.org/",
|
|
1705
1705
|
"@jsr": "https://npm.jsr.io/"
|