@timurproko/a1 0.1.8-dev.518 → 0.1.8-dev.527
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -137
- package/dist/app/session-shell/session-shell-root.js +1 -1
- package/dist/app/session-shell/session-shell.d.ts +2 -2
- package/dist/app/session-shell/session-shell.js +9 -9
- package/dist/foundation/startup/startup-descriptor.js +2 -2
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +2 -1
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +19 -0
- package/dist/integrations/pi/components/shell-presenters-info.js +56 -2
- package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +6 -4
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +5 -4
- package/dist/integrations/pi/components/skills-dialog.js +15 -5
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +2 -2
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +2 -2
- package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
- package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/daxnuts.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/daxnuts.js +1 -1
- package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +2 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +7 -2
- package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/session-footer.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector.d.ts +8 -6
- package/dist/integrations/pi/components/upstream/components/session-selector.js +75 -49
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +18 -10
- package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +3 -3
- package/dist/integrations/pi/components/upstream/components/status-indicator.js +8 -8
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +3 -1
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.js +8 -7
- package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
- package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
- package/dist/integrations/pi/components/upstream/history/text-helpers.d.ts +3 -0
- package/dist/integrations/pi/components/upstream/history/text-helpers.js +4 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
- package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
- package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme.js +1 -1
- package/dist/integrations/pi/engine/index.d.ts +1 -1
- package/dist/integrations/pi/engine/index.js +1 -1
- package/dist/integrations/pi/engine/pi-settings-metadata.json +12 -0
- package/dist/integrations/pi/engine/resources/changelog.json +4 -4
- package/dist/integrations/pi/engine/settings-bridge.d.ts +1 -1
- package/dist/integrations/pi/engine/settings-bridge.js +2 -0
- package/dist/integrations/pi/engine/settings-port.js +11 -1
- package/dist/integrations/pi/engine/usage-view.js +1 -1
- package/dist/integrations/pi/engine/workflow-runner.js +4 -1
- package/dist/integrations/pi/engine/workflow-support.d.ts +6 -1
- package/dist/integrations/pi/engine/workflow-support.js +36 -2
- package/dist/integrations/pi/engine/workflows.d.ts +36 -3
- package/dist/integrations/pi/engine/workflows.js +8 -0
- package/dist/integrations/pi/startup-public.js +1001 -976
- package/dist/integrations/pi/startup-public.manifest.json +1846 -1672
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +7 -1
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/runtime-payload-inventory.json +41121 -34266
- package/docs/architecture/toolchain.md +2 -0
- package/docs/ci-release-runbook.md +32 -24
- package/docs/openspec-archive-automation.md +2 -2
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -45,97 +45,6 @@ a1 pi # vanilla Pi oracle: ~/.pi/agent
|
|
|
45
45
|
Unsupported commands exit quietly without launching anything. The removed
|
|
46
46
|
`update:<preview>` forms are not aliases; use `update --develop`.
|
|
47
47
|
|
|
48
|
-
## Agent input
|
|
49
|
-
|
|
50
|
-
The agent prompt and Settings search share one input component: neutral white
|
|
51
|
-
bars and an undimmed arrow matching submitted prompts. Thinking-level color is
|
|
52
|
-
shown on the level name in the status bar, not on the input bars.
|
|
53
|
-
|
|
54
|
-
In bare A1, **Ctrl+L cycles the thinking level**. **Shift+Tab is unassigned** and
|
|
55
|
-
performs no agent-input action, including while a suggestion is visible. Model
|
|
56
|
-
selection has **no default shortcut**; use `/models`. Explicit keybinding overrides
|
|
57
|
-
remain configurable, and `/hotkeys` shows the resolved bindings. The `a1 pi`
|
|
58
|
-
comparison profile keeps its original presentation and shortcuts.
|
|
59
|
-
|
|
60
|
-
## Models
|
|
61
|
-
|
|
62
|
-
Bare A1 has one model command, `/models`, which replaces the pinned `/model` and
|
|
63
|
-
`/scoped-models` pair (those remain in the `a1 pi` comparison profile). The dialog
|
|
64
|
-
lists every authenticated model with `all` and `scoped` filters (Tab), a search box,
|
|
65
|
-
a scope marker before each model id, and the active checkmark after `[provider]`.
|
|
66
|
-
Enter switches to the highlighted model and persists it as the default; Space adds or
|
|
67
|
-
removes it from the Ctrl+P cycling scope for this session only; Ctrl+S saves that scope
|
|
68
|
-
to settings. While the scope or its order differs from the last save, the title reads
|
|
69
|
-
`Models (unsaved)`; Escape closes without saving and keeps the session-only scope.
|
|
70
|
-
`/models <text>` seeds the search instead of switching. The bulk, provider, and reorder
|
|
71
|
-
scope actions keep their existing bindings and appear under `/hotkeys`.
|
|
72
|
-
|
|
73
|
-
## Reference screens
|
|
74
|
-
|
|
75
|
-
In bare A1, `/changelog` and `/hotkeys` open a full-screen read-only reference
|
|
76
|
-
screen over the session instead of appending a long document to the
|
|
77
|
-
conversation: `What's New` shows the complete pinned changelog and
|
|
78
|
-
`Keyboard Shortcuts` shows the bare-A1 keybinding tables, including extension
|
|
79
|
-
shortcuts as bound when the screen opens. Scroll with ↑/↓, PageUp/PageDown,
|
|
80
|
-
Home/End, the mouse wheel, or the scrollbar rail, which follows the
|
|
81
|
-
`/settings` → Scroll appearance, style, and speed; press `Esc` to close. The
|
|
82
|
-
screen is framed between two border-coloured rules with the hint below, as the
|
|
83
|
-
v2 extension drew it. After
|
|
84
|
-
an upgrade, the release notes newer than the last acknowledged version open the
|
|
85
|
-
same `What's New` screen once at startup while the feed keeps only the
|
|
86
|
-
`Run /changelog to view the full release notes.` hint. If another dialog is up
|
|
87
|
-
at that moment, the screen is not opened for that launch. The `a1 pi`
|
|
88
|
-
comparison profile keeps Pi's in-feed changelog and hotkeys documents.
|
|
89
|
-
|
|
90
|
-
## Prompt suggestions
|
|
91
|
-
|
|
92
|
-
Bare A1's `/settings` → Agent → Prompt suggestions controls faint next-prompt
|
|
93
|
-
predictions. It is enabled by default and uses one additional background request
|
|
94
|
-
with the selected model for eligible turns. Disabling it takes effect immediately.
|
|
95
|
-
Tab accepts a suggestion as editable text; Enter submits it afterward. The setting
|
|
96
|
-
remains stored in A1's profile, and `a1 pi` is unchanged.
|
|
97
|
-
|
|
98
|
-
Suggestions use the selected model's lowest supported reasoning effort without
|
|
99
|
-
changing your main thinking level. Clear next actions such as `archive it` are
|
|
100
|
-
preferred when consistent with your intent; genuinely unclear cases can remain
|
|
101
|
-
empty. [Private diagnostic capture](docs/architecture/prompt-suggestions.md)
|
|
102
|
-
explains how to distinguish skipped, empty, rejected, and timed-out suggestions.
|
|
103
|
-
|
|
104
|
-
## Skills
|
|
105
|
-
|
|
106
|
-
Bare A1's `/settings` → Agent → Skills chooses how discovered skills appear in the
|
|
107
|
-
slash-command menu. `collapse` (the default) replaces the per-skill `/skill:<name>`
|
|
108
|
-
entries with one `/skills` command: bare `/skills` opens a searchable Skills dialog,
|
|
109
|
-
`/skills <name> [args]` applies a skill directly (an unknown name reports
|
|
110
|
-
`Unknown skill: <name>`), and typing `/skills:` lists every skill inline so
|
|
111
|
-
`/skills:<name> args` runs as `/skill:<name> args`. With the `skills` row selected in
|
|
112
|
-
the menu, typing `:` completes to `/skills:`. `expand` lists every `/skill:<name>`
|
|
113
|
-
command as before. Both take effect immediately; a typed `/skill:<name>` always
|
|
114
|
-
works, and the engine's own Skill commands toggle still governs whether skills are
|
|
115
|
-
offered at all. The `a1 pi` comparison profile is unchanged.
|
|
116
|
-
|
|
117
|
-
## Quitting
|
|
118
|
-
|
|
119
|
-
`/quit`, `Ctrl+C` twice, and `Ctrl+D` on an empty prompt end a bare A1 session.
|
|
120
|
-
The last screen dissolves on the alternate screen, the terminal is restored once,
|
|
121
|
-
and only the dim `To resume this session:` hint is printed; the conversation is
|
|
122
|
-
not echoed into your scrollback. `/settings` → Quit chooses the effect (`fall`,
|
|
123
|
-
`dissolve`, `starburst`, `waves`, or `off`) and its duration (300–2000 ms). The
|
|
124
|
-
`a1 pi` comparison profile keeps Pi's `fullscreenExitOutput` behavior.
|
|
125
|
-
|
|
126
|
-
## Prompt history
|
|
127
|
-
|
|
128
|
-
Bare A1 recalls recent unique prompts across sessions with Up/Down. History is
|
|
129
|
-
stored in a separate profile-local SQLite database at
|
|
130
|
-
`~/.a1/data/history/<profile-id>.sqlite3`, or under `<A1_DATA_DIR>/history` when
|
|
131
|
-
explicitly overridden. Other application data stays in its existing location.
|
|
132
|
-
`/settings` → History controls persistence and the 10-100-entry limit (default
|
|
133
|
-
100), effective on next start. The new default starts fresh: old platform history
|
|
134
|
-
is neither imported nor automatically deleted. Ordinary upgrades and npm
|
|
135
|
-
uninstall/reinstall preserve saved history. History is unencrypted user text;
|
|
136
|
-
images are not reattached. See
|
|
137
|
-
[prompt history](docs/features/prompt-history.md) for privacy, storage, and removal.
|
|
138
|
-
|
|
139
48
|
## Extensions
|
|
140
49
|
|
|
141
50
|
Pi extension packages install into A1's own profile (`~/.a1/agent`), so bare `a1`
|
|
@@ -160,7 +69,15 @@ project), never `~/.pi/agent`. Configure MCP with `/mcp setup` inside bare `a1`.
|
|
|
160
69
|
|
|
161
70
|
## Develop
|
|
162
71
|
|
|
72
|
+
A source build needs Node.js `>=22.19.0 <25`, npm 11, git, and Rust/Cargo 1.85 or
|
|
73
|
+
newer—the build compiles the `native/process-guardian` crate. Publishing a release
|
|
74
|
+
or a pull request additionally needs an authenticated [GitHub CLI](https://cli.github.com).
|
|
75
|
+
`npm run doctor` reports every prerequisite with the exact command that installs
|
|
76
|
+
whatever is missing, and `npm run build` runs the same check first so a fresh clone
|
|
77
|
+
fails by name instead of inside a resolver or Cargo.
|
|
78
|
+
|
|
163
79
|
```sh
|
|
80
|
+
npm run doctor # report Node, npm, git, Rust, and dependency readiness
|
|
164
81
|
npm ci # install exact locked dependencies
|
|
165
82
|
npm run build # compile TypeScript and the process guardian into dist
|
|
166
83
|
npm start # build and launch a development `a1`
|
|
@@ -174,33 +91,6 @@ Create every task worktree at `{working-dir}/.worktrees/<task-id>`, where
|
|
|
174
91
|
`D:/Git/a1`, use `D:/Git/a1/.worktrees/<task-id>`—never a sibling such as
|
|
175
92
|
`D:/Git/a1-<task-id>`. The primary worktree remains on `develop` for integration only.
|
|
176
93
|
|
|
177
|
-
## Pull request integration
|
|
178
|
-
|
|
179
|
-
Pull requests whose complete diff is only under `openspec/**`, under `docs/**`,
|
|
180
|
-
exactly the root `README.md`, or a combination of those paths are automatically
|
|
181
|
-
squash-merged after `Development validation required` succeeds. The automation
|
|
182
|
-
reads the complete GitHub changed-file list, including both sides of renames, and
|
|
183
|
-
runs only for trusted branches in this repository.
|
|
184
|
-
|
|
185
|
-
Any other path makes the pull request code/operational. That includes source, tests,
|
|
186
|
-
scripts, workflows, configuration, generated baselines, arbitrary root Markdown,
|
|
187
|
-
and a mixed documentation-plus-code change. Those pull requests remain open after
|
|
188
|
-
CI for local maintainer validation and explicit manual merge; automation disables
|
|
189
|
-
auto-merge if it was armed. Documentation remains exempt from product builds and
|
|
190
|
-
tests, but docs-sensitive generated governance and strict OpenSpec consistency are
|
|
191
|
-
checked before integration.
|
|
192
|
-
|
|
193
|
-
After any same-repository pull request into `develop` merges, trusted automation
|
|
194
|
-
reconciles its remote topic branch. Human merges use the close-event workflow;
|
|
195
|
-
documentation merges authored by `GITHUB_TOKEN` use a synchronous fallback because
|
|
196
|
-
GitHub suppresses recursive workflow events. Both delete only an unprotected live
|
|
197
|
-
ref that still equals the pull request's exact merged head SHA. Fork, advanced,
|
|
198
|
-
reserved, protected, malformed, and unmerged refs are preserved and reported.
|
|
199
|
-
|
|
200
|
-
Specification approval and implementation remain separate pull requests. An
|
|
201
|
-
implementation starts from updated `origin/develop` only after its specification
|
|
202
|
-
has merged and implementation was explicitly requested.
|
|
203
|
-
|
|
204
94
|
## Release
|
|
205
95
|
|
|
206
96
|
Two channels, both published by CI from the exact bytes it validated — never from
|
|
@@ -230,29 +120,30 @@ a1 update --develop 0.1.8-dev.107 # install that exact full preview versio
|
|
|
230
120
|
### Stable
|
|
231
121
|
|
|
232
122
|
```sh
|
|
233
|
-
npm run release -- patch # 0.1.8-dev -> 0.1.8
|
|
123
|
+
npm run release -- patch # 0.1.8-dev -> 0.1.8
|
|
234
124
|
npm run release -- minor # 0.1.8-dev -> 0.2.0
|
|
235
125
|
npm run release -- major # 0.1.8-dev -> 1.0.0
|
|
236
126
|
npm run release -- 0.4.0 # an exact stable version
|
|
237
127
|
```
|
|
238
128
|
|
|
239
|
-
Run from the repository root on a clean `develop` matching `origin/develop
|
|
240
|
-
A target is required; bare `npm run release`
|
|
241
|
-
`patch` promotes the current prerelease rather
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
Only after confirmed publication of `0.1.8` does the command prepare the
|
|
252
|
-
`0.1.9-dev
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
the
|
|
129
|
+
Run from the repository root on a clean `develop` matching `origin/develop` that
|
|
130
|
+
declares the open `-dev` version. A target is required; bare `npm run release`
|
|
131
|
+
displays usage and releases nothing. `patch` promotes the current prerelease rather
|
|
132
|
+
than skipping its stable version.
|
|
133
|
+
|
|
134
|
+
The stable version is never committed. The command dispatches publication for the
|
|
135
|
+
exact authoritative `develop` commit with the stable version named in the request,
|
|
136
|
+
and waits for success. CI stamps that version on the checked-out source before
|
|
137
|
+
packing, validates the packed release on Windows, Linux, and macOS, publishes to
|
|
138
|
+
npm `latest` with provenance, then writes the `v<version>` tag on that same
|
|
139
|
+
`develop` commit, records the GitHub Release, and fast-forwards `master`.
|
|
140
|
+
|
|
141
|
+
Only after confirmed publication of `0.1.8` does the command prepare the one
|
|
142
|
+
version-only PR, `0.1.9-dev`, in an isolated detached worktree, print its URL, and
|
|
143
|
+
wait for you to **merge it manually**. It is not auto-merged, and green CI alone does
|
|
144
|
+
not advance the release. Work added to your checkout during the wait is preserved,
|
|
145
|
+
not reset. If publication fails or is uncertain, no reopening PR is prepared. If
|
|
146
|
+
publication succeeded but reopening failed, merge or repair the reported PR by
|
|
147
|
+
hand; do not republish the immutable stable version.
|
|
257
148
|
|
|
258
149
|
`docs/ci-release-runbook.md` has the full picture.
|
|
@@ -849,7 +849,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
849
849
|
this.#appendAnchoredWorkflowComponent(width => ["", ...announcement.render(width)], () => announcement.dispose?.());
|
|
850
850
|
return;
|
|
851
851
|
}
|
|
852
|
-
// Rationale: pinned
|
|
852
|
+
// Rationale: the pinned engine links both share URLs; the workflow result carries the plain URLs.
|
|
853
853
|
const message = result.command === "share" && result.detail
|
|
854
854
|
? `${linkShareUrl(result.message)}\nGist: ${piShellHyperlink(result.detail)}`
|
|
855
855
|
: result.message;
|
|
@@ -43,10 +43,10 @@ export declare class OwnedUiSessionShell {
|
|
|
43
43
|
showForkSelector(): void;
|
|
44
44
|
showLogoutSelector(): Promise<void>;
|
|
45
45
|
showLoginMethodSelector(providerReference: string): void;
|
|
46
|
-
showTreeSelector(initialSelectedId?: string): void
|
|
46
|
+
showTreeSelector(initialSelectedId?: string): Promise<void>;
|
|
47
47
|
showLoginAuthTypeSelector(): void;
|
|
48
48
|
showLoginProviderSelector(authType?: "oauth" | "api_key", initialSearchInput?: string): void;
|
|
49
|
-
showSessionSelector(): void
|
|
49
|
+
showSessionSelector(): Promise<void>;
|
|
50
50
|
showSettingsSelector(): void;
|
|
51
51
|
shutdown(): Promise<AdapterCommandResult>;
|
|
52
52
|
runWorkflow(request: PiWorkflowRequest): Promise<AdapterCommandResult>;
|
|
@@ -717,7 +717,7 @@ export class OwnedUiSessionShell {
|
|
|
717
717
|
if (now - this.#lastEscapeTime < 500) {
|
|
718
718
|
this.#lastEscapeTime = 0;
|
|
719
719
|
if (action === "tree")
|
|
720
|
-
this.showTreeSelector();
|
|
720
|
+
await this.showTreeSelector();
|
|
721
721
|
else
|
|
722
722
|
this.showForkSelector();
|
|
723
723
|
return { outcome: "completed", diagnostic: null };
|
|
@@ -972,7 +972,7 @@ export class OwnedUiSessionShell {
|
|
|
972
972
|
this.root.setInputSurface(component);
|
|
973
973
|
this.runtime.requestRender();
|
|
974
974
|
}
|
|
975
|
-
showTreeSelector(initialSelectedId) {
|
|
975
|
+
async showTreeSelector(initialSelectedId) {
|
|
976
976
|
const context = this.backend.pinnedTreeSelectorContext();
|
|
977
977
|
if (context.tree.length === 0) {
|
|
978
978
|
this.root.appendWorkflowStatus("No entries in session");
|
|
@@ -983,7 +983,7 @@ export class OwnedUiSessionShell {
|
|
|
983
983
|
this.root.setInputSurface(null);
|
|
984
984
|
this.runtime.requestRender();
|
|
985
985
|
};
|
|
986
|
-
const component = createPiShellTreeSelector({
|
|
986
|
+
const component = await createPiShellTreeSelector({
|
|
987
987
|
tree: context.tree,
|
|
988
988
|
currentLeafId: context.currentLeafId,
|
|
989
989
|
terminalHeight: this.runtime.viewport().rows,
|
|
@@ -1058,13 +1058,13 @@ export class OwnedUiSessionShell {
|
|
|
1058
1058
|
this.root.setInputSurface(component);
|
|
1059
1059
|
this.runtime.requestRender();
|
|
1060
1060
|
}
|
|
1061
|
-
showSessionSelector() {
|
|
1061
|
+
async showSessionSelector() {
|
|
1062
1062
|
const context = this.backend.pinnedSessionSelectorContext();
|
|
1063
1063
|
const close = () => {
|
|
1064
1064
|
this.root.setInputSurface(null);
|
|
1065
1065
|
this.runtime.requestRender();
|
|
1066
1066
|
};
|
|
1067
|
-
const component = createPiShellSessionSelector({
|
|
1067
|
+
const component = await createPiShellSessionSelector({
|
|
1068
1068
|
currentSessionsLoader: context.loadCurrentSessions,
|
|
1069
1069
|
allSessionsLoader: context.loadAllSessions,
|
|
1070
1070
|
currentSessionFilePath: context.currentSessionFilePath,
|
|
@@ -1200,7 +1200,7 @@ export class OwnedUiSessionShell {
|
|
|
1200
1200
|
return { outcome: "completed", diagnostic: null };
|
|
1201
1201
|
}
|
|
1202
1202
|
if (request.command === "resume" && request.selection === undefined && request.confirmed === undefined && request.argument.trim().length === 0) {
|
|
1203
|
-
this.showSessionSelector();
|
|
1203
|
+
await this.showSessionSelector();
|
|
1204
1204
|
return { outcome: "completed", diagnostic: null };
|
|
1205
1205
|
}
|
|
1206
1206
|
if (request.command === "login" && request.selection === undefined && request.confirmed === undefined) {
|
|
@@ -1215,7 +1215,7 @@ export class OwnedUiSessionShell {
|
|
|
1215
1215
|
return { outcome: "completed", diagnostic: null };
|
|
1216
1216
|
}
|
|
1217
1217
|
if (request.command === "tree" && request.selection === undefined && request.confirmed === undefined && request.argument.trim().length === 0) {
|
|
1218
|
-
this.showTreeSelector();
|
|
1218
|
+
await this.showTreeSelector();
|
|
1219
1219
|
return { outcome: "completed", diagnostic: null };
|
|
1220
1220
|
}
|
|
1221
1221
|
if (request.command === "reload") {
|
|
@@ -1913,7 +1913,7 @@ export class OwnedUiSessionShell {
|
|
|
1913
1913
|
"Summarize with custom prompt",
|
|
1914
1914
|
]);
|
|
1915
1915
|
if (choice === undefined) {
|
|
1916
|
-
this.showTreeSelector(entryId);
|
|
1916
|
+
await this.showTreeSelector(entryId);
|
|
1917
1917
|
return;
|
|
1918
1918
|
}
|
|
1919
1919
|
summarize = choice !== "No summary";
|
|
@@ -1935,7 +1935,7 @@ export class OwnedUiSessionShell {
|
|
|
1935
1935
|
},
|
|
1936
1936
|
});
|
|
1937
1937
|
if (result.diagnostic === "Branch summarization cancelled")
|
|
1938
|
-
this.showTreeSelector(entryId);
|
|
1938
|
+
await this.showTreeSelector(entryId);
|
|
1939
1939
|
}
|
|
1940
1940
|
#startWorkflowLogin(request) {
|
|
1941
1941
|
this.#finishWorkflowLogin();
|
|
@@ -10,7 +10,7 @@ export const STARTUP_DESCRIPTOR = Object.freeze({
|
|
|
10
10
|
],
|
|
11
11
|
"generatedArtifact": {
|
|
12
12
|
"path": "dist/integrations/pi/startup-public.js",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "540d60a56c6f2934d243f81dce09bc91e191371bed154b7620d15d22a855697d"
|
|
14
14
|
},
|
|
15
15
|
"dependencyLayerIdentity": {
|
|
16
16
|
"source": "A1_RELEASE_LAYERS",
|
|
@@ -19,7 +19,7 @@ export const STARTUP_DESCRIPTOR = Object.freeze({
|
|
|
19
19
|
"compileCacheNamespace": {
|
|
20
20
|
"strategy": "node-abi-version-and-ordered-layer-sha256-v1"
|
|
21
21
|
},
|
|
22
|
-
"identity": "
|
|
22
|
+
"identity": "a14fa5abdb33493d6a8d11fb1f2e62eff1ddbce083e997187d88531927ca1c24"
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
export function loadDeclaredStartupGraph() {
|
|
@@ -12,6 +12,8 @@ const SELECTED_TUNNEL_ROW = /^(→ skills:\S+)(\s{2,}.*)$/u;
|
|
|
12
12
|
export const PINNED_PI_BUILTIN_SLASH_COMMANDS = [
|
|
13
13
|
{ name: "settings", description: "Open settings menu" },
|
|
14
14
|
{ name: "model", description: "Select model (opens selector UI)", argumentHint: "<provider/model>" },
|
|
15
|
+
{ name: "tree", description: "Navigate session tree (switch branches)" },
|
|
16
|
+
{ name: "thinking", description: "Set thinking level", argumentHint: "<level>" },
|
|
15
17
|
{ name: "scoped-models", description: "Enable/disable models for Ctrl+P cycling" },
|
|
16
18
|
{ name: "export", description: "Export session (HTML default, or specify path: .html/.jsonl)" },
|
|
17
19
|
{ name: "import", description: "Import and resume a session from a JSONL file" },
|
|
@@ -23,7 +25,6 @@ export const PINNED_PI_BUILTIN_SLASH_COMMANDS = [
|
|
|
23
25
|
{ name: "hotkeys", description: "Show all keyboard shortcuts" },
|
|
24
26
|
{ name: "fork", description: "Create a new fork from a previous user message" },
|
|
25
27
|
{ name: "clone", description: "Duplicate the current session at the current position" },
|
|
26
|
-
{ name: "tree", description: "Navigate session tree (switch branches)" },
|
|
27
28
|
{ name: "trust", description: "Save project trust decision for future sessions" },
|
|
28
29
|
{ name: "login", description: "Configure provider authentication", argumentHint: "<provider>" },
|
|
29
30
|
{ name: "logout", description: "Remove provider authentication" },
|
|
@@ -29,6 +29,25 @@ export interface PiShellSessionInfoPresentation {
|
|
|
29
29
|
readonly cost: number;
|
|
30
30
|
readonly tokens: number;
|
|
31
31
|
}[];
|
|
32
|
+
readonly cacheWarming: PiShellCacheWarmingPresentation;
|
|
33
|
+
}
|
|
34
|
+
export interface PiShellCacheWarmingPresentation {
|
|
35
|
+
readonly mode: string;
|
|
36
|
+
readonly status?: {
|
|
37
|
+
readonly state: "inactive" | "scheduled" | "refreshing";
|
|
38
|
+
readonly reason?: string;
|
|
39
|
+
readonly nextWarmAt?: number;
|
|
40
|
+
readonly extensionOverride?: boolean;
|
|
41
|
+
readonly decision?: {
|
|
42
|
+
readonly phase: "streaming" | "idle";
|
|
43
|
+
readonly action: string;
|
|
44
|
+
readonly warmCost: number;
|
|
45
|
+
readonly missCost: number;
|
|
46
|
+
readonly continuationProbability: number;
|
|
47
|
+
readonly expectedSavings: number;
|
|
48
|
+
readonly economicsAvailable: boolean;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
32
51
|
}
|
|
33
52
|
export declare function renderPiShellStatusText(message: string, width: number, outputPad?: 0 | 1): readonly string[];
|
|
34
53
|
export interface PiShellCommandMessagePresentation {
|
|
@@ -23,9 +23,55 @@ export function renderPiShellCommandMessage(presentation, width, outputPad = PIN
|
|
|
23
23
|
...text.render(width),
|
|
24
24
|
];
|
|
25
25
|
}
|
|
26
|
+
const CACHE_WARMING_MINIMUM_EXPECTED_SAVINGS = 0.05;
|
|
27
|
+
function formatWarmingDollars(value) {
|
|
28
|
+
return value < 0 ? `-${Math.abs(value).toFixed(3)}` : `${value.toFixed(3)}`;
|
|
29
|
+
}
|
|
30
|
+
function formatWarmingEconomics(decision) {
|
|
31
|
+
if (!decision.economicsAvailable)
|
|
32
|
+
return "cache economics unavailable";
|
|
33
|
+
const probability = Math.round(decision.continuationProbability * 100);
|
|
34
|
+
const probabilityText = decision.phase === "streaming"
|
|
35
|
+
? `${probability}% continuation probability while agent is running`
|
|
36
|
+
: `${probability}% continuation probability`;
|
|
37
|
+
const comparison = decision.action === "warm" ? ">=" : "<";
|
|
38
|
+
return `${probabilityText}, expected savings ${formatWarmingDollars(decision.expectedSavings)} ${comparison} ${CACHE_WARMING_MINIMUM_EXPECTED_SAVINGS.toFixed(3)}`;
|
|
39
|
+
}
|
|
40
|
+
function formatWarmingDecisionTime(nextWarmAt, now) {
|
|
41
|
+
if (nextWarmAt === undefined || nextWarmAt <= now)
|
|
42
|
+
return "Decision now";
|
|
43
|
+
let remainingSeconds = Math.ceil((nextWarmAt - now) / 1000);
|
|
44
|
+
const hours = Math.floor(remainingSeconds / 3600);
|
|
45
|
+
remainingSeconds %= 3600;
|
|
46
|
+
const minutes = Math.floor(remainingSeconds / 60);
|
|
47
|
+
const seconds = remainingSeconds % 60;
|
|
48
|
+
const parts = [];
|
|
49
|
+
if (hours > 0)
|
|
50
|
+
parts.push(`${hours}h`);
|
|
51
|
+
if (minutes > 0)
|
|
52
|
+
parts.push(`${minutes}m`);
|
|
53
|
+
if (seconds > 0 || parts.length === 0)
|
|
54
|
+
parts.push(`${seconds}s`);
|
|
55
|
+
return `Decision in ${parts.join(" ")}`;
|
|
56
|
+
}
|
|
57
|
+
/** The one-line warming status the pinned session report shows; a decision is attached once warming acted. */
|
|
58
|
+
function formatCacheWarmingStatus(status, now = Date.now()) {
|
|
59
|
+
const decision = status.decision;
|
|
60
|
+
if (!decision || (status.state === "inactive" && !decision.economicsAvailable && !status.extensionOverride)) {
|
|
61
|
+
return `Inactive (${status.reason ?? "unknown reason"})`;
|
|
62
|
+
}
|
|
63
|
+
const details = status.extensionOverride
|
|
64
|
+
? `extension override, ${formatWarmingEconomics(decision)}`
|
|
65
|
+
: `${formatWarmingEconomics(decision)} -> ${decision.action}`;
|
|
66
|
+
if (status.state === "inactive")
|
|
67
|
+
return `Stopped (${details})`;
|
|
68
|
+
if (status.state === "refreshing")
|
|
69
|
+
return `Warming cache (${details})`;
|
|
70
|
+
return `${formatWarmingDecisionTime(status.nextWarmAt, now)} (${details})`;
|
|
71
|
+
}
|
|
26
72
|
export function createPiShellSessionInfo(presentation) {
|
|
27
73
|
ensureTheme();
|
|
28
|
-
const { stats, sessionName, cacheWaste, usageBreakdown } = presentation;
|
|
74
|
+
const { stats, sessionName, cacheWaste, usageBreakdown, cacheWarming } = presentation;
|
|
29
75
|
let info = `${piTheme().bold("Session Info")}\n\n`;
|
|
30
76
|
if (sessionName)
|
|
31
77
|
info += `${piTheme().fg("dim", "Name:")} ${sessionName}\n`;
|
|
@@ -42,6 +88,14 @@ export function createPiShellSessionInfo(presentation) {
|
|
|
42
88
|
info += ` ${piTheme().fg("dim", "Uncached:")} ${(input + cacheWrite).toLocaleString()}${written}\n`;
|
|
43
89
|
}
|
|
44
90
|
info += `${piTheme().fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}\n${piTheme().fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
|
|
91
|
+
const warmingStatus = cacheWarming.status;
|
|
92
|
+
info += `\n${piTheme().bold("Cache Warming")}\n${piTheme().fg("dim", "Mode:")} ${cacheWarming.mode}\n`;
|
|
93
|
+
info += `${piTheme().fg("dim", "Status:")} ${warmingStatus ? formatCacheWarmingStatus(warmingStatus) : "Inactive (cache warming unavailable)"}\n`;
|
|
94
|
+
const warmingDecision = warmingStatus?.decision;
|
|
95
|
+
if (warmingDecision?.economicsAvailable) {
|
|
96
|
+
info += `${piTheme().fg("dim", "Cache miss penalty:")} $${warmingDecision.missCost.toFixed(3)}\n`;
|
|
97
|
+
info += `${piTheme().fg("dim", "Refresh cost:")} $${warmingDecision.warmCost.toFixed(3)}\n`;
|
|
98
|
+
}
|
|
45
99
|
if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
|
|
46
100
|
info += `\n${piTheme().bold("Cost")}\n${piTheme().fg("dim", "Total:")} $${stats.cost.toFixed(3)}`;
|
|
47
101
|
if (usageBreakdown.length > 1)
|
|
@@ -124,7 +178,7 @@ function hotkeysMarkdown(bindings, getShortcuts, profile) {
|
|
|
124
178
|
? action === "app.model.select" ? "Unbound (`/models`)" : "Unbound"
|
|
125
179
|
: `\`${label}\``;
|
|
126
180
|
}).join(" / ")} | ${description} |`;
|
|
127
|
-
let markdown = ["**Navigation**", "| Key | Action |", "|-----|--------|", row(["tui.editor.cursorUp", "tui.editor.cursorDown", "tui.editor.cursorLeft", "tui.editor.cursorRight"], "Move cursor / browse history"), row(["tui.editor.cursorWordLeft", "tui.editor.cursorWordRight"], "Move by word"), row(["tui.editor.cursorLineStart"], profile === "a1" ? "Start of prompt line" : "Start of line"), row(["tui.editor.cursorLineEnd"], profile === "a1" ? "End of prompt line" : "End of line"), ...(profile === "a1" ? ["| `Ctrl+Home` | Start of content |", "| `Ctrl+End` | End of content / follow output |"] : []), row(["tui.editor.jumpForward"], "Jump forward to character"), row(["tui.editor.jumpBackward"], "Jump backward to character"), row(["tui.editor.pageUp", "tui.editor.pageDown"], "Scroll by page"), "", "**Editing**", "| Key | Action |", "|-----|--------|", row(["tui.input.submit"], "Send message"), row(["tui.input.newLine"], `New line${process.platform === "win32" ? " (Ctrl+Enter on Windows Terminal)" : ""}`), row(["tui.editor.deleteWordBackward"], "Delete word backwards"), row(["tui.editor.deleteWordForward"], "Delete word forwards"), row(["tui.editor.deleteToLineStart"], "Delete to start of line"), row(["tui.editor.deleteToLineEnd"], "Delete to end of line"), row(["tui.editor.yank"], "Paste the most-recently-deleted text"), row(["tui.editor.yankPop"], "Cycle through the deleted text after pasting"), row(["tui.editor.undo"], "Undo"), "", "**Other**", "| Key | Action |", "|-----|--------|", row(["tui.input.tab"], "Path completion / accept autocomplete"), row(["app.interrupt"], "Cancel autocomplete / abort streaming"), row(["app.clear"], "Clear editor (first) / exit (second)"), row(["app.exit"], "Exit (when editor is empty)"), row(["app.suspend"], "Suspend to background"), row(["app.thinking.cycle"], "Cycle thinking level"), row(["app.model.cycleForward", "app.model.cycleBackward"], "Cycle models"), row(["app.model.select"], profile === "a1" ? "Open the Models dialog" : "Open model selector"), row(["app.tools.expand"], "Toggle tool output expansion"), row(["app.thinking.toggle"], "Toggle thinking block visibility"), row(["app.editor.external"], "Edit message in external editor"), row(["app.message.copy"], "Copy last assistant message"), row(["app.message.followUp"], "Queue follow-up message"), row(["app.message.dequeue"], "Restore queued messages"), row(["app.clipboard.pasteImage"], "Paste image or text from clipboard"), "| `/` | Slash commands |", "| `!` | Run bash command |", "| `!!` | Run bash command (excluded from context) |", ...(profile === "a1" ? ["", "**Models dialog**", "| Key | Action |", "|-----|--------|", "| `Space` | Toggle the selected model in the cycling scope |", "| `Tab` | Switch the all/scoped filter |", row(["app.models.save"], "Save the scope to settings"), row(["app.models.enableAll"], "Scope every listed model"), row(["app.models.clearAll"], "Clear the listed models from the scope"), row(["app.models.toggleProvider"], "Toggle the selected model's provider"), row(["app.models.reorderUp", "app.models.reorderDown"], "Reorder the cycling scope")] : [])].join("\n");
|
|
181
|
+
let markdown = ["**Navigation**", "| Key | Action |", "|-----|--------|", row(["tui.editor.cursorUp", "tui.editor.cursorDown", "tui.editor.cursorLeft", "tui.editor.cursorRight"], "Move cursor / browse history"), row(["tui.editor.cursorWordLeft", "tui.editor.cursorWordRight"], "Move by word"), row(["tui.editor.cursorLineStart"], profile === "a1" ? "Start of prompt line" : "Start of line"), row(["tui.editor.cursorLineEnd"], profile === "a1" ? "End of prompt line" : "End of line"), ...(profile === "a1" ? ["| `Ctrl+Home` | Start of content |", "| `Ctrl+End` | End of content / follow output |"] : []), row(["tui.editor.jumpForward"], "Jump forward to character"), row(["tui.editor.jumpBackward"], "Jump backward to character"), row(["tui.editor.pageUp", "tui.editor.pageDown"], "Scroll by page"), "", "**Editing**", "| Key | Action |", "|-----|--------|", row(["tui.input.submit"], "Send message"), row(["tui.input.newLine"], `New line${process.platform === "win32" ? " (Ctrl+Enter on Windows Terminal)" : ""}`), row(["tui.editor.deleteWordBackward"], "Delete word backwards"), row(["tui.editor.deleteWordForward"], "Delete word forwards"), row(["tui.editor.deleteToLineStart"], "Delete to start of line"), row(["tui.editor.deleteToLineEnd"], "Delete to end of line"), row(["tui.editor.yank"], "Paste the most-recently-deleted text"), row(["tui.editor.yankPop"], "Cycle through the deleted text after pasting"), row(["tui.editor.undo"], "Undo"), "", "**Other**", "| Key | Action |", "|-----|--------|", row(["tui.input.tab"], "Path completion / accept autocomplete"), row(["app.interrupt"], "Cancel autocomplete / abort streaming"), row(["app.clear"], "Clear editor (first) / exit (second)"), row(["app.exit"], "Exit (when editor is empty)"), row(["app.suspend"], "Suspend to background"), row(["app.thinking.cycle"], "Cycle thinking level"), row(["app.model.cycleForward", "app.model.cycleBackward"], "Cycle models"), row(["app.model.select"], profile === "a1" ? "Open the Models dialog" : "Open model selector"), row(["app.tools.expand"], "Toggle tool output expansion"), row(["app.thinking.toggle"], "Toggle thinking block visibility"), row(["app.editor.external"], "Edit message in external editor"), row(["app.message.copy"], "Copy selection or last assistant message"), row(["app.message.followUp"], "Queue follow-up message"), row(["app.message.dequeue"], "Restore queued messages"), row(["app.clipboard.pasteImage"], "Paste image or text from clipboard"), "| `/` | Slash commands |", "| `!` | Run bash command |", "| `!!` | Run bash command (excluded from context) |", ...(profile === "a1" ? ["", "**Models dialog**", "| Key | Action |", "|-----|--------|", "| `Space` | Toggle the selected model in the cycling scope |", "| `Tab` | Switch the all/scoped filter |", row(["app.models.save"], "Save the scope to settings"), row(["app.models.enableAll"], "Scope every listed model"), row(["app.models.clearAll"], "Clear the listed models from the scope"), row(["app.models.toggleProvider"], "Toggle the selected model's provider"), row(["app.models.reorderUp", "app.models.reorderDown"], "Reorder the cycling scope")] : [])].join("\n");
|
|
128
182
|
const shortcuts = getShortcuts(bindings ?? keys.getEffectiveConfig());
|
|
129
183
|
if (shortcuts.length > 0) {
|
|
130
184
|
markdown += "\n\n**Extensions**\n| Key | Action |\n|-----|--------|\n";
|
|
@@ -67,16 +67,18 @@ export declare function createPiShellTrustSelector(options: {
|
|
|
67
67
|
}) => void;
|
|
68
68
|
readonly onCancel: () => void;
|
|
69
69
|
}): PiShellComponentPort;
|
|
70
|
+
/** Mirrors the pinned session manager's progress callback, including its partial results. */
|
|
71
|
+
type SessionListProgress = (loaded: number, total: number, partialSessions?: readonly SessionInfo[]) => void;
|
|
70
72
|
export declare function createPiShellSessionSelector(options: {
|
|
71
|
-
readonly currentSessionsLoader: (onProgress?:
|
|
72
|
-
readonly allSessionsLoader: (onProgress?:
|
|
73
|
+
readonly currentSessionsLoader: (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;
|
|
74
|
+
readonly allSessionsLoader: (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;
|
|
73
75
|
readonly onSelect: (path: string) => void;
|
|
74
76
|
readonly onCancel: () => void;
|
|
75
77
|
readonly onExit: () => void;
|
|
76
78
|
readonly requestRender: () => void;
|
|
77
79
|
readonly renameSession: (sessionFilePath: string, nextName: string | undefined) => Promise<void>;
|
|
78
80
|
readonly currentSessionFilePath: string | undefined;
|
|
79
|
-
}): PiShellComponentPort
|
|
81
|
+
}): Promise<PiShellComponentPort>;
|
|
80
82
|
export declare function createPiShellTreeSelector(options: {
|
|
81
83
|
readonly tree: readonly unknown[];
|
|
82
84
|
readonly currentLeafId: string | null;
|
|
@@ -87,7 +89,7 @@ export declare function createPiShellTreeSelector(options: {
|
|
|
87
89
|
readonly onCopy?: (text: string | undefined) => void;
|
|
88
90
|
readonly initialSelectedId?: string;
|
|
89
91
|
readonly initialFilterMode?: "default" | "no-tools" | "user-only" | "labeled-only" | "all";
|
|
90
|
-
}): PiShellComponentPort
|
|
92
|
+
}): Promise<PiShellComponentPort>;
|
|
91
93
|
export declare function createPiShellUserMessageSelector(messages: readonly PiShellSelectorOption[], onSelect: (id: string) => void, onCancel: () => void, initialSelectedId?: string): PiShellComponentPort;
|
|
92
94
|
export interface PiShellLoginDialogPort extends PiShellComponentPort {
|
|
93
95
|
showAuth(url: string, instructions?: string): void;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { ArminComponent, BorderedLoader, DynamicBorder, ExtensionSelectorComponent, getSelectListTheme, LoginDialogComponent, ModelSelectorComponent, OAuthSelectorComponent, SettingsSelectorComponent, ShowImagesSelectorComponent, ThemeSelectorComponent, ThinkingSelectorComponent, UserMessageSelectorComponent, } from "../startup-public.js";
|
|
2
2
|
import { DaxnutsComponent, } from "./upstream/components/daxnuts.js";
|
|
3
3
|
import { EarendilAnnouncementComponent, } from "./upstream/components/earendil-announcement.js";
|
|
4
|
-
import { SessionSelectorComponent, } from "./upstream/components/session-selector.js";
|
|
5
|
-
import { TreeSelectorComponent, } from "./upstream/components/tree-selector.js";
|
|
6
4
|
import { Box, Container, SelectList, Spacer, Text, } from "@earendil-works/pi-tui";
|
|
7
5
|
import { ScopedModelsSelectorComponent, } from "./upstream/components/scoped-models-selector.js";
|
|
8
6
|
import { ModelsDialogComponent, } from "./models-dialog.js";
|
|
@@ -40,6 +38,7 @@ export function createPiShellSettingsSelector(options) {
|
|
|
40
38
|
onFollowUpModeChange: change("onFollowUpModeChange"),
|
|
41
39
|
onTransportChange: change("onTransportChange"),
|
|
42
40
|
onHttpIdleTimeoutMsChange: change("onHttpIdleTimeoutMsChange"),
|
|
41
|
+
onCacheWarmingModeChange: change("onCacheWarmingModeChange"),
|
|
43
42
|
onModelThinkingLevelChange: change("onModelThinkingLevelChange"),
|
|
44
43
|
onModelThinkingLevelRemove: change("onModelThinkingLevelRemove"),
|
|
45
44
|
onThemeChange: change("onThemeChange"),
|
|
@@ -120,13 +119,15 @@ export function createPiShellTrustSelector(options) {
|
|
|
120
119
|
ensureTheme();
|
|
121
120
|
return componentPort(new TrustSelectorComponent(options));
|
|
122
121
|
}
|
|
123
|
-
export function createPiShellSessionSelector(options) {
|
|
122
|
+
export async function createPiShellSessionSelector(options) {
|
|
124
123
|
ensureTheme();
|
|
124
|
+
const { SessionSelectorComponent } = await import("./upstream/components/session-selector.js");
|
|
125
125
|
const selector = new SessionSelectorComponent(options.currentSessionsLoader, options.allSessionsLoader, options.onSelect, options.onCancel, options.onExit, options.requestRender, { renameSession: options.renameSession, showRenameHint: true }, options.currentSessionFilePath);
|
|
126
126
|
return componentPort(selector);
|
|
127
127
|
}
|
|
128
|
-
export function createPiShellTreeSelector(options) {
|
|
128
|
+
export async function createPiShellTreeSelector(options) {
|
|
129
129
|
ensureTheme();
|
|
130
|
+
const { TreeSelectorComponent } = await import("./upstream/components/tree-selector.js");
|
|
130
131
|
const selector = new TreeSelectorComponent([...options.tree], options.currentLeafId, options.terminalHeight, options.onSelect, options.onCancel, options.onLabelChange, options.initialSelectedId, options.initialFilterMode);
|
|
131
132
|
if (options.onCopy)
|
|
132
133
|
selector.onCopy = options.onCopy;
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { DynamicBorder, keyHint, rawKeyHint } from "../startup-public.js";
|
|
2
|
-
import { Container, getKeybindings, Input, Spacer, Text
|
|
2
|
+
import { Container, getKeybindings, Input, Spacer, Text } from "@earendil-works/pi-tui";
|
|
3
3
|
import { PINNED_PI_LAYOUT, piTheme } from "./theme.js";
|
|
4
|
-
import { componentPort, ensureTheme } from "./shell-shared-facade.js";
|
|
4
|
+
import { componentPort, ensureTheme, piShellTruncateToWidth, piShellVisibleWidth } from "./shell-shared-facade.js";
|
|
5
5
|
import { SKILL_COMMAND_PREFIX, skillMatchesQuery } from "./skills-command.js";
|
|
6
|
+
/** A single line clipped at the viewport width: no wrap, no ellipsis, padded to the full width. */
|
|
7
|
+
class ClippedLine {
|
|
8
|
+
#text;
|
|
9
|
+
constructor(text) { this.#text = text; }
|
|
10
|
+
invalidate() { }
|
|
11
|
+
render(width) {
|
|
12
|
+
const line = piShellTruncateToWidth(this.#text.split("\n", 1)[0] ?? "", width);
|
|
13
|
+
return [line + " ".repeat(Math.max(0, width - piShellVisibleWidth(line)))];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
6
16
|
/**
|
|
7
17
|
* The A1-owned searchable Skills dialog. Its composition is the model selector's (border, spacer,
|
|
8
18
|
* search input, spacer, list, spacer, hint footer, border) built from public pi-tui components; its
|
|
9
19
|
* content follows the v2 skills extension: an accent bold title, `skill:<name>` rows, the selected
|
|
10
|
-
* skill's description
|
|
20
|
+
* skill's description cut to one line under the rows, the pinned scroll counter on overflow,
|
|
11
21
|
* and the two empty states. Enter applies the selected skill with no arguments; the query is never appended.
|
|
12
22
|
*/
|
|
13
23
|
class SkillsSelectorComponent extends Container {
|
|
@@ -102,8 +112,8 @@ class SkillsSelectorComponent extends Container {
|
|
|
102
112
|
const description = this.#filtered[this.#selectedIndex]?.description ?? "";
|
|
103
113
|
if (description.length > 0) {
|
|
104
114
|
this.#listContainer.addChild(new Spacer(1));
|
|
105
|
-
// Invariant: the description never wraps; it is cut
|
|
106
|
-
this.#listContainer.addChild(new
|
|
115
|
+
// Invariant: the description never wraps; it is cut at the viewport width with no ellipsis.
|
|
116
|
+
this.#listContainer.addChild(new ClippedLine(theme.fg("muted", ` ${description}`)));
|
|
107
117
|
}
|
|
108
118
|
}
|
|
109
119
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 0.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 0.86.1 (MIT), commit 13cbf77df2396303013a41646bcfa77b4271ae56,
|
|
3
3
|
* packages/coding-agent/src/core/keybindings.ts.
|
|
4
4
|
* Modifications: Mechanical source port with Node import prefixes, public package-root agent-directory
|
|
5
5
|
* resolution, and an opt-in bare-A1 input profile including Ctrl+L level cycling and unbound model
|
|
@@ -136,7 +136,7 @@ export declare const KEYBINDINGS: {
|
|
|
136
136
|
};
|
|
137
137
|
readonly "app.message.copy": {
|
|
138
138
|
readonly defaultKeys: "ctrl+x";
|
|
139
|
-
readonly description: "Copy
|
|
139
|
+
readonly description: "Copy selection or last assistant message";
|
|
140
140
|
};
|
|
141
141
|
readonly "app.message.followUp": {
|
|
142
142
|
readonly defaultKeys: "ctrl+q" | "alt+enter";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 0.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 0.86.1 (MIT), commit 13cbf77df2396303013a41646bcfa77b4271ae56,
|
|
3
3
|
* packages/coding-agent/src/core/keybindings.ts.
|
|
4
4
|
* Modifications: Mechanical source port with Node import prefixes, public package-root agent-directory
|
|
5
5
|
* resolution, and an opt-in bare-A1 input profile including Ctrl+L level cycling and unbound model
|
|
@@ -72,7 +72,7 @@ export const KEYBINDINGS = {
|
|
|
72
72
|
},
|
|
73
73
|
"app.message.copy": {
|
|
74
74
|
defaultKeys: "ctrl+x",
|
|
75
|
-
description: "Copy
|
|
75
|
+
description: "Copy selection or last assistant message",
|
|
76
76
|
},
|
|
77
77
|
"app.message.followUp": {
|
|
78
78
|
defaultKeys: windowsKeybindings ? "ctrl+q" : "alt+enter",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"sourcePackage": "@earendil-works/pi-coding-agent",
|
|
3
|
-
"sourceVersion": "0.
|
|
3
|
+
"sourceVersion": "0.86.1",
|
|
4
4
|
"upstreamRepository": "https://github.com/earendil-works/pi.git",
|
|
5
|
-
"upstreamCommit": "
|
|
5
|
+
"upstreamCommit": "13cbf77df2396303013a41646bcfa77b4271ae56",
|
|
6
6
|
"sourcePath": "dist/modes/interactive/assets/clankolas.png",
|
|
7
7
|
"sourceSha256": "169acd0dfe6fbb8d8742ed24a3fc654fd0b2e2d4223c733249c5493723f1b72d",
|
|
8
8
|
"license": "MIT",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 0.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 0.86.1 (MIT), commit 13cbf77df2396303013a41646bcfa77b4271ae56,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/countdown-timer.ts.
|
|
4
4
|
* Modifications: Mechanical source port with ECMAScript private fields; imports remain on the public
|
|
5
5
|
* Pi TUI package root.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 0.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 0.86.1 (MIT), commit 13cbf77df2396303013a41646bcfa77b4271ae56,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/daxnuts.ts.
|
|
4
4
|
* Modifications: Mechanical pinned source port with private imports remapped to public package-root
|
|
5
5
|
* types/APIs and A1-owned theme boundaries; behavior remains acceptance-tested.
|