@timurproko/a1 0.1.8-dev.544 → 0.1.8-dev.546
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/bin/cli.js +4 -0
- package/dist/app/session-shell/session-shell-root.js +15 -5
- package/dist/cli/dispatch.d.ts +5 -0
- package/dist/cli/dispatch.js +26 -0
- package/dist/cli/session-context.d.ts +9 -0
- package/dist/cli/session-context.js +29 -0
- package/dist/composition/owned-ui.js +6 -2
- package/dist/contracts/owned-ui/model.d.ts +5 -0
- package/dist/contracts/owned-ui/validation.js +6 -0
- package/dist/contracts/presentation/index.d.ts +13 -0
- package/dist/contracts/presentation/index.js +30 -0
- package/dist/features/launch/index.d.ts +2 -0
- package/dist/features/launch/index.js +1 -0
- package/dist/features/launch/session-context.d.ts +8 -0
- package/dist/features/launch/session-context.js +8 -0
- package/dist/features/owned-ui/project-trust-prompt.js +1 -1
- package/dist/features/owned-ui/reference-screen-app.js +7 -8
- package/dist/features/owned-ui/settings-app.js +9 -5
- package/dist/foundation/lifecycle/index.d.ts +2 -0
- package/dist/foundation/lifecycle/index.js +1 -0
- package/dist/foundation/lifecycle/session-repository-context.d.ts +18 -0
- package/dist/foundation/lifecycle/session-repository-context.js +173 -0
- package/dist/integrations/pi/components/models-dialog.js +9 -9
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +27 -3
- package/dist/integrations/pi/components/shell-extension-ui.js +4 -2
- package/dist/integrations/pi/components/shell-footer-status.js +1 -1
- package/dist/integrations/pi/components/shell-presenters-transcript.js +4 -2
- package/dist/integrations/pi/components/skills-command.d.ts +2 -0
- package/dist/integrations/pi/components/skills-command.js +11 -10
- package/dist/integrations/pi/components/skills-dialog.js +8 -3
- package/dist/integrations/pi/components/theme.d.ts +4 -0
- package/dist/integrations/pi/components/theme.js +10 -0
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +4 -4
- package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +2 -2
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +9 -10
- package/dist/integrations/pi/components/upstream/components/extension-input.d.ts +17 -0
- package/dist/integrations/pi/components/upstream/components/extension-input.js +72 -0
- package/dist/integrations/pi/components/upstream/components/extension-selector.d.ts +15 -0
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +92 -0
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +3 -2
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +16 -15
- package/dist/integrations/pi/components/upstream/components/session-footer.js +25 -9
- package/dist/integrations/pi/components/upstream/components/session-selector.js +25 -16
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +6 -4
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +22 -12
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +3 -2
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +14 -12
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +11 -5
- package/dist/integrations/pi/engine/adapter.d.ts +2 -1
- package/dist/integrations/pi/engine/adapter.js +2 -0
- package/dist/integrations/pi/engine/message-values.js +1 -0
- package/dist/integrations/pi/engine/session-runtime.d.ts +11 -2
- package/dist/integrations/pi/engine/session-runtime.js +136 -33
- package/dist/integrations/pi/engine/transcript-projection.js +35 -0
- package/dist/integrations/pi/startup-public.manifest.json +2 -0
- 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/product-identity.d.ts +1 -1
- package/dist/product-identity.js +1 -1
- package/dist/product-identity.json +2 -1
- package/dist/ui/components/dialog-panel.d.ts +2 -1
- package/dist/ui/components/dialog-panel.js +6 -1
- package/dist/ui/components/index.d.ts +2 -0
- package/dist/ui/components/index.js +1 -0
- package/dist/ui/components/shortcut-hints.d.ts +7 -0
- package/dist/ui/components/shortcut-hints.js +12 -0
- package/dist/ui/components/shortcuts.d.ts +2 -0
- package/dist/ui/components/shortcuts.js +5 -2
- package/dist/ui/components/transcript-viewport.d.ts +1 -1
- package/docs/ci-release-runbook.md +9 -7
- package/docs/openspec-archive-automation.md +6 -0
- package/docs/validation.md +5 -2
- package/package.json +1 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 0.87.0 (MIT), commit 16787ad5b2dc748047f314ca1bfe7708f30f54f3,
|
|
3
|
+
* packages/coding-agent/src/modes/interactive/components/extension-selector.ts.
|
|
4
|
+
* Modifications: Mechanical port: remap public imports, use ECMAScript private fields, and route the
|
|
5
|
+
* bare-A1 instruction row through the shared semantic shortcut renderer while preserving options,
|
|
6
|
+
* timeout, navigation, selection, cancellation, and disposal behavior.
|
|
7
|
+
* Deviations: owned-modal-shortcut-hints.
|
|
8
|
+
*/
|
|
9
|
+
import { DynamicBorder } from "../../../startup-public.js";
|
|
10
|
+
import { Container, getKeybindings, Spacer, Text } from "@earendil-works/pi-tui";
|
|
11
|
+
import { piTheme, renderPiModalShortcutHints } from "../../theme.js";
|
|
12
|
+
import { CountdownTimer } from "./countdown-timer.js";
|
|
13
|
+
/** Bare-A1 extension selector using the common modal shortcut row. */
|
|
14
|
+
export class ExtensionSelectorComponent extends Container {
|
|
15
|
+
#options;
|
|
16
|
+
#selectedIndex = 0;
|
|
17
|
+
#listContainer = new Container();
|
|
18
|
+
#onSelect;
|
|
19
|
+
#onCancel;
|
|
20
|
+
#titleText;
|
|
21
|
+
#baseTitle;
|
|
22
|
+
#countdown;
|
|
23
|
+
#onToggleToolsExpanded;
|
|
24
|
+
constructor(title, options, onSelect, onCancel, opts) {
|
|
25
|
+
super();
|
|
26
|
+
this.#options = options;
|
|
27
|
+
this.#onSelect = onSelect;
|
|
28
|
+
this.#onCancel = onCancel;
|
|
29
|
+
this.#baseTitle = title;
|
|
30
|
+
this.#onToggleToolsExpanded = opts?.onToggleToolsExpanded;
|
|
31
|
+
const theme = piTheme();
|
|
32
|
+
this.addChild(new DynamicBorder());
|
|
33
|
+
this.addChild(new Spacer(1));
|
|
34
|
+
this.#titleText = new Text(theme.fg("accent", theme.bold(title)), 1, 0);
|
|
35
|
+
this.addChild(this.#titleText);
|
|
36
|
+
if (opts?.description) {
|
|
37
|
+
this.addChild(new Spacer(1));
|
|
38
|
+
this.addChild(new Text(theme.fg("text", opts.description), 1, 0));
|
|
39
|
+
}
|
|
40
|
+
this.addChild(new Spacer(1));
|
|
41
|
+
this.#countdown = opts?.timeout !== undefined && opts.timeout > 0 && opts.tui !== undefined
|
|
42
|
+
? new CountdownTimer(opts.timeout, opts.tui, seconds => {
|
|
43
|
+
const current = piTheme();
|
|
44
|
+
this.#titleText.setText(current.fg("accent", current.bold(`${this.#baseTitle} (${seconds}s)`)));
|
|
45
|
+
}, () => this.#onCancel())
|
|
46
|
+
: undefined;
|
|
47
|
+
this.addChild(this.#listContainer);
|
|
48
|
+
this.addChild(new Spacer(1));
|
|
49
|
+
const keys = getKeybindings();
|
|
50
|
+
this.addChild(new Text(renderPiModalShortcutHints([
|
|
51
|
+
{ key: "↑↓", action: "navigate" },
|
|
52
|
+
{ key: keys.getKeys("tui.select.confirm").join("/"), action: "select" },
|
|
53
|
+
{ key: keys.getKeys("tui.select.cancel").join("/"), action: "cancel" },
|
|
54
|
+
]), 1, 0));
|
|
55
|
+
this.addChild(new Spacer(1));
|
|
56
|
+
this.addChild(new DynamicBorder());
|
|
57
|
+
this.#updateList();
|
|
58
|
+
}
|
|
59
|
+
#updateList() {
|
|
60
|
+
this.#listContainer.clear();
|
|
61
|
+
const theme = piTheme();
|
|
62
|
+
for (let index = 0; index < this.#options.length; index += 1) {
|
|
63
|
+
const option = this.#options[index];
|
|
64
|
+
this.#listContainer.addChild(new Text(index === this.#selectedIndex
|
|
65
|
+
? theme.fg("accent", "→ ") + theme.fg("accent", option)
|
|
66
|
+
: ` ${theme.fg("text", option)}`, 1, 0));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
handleInput(keyData) {
|
|
70
|
+
const keys = getKeybindings();
|
|
71
|
+
if (keys.matches(keyData, "app.tools.expand"))
|
|
72
|
+
this.#onToggleToolsExpanded?.();
|
|
73
|
+
else if (keys.matches(keyData, "tui.select.up") || keyData === "k") {
|
|
74
|
+
this.#selectedIndex = Math.max(0, this.#selectedIndex - 1);
|
|
75
|
+
this.#updateList();
|
|
76
|
+
}
|
|
77
|
+
else if (keys.matches(keyData, "tui.select.down") || keyData === "j") {
|
|
78
|
+
this.#selectedIndex = Math.min(this.#options.length - 1, this.#selectedIndex + 1);
|
|
79
|
+
this.#updateList();
|
|
80
|
+
}
|
|
81
|
+
else if (keys.matches(keyData, "tui.select.confirm") || keyData === "\n") {
|
|
82
|
+
const selected = this.#options[this.#selectedIndex];
|
|
83
|
+
if (selected !== undefined)
|
|
84
|
+
this.#onSelect(selected);
|
|
85
|
+
}
|
|
86
|
+
else if (keys.matches(keyData, "tui.select.cancel"))
|
|
87
|
+
this.#onCancel();
|
|
88
|
+
}
|
|
89
|
+
dispose() {
|
|
90
|
+
this.#countdown?.dispose();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Modifications: Source-synchronized scoped-model selector port: preserve session-only toggles,
|
|
5
5
|
* search, bulk/provider/reorder actions, dirty state, Ctrl+S persistence, refresh status,
|
|
6
6
|
* cancellation, and focus while remapping theme and public helper imports; local key labels preserve
|
|
7
|
-
* pinned platform formatting before layout without changing binding identities
|
|
8
|
-
*
|
|
7
|
+
* pinned platform formatting before layout without changing binding identities, and bare A1 uses the
|
|
8
|
+
* shared semantic modal shortcut row.
|
|
9
|
+
* Deviations: owned-modal-shortcut-hints.
|
|
9
10
|
*/
|
|
10
11
|
interface ScopedModel {
|
|
11
12
|
readonly provider: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Container, fuzzyFilter, getKeybindings, Input, Key, matchesKey, Spacer, Text, } from "@earendil-works/pi-tui";
|
|
2
2
|
import { DynamicBorder } from "../../../startup-public.js";
|
|
3
3
|
import { getModelSearchText } from "../model-search.js";
|
|
4
|
-
import { piTheme } from "
|
|
4
|
+
import { piTheme, renderPiModalShortcutHints } from "../../theme.js";
|
|
5
5
|
// Rationale: upstream's capitalized hint formatter is private to the package; the same mapping lives here.
|
|
6
6
|
function keyDisplayText(keybinding) {
|
|
7
7
|
return getKeybindings().getKeys(keybinding)
|
|
@@ -113,7 +113,9 @@ export class ScopedModelsSelectorComponent extends Container {
|
|
|
113
113
|
this.addChild(new DynamicBorder());
|
|
114
114
|
this.addChild(new Spacer(1));
|
|
115
115
|
this.addChild(new Text(theme.fg("accent", theme.bold("Model Configuration")), 0, 0));
|
|
116
|
-
|
|
116
|
+
const saveKey = keyDisplayText("app.models.save");
|
|
117
|
+
this.addChild(new Text(theme.fg("muted", "Session-only.")
|
|
118
|
+
+ (saveKey ? ` ${renderPiModalShortcutHints([{ key: saveKey, action: "to save to settings." }])}` : ""), 0, 0));
|
|
117
119
|
this.addChild(new Spacer(1));
|
|
118
120
|
// Search input
|
|
119
121
|
this.searchInput = new Input();
|
|
@@ -167,19 +169,18 @@ export class ScopedModelsSelectorComponent extends Container {
|
|
|
167
169
|
const allEnabled = this.enabledIds === null;
|
|
168
170
|
const countText = allEnabled
|
|
169
171
|
? "all enabled"
|
|
170
|
-
: `${enabledCount}/${this.allIds.length} enabled${unavailableCount ?
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
: theme.fg("dim", ` ${parts.join(" · ")}`);
|
|
172
|
+
: `${enabledCount}/${this.allIds.length} enabled${unavailableCount ? `, ${unavailableCount} unavailable` : ""}`;
|
|
173
|
+
const reorderKeys = [keyDisplayText("app.models.reorderUp"), keyDisplayText("app.models.reorderDown")].filter(Boolean).join("/");
|
|
174
|
+
const hint = renderPiModalShortcutHints([
|
|
175
|
+
{ key: keyDisplayText("tui.select.confirm"), action: "toggle" },
|
|
176
|
+
{ key: keyDisplayText("app.models.enableAll"), action: "all" },
|
|
177
|
+
{ key: keyDisplayText("app.models.clearAll"), action: "clear" },
|
|
178
|
+
{ key: keyDisplayText("app.models.toggleProvider"), action: "provider" },
|
|
179
|
+
{ key: reorderKeys, action: "reorder" },
|
|
180
|
+
{ key: keyDisplayText("app.models.save"), action: "save" },
|
|
181
|
+
{ action: countText },
|
|
182
|
+
], 2);
|
|
183
|
+
return this.isDirty ? `${hint} ${theme.fg("warning", "(unsaved)")}` : hint;
|
|
183
184
|
}
|
|
184
185
|
refresh() {
|
|
185
186
|
const query = this.searchInput.getValue();
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Provenance: @earendil-works/pi-coding-agent 0.87.0 (MIT), commit 16787ad5b2dc748047f314ca1bfe7708f30f54f3,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/footer.ts.
|
|
4
4
|
* Modifications: Consumes neutral owned-UI view data instead of a fabricated concrete AgentSession; an
|
|
5
|
-
* explicit bare-A1 profile colors the thinking-level name
|
|
6
|
-
*
|
|
7
|
-
* thinking level they already present.
|
|
5
|
+
* explicit bare-A1 profile colors the thinking-level name, renders its repository-context path, and
|
|
6
|
+
* reserves its linked pull-request badge before path truncation while preserving the remaining footer
|
|
7
|
+
* layout and formatting; replacement surfaces may suppress a thinking level they already present.
|
|
8
8
|
* Deviations: owned-status-level-color, owned-pull-request-badge.
|
|
9
9
|
*/
|
|
10
10
|
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
@@ -36,17 +36,33 @@ export class SessionFooter {
|
|
|
36
36
|
const contextPercentValue = usage?.contextPercent ?? 0;
|
|
37
37
|
const contextPercentSource = usage?.contextAvailable === false ? undefined : usage?.contextPercent;
|
|
38
38
|
const contextPercent = contextPercentSource !== null ? contextPercentValue.toFixed(1) : "?";
|
|
39
|
-
|
|
39
|
+
const repositoryPath = this.profile === "a1" ? view.status.footer?.repositoryPath ?? this.cwd : this.cwd;
|
|
40
|
+
let pwd = formatCwd(repositoryPath, process.env.HOME || process.env.USERPROFILE);
|
|
40
41
|
const branch = view.status.footer?.branch;
|
|
41
42
|
if (branch)
|
|
42
43
|
pwd = `${pwd} (${branch})`;
|
|
43
44
|
const sessionName = view.status.footer?.sessionName;
|
|
44
45
|
const pullRequest = this.profile === "a1" ? view.status.footer?.pullRequest : null;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
let pathRow;
|
|
47
|
+
if (pullRequest === undefined || pullRequest === null) {
|
|
48
|
+
pathRow = theme.fg("dim", sessionName ? `${pwd} • ${sessionName}` : pwd);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const badge = theme.fg("dim", " ")
|
|
52
|
+
+ hyperlink(theme.fg("mdLink", `#${pullRequest.number}`), pullRequest.url);
|
|
53
|
+
const sessionSuffix = sessionName ? theme.fg("dim", ` • ${sessionName}`) : "";
|
|
54
|
+
const full = theme.fg("dim", pwd) + badge + sessionSuffix;
|
|
55
|
+
if (visibleWidth(full) <= width)
|
|
56
|
+
pathRow = full;
|
|
57
|
+
else if (visibleWidth(badge) <= width) {
|
|
58
|
+
const pathWidth = Math.max(0, width - visibleWidth(badge));
|
|
59
|
+
const path = pathWidth === 0 ? "" : truncateToWidth(theme.fg("dim", pwd), pathWidth, theme.fg("dim", "..."));
|
|
60
|
+
pathRow = path + badge;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
pathRow = truncateToWidth(badge, width, theme.fg("dim", "..."));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
50
66
|
const parts = [];
|
|
51
67
|
if (input)
|
|
52
68
|
parts.push(`↑${formatTokens(input)}`);
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Modifications: Source-synchronized session selector port: preserve threaded/current/all scope,
|
|
5
5
|
* search, sort, named/path filters, rename, delete confirmation, active-session protection, loading
|
|
6
6
|
* progress, cancellation, focus, and disposal while remapping public helpers, owned keybindings/theme,
|
|
7
|
-
*
|
|
8
|
-
* Deviations:
|
|
7
|
+
* canonical path handling, and the shared bare-A1 modal shortcut row.
|
|
8
|
+
* Deviations: owned-modal-shortcut-hints.
|
|
9
9
|
*/
|
|
10
10
|
import { spawnSync } from "node:child_process";
|
|
11
11
|
import { existsSync, realpathSync } from "node:fs";
|
|
@@ -14,7 +14,7 @@ import * as os from "node:os";
|
|
|
14
14
|
import { Container, getKeybindings, Input, Spacer, Text, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
|
|
15
15
|
import { KeybindingsManager } from "../adjacent/core/keybindings.js";
|
|
16
16
|
import { DynamicBorder } from "../../../startup-public.js";
|
|
17
|
-
import { piTheme } from "
|
|
17
|
+
import { piTheme, renderPiModalShortcutHints } from "../../theme.js";
|
|
18
18
|
const theme = new Proxy({}, {
|
|
19
19
|
get(_target, property) {
|
|
20
20
|
const active = piTheme();
|
|
@@ -25,8 +25,8 @@ const theme = new Proxy({}, {
|
|
|
25
25
|
function keyText(keybinding, keybindings) {
|
|
26
26
|
return keybindings.getKeys(keybinding).join("/");
|
|
27
27
|
}
|
|
28
|
-
function
|
|
29
|
-
return
|
|
28
|
+
function shortcutHint(keybinding, action, keybindings) {
|
|
29
|
+
return { key: keyText(keybinding, keybindings), action };
|
|
30
30
|
}
|
|
31
31
|
import { filterAndSortSessions, hasSessionName } from "./session-selector-search.js";
|
|
32
32
|
function shortenPath(path) {
|
|
@@ -158,8 +158,11 @@ class SessionSelectorHeader {
|
|
|
158
158
|
let hintLine1;
|
|
159
159
|
let hintLine2;
|
|
160
160
|
if (this.confirmingDeletePath !== null) {
|
|
161
|
-
const confirmHint =
|
|
162
|
-
|
|
161
|
+
const confirmHint = theme.fg("error", "Delete session? ") + renderPiModalShortcutHints([
|
|
162
|
+
shortcutHint("tui.select.confirm", "confirm", this.keybindings),
|
|
163
|
+
shortcutHint("tui.select.cancel", "cancel", this.keybindings),
|
|
164
|
+
]);
|
|
165
|
+
hintLine1 = truncateToWidth(confirmHint, width, "…");
|
|
163
166
|
hintLine2 = "";
|
|
164
167
|
}
|
|
165
168
|
else if (this.statusMessage) {
|
|
@@ -169,18 +172,21 @@ class SessionSelectorHeader {
|
|
|
169
172
|
}
|
|
170
173
|
else {
|
|
171
174
|
const pathState = this.showPath ? "(on)" : "(off)";
|
|
172
|
-
const
|
|
173
|
-
|
|
175
|
+
const hint1 = renderPiModalShortcutHints([
|
|
176
|
+
shortcutHint("tui.input.tab", "scope", this.keybindings),
|
|
177
|
+
{ action: "re:<pattern> regex" },
|
|
178
|
+
{ action: '"phrase" exact' },
|
|
179
|
+
]);
|
|
174
180
|
const hint2Parts = [
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
181
|
+
shortcutHint("app.session.toggleSort", "sort", this.keybindings),
|
|
182
|
+
shortcutHint("app.session.toggleNamedFilter", "named", this.keybindings),
|
|
183
|
+
shortcutHint("app.session.delete", "delete", this.keybindings),
|
|
184
|
+
shortcutHint("app.session.togglePath", `path ${pathState}`, this.keybindings),
|
|
179
185
|
];
|
|
180
186
|
if (this.showRenameHint) {
|
|
181
|
-
hint2Parts.push(
|
|
187
|
+
hint2Parts.push(shortcutHint("app.session.rename", "rename", this.keybindings));
|
|
182
188
|
}
|
|
183
|
-
const hint2 = hint2Parts
|
|
189
|
+
const hint2 = renderPiModalShortcutHints(hint2Parts);
|
|
184
190
|
hintLine1 = truncateToWidth(hint1, width, "…");
|
|
185
191
|
hintLine2 = truncateToWidth(hint2, width, "…");
|
|
186
192
|
}
|
|
@@ -776,7 +782,10 @@ export class SessionSelectorComponent extends Container {
|
|
|
776
782
|
panel.addChild(new Spacer(1));
|
|
777
783
|
panel.addChild(this.renameInput);
|
|
778
784
|
panel.addChild(new Spacer(1));
|
|
779
|
-
panel.addChild(new Text(
|
|
785
|
+
panel.addChild(new Text(renderPiModalShortcutHints([
|
|
786
|
+
shortcutHint("tui.select.confirm", "to save", this.keybindings),
|
|
787
|
+
shortcutHint("tui.select.cancel", "to cancel", this.keybindings),
|
|
788
|
+
]), 1, 0));
|
|
780
789
|
this.buildBaseLayout(panel, { showHeader: false });
|
|
781
790
|
this.requestRender();
|
|
782
791
|
}
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
* Modifications: Preserve the searchable thinking-level selector, current/default semantics,
|
|
5
5
|
* selection, save, cancellation, and focus while accepting the active bare-A1 cycle-key label from the
|
|
6
6
|
* shell, styling the title with the established bold semantic accent treatment, placing its muted hint
|
|
7
|
-
* directly below it, deduplicating levels, and rendering aligned muted descriptions after
|
|
8
|
-
*
|
|
9
|
-
* mode
|
|
10
|
-
*
|
|
7
|
+
* directly below it, deduplicating levels, and rendering aligned muted descriptions after adjacent
|
|
8
|
+
* active and bracketed default markers. All list and border colors use the owned theme and its
|
|
9
|
+
* explicit color mode, and the footer uses the shared bare-A1 modal shortcut row. The comparison
|
|
10
|
+
* profile retains the public pinned component.
|
|
11
|
+
* Deviations: owned-modal-shortcut-hints, owned-level-cycle-shortcut, owned-thinking-selector-heading.
|
|
11
12
|
*/
|
|
12
13
|
import { Container, type Focusable, SelectList } from "@earendil-works/pi-tui";
|
|
13
14
|
export type ThinkingSelectorLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
@@ -21,6 +22,7 @@ export declare class OwnedThinkingSelectorComponent extends Container implements
|
|
|
21
22
|
private onCancel;
|
|
22
23
|
private onSelectAsDefault;
|
|
23
24
|
private currentLevel;
|
|
25
|
+
private defaultThinkingLevel;
|
|
24
26
|
private _focused;
|
|
25
27
|
get focused(): boolean;
|
|
26
28
|
set focused(value: boolean);
|
|
@@ -4,14 +4,15 @@
|
|
|
4
4
|
* Modifications: Preserve the searchable thinking-level selector, current/default semantics,
|
|
5
5
|
* selection, save, cancellation, and focus while accepting the active bare-A1 cycle-key label from the
|
|
6
6
|
* shell, styling the title with the established bold semantic accent treatment, placing its muted hint
|
|
7
|
-
* directly below it, deduplicating levels, and rendering aligned muted descriptions after
|
|
8
|
-
*
|
|
9
|
-
* mode
|
|
10
|
-
*
|
|
7
|
+
* directly below it, deduplicating levels, and rendering aligned muted descriptions after adjacent
|
|
8
|
+
* active and bracketed default markers. All list and border colors use the owned theme and its
|
|
9
|
+
* explicit color mode, and the footer uses the shared bare-A1 modal shortcut row. The comparison
|
|
10
|
+
* profile retains the public pinned component.
|
|
11
|
+
* Deviations: owned-modal-shortcut-hints, owned-level-cycle-shortcut, owned-thinking-selector-heading.
|
|
11
12
|
*/
|
|
12
13
|
import { Container, fuzzyFilter, getKeybindings, Input, SelectList, Spacer, Text, } from "@earendil-works/pi-tui";
|
|
13
14
|
import { DynamicBorder } from "../../../startup-public.js";
|
|
14
|
-
import { piTheme } from "
|
|
15
|
+
import { piTheme, renderPiModalShortcutHints } from "../../theme.js";
|
|
15
16
|
const THINKING_SELECT_LIST_LAYOUT = {
|
|
16
17
|
minPrimaryColumnWidth: 12,
|
|
17
18
|
maxPrimaryColumnWidth: 32,
|
|
@@ -35,6 +36,7 @@ export class OwnedThinkingSelectorComponent extends Container {
|
|
|
35
36
|
onCancel;
|
|
36
37
|
onSelectAsDefault;
|
|
37
38
|
currentLevel;
|
|
39
|
+
defaultThinkingLevel;
|
|
38
40
|
_focused = false;
|
|
39
41
|
get focused() {
|
|
40
42
|
return this._focused;
|
|
@@ -49,10 +51,11 @@ export class OwnedThinkingSelectorComponent extends Container {
|
|
|
49
51
|
this.onCancel = onCancel;
|
|
50
52
|
this.onSelectAsDefault = onSelectAsDefault;
|
|
51
53
|
this.currentLevel = currentLevel;
|
|
54
|
+
this.defaultThinkingLevel = defaultThinkingLevel;
|
|
52
55
|
this.allItems = [...new Set(availableLevels)].map((level) => ({
|
|
53
56
|
value: level,
|
|
54
57
|
label: level,
|
|
55
|
-
description:
|
|
58
|
+
description: LEVEL_DESCRIPTIONS[level],
|
|
56
59
|
}));
|
|
57
60
|
this.addChild(new DynamicBorder((text) => piTheme().fg("border", text)));
|
|
58
61
|
this.addChild(new Spacer(1));
|
|
@@ -67,7 +70,11 @@ export class OwnedThinkingSelectorComponent extends Container {
|
|
|
67
70
|
this.selectListChildIndex = this.children.length;
|
|
68
71
|
this.addChild(this.selectList);
|
|
69
72
|
this.addChild(new Spacer(1));
|
|
70
|
-
this.addChild(new Text(
|
|
73
|
+
this.addChild(new Text(renderPiModalShortcutHints([
|
|
74
|
+
{ key: this.keyDisplayText("tui.select.confirm"), action: "to select" },
|
|
75
|
+
{ key: this.keyDisplayText("app.thinking.save"), action: "to set as default" },
|
|
76
|
+
{ key: this.keyDisplayText("tui.select.cancel"), action: "to cancel" },
|
|
77
|
+
], 2), 0, 0));
|
|
71
78
|
this.addChild(new DynamicBorder((text) => piTheme().fg("border", text)));
|
|
72
79
|
}
|
|
73
80
|
keyDisplayText(keybinding) {
|
|
@@ -79,17 +86,20 @@ export class OwnedThinkingSelectorComponent extends Container {
|
|
|
79
86
|
.join("/");
|
|
80
87
|
}
|
|
81
88
|
buildSelectList(items, preselect) {
|
|
89
|
+
const markerWidth = (item) => (item.value === this.currentLevel ? 2 : 0) + (item.value === this.defaultThinkingLevel ? 10 : 0);
|
|
82
90
|
const primaryWidth = this.allItems.reduce((widest, item) => {
|
|
83
91
|
const level = item.label ?? item.value;
|
|
84
|
-
return Math.max(widest, level.length + (item
|
|
92
|
+
return Math.max(widest, level.length + markerWidth(item));
|
|
85
93
|
}, 0);
|
|
86
94
|
const themedItems = items.map((item) => {
|
|
87
95
|
const level = item.label ?? item.value;
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
|
|
96
|
+
const currentMarker = item.value === this.currentLevel ? ` ${piTheme().fg("success", "✓")}` : "";
|
|
97
|
+
const defaultMarker = item.value === this.defaultThinkingLevel
|
|
98
|
+
? ` ${piTheme().fg("muted", "[default]")}`
|
|
99
|
+
: "";
|
|
100
|
+
const separator = " ".repeat(Math.max(1, primaryWidth - level.length - markerWidth(item) + 1));
|
|
91
101
|
const description = item.description ? piTheme().fg("muted", item.description) : "";
|
|
92
|
-
return { value: item.value, label: `${level}${currentMarker}${separator}${description}` };
|
|
102
|
+
return { value: item.value, label: `${level}${currentMarker}${defaultMarker}${separator}${description}` };
|
|
93
103
|
});
|
|
94
104
|
// Invariant: the bare selector uses the owned theme's explicit color mode, not upstream's host detection.
|
|
95
105
|
const list = new SelectList(themedItems, Math.max(1, themedItems.length), {
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/tree-selector.ts.
|
|
4
4
|
* Modifications: Source-synchronized tree selector port: preserve filtering, folding, labels, copying,
|
|
5
5
|
* tree navigation, key hints, focus, and viewport behavior while remapping public types/components
|
|
6
|
-
* plus owned keybindings/theme helpers required to avoid the pinned package nested pi-tui singleton
|
|
7
|
-
*
|
|
6
|
+
* plus owned keybindings/theme helpers required to avoid the pinned package nested pi-tui singleton;
|
|
7
|
+
* bare A1 uses the shared semantic modal shortcut row.
|
|
8
|
+
* Deviations: owned-modal-shortcut-hints.
|
|
8
9
|
*/
|
|
9
10
|
import { type Component, Container, type Focusable } from "@earendil-works/pi-tui";
|
|
10
11
|
import { type SessionTreeNode } from "@earendil-works/pi-coding-agent";
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/tree-selector.ts.
|
|
4
4
|
* Modifications: Source-synchronized tree selector port: preserve filtering, folding, labels, copying,
|
|
5
5
|
* tree navigation, key hints, focus, and viewport behavior while remapping public types/components
|
|
6
|
-
* plus owned keybindings/theme helpers required to avoid the pinned package nested pi-tui singleton
|
|
7
|
-
*
|
|
6
|
+
* plus owned keybindings/theme helpers required to avoid the pinned package nested pi-tui singleton;
|
|
7
|
+
* bare A1 uses the shared semantic modal shortcut row.
|
|
8
|
+
* Deviations: owned-modal-shortcut-hints.
|
|
8
9
|
*/
|
|
9
10
|
import { Container, Input, Spacer, sliceByColumn, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi, } from "@earendil-works/pi-tui";
|
|
10
11
|
import { DynamicBorder } from "../../../startup-public.js";
|
|
11
12
|
import { KeybindingsManager } from "../adjacent/core/keybindings.js";
|
|
12
|
-
import { piTheme } from "
|
|
13
|
+
import { piTheme, renderPiModalShortcutHints } from "../../theme.js";
|
|
13
14
|
const theme = new Proxy({}, {
|
|
14
15
|
get(_target, property) {
|
|
15
16
|
const active = piTheme();
|
|
@@ -24,8 +25,8 @@ function formatKeyText(key) {
|
|
|
24
25
|
.map((value) => value.split("+").map((part) => process.platform === "darwin" && part.toLowerCase() === "alt" ? "option" : part).join("+"))
|
|
25
26
|
.join("/");
|
|
26
27
|
}
|
|
27
|
-
function
|
|
28
|
-
return
|
|
28
|
+
function shortcutHint(keybinding, action) {
|
|
29
|
+
return { key: formatKeyText(treeKeybindings.getKeys(keybinding).join("/")), action };
|
|
29
30
|
}
|
|
30
31
|
const TREE_GUTTER_WIDTH = 2;
|
|
31
32
|
const MIN_VISIBLE_ANCHOR_CONTENT_WIDTH = 4;
|
|
@@ -1075,14 +1076,12 @@ class TreeHelp {
|
|
|
1075
1076
|
invalidate() { }
|
|
1076
1077
|
render(width) {
|
|
1077
1078
|
const items = TREE_HELP_ITEMS.map(({ keys, label, labelFirst }) => {
|
|
1078
|
-
const
|
|
1079
|
-
|
|
1080
|
-
return label;
|
|
1081
|
-
return labelFirst ? `${label} ${text}` : `${text} ${label}`;
|
|
1079
|
+
const key = formatHelpKeys(keys);
|
|
1080
|
+
return renderPiModalShortcutHints([key ? { key, action: label, ...(labelFirst === undefined ? {} : { actionFirst: labelFirst }) } : { action: label }]);
|
|
1082
1081
|
});
|
|
1083
1082
|
const availableWidth = Math.max(1, width);
|
|
1084
1083
|
const indent = " ";
|
|
1085
|
-
const separator = "
|
|
1084
|
+
const separator = " ";
|
|
1086
1085
|
const lines = [];
|
|
1087
1086
|
let currentLine = "";
|
|
1088
1087
|
for (const item of items) {
|
|
@@ -1101,7 +1100,7 @@ class TreeHelp {
|
|
|
1101
1100
|
if (currentLine) {
|
|
1102
1101
|
lines.push(...wrapTextWithAnsi(currentLine.trimEnd(), availableWidth));
|
|
1103
1102
|
}
|
|
1104
|
-
return lines
|
|
1103
|
+
return lines;
|
|
1105
1104
|
}
|
|
1106
1105
|
}
|
|
1107
1106
|
const TREE_HELP_ITEMS = [
|
|
@@ -1184,7 +1183,10 @@ class LabelInput {
|
|
|
1184
1183
|
const availableWidth = width - indent.length;
|
|
1185
1184
|
lines.push(truncateToWidth(`${indent}${theme.fg("muted", "Label (empty to remove):")}`, width));
|
|
1186
1185
|
lines.push(...this.input.render(availableWidth).map((line) => truncateToWidth(`${indent}${line}`, width)));
|
|
1187
|
-
lines.push(truncateToWidth(
|
|
1186
|
+
lines.push(truncateToWidth(renderPiModalShortcutHints([
|
|
1187
|
+
shortcutHint("tui.select.confirm", "save"),
|
|
1188
|
+
shortcutHint("tui.select.cancel", "cancel"),
|
|
1189
|
+
], indent.length), width));
|
|
1188
1190
|
return lines;
|
|
1189
1191
|
}
|
|
1190
1192
|
handleInput(keyData) {
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
* Provenance: @earendil-works/pi-coding-agent 0.87.0 (MIT), commit 16787ad5b2dc748047f314ca1bfe7708f30f54f3,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/trust-selector.ts.
|
|
4
4
|
* Modifications: Mechanical source-synchronized trust selector port with injected public
|
|
5
|
-
* ProjectTrustStore-derived options
|
|
6
|
-
*
|
|
5
|
+
* ProjectTrustStore-derived options, remapped owned theme imports, and the shared bare-A1 modal
|
|
6
|
+
* shortcut row.
|
|
7
|
+
* Deviations: owned-modal-shortcut-hints.
|
|
7
8
|
*/
|
|
8
|
-
import { DynamicBorder
|
|
9
|
+
import { DynamicBorder } from "../../../startup-public.js";
|
|
9
10
|
import { Container, getKeybindings, Spacer, Text } from "@earendil-works/pi-tui";
|
|
10
|
-
import { piTheme } from "
|
|
11
|
+
import { piTheme, renderPiModalShortcutHints } from "../../theme.js";
|
|
11
12
|
function formatDecision(trustPath, decision) {
|
|
12
13
|
if (decision === null)
|
|
13
14
|
return "none";
|
|
@@ -39,7 +40,12 @@ export class TrustSelectorComponent extends Container {
|
|
|
39
40
|
this.listContainer = new Container();
|
|
40
41
|
this.addChild(this.listContainer);
|
|
41
42
|
this.addChild(new Spacer(1));
|
|
42
|
-
|
|
43
|
+
const keybindings = getKeybindings();
|
|
44
|
+
this.addChild(new Text(renderPiModalShortcutHints([
|
|
45
|
+
{ key: "↑↓", action: "navigate" },
|
|
46
|
+
{ key: keybindings.getKeys("tui.select.confirm").join("/"), action: "save" },
|
|
47
|
+
{ key: keybindings.getKeys("tui.select.cancel").join("/"), action: "cancel" },
|
|
48
|
+
]), 1, 0));
|
|
43
49
|
this.addChild(new Spacer(1));
|
|
44
50
|
this.addChild(new DynamicBorder());
|
|
45
51
|
this.updateList(options.savedDecision);
|
|
@@ -9,7 +9,7 @@ import type { AgentSettingOwner } from "../../../contracts/agent-engine/index.js
|
|
|
9
9
|
import { type AdapterCommandResult } from "./command-dispatch.js";
|
|
10
10
|
import { type OwnedPiVisualExtensionSupport } from "./extension-ui-binding.js";
|
|
11
11
|
import { type OwnedPiExtensionResourceSummary, type OwnedPiResourceSummary } from "./resource-catalog.js";
|
|
12
|
-
import { type PiEnginePackageUpdateProbe, type PiEngineRuntimeFactory } from "./session-runtime.js";
|
|
12
|
+
import { type PiEnginePackageUpdateProbe, type PiEngineRuntimeFactory, type PiRepositoryContextReader } from "./session-runtime.js";
|
|
13
13
|
import { PiWorkflowContexts } from "./workflow-contexts.js";
|
|
14
14
|
export type { OwnedPiExtensionResourceSummary, OwnedPiExtensionSourceSummary, OwnedPiResourceSummary } from "./resource-catalog.js";
|
|
15
15
|
export type { PiEngineRuntimeFactory, PiEngineRuntimeFactoryInput } from "./session-runtime.js";
|
|
@@ -41,6 +41,7 @@ export interface PiEngineAdapterOptions {
|
|
|
41
41
|
* mode. Returns display names of packages with updates available.
|
|
42
42
|
*/
|
|
43
43
|
readonly checkPackageUpdates?: PiEnginePackageUpdateProbe;
|
|
44
|
+
readonly repositoryContextReader?: PiRepositoryContextReader;
|
|
44
45
|
}
|
|
45
46
|
/** Owns the pinned Pi session lifecycle and translates its events into the neutral agent-engine contract. */
|
|
46
47
|
export declare class PiEngineAdapter implements OwnedUiPromptSuggestionGeneratorPort {
|
|
@@ -133,6 +133,7 @@ export class PiEngineAdapter {
|
|
|
133
133
|
projectTrustPrompt: options.projectTrustPrompt,
|
|
134
134
|
createRuntime: options.createRuntime,
|
|
135
135
|
checkPackageUpdates: options.checkPackageUpdates,
|
|
136
|
+
...(options.repositoryContextReader === undefined ? {} : { repositoryContextReader: options.repositoryContextReader }),
|
|
136
137
|
host: this.#workflowHost,
|
|
137
138
|
}, {
|
|
138
139
|
disposed: () => this.#disposed,
|
|
@@ -428,6 +429,7 @@ export class PiEngineAdapter {
|
|
|
428
429
|
usage: this.#usageCache ??= readUsageView(this.#engine.session, this.#engine.runtime, this.#activeModel),
|
|
429
430
|
footer: {
|
|
430
431
|
branch: this.#engine.gitBranch,
|
|
432
|
+
repositoryPath: this.#engine.repositoryCwd,
|
|
431
433
|
pullRequest: this.#engine.pullRequest,
|
|
432
434
|
sessionName: this.#engine.session?.sessionManager?.getSessionName() ?? null,
|
|
433
435
|
availableProviderCount: new Set(this.#engine.runtime?.services.modelRuntime.getAvailableSnapshot?.().map(model => model.provider).filter(provider => provider !== undefined) ?? []).size,
|
|
@@ -29,6 +29,7 @@ export function sameBlockContent(left, right) {
|
|
|
29
29
|
&& left.status === right.status
|
|
30
30
|
&& left.title === right.title
|
|
31
31
|
&& left.text === right.text
|
|
32
|
+
&& sameValue(left.userPresentation, right.userPresentation)
|
|
32
33
|
&& sameValue(left.toolState, right.toolState)
|
|
33
34
|
&& sameValue(left.toolRendering, right.toolRendering)
|
|
34
35
|
&& sameValue(left.payload, right.payload)
|
|
@@ -16,6 +16,12 @@ export interface PiEngineRuntimeFactoryInput {
|
|
|
16
16
|
}
|
|
17
17
|
export type PiEngineRuntimeFactory = (input: PiEngineRuntimeFactoryInput) => Promise<AgentSessionRuntime>;
|
|
18
18
|
export type PiEnginePackageUpdateProbe = (settingsManager: AgentSessionServices["settingsManager"]) => Promise<readonly string[]>;
|
|
19
|
+
export interface PiRepositoryContextSelection {
|
|
20
|
+
readonly cwd: string;
|
|
21
|
+
readonly branch: string;
|
|
22
|
+
}
|
|
23
|
+
export type PiRepositoryContextReader = (sessionId: string, sessionFile: string, signal: AbortSignal) => Promise<PiRepositoryContextSelection | null>;
|
|
24
|
+
export type PiGitBranchReader = (cwd: string, signal: AbortSignal) => Promise<string | null>;
|
|
19
25
|
export interface PiEngineRuntimeOptions {
|
|
20
26
|
readonly cwd: string;
|
|
21
27
|
readonly agentDir: string;
|
|
@@ -28,12 +34,14 @@ export interface PiEngineRuntimeOptions {
|
|
|
28
34
|
readonly checkPackageUpdates: PiEnginePackageUpdateProbe | undefined;
|
|
29
35
|
readonly pullRequestProbe?: PiPullRequestProbe;
|
|
30
36
|
readonly pullRequestRefreshMs?: number;
|
|
31
|
-
readonly
|
|
37
|
+
readonly repositoryContextPollMs?: number;
|
|
38
|
+
readonly repositoryContextReader?: PiRepositoryContextReader;
|
|
39
|
+
readonly gitBranchReader?: PiGitBranchReader;
|
|
32
40
|
readonly host: PiWorkflowHost;
|
|
33
41
|
}
|
|
34
42
|
export interface PiEngineRuntimePorts {
|
|
35
43
|
disposed(): boolean;
|
|
36
|
-
/** The runtime exists and its cwd
|
|
44
|
+
/** The runtime exists and its startup cwd is known; repository metadata resolves after binding. */
|
|
37
45
|
started(runtime: AgentSessionRuntime): void;
|
|
38
46
|
/** True while a runtime-initiated rebind must be ignored: delivery overload, stopped admission, or disposal. */
|
|
39
47
|
rebindBlocked(): boolean;
|
|
@@ -65,6 +73,7 @@ export declare class PiEngineRuntime {
|
|
|
65
73
|
/** Actual session replacements, excluding delivery-only invalidation of callbacks. */
|
|
66
74
|
get bindingGeneration(): number;
|
|
67
75
|
get cwd(): string;
|
|
76
|
+
get repositoryCwd(): string;
|
|
68
77
|
get gitBranch(): string | null;
|
|
69
78
|
get pullRequest(): PiPullRequestIdentity | null;
|
|
70
79
|
get sessionCommands(): PiSessionCommandIntegration | undefined;
|