@xingular/harness 1.2.0 → 1.3.1-unstable.1
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/CHANGELOG.md +63 -0
- package/README.md +26 -17
- package/builtin/skills/plugin-authoring/SKILL.md +34 -0
- package/dist/cli.js +7362 -6239
- package/dist/sdk/agents/builtin.js +3 -3
- package/dist/sdk/agents/planResearch.d.ts +23 -1
- package/dist/sdk/agents/planResearch.js +71 -8
- package/dist/sdk/agents/profiles.d.ts +16 -4
- package/dist/sdk/agents/profiles.js +75 -12
- package/dist/sdk/annotations/bridge.d.ts +2 -0
- package/dist/sdk/annotations/bridge.js +4 -0
- package/dist/sdk/annotations/capture.d.ts +44 -2
- package/dist/sdk/annotations/capture.js +104 -3
- package/dist/sdk/annotations/delivery.d.ts +24 -17
- package/dist/sdk/annotations/delivery.js +82 -49
- package/dist/sdk/annotations/inspect.js +7 -6
- package/dist/sdk/annotations/pageScript.js +4 -4
- package/dist/sdk/annotations/part.d.ts +0 -2
- package/dist/sdk/annotations/part.js +4 -33
- package/dist/sdk/annotations/queue.d.ts +2 -2
- package/dist/sdk/annotations/queue.js +12 -7
- package/dist/sdk/annotations/serverMethods.js +11 -7
- package/dist/sdk/annotations/store.d.ts +13 -21
- package/dist/sdk/annotations/store.js +47 -37
- package/dist/sdk/capabilities/runSnapshot.js +10 -4
- package/dist/sdk/commands/list.js +2 -0
- package/dist/sdk/commands/registry.d.ts +11 -3
- package/dist/sdk/commands/registry.js +3 -2
- package/dist/sdk/core/links.d.ts +51 -0
- package/dist/sdk/core/links.js +155 -0
- package/dist/sdk/core/shell.d.ts +20 -0
- package/dist/sdk/core/shell.js +73 -0
- package/dist/sdk/core/workspaceBashTool.d.ts +17 -1
- package/dist/sdk/core/workspaceBashTool.js +16 -2
- package/dist/sdk/core/workspaceSandbox.d.ts +10 -0
- package/dist/sdk/core/workspaceSandbox.js +52 -12
- package/dist/sdk/core/workspaceWriteOperations.d.ts +11 -0
- package/dist/sdk/core/workspaceWriteOperations.js +26 -8
- package/dist/sdk/doctor/checks.js +71 -12
- package/dist/sdk/harness.d.ts +5 -0
- package/dist/sdk/harness.js +11 -6
- package/dist/sdk/hub/hub.js +5 -3
- package/dist/sdk/index.d.ts +3 -2
- package/dist/sdk/index.js +2 -1
- package/dist/sdk/plugins/builtin.js +14 -9
- package/dist/sdk/plugins/builtinRegistry.d.ts +3 -1
- package/dist/sdk/plugins/builtinRegistry.js +9 -3
- package/dist/sdk/plugins/discover.d.ts +7 -1
- package/dist/sdk/plugins/discover.js +41 -2
- package/dist/sdk/plugins/identity.js +1 -1
- package/dist/sdk/plugins/install.d.ts +6 -2
- package/dist/sdk/plugins/install.js +29 -5
- package/dist/sdk/plugins/inventory.js +3 -3
- package/dist/sdk/plugins/manifest.d.ts +2 -0
- package/dist/sdk/plugins/manifest.js +21 -4
- package/dist/sdk/plugins/plugins.d.ts +2 -0
- package/dist/sdk/plugins/plugins.js +1 -0
- package/dist/sdk/plugins/proposals.d.ts +17 -0
- package/dist/sdk/plugins/proposals.js +147 -0
- package/dist/sdk/plugins/types.d.ts +1 -1
- package/dist/sdk/plugins/types.js +1 -1
- package/dist/sdk/prompt/compile.d.ts +13 -4
- package/dist/sdk/prompt/compile.js +46 -20
- package/dist/sdk/prompt/standard.d.ts +1 -1
- package/dist/sdk/prompt/standard.js +1 -1
- package/dist/sdk/server/methods.js +14 -2
- package/dist/sdk/sessions/compactionCheckpoint.d.ts +3 -3
- package/dist/sdk/sessions/compactionCheckpoint.js +12 -12
- package/dist/sdk/sessions/continuation.d.ts +4 -2
- package/dist/sdk/sessions/continuation.js +7 -6
- package/dist/sdk/sessions/contracts.d.ts +22 -4
- package/dist/sdk/sessions/contracts.js +12 -7
- package/dist/sdk/sessions/planMode.js +2 -2
- package/dist/sdk/sessions/runStore.js +3 -1
- package/dist/sdk/sessions/runner.js +2 -2
- package/dist/sdk/sessions/sessionState.d.ts +13 -0
- package/dist/sdk/sessions/sessionState.js +31 -0
- package/dist/sdk/sessions/sessions.d.ts +7 -0
- package/dist/sdk/sessions/sessions.js +73 -15
- package/dist/sdk/sessions/subagentService.d.ts +15 -0
- package/dist/sdk/sessions/subagentService.js +195 -55
- package/dist/sdk/sessions/subagents.d.ts +10 -1
- package/dist/sdk/sessions/subagents.js +4 -0
- package/dist/sdk/sessions/workSlice.d.ts +8 -5
- package/dist/sdk/sessions/workSlice.js +77 -45
- package/dist/sdk/terminal/controller.d.ts +20 -0
- package/dist/sdk/terminal/controller.js +43 -18
- package/dist/sdk/terminal/opentui/ansi.d.ts +25 -0
- package/dist/sdk/terminal/opentui/ansi.js +192 -0
- package/dist/sdk/terminal/opentui/model.d.ts +163 -0
- package/dist/sdk/terminal/opentui/model.js +482 -0
- package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +3 -3
- package/dist/sdk/terminal/opentui/subagentsWidget.js +7 -5
- package/dist/sdk/terminal/opentui/theme.d.ts +2 -0
- package/dist/sdk/terminal/opentui/theme.js +2 -0
- package/dist/sdk/terminal/piExtension.js +98 -15
- package/dist/sdk/terminal/subagentMonitor.d.ts +17 -4
- package/dist/sdk/terminal/subagentMonitor.js +29 -8
- package/dist/sdk/terminal/terminals.d.ts +16 -0
- package/dist/sdk/terminal/terminals.js +130 -26
- package/dist/sdk/terminal/trajectory.d.ts +6 -1
- package/dist/sdk/terminal/trajectory.js +8 -0
- package/dist/sdk/terminal/tui/annotateCommand.d.ts +5 -1
- package/dist/sdk/terminal/tui/annotateCommand.js +21 -7
- package/dist/sdk/terminal/tui/annotateSend.d.ts +30 -0
- package/dist/sdk/terminal/tui/annotateSend.js +40 -0
- package/dist/sdk/terminal/tui/chrome.d.ts +4 -0
- package/dist/sdk/terminal/tui/chrome.js +13 -0
- package/dist/sdk/terminal/tui/commandPages.d.ts +1 -1
- package/dist/sdk/terminal/tui/commandPages.js +16 -11
- package/dist/sdk/terminal/tui/commands.d.ts +4 -0
- package/dist/sdk/terminal/tui/commands.js +12 -2
- package/dist/sdk/terminal/tui/dialogs.js +1 -0
- package/dist/sdk/terminal/tui/pageOverlay.d.ts +3 -0
- package/dist/sdk/terminal/tui/pageOverlay.js +25 -7
- package/dist/sdk/terminal/tui/pages/agentsPage.js +5 -2
- package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +70 -16
- package/dist/sdk/terminal/tui/pages/annotatePage.js +349 -115
- package/dist/sdk/terminal/tui/pages/browserPage.js +5 -4
- package/dist/sdk/terminal/tui/pages/hubPage.d.ts +14 -1
- package/dist/sdk/terminal/tui/pages/hubPage.js +192 -28
- package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +14 -1
- package/dist/sdk/terminal/tui/pages/pluginsPage.js +295 -25
- package/dist/sdk/terminal/tui/pages/subagentsPage.js +8 -5
- package/dist/sdk/terminal/tui/pages/usagePage.d.ts +4 -2
- package/dist/sdk/terminal/tui/pages/usagePage.js +39 -12
- package/dist/sdk/terminal/tui/pluginCommands.d.ts +1 -1
- package/dist/sdk/terminal/tui/pluginCommands.js +13 -3
- package/dist/sdk/tools/defaultSkills.d.ts +4 -0
- package/dist/sdk/tools/defaultSkills.js +20 -0
- package/dist/sdk/tools/definitions.d.ts +3 -1
- package/dist/sdk/tools/definitions.js +17 -1
- package/dist/sdk/tools/dispatch.js +12 -0
- package/dist/sdk/tools/harnessTools.js +1 -1
- package/dist/sdk/tools/sessionName.d.ts +9 -0
- package/dist/sdk/tools/sessionName.js +58 -11
- package/dist/sdk/tools/spawnSubagent.js +9 -7
- package/dist/sdk/tools/todo.d.ts +15 -0
- package/dist/sdk/tools/todo.js +64 -0
- package/dist/sdk/world/world.d.ts +0 -2
- package/dist/terminal-opentui.js +3331 -1584
- package/dist/terminal-pi.js +421 -133
- package/docs/README.md +3 -0
- package/docs/architecture/00-overview.md +1 -1
- package/docs/architecture/01-extension-points.md +1 -1
- package/docs/architecture/02-sessions-and-runs.md +73 -36
- package/docs/architecture/03-variants.md +1 -3
- package/docs/architecture/04-prompt.md +24 -13
- package/docs/architecture/06-plugins-and-capabilities.md +46 -10
- package/docs/architecture/07-tools-and-gate.md +49 -8
- package/docs/architecture/09-accounts-and-connectors.md +8 -2
- package/docs/architecture/10-server-protocol.md +68 -16
- package/docs/architecture/11-terminal.md +94 -45
- package/docs/architecture/12-storage.md +1 -0
- package/docs/architecture/13-world-tools.md +8 -6
- package/docs/architecture/14-surfaces-and-parity.md +4 -1
- package/docs/architecture/README.md +20 -18
- package/docs/architecture/proposals/PROP-0006-run-checklist.md +2 -0
- package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +6 -2
- package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +32 -21
- package/docs/architecture/proposals/PROP-0044-work-slice-defaults.md +93 -0
- package/docs/architecture/proposals/PROP-0045-rename-checklist-to-todo.md +132 -0
- package/docs/architecture/proposals/PROP-0046-progress-aware-stall-guards.md +82 -0
- package/docs/architecture/proposals/PROP-0047-plugins-hub-separation.md +122 -0
- package/docs/architecture/proposals/PROP-0048-simple-annotate.md +85 -0
- package/docs/architecture/proposals/README.md +11 -6
- package/docs/decisions/ADR-0039-progress-aware-stall-guards.md +39 -0
- package/docs/decisions/ADR-0040-architecture-change-workflow.md +31 -0
- package/docs/decisions/ADR-0041-plugins-hub-separation.md +41 -0
- package/docs/decisions/ADR-0042-windows-shell-without-sandbox.md +40 -0
- package/docs/decisions/ADR-0043-parents-continue-stopped-subagents.md +49 -0
- package/docs/decisions/ADR-0044-annotations-pending-or-sent.md +24 -0
- package/docs/decisions/ADR-0045-default-plugin-authoring-skill.md +9 -0
- package/docs/decisions/ADR-0046-hash-bound-plugin-proposals.md +20 -0
- package/docs/decisions/ADR-0047-links-open-with-the-os-handler.md +47 -0
- package/docs/doctor.md +14 -1
- package/docs/parity.md +16 -13
- package/docs/releases/1.3.0.md +21 -0
- package/docs/releases/1.3.1-unstable.1.md +8 -0
- package/docs/releases/README.md +9 -6
- package/docs/terminal-tui.md +127 -65
- package/package.json +1 -1
- package/dist/sdk/terminal/tui/pages/notesPage.d.ts +0 -75
- package/dist/sdk/terminal/tui/pages/notesPage.js +0 -201
- package/dist/sdk/tools/checklist.d.ts +0 -9
- package/dist/sdk/tools/checklist.js +0 -55
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The Hub page: the
|
|
2
|
+
* The Hub page: the Community catalog and all installed Hub receipts. Installing asks first,
|
|
3
3
|
* installs exactly the listed version, and leaves code switched off and untrusted.
|
|
4
4
|
*/
|
|
5
5
|
import type { Theme } from '@earendil-works/pi-coding-agent';
|
|
@@ -15,12 +15,20 @@ export interface HubPageOptions {
|
|
|
15
15
|
}
|
|
16
16
|
export declare class HubPage implements TerminalPage {
|
|
17
17
|
private readonly options;
|
|
18
|
+
readonly presentation = "fullscreen";
|
|
18
19
|
private catalog;
|
|
19
20
|
private section;
|
|
20
21
|
private error;
|
|
22
|
+
private refreshError;
|
|
23
|
+
private refreshing;
|
|
24
|
+
private previewTitle;
|
|
25
|
+
private previewText;
|
|
26
|
+
private previewOffset;
|
|
27
|
+
private previewRows;
|
|
21
28
|
private busy;
|
|
22
29
|
private disposed;
|
|
23
30
|
private readonly list;
|
|
31
|
+
private pointerLayout?;
|
|
24
32
|
constructor(options: HubPageOptions);
|
|
25
33
|
get focused(): boolean;
|
|
26
34
|
set focused(value: boolean);
|
|
@@ -29,11 +37,16 @@ export declare class HubPage implements TerminalPage {
|
|
|
29
37
|
tabs(): readonly TabInfo[];
|
|
30
38
|
activeTab(): string;
|
|
31
39
|
hint(): string;
|
|
40
|
+
private refreshOnOpen;
|
|
32
41
|
private load;
|
|
33
42
|
private fill;
|
|
34
43
|
private rows;
|
|
35
44
|
private activateRow;
|
|
45
|
+
private previewEntry;
|
|
46
|
+
private manageReceipt;
|
|
47
|
+
private status;
|
|
36
48
|
handleMouse(event: TerminalMouseInput): import("@earendil-works/pi-tui").TuiMouseEventResult | undefined;
|
|
37
49
|
handleInput(data: string): boolean;
|
|
50
|
+
private entryInspector;
|
|
38
51
|
render(width: number, rows: number): string[];
|
|
39
52
|
}
|
|
@@ -1,47 +1,87 @@
|
|
|
1
1
|
import { matchesKey, truncateToWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
2
2
|
import { installHubEntry } from "../../hubMenu.js";
|
|
3
|
-
import { safeText } from "../chrome.js";
|
|
3
|
+
import { inspectorListWidth, safeText, splitColumns } from "../chrome.js";
|
|
4
4
|
import { FilterList } from "../list.js";
|
|
5
5
|
const SECTIONS = [
|
|
6
6
|
{ id: 'catalog', title: 'Catalog' },
|
|
7
7
|
{ id: 'installed', title: 'Installed' }
|
|
8
8
|
];
|
|
9
9
|
const REFRESH = 'action:refresh';
|
|
10
|
+
const installedId = (id, version) => `installed:${id}@${version}`;
|
|
10
11
|
export class HubPage {
|
|
11
12
|
options;
|
|
13
|
+
presentation = 'fullscreen';
|
|
12
14
|
catalog;
|
|
13
15
|
section = 'catalog';
|
|
14
16
|
error;
|
|
17
|
+
refreshError;
|
|
18
|
+
refreshing = false;
|
|
19
|
+
previewTitle;
|
|
20
|
+
previewText;
|
|
21
|
+
previewOffset = 0;
|
|
22
|
+
previewRows = 1;
|
|
15
23
|
busy = false;
|
|
16
24
|
disposed = false;
|
|
17
25
|
list;
|
|
26
|
+
pointerLayout;
|
|
18
27
|
constructor(options) {
|
|
19
28
|
this.options = options;
|
|
20
29
|
this.list = new FilterList({
|
|
21
|
-
theme: options.theme, search: 'always', noun: ['entry', 'entries'], empty: '
|
|
30
|
+
theme: options.theme, search: 'always', noun: ['entry', 'entries'], empty: 'No Community entries have been published yet.',
|
|
22
31
|
onActivate: row => { void this.activateRow(row.id); }
|
|
23
32
|
});
|
|
24
33
|
}
|
|
25
34
|
get focused() { return this.list.focused; }
|
|
26
35
|
set focused(value) { this.list.focused = value; }
|
|
27
|
-
activate() {
|
|
28
|
-
void this.load(false); }
|
|
36
|
+
activate() { void this.refreshOnOpen(); }
|
|
29
37
|
dispose() { this.disposed = true; }
|
|
30
38
|
tabs() { return SECTIONS; }
|
|
31
39
|
activeTab() { return this.section; }
|
|
32
40
|
hint() {
|
|
33
|
-
|
|
41
|
+
if (this.previewText !== undefined)
|
|
42
|
+
return '↑↓ scroll · PgUp/PgDn page · Esc back';
|
|
43
|
+
if (this.list.query)
|
|
44
|
+
return 'Enter open · Esc clear';
|
|
45
|
+
if (this.section === 'installed')
|
|
46
|
+
return 'Enter manage receipt · type to search';
|
|
47
|
+
const selectedId = this.list.selected?.id;
|
|
48
|
+
const entry = this.catalog?.entries.find(candidate => candidate.channel === 'community' && candidate.id + '@' + candidate.version === selectedId);
|
|
49
|
+
if (entry?.delivery.kind === 'pi-package')
|
|
50
|
+
return 'Enter install exact version · type to search';
|
|
51
|
+
return entry ? 'Enter preview or install · type to search' : 'Enter refresh catalog · type to search';
|
|
52
|
+
}
|
|
53
|
+
async refreshOnOpen() {
|
|
54
|
+
await this.load(false);
|
|
55
|
+
if (!this.disposed)
|
|
56
|
+
await this.load(true);
|
|
34
57
|
}
|
|
35
58
|
async load(refresh) {
|
|
59
|
+
if (refresh) {
|
|
60
|
+
this.refreshing = true;
|
|
61
|
+
this.options.changed();
|
|
62
|
+
}
|
|
36
63
|
try {
|
|
37
64
|
const catalog = await this.options.call('hub.list', refresh ? { refresh: true } : {});
|
|
38
65
|
this.catalog = catalog;
|
|
39
66
|
this.error = undefined;
|
|
40
|
-
if (refresh
|
|
41
|
-
this.
|
|
67
|
+
if (refresh) {
|
|
68
|
+
this.refreshError = catalog.error ?? undefined;
|
|
69
|
+
if (catalog.error)
|
|
70
|
+
this.options.ui.notify(`${catalog.error} Using ${catalog.origin} content.`, 'warning');
|
|
71
|
+
}
|
|
72
|
+
else if (catalog.error) {
|
|
73
|
+
this.refreshError = catalog.error;
|
|
74
|
+
}
|
|
42
75
|
}
|
|
43
76
|
catch (error) {
|
|
44
|
-
|
|
77
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
78
|
+
if (refresh)
|
|
79
|
+
this.refreshError = message;
|
|
80
|
+
else if (!this.catalog)
|
|
81
|
+
this.error = message;
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
this.refreshing = false;
|
|
45
85
|
}
|
|
46
86
|
if (this.disposed)
|
|
47
87
|
return;
|
|
@@ -53,22 +93,24 @@ export class HubPage {
|
|
|
53
93
|
}
|
|
54
94
|
rows() {
|
|
55
95
|
if (this.section === 'installed') {
|
|
96
|
+
const receipts = this.catalog?.installed ?? [];
|
|
56
97
|
return [
|
|
57
|
-
...
|
|
58
|
-
id:
|
|
98
|
+
...receipts.map(receipt => ({
|
|
99
|
+
id: installedId(receipt.entry.id, receipt.entry.version),
|
|
59
100
|
label: safeText(receipt.entry.title),
|
|
60
|
-
group: receipt.entry.category,
|
|
61
|
-
detail:
|
|
101
|
+
group: safeText(receipt.entry.category),
|
|
102
|
+
detail: `${receipt.entry.channel} · ${receipt.state ?? 'installed'} · ${receipt.entry.version}`,
|
|
62
103
|
tone: receipt.state === 'installed' ? 'success' : 'warning',
|
|
63
|
-
searchText: receipt.entry.title
|
|
64
|
-
}))
|
|
104
|
+
searchText: `${receipt.entry.title} ${receipt.entry.category} ${receipt.entry.id} ${receipt.entry.publisher} ${receipt.entry.channel} ${receipt.state ?? ''}`
|
|
105
|
+
})),
|
|
106
|
+
{ id: REFRESH, label: '⟳ Refresh catalog', group: 'Actions', tone: 'accent' }
|
|
65
107
|
];
|
|
66
108
|
}
|
|
67
|
-
const entries =
|
|
109
|
+
const entries = (this.catalog?.entries ?? []).filter(entry => entry.channel === 'community').sort((left, right) => left.category.localeCompare(right.category));
|
|
68
110
|
return [
|
|
69
111
|
...entries.map(entry => ({
|
|
70
112
|
id: entry.id + '@' + entry.version, label: safeText(entry.title), group: safeText(entry.category),
|
|
71
|
-
detail: entry.version, tone: 'muted', searchText: entry.title
|
|
113
|
+
detail: entry.version, tone: 'muted', searchText: `${entry.title} ${entry.category} ${entry.id} ${entry.publisher} ${entry.tags.join(' ')}`
|
|
72
114
|
})),
|
|
73
115
|
{ id: REFRESH, label: '⟳ Refresh catalog', group: 'Actions', tone: 'accent' }
|
|
74
116
|
];
|
|
@@ -82,20 +124,103 @@ export class HubPage {
|
|
|
82
124
|
await this.load(true);
|
|
83
125
|
return;
|
|
84
126
|
}
|
|
85
|
-
if (id.startsWith('installed:'))
|
|
127
|
+
if (id.startsWith('installed:')) {
|
|
128
|
+
const receipt = this.catalog?.installed.find(candidate => installedId(candidate.entry.id, candidate.entry.version) === id);
|
|
129
|
+
if (receipt)
|
|
130
|
+
await this.manageReceipt(receipt);
|
|
86
131
|
return;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
132
|
+
}
|
|
133
|
+
const entry = this.catalog?.entries.find(candidate => candidate.channel === 'community' && candidate.id + '@' + candidate.version === id);
|
|
134
|
+
if (entry) {
|
|
135
|
+
const installAction = `Install exact version ${entry.version}`;
|
|
136
|
+
const actions = entry.delivery.kind === 'pi-package'
|
|
137
|
+
? [installAction, 'Back']
|
|
138
|
+
: ['Preview reviewed content', installAction, 'Back'];
|
|
139
|
+
const action = await this.options.ui.select(`${safeText(entry.title)} · ${entry.version}`, actions);
|
|
140
|
+
if (action === 'Preview reviewed content')
|
|
141
|
+
await this.previewEntry(entry);
|
|
142
|
+
else if (action === installAction) {
|
|
143
|
+
await installHubEntry(this.options.ui, this.options.call, entry);
|
|
144
|
+
await this.load(false);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
90
147
|
}
|
|
91
148
|
finally {
|
|
92
149
|
this.busy = false;
|
|
93
150
|
}
|
|
94
151
|
}
|
|
152
|
+
async previewEntry(entry) {
|
|
153
|
+
if (entry.delivery.kind === 'pi-package')
|
|
154
|
+
return;
|
|
155
|
+
try {
|
|
156
|
+
const page = await this.options.call('terminal.browser.hubPreview', { id: entry.id, version: entry.version });
|
|
157
|
+
this.previewTitle = safeText(entry.title);
|
|
158
|
+
this.previewText = page.content + (page.done ? '' : '\n\n[Preview limited to first page.]');
|
|
159
|
+
this.previewOffset = 0;
|
|
160
|
+
this.pointerLayout = undefined;
|
|
161
|
+
this.options.changed();
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
this.options.ui.notify(error instanceof Error ? error.message : String(error), 'error');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async manageReceipt(receipt) {
|
|
168
|
+
const action = await this.options.ui.select(`${receipt.entry.title} · ${receipt.entry.channel} · ${receipt.entry.version}`, ['Uninstall this version', 'Back']);
|
|
169
|
+
if (action !== 'Uninstall this version')
|
|
170
|
+
return;
|
|
171
|
+
const confirmed = await this.options.ui.confirm(`Uninstall ${receipt.entry.title}?`, `This removes only resources recorded by the ${receipt.entry.channel} receipt ${receipt.entry.id}@${receipt.entry.version} and revokes their attachment choices.`);
|
|
172
|
+
if (!confirmed)
|
|
173
|
+
return;
|
|
174
|
+
try {
|
|
175
|
+
await this.options.call('hub.uninstall', { id: receipt.entry.id, version: receipt.entry.version });
|
|
176
|
+
this.options.ui.notify(`Uninstalled ${receipt.entry.title} ${receipt.entry.version}.`, 'info');
|
|
177
|
+
await this.load(false);
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
this.options.ui.notify(error instanceof Error ? error.message : String(error), 'error');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
status() {
|
|
184
|
+
const catalog = this.catalog;
|
|
185
|
+
const error = this.refreshError ?? catalog.error;
|
|
186
|
+
const lastRefresh = catalog.refreshedAt ? ` · last refreshed ${catalog.refreshedAt}` : '';
|
|
187
|
+
if (this.refreshing)
|
|
188
|
+
return { text: `${catalog.origin} catalog · refreshing…${lastRefresh}`, tone: 'muted' };
|
|
189
|
+
if (error)
|
|
190
|
+
return { text: `${catalog.origin} catalog · refresh failed: ${error}${lastRefresh}`, tone: 'warning' };
|
|
191
|
+
return { text: `${catalog.origin} catalog${catalog.refreshedAt ? ` · refreshed ${catalog.refreshedAt}` : ''}`, tone: 'dim' };
|
|
192
|
+
}
|
|
95
193
|
handleMouse(event) {
|
|
96
|
-
|
|
194
|
+
if (this.previewText !== undefined)
|
|
195
|
+
return { handled: true, render: false };
|
|
196
|
+
const layout = this.pointerLayout;
|
|
197
|
+
if (!layout)
|
|
198
|
+
return undefined;
|
|
199
|
+
if (event.x < 0 || event.x >= layout.width || event.y < layout.top || event.y >= layout.top + layout.rows)
|
|
200
|
+
return { handled: true, render: false };
|
|
201
|
+
return this.list.handleMouse({ ...event, y: event.y - layout.top });
|
|
97
202
|
}
|
|
98
203
|
handleInput(data) {
|
|
204
|
+
if (this.previewText !== undefined) {
|
|
205
|
+
if (matchesKey(data, 'escape')) {
|
|
206
|
+
this.previewTitle = undefined;
|
|
207
|
+
this.previewText = undefined;
|
|
208
|
+
this.previewOffset = 0;
|
|
209
|
+
this.options.changed();
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
const page = Math.max(1, this.previewRows);
|
|
213
|
+
const delta = matchesKey(data, 'down') ? 1 : matchesKey(data, 'up') ? -1
|
|
214
|
+
: matchesKey(data, 'pageDown') ? page : matchesKey(data, 'pageUp') ? -page : 0;
|
|
215
|
+
if (matchesKey(data, 'home'))
|
|
216
|
+
this.previewOffset = 0;
|
|
217
|
+
else if (matchesKey(data, 'end'))
|
|
218
|
+
this.previewOffset = Number.MAX_SAFE_INTEGER;
|
|
219
|
+
else
|
|
220
|
+
this.previewOffset += delta;
|
|
221
|
+
this.options.changed();
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
99
224
|
if (matchesKey(data, 'tab') || matchesKey(data, 'shift+tab')) {
|
|
100
225
|
if (!this.list.query) {
|
|
101
226
|
this.section = this.section === 'catalog' ? 'installed' : 'catalog';
|
|
@@ -105,22 +230,61 @@ export class HubPage {
|
|
|
105
230
|
}
|
|
106
231
|
return this.list.handleInput(data);
|
|
107
232
|
}
|
|
233
|
+
entryInspector(entry, installed, width, rows) {
|
|
234
|
+
const theme = this.options.theme();
|
|
235
|
+
if (width < 1 || rows < 1)
|
|
236
|
+
return [];
|
|
237
|
+
if (!entry)
|
|
238
|
+
return [theme.fg('muted', 'Select an entry to review its publisher, license, and version.')].slice(0, rows);
|
|
239
|
+
const lines = [theme.bold(safeText(entry.title)), '', ...wrapTextWithAnsi(safeText(entry.description), width), ''];
|
|
240
|
+
lines.push(`Category: ${safeText(entry.category)}`, `Publisher: ${safeText(entry.publisher)}`, `License: ${safeText(entry.license)}`, `Version: ${safeText(entry.version)}`, `Channel: ${safeText(entry.channel)}`, `ID: ${safeText(entry.id)}`);
|
|
241
|
+
lines.push('', ...wrapTextWithAnsi(theme.fg('dim', `Source: ${safeText(entry.sourceUrl)}`), width));
|
|
242
|
+
if (installed)
|
|
243
|
+
lines.push('', `Installed: ${safeText(installed.installedAt)}`, `Receipt: ${safeText(installed.state ?? 'installed')} · ${safeText(installed.entry.channel)}`);
|
|
244
|
+
if (entry.delivery.kind === 'pi-package')
|
|
245
|
+
lines.push('', theme.fg('warning', 'Package code stays switched off and untrusted until reviewed.'));
|
|
246
|
+
return lines.slice(0, rows).map(line => truncateToWidth(line, width, ''));
|
|
247
|
+
}
|
|
108
248
|
render(width, rows) {
|
|
109
249
|
const theme = this.options.theme();
|
|
110
250
|
if (width < 1 || rows < 1)
|
|
111
251
|
return [];
|
|
112
|
-
if (
|
|
113
|
-
|
|
252
|
+
if (this.previewText !== undefined) {
|
|
253
|
+
const content = this.previewText.split('\n').flatMap(line => wrapTextWithAnsi(safeText(line), width));
|
|
254
|
+
this.previewRows = Math.max(1, rows - 1);
|
|
255
|
+
this.previewOffset = Math.min(this.previewOffset, Math.max(0, content.length - this.previewRows));
|
|
256
|
+
const header = theme.bold(`Preview · ${this.previewTitle ?? 'Hub entry'} · ${this.previewOffset + 1}/${Math.max(1, content.length)}`);
|
|
257
|
+
return [header, ...content.slice(this.previewOffset, this.previewOffset + this.previewRows)]
|
|
258
|
+
.slice(0, rows).map(line => truncateToWidth(line, width, ''));
|
|
259
|
+
}
|
|
260
|
+
if (!this.catalog) {
|
|
261
|
+
this.pointerLayout = undefined;
|
|
262
|
+
return [theme.fg(this.error ? 'error' : 'dim', this.error ? 'Could not read the catalog: ' + safeText(this.error) : 'Reading the catalog…')];
|
|
263
|
+
}
|
|
114
264
|
const selectedId = this.list.selected?.id;
|
|
115
265
|
const installed = this.section === 'installed'
|
|
116
|
-
? this.catalog.installed.find(receipt =>
|
|
266
|
+
? this.catalog.installed.find(receipt => installedId(receipt.entry.id, receipt.entry.version) === selectedId)
|
|
117
267
|
: undefined;
|
|
118
|
-
const entry = installed?.entry ?? this.catalog.entries.find(candidate => candidate.id + '@' + candidate.version === selectedId);
|
|
268
|
+
const entry = installed?.entry ?? this.catalog.entries.find(candidate => candidate.channel === 'community' && candidate.id + '@' + candidate.version === selectedId);
|
|
269
|
+
const status = this.status();
|
|
270
|
+
const statusLine = theme.fg(status.tone, truncateToWidth(safeText(status.text), width, ''));
|
|
271
|
+
const paneWidth = inspectorListWidth(width);
|
|
272
|
+
if (paneWidth !== undefined) {
|
|
273
|
+
const bodyRows = Math.max(0, rows - 1);
|
|
274
|
+
const rightWidth = Math.max(0, width - paneWidth - 3);
|
|
275
|
+
const listLines = this.list.render(paneWidth, bodyRows);
|
|
276
|
+
this.pointerLayout = { width: paneWidth, top: 1, rows: listLines.length };
|
|
277
|
+
return [statusLine, ...splitColumns(listLines, this.entryInspector(entry, installed, rightWidth, bodyRows), paneWidth, width, bodyRows, theme)]
|
|
278
|
+
.slice(0, rows).map(line => truncateToWidth(line, width, ''));
|
|
279
|
+
}
|
|
119
280
|
const detail = entry && rows >= 9
|
|
120
|
-
? [...wrapTextWithAnsi(safeText(entry.description), width).slice(0, 3), entry.publisher
|
|
121
|
-
...(installed ? [
|
|
281
|
+
? [...wrapTextWithAnsi(safeText(entry.description), width).slice(0, 3), `${entry.publisher} · ${entry.license} · ${entry.id}`,
|
|
282
|
+
...(installed ? [`Installed ${installed.installedAt} · ${installed.entry.channel} · ${installed.state ?? 'installed'}`] : [])]
|
|
122
283
|
: [];
|
|
123
|
-
const
|
|
284
|
+
const detailHeight = detail.length ? detail.length + 1 : 0;
|
|
285
|
+
const listLines = this.list.render(width, Math.max(1, rows - 1 - detailHeight));
|
|
286
|
+
this.pointerLayout = { width, top: 1, rows: Math.min(listLines.length, Math.max(0, rows - 1)) };
|
|
287
|
+
const lines = [statusLine, ...listLines];
|
|
124
288
|
if (detail.length)
|
|
125
289
|
lines.push('', ...detail.map(line => theme.fg('muted', safeText(line))));
|
|
126
290
|
return lines.slice(0, rows).map(line => truncateToWidth(line, width, ''));
|
|
@@ -13,14 +13,22 @@ export interface PluginsPageOptions {
|
|
|
13
13
|
}
|
|
14
14
|
export declare class PluginsPage implements TerminalPage {
|
|
15
15
|
private readonly options;
|
|
16
|
+
readonly presentation = "fullscreen";
|
|
16
17
|
private plugins;
|
|
18
|
+
private proposals;
|
|
19
|
+
private proposalError;
|
|
20
|
+
private preview;
|
|
21
|
+
private previewOffset;
|
|
22
|
+
private previewRows;
|
|
17
23
|
private section;
|
|
18
24
|
private projectId;
|
|
25
|
+
private hubManagedIds;
|
|
19
26
|
private error;
|
|
20
27
|
private restart;
|
|
21
28
|
private busy;
|
|
22
29
|
private disposed;
|
|
23
30
|
private readonly list;
|
|
31
|
+
private pointerLayout?;
|
|
24
32
|
/** The plugin whose settings are open, or null on the list. */
|
|
25
33
|
private settingsFor;
|
|
26
34
|
private saved;
|
|
@@ -36,17 +44,22 @@ export declare class PluginsPage implements TerminalPage {
|
|
|
36
44
|
private settingsPlugin;
|
|
37
45
|
private reload;
|
|
38
46
|
private fill;
|
|
39
|
-
/**
|
|
47
|
+
/** Switch, trust, settings and package actions stay grouped under their owning plugin. */
|
|
40
48
|
private rows;
|
|
41
49
|
private menu;
|
|
42
50
|
private key;
|
|
43
51
|
private toRow;
|
|
44
52
|
private open;
|
|
53
|
+
private decideProposal;
|
|
54
|
+
private installPackage;
|
|
55
|
+
private managePackage;
|
|
45
56
|
private back;
|
|
46
57
|
/** Flips a switch, or asks for a number inside the setting's range, and saves it. */
|
|
47
58
|
private change;
|
|
48
59
|
handleMouse(event: TerminalMouseInput): import("@earendil-works/pi-tui").TuiMouseEventResult | undefined;
|
|
49
60
|
handleInput(data: string): boolean;
|
|
61
|
+
private selectedPlugin;
|
|
62
|
+
private pluginInspector;
|
|
50
63
|
render(width: number, rows: number): string[];
|
|
51
64
|
private renderSettings;
|
|
52
65
|
}
|