@timurproko/a1 0.2.7-dev.754 → 0.2.7-dev.772
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 +30 -0
- package/bin/cli.js +4 -0
- package/bin/guardian.js +5 -0
- package/bin/tab-launch-context.d.ts +26 -0
- package/bin/tab-launch-context.js +94 -0
- package/bin/ui.js +24 -6
- package/dist/app/session-shell/helper-pool.d.ts +3 -5
- package/dist/app/session-shell/helper-pool.js +3 -5
- package/dist/app/session-shell/session-shell-root.d.ts +28 -1
- package/dist/app/session-shell/session-shell-root.js +4 -3
- package/dist/app/session-shell/session-shell.js +149 -31
- package/dist/app/session-shell/session-viewport-controller.d.ts +1 -1
- package/dist/app/session-shell/session-viewport-controller.js +3 -3
- package/dist/app/session-shell/shell-host.d.ts +2 -0
- package/dist/app/session-shell/shell-host.js +20 -1
- package/dist/cli/dispatch.d.ts +11 -1
- package/dist/cli/dispatch.js +79 -5
- package/dist/cli/tabs-request.d.ts +7 -0
- package/dist/cli/tabs-request.js +1 -0
- package/dist/cli/tabs.d.ts +14 -0
- package/dist/cli/tabs.js +140 -0
- package/dist/composition/owned-ui.d.ts +26 -0
- package/dist/composition/owned-ui.js +176 -6
- package/dist/contracts/owned-ui/session-backend.d.ts +1 -0
- package/dist/features/launch/index.d.ts +1 -1
- package/dist/features/launch/intent.d.ts +3 -1
- package/dist/features/launch/intent.js +7 -4
- package/dist/features/owned-ui/settings-app.js +8 -35
- package/dist/features/resident-tab/auto-name.d.ts +11 -0
- package/dist/features/resident-tab/auto-name.js +42 -0
- package/dist/features/resident-tab/index.d.ts +3 -0
- package/dist/features/resident-tab/index.js +3 -0
- package/dist/features/resident-tab/shortcuts.d.ts +10 -0
- package/dist/features/resident-tab/shortcuts.js +35 -0
- package/dist/features/resident-tab/status-deriver.d.ts +9 -0
- package/dist/features/resident-tab/status-deriver.js +15 -0
- package/dist/foundation/launch-context/index.d.ts +10 -0
- package/dist/foundation/launch-context/index.js +25 -0
- package/dist/foundation/launch-guardian/main.d.ts +5 -0
- package/dist/foundation/launch-guardian/main.js +2 -1
- package/dist/foundation/release/bootstrap.d.ts +6 -0
- package/dist/foundation/release/bootstrap.js +51 -10
- package/dist/foundation/release/cohort-state.d.ts +1 -1
- package/dist/foundation/release/cohort-state.js +1 -1
- package/dist/foundation/release/dependency-certification.js +54 -19
- package/dist/foundation/release/progress-palette.generated.d.ts +2 -2
- package/dist/foundation/release/progress-palette.generated.js +2 -2
- package/dist/foundation/release/release-gc.d.ts +3 -0
- package/dist/foundation/release/release-gc.js +44 -8
- package/dist/foundation/resident-tabs/bounded-host-command.d.ts +16 -0
- package/dist/foundation/resident-tabs/bounded-host-command.js +35 -0
- package/dist/foundation/resident-tabs/bridge-client.d.ts +56 -0
- package/dist/foundation/resident-tabs/bridge-client.js +279 -0
- package/dist/foundation/resident-tabs/doctor.d.ts +29 -0
- package/dist/foundation/resident-tabs/doctor.js +166 -0
- package/dist/foundation/resident-tabs/draft-checkpoint.d.ts +27 -0
- package/dist/foundation/resident-tabs/draft-checkpoint.js +145 -0
- package/dist/foundation/resident-tabs/ensure-terminal-host.d.ts +31 -0
- package/dist/foundation/resident-tabs/ensure-terminal-host.js +147 -0
- package/dist/foundation/resident-tabs/fault-injection.d.ts +8 -0
- package/dist/foundation/resident-tabs/fault-injection.js +26 -0
- package/dist/foundation/resident-tabs/index.d.ts +12 -0
- package/dist/foundation/resident-tabs/index.js +6 -0
- package/dist/foundation/resident-tabs/maintenance.d.ts +42 -0
- package/dist/foundation/resident-tabs/maintenance.js +78 -0
- package/dist/foundation/resident-tabs/prompt-journal.d.ts +65 -0
- package/dist/foundation/resident-tabs/prompt-journal.js +214 -0
- package/dist/foundation/resident-tabs/protocol.d.ts +12 -0
- package/dist/foundation/resident-tabs/protocol.js +195 -0
- package/dist/foundation/resident-tabs/recovery.d.ts +26 -0
- package/dist/foundation/resident-tabs/recovery.js +205 -0
- package/dist/foundation/resident-tabs/release-holds.d.ts +27 -0
- package/dist/foundation/resident-tabs/release-holds.js +77 -0
- package/dist/foundation/resident-tabs/routing.d.ts +11 -0
- package/dist/foundation/resident-tabs/routing.js +10 -0
- package/dist/foundation/resident-tabs/session-sync.d.ts +14 -0
- package/dist/foundation/resident-tabs/session-sync.js +37 -0
- package/dist/foundation/resident-tabs/settings.d.ts +14 -0
- package/dist/foundation/resident-tabs/settings.js +66 -0
- package/dist/foundation/resident-tabs/terminal-host-artifact.d.ts +18 -0
- package/dist/foundation/resident-tabs/terminal-host-artifact.js +53 -0
- package/dist/foundation/resident-tabs/zip-archive.d.ts +9 -0
- package/dist/foundation/resident-tabs/zip-archive.js +56 -0
- package/dist/foundation/session-writer-lock/index.d.ts +32 -0
- package/dist/foundation/session-writer-lock/index.js +201 -0
- package/dist/foundation/startup/startup-descriptor.js +2 -2
- package/dist/foundation/terminal-cleanup/index.d.ts +1 -1
- package/dist/foundation/terminal-cleanup/index.js +1 -1
- package/dist/foundation/terminal-cleanup/terminal-reset.d.ts +1 -0
- package/dist/foundation/terminal-cleanup/terminal-reset.js +1 -0
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +1 -1
- package/dist/integrations/pi/components/owned-editor-ux.js +2 -2
- package/dist/integrations/pi/components/resources/builtin-themes.d.ts +4 -4
- package/dist/integrations/pi/components/resources/builtin-themes.js +4 -4
- package/dist/integrations/pi/components/shell-hotkey-sections.js +1 -1
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +4 -2
- package/dist/integrations/pi/components/shell-presenters-info.js +38 -4
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +17 -4
- 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/earendil-announcement.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +1 -1
- 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/pi-logo.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.js +1 -1
- 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 +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +2 -2
- package/dist/integrations/pi/components/upstream/components/status-indicator.js +3 -3
- package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +0 -2
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +41 -20
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +1 -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 +2 -2
- package/dist/integrations/pi/components/upstream/history/editor-core.js +5 -5
- 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.js +1 -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/program-status-reporter.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.d.ts +3 -0
- package/dist/integrations/pi/components/upstream/theme/theme.js +24 -1
- package/dist/integrations/pi/engine/adapter.d.ts +1 -0
- package/dist/integrations/pi/engine/adapter.js +4 -0
- package/dist/integrations/pi/engine/pi-settings-metadata.json +2 -2
- package/dist/integrations/pi/engine/prompt-suggestions.d.ts +1 -0
- package/dist/integrations/pi/engine/prompt-suggestions.js +40 -0
- package/dist/integrations/pi/engine/resources/changelog.json +4 -4
- package/dist/integrations/pi/engine/runtime-integration.js +102 -29
- package/dist/integrations/pi/engine/session-runtime.d.ts +0 -6
- package/dist/integrations/pi/engine/session-runtime.js +8 -3
- package/dist/integrations/pi/engine/session-selection.d.ts +3 -0
- package/dist/integrations/pi/engine/session-selection.js +45 -9
- package/dist/integrations/pi/engine/workflow-contexts.js +10 -1
- package/dist/integrations/pi/startup-public.js +152 -222
- package/dist/integrations/pi/startup-public.manifest.json +266 -177
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +1 -1
- package/dist/native/darwin-arm64/a1_session_lock.node +0 -0
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/darwin-arm64/terminal-host +0 -0
- package/dist/native/darwin-arm64/terminal-host-THIRD-PARTY-NOTICES.txt +10500 -0
- package/dist/native/darwin-arm64/terminal-host.manifest.json +44 -0
- package/dist/native/darwin-x64/a1_session_lock.node +0 -0
- package/dist/native/darwin-x64/manifest.json +20 -0
- package/dist/native/darwin-x64/process-guardian +0 -0
- package/dist/native/darwin-x64/terminal-host +0 -0
- package/dist/native/darwin-x64/terminal-host-THIRD-PARTY-NOTICES.txt +10737 -0
- package/dist/native/darwin-x64/terminal-host.manifest.json +44 -0
- package/dist/native/linux-x64/a1_session_lock.node +0 -0
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/linux-x64/terminal-host +0 -0
- package/dist/native/linux-x64/terminal-host-THIRD-PARTY-NOTICES.txt +11226 -0
- package/dist/native/linux-x64/terminal-host.manifest.json +44 -0
- package/dist/native/win32-x64/a1_session_lock.node +0 -0
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/native/win32-x64/terminal-host-THIRD-PARTY-NOTICES.txt +10757 -0
- package/dist/native/win32-x64/terminal-host.exe +0 -0
- package/dist/native/win32-x64/terminal-host.manifest.json +44 -0
- package/dist/product-identity.d.ts +1 -1
- package/dist/product-identity.js +1 -1
- package/dist/product-identity.json +5 -0
- package/dist/runtime-payload-inventory.json +5349 -6035
- package/dist/ui/components/line-input.d.ts +1 -1
- package/dist/ui/components/prompt-input.d.ts +7 -5
- package/dist/ui/components/prompt-input.js +7 -7
- package/dist/ui/components/transcript-viewport.d.ts +6 -3
- package/dist/ui/components/transcript-viewport.js +13 -15
- package/dist/ui/settings/declarations.d.ts +25 -1
- package/dist/ui/settings/declarations.js +21 -1
- package/dist/ui/settings/index.d.ts +4 -2
- package/dist/ui/settings/index.js +2 -1
- package/dist/ui/settings/manager.d.ts +10 -3
- package/dist/ui/settings/manager.js +90 -30
- package/dist/ui/settings/migrations.d.ts +6 -0
- package/dist/ui/settings/migrations.js +44 -0
- package/dist/ui/settings/profile-document.d.ts +26 -0
- package/dist/ui/settings/profile-document.js +164 -0
- package/docs/architecture/evidence/resident-tabs/linux-x64.md +37 -0
- package/docs/architecture/evidence/resident-tabs/macos-arm64.md +36 -0
- package/docs/architecture/evidence/resident-tabs/macos-x64.md +35 -0
- package/docs/architecture/evidence/resident-tabs/windows-x64.md +36 -0
- package/docs/architecture/internal-naming.md +3 -1
- package/docs/architecture/process-guardian-provenance.md +2 -0
- package/docs/architecture/resident-tabs-requirements.md +18 -0
- package/docs/architecture/resident-tabs.md +594 -0
- package/docs/architecture/terminal-host-proof-gate.md +2 -0
- package/docs/architecture/terminal-host-provenance.md +13 -3
- package/docs/architecture/toolchain.md +1 -1
- package/docs/ci-release-runbook.md +2 -2
- package/docs/features/launch-profiles.md +11 -8
- package/docs/manual-resident-tabs-acceptance.md +51 -0
- package/docs/openspec-archive-automation.md +17 -16
- package/docs/validation.md +9 -1
- package/package.json +10 -4
package/dist/cli/tabs.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { resolveProductPaths } from "../foundation/lifecycle/index.js";
|
|
2
|
+
import { CohortStateStore } from "../foundation/release/index.js";
|
|
3
|
+
import { readResidentTabLaunchSettings, runTerminalHostMaintenance, writeDoctorBundle, } from "../foundation/resident-tabs/index.js";
|
|
4
|
+
import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../product-identity.js";
|
|
5
|
+
/** `a1 tabs`: inspect or stop resident tabs without attaching, and never start a host to report state. */
|
|
6
|
+
export async function runTabsCommand(request, options = {}) {
|
|
7
|
+
const environment = options.environment ?? process.env;
|
|
8
|
+
const stdout = options.stdout ?? (message => process.stdout.write(message));
|
|
9
|
+
const stderr = options.stderr ?? (message => process.stderr.write(message));
|
|
10
|
+
const paths = resolveProductPaths(environment);
|
|
11
|
+
const profileRoot = environment[PRODUCT_IDENTITY.environment.profileHome] ?? paths.configDir;
|
|
12
|
+
const releaseRoots = await installedReleaseRoots(paths.dataDir, options.packageRoot);
|
|
13
|
+
const maintenance = options.maintenance ?? runTerminalHostMaintenance;
|
|
14
|
+
const report = await maintenance({
|
|
15
|
+
action: request.action === "doctor" ? "host-status" : request.action,
|
|
16
|
+
...(request.tabId === undefined ? {} : { tabId: request.tabId }),
|
|
17
|
+
profileRoot,
|
|
18
|
+
dataDir: paths.dataDir,
|
|
19
|
+
runtimeDir: paths.runtimeDir,
|
|
20
|
+
releaseRoots,
|
|
21
|
+
environment,
|
|
22
|
+
});
|
|
23
|
+
if (request.action === "doctor") {
|
|
24
|
+
if (!report.stateDir) {
|
|
25
|
+
stderr(`${PRODUCT_TEXT.diagnostic(`tabs doctor could not locate resident state: ${report.message ?? report.host}`)}\n`);
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
const settings = await readResidentTabLaunchSettings(environment.PI_CODING_AGENT_DIR ?? paths.configDir, PRODUCT_IDENTITY.commandName, paths.configDir, "a1");
|
|
29
|
+
const bundle = await (options.doctor ?? writeDoctorBundle)({
|
|
30
|
+
stateDir: report.stateDir,
|
|
31
|
+
hostStatus: report,
|
|
32
|
+
releaseRoots,
|
|
33
|
+
settings: { tabsMax: settings.tabsMax, tabsAutoName: settings.tabsAutoName },
|
|
34
|
+
});
|
|
35
|
+
if (request.json)
|
|
36
|
+
stdout(`${JSON.stringify({ schema: "a1-tabs-doctor-v1", path: bundle.path, bytes: bundle.bytes, dropped: bundle.dropped })}\n`);
|
|
37
|
+
else
|
|
38
|
+
stdout(`Wrote ${bundle.path}\n`);
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
if (request.json) {
|
|
42
|
+
const { exitCode: _exitCode, ...printed } = report;
|
|
43
|
+
stdout(`${JSON.stringify(printed)}\n`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const text = describe(request, report);
|
|
47
|
+
if (report.exitCode === 0)
|
|
48
|
+
stdout(text);
|
|
49
|
+
else
|
|
50
|
+
stderr(text);
|
|
51
|
+
}
|
|
52
|
+
return report.exitCode === 0 ? 0 : 1;
|
|
53
|
+
}
|
|
54
|
+
async function installedReleaseRoots(dataDir, packageRoot) {
|
|
55
|
+
const roots = [];
|
|
56
|
+
try {
|
|
57
|
+
const state = await new CohortStateStore(dataDir).read();
|
|
58
|
+
for (const id of [state.references.active, state.references.rollback]) {
|
|
59
|
+
if (id && state.releases[id])
|
|
60
|
+
roots.push(state.releases[id].releaseRoot);
|
|
61
|
+
}
|
|
62
|
+
roots.push(...Object.values(state.releases).map(record => record.releaseRoot));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Rationale: unreadable release state still leaves the running package's own host.
|
|
66
|
+
}
|
|
67
|
+
if (packageRoot)
|
|
68
|
+
roots.push(packageRoot);
|
|
69
|
+
return [...new Set(roots)];
|
|
70
|
+
}
|
|
71
|
+
const NO_TABS = "No resident tabs are running.\n";
|
|
72
|
+
function describe(request, report) {
|
|
73
|
+
const command = PRODUCT_TEXT.commandName;
|
|
74
|
+
if (report.host === "none")
|
|
75
|
+
return NO_TABS;
|
|
76
|
+
if (report.host === "unavailable")
|
|
77
|
+
return `${PRODUCT_TEXT.diagnostic(`tabs could not run maintenance: ${report.message ?? "terminal host unavailable"}`)}\n`;
|
|
78
|
+
if (report.host === "unresponsive") {
|
|
79
|
+
return `The resident host (pid ${report.pid ?? "unknown"}) is not responding. Run \`${command} tabs host stop\` to stop it.\n`;
|
|
80
|
+
}
|
|
81
|
+
if (report.host === "incompatible") {
|
|
82
|
+
return `${PRODUCT_TEXT.diagnostic(report.message ?? "running tabs use another version")} Run \`${command} tabs host stop\` from that version.\n`;
|
|
83
|
+
}
|
|
84
|
+
if (report.host === "unverifiable" || report.host === "refused") {
|
|
85
|
+
return `${PRODUCT_TEXT.diagnostic(report.message ?? "the resident host could not be verified; nothing was changed")}\n`;
|
|
86
|
+
}
|
|
87
|
+
const result = report.result ?? {};
|
|
88
|
+
if (request.action === "list")
|
|
89
|
+
return listing(result);
|
|
90
|
+
if (request.action === "host-status")
|
|
91
|
+
return status(result);
|
|
92
|
+
if (request.action === "host-stop") {
|
|
93
|
+
if (report.host === "stopped")
|
|
94
|
+
return "Stopped every tab and the resident host.\n";
|
|
95
|
+
return `Could not stop every tab: ${remaining(result)}. The host is still running.\n`;
|
|
96
|
+
}
|
|
97
|
+
if (result.accepted === false && typeof result.message === "string") {
|
|
98
|
+
return `${PRODUCT_TEXT.diagnostic(`tabs stop: ${result.message === "unknown tab" ? `no tab ${request.tabId ?? ""}` : result.message}`)}\n`;
|
|
99
|
+
}
|
|
100
|
+
const stopped = Array.isArray(result.stopped) ? result.stopped.length : 0;
|
|
101
|
+
if (result.accepted === false)
|
|
102
|
+
return `Could not stop: ${remaining(result)}.\n`;
|
|
103
|
+
if (request.action === "stop")
|
|
104
|
+
return `Stopped tab ${request.tabId ?? ""}; its session can be resumed.\n`;
|
|
105
|
+
return stopped === 0 ? NO_TABS : `Stopped ${stopped} tab${stopped === 1 ? "" : "s"}; their sessions can be resumed.\n`;
|
|
106
|
+
}
|
|
107
|
+
function remaining(result) {
|
|
108
|
+
return Array.isArray(result.remaining) && result.remaining.length > 0 ? result.remaining.join(", ") : "unknown tabs";
|
|
109
|
+
}
|
|
110
|
+
function listing(result) {
|
|
111
|
+
const tabs = Array.isArray(result.tabs) ? result.tabs : [];
|
|
112
|
+
if (tabs.length === 0)
|
|
113
|
+
return NO_TABS;
|
|
114
|
+
const rows = [
|
|
115
|
+
["ID", "NAME", "STATUS", "CWD", "RELEASE", "HOLDER"],
|
|
116
|
+
...tabs.map(tab => [tab.tabId, tab.name, tab.status, tab.cwd, tab.release, tab.holderPid ?? "-"].map(value => String(value ?? "-"))),
|
|
117
|
+
];
|
|
118
|
+
const widths = rows[0].map((_, column) => Math.max(...rows.map(row => row[column].length)));
|
|
119
|
+
return `${rows.map(row => row.map((cell, column) => column === row.length - 1 ? cell : cell.padEnd(widths[column])).join(" ")).join("\n")}\n`;
|
|
120
|
+
}
|
|
121
|
+
function status(result) {
|
|
122
|
+
const limits = (result.limits ?? {});
|
|
123
|
+
const counters = (result.counters ?? {});
|
|
124
|
+
const byStatus = (result.tabsByStatus ?? {});
|
|
125
|
+
const lines = [
|
|
126
|
+
`pid: ${String(result.pid ?? "-")}`,
|
|
127
|
+
`build: ${String(result.build ?? "-")}`,
|
|
128
|
+
`release: ${String(result.release ?? "-")}`,
|
|
129
|
+
`generation: ${String(result.generation ?? "-")}`,
|
|
130
|
+
`epoch: ${String(result.epoch ?? "-")}`,
|
|
131
|
+
`uptime: ${String(result.uptimeSeconds ?? "-")}s`,
|
|
132
|
+
`detachment: ${String(result.detachmentMode ?? "unknown")}${result.detachmentVerified === false ? " (not verified)" : ""}`,
|
|
133
|
+
`tabs: ${String(result.tabs ?? 0)}${Object.keys(byStatus).length > 0 ? ` (${Object.entries(byStatus).map(([key, value]) => `${key} ${String(value)}`).join(", ")})` : ""}`,
|
|
134
|
+
`clients: ${String(result.clients ?? 0)}`,
|
|
135
|
+
`limits: ${Object.entries(limits).map(([key, value]) => `${key} ${String(value)}`).join(", ")}`,
|
|
136
|
+
`counters: ${Object.entries(counters).map(([key, value]) => `${key} ${String(value)}`).join(", ")}`,
|
|
137
|
+
...(Array.isArray(result.logs) ? result.logs.map(path => `log: ${String(path)}`) : []),
|
|
138
|
+
];
|
|
139
|
+
return `${lines.join("\n")}\n`;
|
|
140
|
+
}
|
|
@@ -10,6 +10,8 @@ import type { OwnedUiApplicationPort, PresentationTerminalPort } from "../contra
|
|
|
10
10
|
import type { AgentSettingsPort } from "../contracts/agent-engine/index.js";
|
|
11
11
|
import type { OwnedUiPromptSuggestionGeneratorPort, UiAccentColor } from "../contracts/owned-ui/index.js";
|
|
12
12
|
import type { ReleaseNoteCatalog } from "../features/owned-ui/release-notes.js";
|
|
13
|
+
import type { TabBridgeClient } from "../foundation/resident-tabs/bridge-client.js";
|
|
14
|
+
import { ResidentTabRecovery } from "../foundation/resident-tabs/recovery.js";
|
|
13
15
|
/**
|
|
14
16
|
* The session backend composition wires: the owned-UI port, the prompt-suggestion generator, and
|
|
15
17
|
* the agent settings port. `settingsPort` stays outside the owned-UI contract because its type
|
|
@@ -17,6 +19,7 @@ import type { ReleaseNoteCatalog } from "../features/owned-ui/release-notes.js";
|
|
|
17
19
|
*/
|
|
18
20
|
export interface ComposedSessionBackend extends PiSessionPresenterBackend, OwnedUiPromptSuggestionGeneratorPort {
|
|
19
21
|
settingsPort(): AgentSettingsPort | null;
|
|
22
|
+
generateResidentTabName(instruction: string, maxTokens: number, signal: AbortSignal): Promise<string | null>;
|
|
20
23
|
}
|
|
21
24
|
/** The process-level engine host as composition drives it: sessions, the live accent, and disposal. */
|
|
22
25
|
export interface ComposedEngineHost {
|
|
@@ -38,6 +41,8 @@ export interface OwnedUiCompositionOptions {
|
|
|
38
41
|
* session settings-free, which is what the pinned comparison paths use.
|
|
39
42
|
*/
|
|
40
43
|
readonly profileId?: string;
|
|
44
|
+
/** Hide resident-only tab controls for the explicit direct single-agent launch. */
|
|
45
|
+
readonly hideTabSettings?: boolean;
|
|
41
46
|
/**
|
|
42
47
|
* Whether A1's product-specific surfaces are reachable. Comparison profiles
|
|
43
48
|
* use the same composition with those surfaces withheld.
|
|
@@ -55,11 +60,32 @@ export interface OwnedUiCompositionOptions {
|
|
|
55
60
|
readonly checkForNewerRelease?: (options: StartupReleaseCheckOptions) => Promise<AvailableRelease | null>;
|
|
56
61
|
/** Exact native process inspection injected by the shipped entry; absent SDK seams do not publish claims. */
|
|
57
62
|
readonly inspectProcess?: (pid: number) => Promise<NativeProcessIdentity | null>;
|
|
63
|
+
/** Private credentials were consumed by the entry before composition or extensions loaded. */
|
|
64
|
+
readonly tab?: {
|
|
65
|
+
readonly bridge: TabBridgeClient;
|
|
66
|
+
readonly dataDir: string;
|
|
67
|
+
readonly incarnation: number;
|
|
68
|
+
};
|
|
69
|
+
/** One prompt-adjacent notice explaining why a resident launch fell back. */
|
|
70
|
+
readonly residentFallbackNotice?: string;
|
|
58
71
|
}
|
|
59
72
|
export interface OwnedUiComposition {
|
|
60
73
|
readonly application: OwnedUiApplicationPort;
|
|
61
74
|
/** Present when a profile was supplied, so the caller can resolve settings before start. */
|
|
62
75
|
readonly settings: OwnedSettingsManager | null;
|
|
63
76
|
}
|
|
77
|
+
export declare function residentStartupPresentation(resident: boolean, fallbackNotice?: string): {
|
|
78
|
+
readonly startup?: {
|
|
79
|
+
readonly quiet?: boolean;
|
|
80
|
+
readonly notices?: readonly [{
|
|
81
|
+
readonly kind: "warning";
|
|
82
|
+
readonly message: string;
|
|
83
|
+
}];
|
|
84
|
+
};
|
|
85
|
+
};
|
|
64
86
|
export declare function composeOwnedUiApplication(options?: OwnedUiCompositionOptions): Promise<OwnedUiApplicationPort>;
|
|
65
87
|
export declare function composeOwnedUi(options?: OwnedUiCompositionOptions): Promise<OwnedUiComposition>;
|
|
88
|
+
export declare function bindResidentTabBridge(tabBridge: TabBridgeClient, backend: Pick<ComposedSessionBackend, "identity" | "session" | "workflows" | "generateResidentTabName">, recovery?: Pick<ResidentTabRecovery, "settled"> | null, options?: {
|
|
89
|
+
readonly autoName?: boolean;
|
|
90
|
+
readonly onVisibility?: (visible: boolean) => void;
|
|
91
|
+
}): Promise<() => void>;
|
|
@@ -4,7 +4,7 @@ import { PRODUCT_IDENTITY } from "../product-identity.js";
|
|
|
4
4
|
import { PromptHistoryService } from "../features/prompt-history/service.js";
|
|
5
5
|
import { PromptImageSidecar } from "../features/prompt-history/image-sidecar.js";
|
|
6
6
|
import { resolvePromptHistoryPath } from "../features/prompt-history/paths.js";
|
|
7
|
-
import { resolvePromptHistoryDataDir } from "../features/launch/profile-paths.js";
|
|
7
|
+
import { resolveLaunchProfilePaths, resolvePromptHistoryDataDir } from "../features/launch/profile-paths.js";
|
|
8
8
|
import { resolveProductPaths } from "../foundation/lifecycle/paths.js";
|
|
9
9
|
import { applyConfiguredPiTheme, getAvailablePiThemes, setPiAccentColor, setPiPackageBorderProjectionEnabled } from "../integrations/pi/components/upstream/theme/theme.js";
|
|
10
10
|
import { createPiEngineHost } from "../integrations/pi/engine/host.js";
|
|
@@ -18,7 +18,14 @@ import { createPiTerminalBridge } from "../integrations/pi/tui-runtime/presentat
|
|
|
18
18
|
import { createOwnedRouteHost } from "./settings-route-host.js";
|
|
19
19
|
import { renderPiShellChangelogLines } from "../integrations/pi/components/shell-presenters-info.js";
|
|
20
20
|
import { nativeHyperlinkStyle } from "../ui/components/spans.js";
|
|
21
|
+
import { ResidentTabRecovery } from "../foundation/resident-tabs/recovery.js";
|
|
22
|
+
import { deriveResidentTabStatus } from "../features/resident-tab/status-deriver.js";
|
|
21
23
|
const SESSION_RUNTIME_REFRESH_MS = 30_000;
|
|
24
|
+
export function residentStartupPresentation(resident, fallbackNotice) {
|
|
25
|
+
if (resident)
|
|
26
|
+
return { startup: { quiet: true } };
|
|
27
|
+
return fallbackNotice === undefined ? {} : { startup: { notices: [{ kind: "warning", message: fallbackNotice }] } };
|
|
28
|
+
}
|
|
22
29
|
export async function composeOwnedUiApplication(options = {}) {
|
|
23
30
|
return (await composeOwnedUi(options)).application;
|
|
24
31
|
}
|
|
@@ -82,17 +89,33 @@ export async function composeOwnedUi(options = {}) {
|
|
|
82
89
|
sessionRuntimeRefreshTimer.unref();
|
|
83
90
|
};
|
|
84
91
|
const productPaths = resolveProductPaths();
|
|
92
|
+
const profilePaths = resolveLaunchProfilePaths();
|
|
85
93
|
// Rationale: the manager reads the engine's settings port lazily, after the session exists.
|
|
86
94
|
let backend;
|
|
87
95
|
const settings = options.profileId === undefined
|
|
88
96
|
? null
|
|
89
97
|
: new OwnedSettingsManager({
|
|
90
|
-
|
|
98
|
+
profileDir: profilePaths.agentProfile,
|
|
91
99
|
profileId: options.profileId,
|
|
100
|
+
namespace: PRODUCT_IDENTITY.commandName,
|
|
101
|
+
legacyConfigDir: productPaths.configDir,
|
|
92
102
|
agentProvider: () => backend.settingsPort(),
|
|
103
|
+
...(options.hideTabSettings ? { hiddenOwnedSettingIds: ["tabsMax", "tabsAutoName"] } : {}),
|
|
93
104
|
hiddenAgentSettingIds: ["fullscreenWheelScrollLines"],
|
|
94
105
|
agentSettingLabelOverrides: { fullscreenCopyOnSelect: "Copy on select" },
|
|
95
106
|
});
|
|
107
|
+
const tabBridge = options.tab?.bridge ?? null;
|
|
108
|
+
if (tabBridge !== null)
|
|
109
|
+
await tabBridge.start().catch(() => false);
|
|
110
|
+
const projectTrustPrompt = options.projectTrustPrompt === undefined ? undefined : async (request) => {
|
|
111
|
+
tabBridge?.status("needs-input", false, 1, 0);
|
|
112
|
+
try {
|
|
113
|
+
return await options.projectTrustPrompt(request);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
tabBridge?.status("starting");
|
|
117
|
+
}
|
|
118
|
+
};
|
|
96
119
|
// Invariant: process-wide engine state has one owner. The host installs the HTTP dispatcher, applies
|
|
97
120
|
// the theme singletons, and announces startup notices once; every session is created through it.
|
|
98
121
|
const host = await (options.createEngineHost ?? (async (hostOptions) => createPiEngineHost(hostOptions)))({
|
|
@@ -105,21 +128,49 @@ export async function composeOwnedUi(options = {}) {
|
|
|
105
128
|
packageBorderProjection: ownedSurfaces,
|
|
106
129
|
apply: { base: applyConfiguredPiTheme, accentColor: setPiAccentColor, packageBorderProjection: setPiPackageBorderProjectionEnabled },
|
|
107
130
|
},
|
|
108
|
-
...(
|
|
131
|
+
...(projectTrustPrompt === undefined ? {} : { projectTrustPrompt }),
|
|
109
132
|
});
|
|
133
|
+
const sessionForkPrompt = options.sessionForkPrompt === undefined ? undefined : async (request) => {
|
|
134
|
+
tabBridge?.status("needs-input", false, 1, 0);
|
|
135
|
+
try {
|
|
136
|
+
return await options.sessionForkPrompt(request);
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
tabBridge?.status("starting");
|
|
140
|
+
}
|
|
141
|
+
};
|
|
110
142
|
try {
|
|
111
143
|
backend = await host.create({
|
|
112
144
|
cwd,
|
|
113
145
|
...(ownedSurfaces ? { repositoryContextReader: repositoryContextReaderFor(undefined) } : {}),
|
|
114
146
|
...(options.sessionPath === undefined ? {} : { sessionPath: options.sessionPath }),
|
|
115
147
|
...(options.sessionSelection === undefined ? {} : { sessionSelection: options.sessionSelection }),
|
|
116
|
-
...(
|
|
148
|
+
...(sessionForkPrompt === undefined ? {} : { sessionForkPrompt }),
|
|
117
149
|
});
|
|
118
150
|
}
|
|
119
151
|
catch (error) {
|
|
120
152
|
await host.dispose();
|
|
121
153
|
throw error;
|
|
122
154
|
}
|
|
155
|
+
let recoveryDegraded = false;
|
|
156
|
+
let presentRecoveryDegraded = (_degraded) => { };
|
|
157
|
+
const tabRecovery = options.tab === undefined ? null : new ResidentTabRecovery(options.tab.dataDir, {
|
|
158
|
+
onDegraded: degraded => {
|
|
159
|
+
recoveryDegraded = degraded;
|
|
160
|
+
options.tab.bridge.degraded(degraded);
|
|
161
|
+
presentRecoveryDegraded(degraded);
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
const recoveredTabInput = await tabRecovery?.initialize(currentBackendSessionFile(backend), backend.identity.sessionId);
|
|
165
|
+
if (tabBridge !== null && settings !== null && ownedSurfaces)
|
|
166
|
+
tabBridge.accent(settings.value("accentColor"));
|
|
167
|
+
let residentTabVisible = true;
|
|
168
|
+
let applyResidentTabVisibility = () => { };
|
|
169
|
+
let removeControllerBoundaryInput = () => { };
|
|
170
|
+
const unsubscribeTabBridge = tabBridge === null ? () => { } : await bindResidentTabBridge(tabBridge, backend, tabRecovery, {
|
|
171
|
+
autoName: settings?.value("tabsAutoName") ?? true,
|
|
172
|
+
onVisibility: visible => { residentTabVisible = visible; applyResidentTabVisibility(); },
|
|
173
|
+
});
|
|
123
174
|
let releaseNotes = null;
|
|
124
175
|
let releaseNotesFailure;
|
|
125
176
|
if (ownedSurfaces) {
|
|
@@ -142,7 +193,11 @@ export async function composeOwnedUi(options = {}) {
|
|
|
142
193
|
}));
|
|
143
194
|
const unsubscribeAccent = settings === null || !ownedSurfaces
|
|
144
195
|
? () => { }
|
|
145
|
-
: settings.onChange(current =>
|
|
196
|
+
: settings.onChange(current => {
|
|
197
|
+
const accent = current.value("accentColor");
|
|
198
|
+
host.setAccentColor(accent);
|
|
199
|
+
tabBridge?.accent(accent);
|
|
200
|
+
});
|
|
146
201
|
// Rationale: Routes open only after shell construction.
|
|
147
202
|
const references = {
|
|
148
203
|
changelog: async (input) => {
|
|
@@ -228,13 +283,25 @@ export async function composeOwnedUi(options = {}) {
|
|
|
228
283
|
},
|
|
229
284
|
}),
|
|
230
285
|
...(ownedSurfaces ? { sessionLayout: "custom-viewport" } : {}),
|
|
286
|
+
...(tabBridge === null || tabRecovery === null ? {} : { residentTab: {
|
|
287
|
+
requestDetach: () => tabBridge.requestDetach(),
|
|
288
|
+
reportStatus: status => tabBridge.status(status),
|
|
289
|
+
stallNoticeSeconds: 300,
|
|
290
|
+
admit: input => tabRecovery.admit({ ...input, incarnation: options.tab.incarnation }),
|
|
291
|
+
dispatched: () => tabRecovery.dispatched(),
|
|
292
|
+
correlated: (submissionId, entryId) => tabRecovery.correlated(submissionId, entryId),
|
|
293
|
+
checkpoint: text => tabRecovery.checkpoint(text),
|
|
294
|
+
gracefulStop: sessionFile => tabRecovery.gracefulStop(sessionFile),
|
|
295
|
+
...(recoveredTabInput === undefined ? {} : { recovered: recoveredTabInput }),
|
|
296
|
+
} }),
|
|
231
297
|
},
|
|
232
298
|
presentation: {
|
|
233
299
|
...(options.terminal === undefined ? {} : { terminal: createPiTerminalBridge(options.terminal) }),
|
|
300
|
+
...residentStartupPresentation(tabBridge !== null, options.residentFallbackNotice),
|
|
234
301
|
...(clipboardDiagnostics === null ? {} : { input: { onEvent: event => clipboardDiagnostics.runtime(event) } }),
|
|
235
302
|
...(viewportSettings === null ? {} : { viewportSettings }),
|
|
236
303
|
...(backgroundSettings === null ? {} : { backgroundSettings }),
|
|
237
|
-
...(settings === null || !ownedSurfaces ? {} : {
|
|
304
|
+
...(settings === null || !ownedSurfaces || tabBridge !== null ? {} : {
|
|
238
305
|
quitOutro: { snapshot: () => quitOutroSettingsSnapshot(settings), interactive: process.stdout.isTTY === true },
|
|
239
306
|
}),
|
|
240
307
|
},
|
|
@@ -254,7 +321,21 @@ export async function composeOwnedUi(options = {}) {
|
|
|
254
321
|
// Invariant: one terminal host owns the process terminal; the session presenter reaches it only through
|
|
255
322
|
// the host and paints once attached.
|
|
256
323
|
terminalHost = createdTerminalHost = new OwnedUiTerminalHost(sessionTerminalHostOptions(presenterOptions));
|
|
324
|
+
if (tabBridge !== null) {
|
|
325
|
+
applyResidentTabVisibility = () => terminalHost.setPresentationVisible(residentTabVisible);
|
|
326
|
+
removeControllerBoundaryInput = terminalHost.runtime.addPreInputListener(data => ({
|
|
327
|
+
data: tabBridge.consumeControllerBoundaryInput(data),
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
257
330
|
presenter = new OwnedUiSessionPresenter(terminalHost, presenterOptions);
|
|
331
|
+
presentRecoveryDegraded = degraded => {
|
|
332
|
+
if (!degraded)
|
|
333
|
+
return;
|
|
334
|
+
presenter.root.appendWorkflowStatus("draft recovery degraded");
|
|
335
|
+
terminalHost.runtime.requestRender();
|
|
336
|
+
};
|
|
337
|
+
if (recoveryDegraded)
|
|
338
|
+
presentRecoveryDegraded(true);
|
|
258
339
|
terminalHost.attach(presenter);
|
|
259
340
|
}
|
|
260
341
|
catch (error) {
|
|
@@ -294,6 +375,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
294
375
|
exitNotice = import("../app/session-shell/exit-notice.js")
|
|
295
376
|
.then(module => module.armExitNotice(backend, exitNoticePath), () => null);
|
|
296
377
|
presenter.start();
|
|
378
|
+
applyResidentTabVisibility();
|
|
297
379
|
void announceNewerRelease().catch(() => undefined);
|
|
298
380
|
},
|
|
299
381
|
flush: () => backend.session.flushEvents(),
|
|
@@ -308,6 +390,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
308
390
|
finally {
|
|
309
391
|
// Invariant: the shared spares outlive every shell and stop only after the last one is disposed.
|
|
310
392
|
clipboardServices?.dispose();
|
|
393
|
+
removeControllerBoundaryInput();
|
|
311
394
|
unsubscribeAccent();
|
|
312
395
|
sessionRuntimeDisposed = true;
|
|
313
396
|
if (sessionRuntimeRefreshTimer !== null)
|
|
@@ -323,6 +406,8 @@ export async function composeOwnedUi(options = {}) {
|
|
|
323
406
|
await releaseNoteClaim?.release();
|
|
324
407
|
suggestionDiagnostics?.dispose();
|
|
325
408
|
clipboardDiagnostics?.dispose();
|
|
409
|
+
unsubscribeTabBridge();
|
|
410
|
+
tabBridge?.close();
|
|
326
411
|
// Invariant: the host outlives the application; disposing it cancels host-level probes last.
|
|
327
412
|
await host.dispose();
|
|
328
413
|
}
|
|
@@ -330,6 +415,91 @@ export async function composeOwnedUi(options = {}) {
|
|
|
330
415
|
};
|
|
331
416
|
return { application, settings };
|
|
332
417
|
}
|
|
418
|
+
export async function bindResidentTabBridge(tabBridge, backend, recovery = null, options = {}) {
|
|
419
|
+
await tabBridge.start().catch(() => false);
|
|
420
|
+
tabBridge.status("starting");
|
|
421
|
+
const currentSessionFile = () => currentBackendSessionFile(backend);
|
|
422
|
+
let pendingAutoName = null;
|
|
423
|
+
const announceSession = () => {
|
|
424
|
+
const name = backend.session.view().status.footer?.sessionName ?? null;
|
|
425
|
+
const nameSource = name === pendingAutoName ? "auto" : name === null || /^agent(?: \d+)?$/i.test(name) ? "default" : "user";
|
|
426
|
+
tabBridge.session(currentSessionFile(), name, nameSource);
|
|
427
|
+
};
|
|
428
|
+
let working = false;
|
|
429
|
+
let lastTurnFailed = false;
|
|
430
|
+
let autoNameAttempted = false;
|
|
431
|
+
const reportStatus = (lifecycle) => {
|
|
432
|
+
const view = backend.session.view();
|
|
433
|
+
const pendingRequests = view.dialog == null ? 0 : 1;
|
|
434
|
+
const queuedInput = view.editor?.queuedSubmissions.length ?? 0;
|
|
435
|
+
tabBridge.status(deriveResidentTabStatus({
|
|
436
|
+
lifecycle: lifecycle ?? view.lifecycle,
|
|
437
|
+
pendingRequests,
|
|
438
|
+
queuedInput,
|
|
439
|
+
...(lastTurnFailed ? { stopReason: "error" } : {}),
|
|
440
|
+
}), false, pendingRequests, queuedInput);
|
|
441
|
+
};
|
|
442
|
+
announceSession();
|
|
443
|
+
const unsubscribeCommands = typeof tabBridge.onCommand === "function" ? tabBridge.onCommand(command => {
|
|
444
|
+
if (command.type === "visibility") {
|
|
445
|
+
options.onVisibility?.(command.visible);
|
|
446
|
+
}
|
|
447
|
+
else if (command.type === "rename") {
|
|
448
|
+
void backend.workflows.executeWorkflow({ command: "name", argument: command.name }).catch(() => { });
|
|
449
|
+
}
|
|
450
|
+
else if (command.type === "stop") {
|
|
451
|
+
void backend.session.dispose().catch(() => { });
|
|
452
|
+
}
|
|
453
|
+
}) : () => { };
|
|
454
|
+
const unsubscribeEvents = backend.session.onEvent(event => {
|
|
455
|
+
if (event.type === "session-lifecycle") {
|
|
456
|
+
const wasWorking = working;
|
|
457
|
+
working = event.lifecycle === "busy";
|
|
458
|
+
if (working)
|
|
459
|
+
lastTurnFailed = false;
|
|
460
|
+
reportStatus(event.lifecycle);
|
|
461
|
+
if (wasWorking && !working && recovery !== null) {
|
|
462
|
+
void recovery.settled(currentSessionFile()).catch(() => tabBridge.degraded(true));
|
|
463
|
+
}
|
|
464
|
+
if (wasWorking && !working && options.autoName === true && !autoNameAttempted) {
|
|
465
|
+
autoNameAttempted = true;
|
|
466
|
+
const view = backend.session.view();
|
|
467
|
+
const currentName = view.status.footer?.sessionName;
|
|
468
|
+
const prompt = view.transcript.find(block => block.kind === "user")?.text.trim();
|
|
469
|
+
if (prompt && (currentName == null || /^agent(?: \d+)?$/i.test(currentName))) {
|
|
470
|
+
void import("../features/resident-tab/index.js").then(({ generateAutoName }) => generateAutoName(prompt, request => backend.generateResidentTabName(request.prompt, request.maxTokens, request.signal))).then(async (name) => {
|
|
471
|
+
pendingAutoName = name;
|
|
472
|
+
const result = await backend.workflows.executeWorkflow({ command: "name", argument: name });
|
|
473
|
+
if (result.outcome === "completed")
|
|
474
|
+
tabBridge.session(currentSessionFile(), name, "auto");
|
|
475
|
+
else if (pendingAutoName === name)
|
|
476
|
+
pendingAutoName = null;
|
|
477
|
+
}).catch(() => { pendingAutoName = null; });
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (event.type === "agent-run-settled") {
|
|
482
|
+
lastTurnFailed = !event.successful && !event.aborted;
|
|
483
|
+
tabBridge.prompt(event.aborted);
|
|
484
|
+
reportStatus();
|
|
485
|
+
}
|
|
486
|
+
if (event.type === "session-view") {
|
|
487
|
+
announceSession();
|
|
488
|
+
reportStatus();
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
return () => {
|
|
492
|
+
unsubscribeCommands();
|
|
493
|
+
unsubscribeEvents();
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
function currentBackendSessionFile(backend) {
|
|
497
|
+
const direct = backend.identity.currentSessionFile?.();
|
|
498
|
+
if (direct !== undefined && direct !== null)
|
|
499
|
+
return direct;
|
|
500
|
+
const resume = backend.identity.currentSessionResumeMetadata();
|
|
501
|
+
return resume === null ? null : `${resume.sessionDir}/${resume.sessionId}`;
|
|
502
|
+
}
|
|
333
503
|
async function readPackageVersion() {
|
|
334
504
|
const manifest = JSON.parse(await readFile(new URL("../../package.json", import.meta.url), "utf8"));
|
|
335
505
|
const version = manifest?.version;
|
|
@@ -36,6 +36,7 @@ export interface OwnedUiSessionIdentityPort {
|
|
|
36
36
|
/** Actual session replacements, excluding delivery-only invalidation of callbacks. */
|
|
37
37
|
readonly sessionBindingGeneration: number;
|
|
38
38
|
readonly disposed: boolean;
|
|
39
|
+
currentSessionFile(): string | null;
|
|
39
40
|
currentSessionResumeMetadata(): OwnedUiSessionResumeMetadata | null;
|
|
40
41
|
}
|
|
41
42
|
/** The session lifecycle, its view, its event stream, and command admission. */
|
|
@@ -3,7 +3,7 @@ export type { DevelopmentLaunchEnvironment } from "./development-launch.js";
|
|
|
3
3
|
export { PI_PROFILE_RESOURCE_DIRECTORIES, initializeProductProfile } from "./initialize-profile.js";
|
|
4
4
|
export type { InitializedProfile } from "./initialize-profile.js";
|
|
5
5
|
export { interactiveLaunchIntent, parseSessionSelection } from "./intent.js";
|
|
6
|
-
export type { InteractiveLaunchIntent, LaunchIntent, LaunchProfileId, SessionSelection } from "./intent.js";
|
|
6
|
+
export type { InteractiveLaunchIntent, InteractiveLaunchMode, LaunchIntent, LaunchProfileId, SessionSelection } from "./intent.js";
|
|
7
7
|
export { configurationRootForProfile, resolveLaunchProfilePaths, resolvePromptHistoryDataDir } from "./profile-paths.js";
|
|
8
8
|
export type { LaunchProfilePathOptions, LaunchProfilePaths } from "./profile-paths.js";
|
|
9
9
|
export { prepareInteractiveLaunch } from "./prepare-launch.js";
|
|
@@ -3,10 +3,12 @@ import type { LaunchProfileId } from "../../foundation/lifecycle/index.js";
|
|
|
3
3
|
export { parseSessionSelection } from "../../foundation/lifecycle/index.js";
|
|
4
4
|
export type { SessionSelection } from "../../foundation/lifecycle/index.js";
|
|
5
5
|
export type { LaunchProfileId } from "../../foundation/lifecycle/index.js";
|
|
6
|
+
export type InteractiveLaunchMode = "tabs" | "solo";
|
|
6
7
|
export interface InteractiveLaunchIntent {
|
|
7
8
|
readonly kind: "interactive";
|
|
8
9
|
readonly profileId: LaunchProfileId;
|
|
10
|
+
readonly launchMode: InteractiveLaunchMode;
|
|
9
11
|
readonly sessionSelection?: SessionSelection;
|
|
10
12
|
}
|
|
11
13
|
export type LaunchIntent = InteractiveLaunchIntent;
|
|
12
|
-
export declare function interactiveLaunchIntent(profileId: LaunchProfileId, sessionSelection?: SessionSelection): InteractiveLaunchIntent;
|
|
14
|
+
export declare function interactiveLaunchIntent(profileId: LaunchProfileId, sessionSelection?: SessionSelection, launchMode?: InteractiveLaunchMode): InteractiveLaunchIntent;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { sessionSelectionArguments } from "../../foundation/lifecycle/index.js";
|
|
2
2
|
export { parseSessionSelection } from "../../foundation/lifecycle/index.js";
|
|
3
|
-
export function interactiveLaunchIntent(profileId, sessionSelection) {
|
|
4
|
-
if (sessionSelection !== undefined && profileId !== "a1")
|
|
5
|
-
throw new Error("session selection requires the normal A1
|
|
3
|
+
export function interactiveLaunchIntent(profileId, sessionSelection, launchMode = profileId === "a1" ? "tabs" : "solo") {
|
|
4
|
+
if (sessionSelection !== undefined && (profileId !== "a1" || launchMode === "solo")) {
|
|
5
|
+
throw new Error("session selection requires the normal tabbed A1 launch");
|
|
6
|
+
}
|
|
7
|
+
if (profileId === "pi" && launchMode !== "solo")
|
|
8
|
+
throw new Error("the Pi comparison launch is always solo");
|
|
6
9
|
sessionSelectionArguments(sessionSelection);
|
|
7
|
-
return Object.freeze({ kind: "interactive", profileId, ...(sessionSelection === undefined ? {} : { sessionSelection }) });
|
|
10
|
+
return Object.freeze({ kind: "interactive", profileId, launchMode, ...(sessionSelection === undefined ? {} : { sessionSelection }) });
|
|
8
11
|
}
|