@timurproko/a1 0.2.7-dev.746 → 0.2.7-dev.767
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/tab-launch-context.d.ts +6 -1
- package/bin/tab-launch-context.js +11 -2
- package/bin/ui.js +7 -3
- package/dist/app/session-shell/session-shell-root.d.ts +23 -0
- package/dist/app/session-shell/session-shell.js +112 -6
- package/dist/composition/owned-ui.d.ts +4 -1
- package/dist/composition/owned-ui.js +54 -8
- package/dist/contracts/owned-ui/session-backend.d.ts +1 -0
- package/dist/features/owned-ui/settings-app.js +8 -35
- package/dist/foundation/release/bootstrap.d.ts +1 -1
- package/dist/foundation/release/bootstrap.js +15 -4
- 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/resident-tabs/bridge-client.d.ts +7 -2
- package/dist/foundation/resident-tabs/bridge-client.js +58 -16
- 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 +2 -0
- package/dist/foundation/resident-tabs/ensure-terminal-host.js +7 -1
- 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 +2 -1
- package/dist/foundation/resident-tabs/index.js +1 -1
- 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/recovery.d.ts +26 -0
- package/dist/foundation/resident-tabs/recovery.js +205 -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 +9 -2
- package/dist/foundation/resident-tabs/settings.js +55 -7
- package/dist/foundation/session-writer-lock/index.d.ts +27 -0
- package/dist/foundation/session-writer-lock/index.js +197 -0
- package/dist/foundation/startup/startup-descriptor.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/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.js +1 -0
- package/dist/integrations/pi/engine/pi-settings-metadata.json +2 -2
- 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/manifest.json +1 -1
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/runtime-payload-inventory.json +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/settings/declarations.d.ts +38 -2
- package/dist/ui/settings/declarations.js +29 -2
- package/dist/ui/settings/index.d.ts +4 -2
- package/dist/ui/settings/index.js +2 -1
- package/dist/ui/settings/manager.d.ts +9 -3
- package/dist/ui/settings/manager.js +81 -29
- package/dist/ui/settings/migrations.d.ts +6 -0
- package/dist/ui/settings/migrations.js +25 -0
- package/dist/ui/settings/profile-document.d.ts +26 -0
- package/dist/ui/settings/profile-document.js +164 -0
- package/dist/ui/settings/sections.js +4 -0
- package/docs/architecture/resident-tabs-requirements.md +1 -234
- package/docs/architecture/resident-tabs.md +30 -10
- package/docs/openspec-archive-automation.md +7 -7
- package/package.json +6 -4
|
@@ -2,7 +2,11 @@ export const AGENT_SECTION_ID = "agent";
|
|
|
2
2
|
const BOOLEAN_CHOICES = Object.freeze([true, false]);
|
|
3
3
|
export function buildOwnedUiSettingsSections(input) {
|
|
4
4
|
const grouped = new Map();
|
|
5
|
+
const residentTabsEnabled = input.resolution.settings
|
|
6
|
+
.find(setting => setting.declaration.id === "residentTabs")?.value === true;
|
|
5
7
|
for (const setting of input.resolution.settings) {
|
|
8
|
+
if (!residentTabsEnabled && ["tabsUnresponsiveRestartSeconds", "tabsStallNoticeSeconds"].includes(setting.declaration.id))
|
|
9
|
+
continue;
|
|
6
10
|
const section = setting.declaration.section ?? { id: "a1", title: "A1" };
|
|
7
11
|
const group = grouped.get(section.id) ?? { title: section.title, entries: [] };
|
|
8
12
|
group.entries.push({
|
|
@@ -159,17 +159,6 @@ Bare `a1` SHALL connect to the profile's resident server, show every tab, and vi
|
|
|
159
159
|
- **THEN** both SHALL show the same tabs and each SHALL keep its own viewed tab
|
|
160
160
|
- **AND** only the current input controller of a tab SHALL send input or resize its PTY while the other client remains a read-only viewer until it claims control
|
|
161
161
|
|
|
162
|
-
#### Requirement: Tab failure is presented and recoverable per tab
|
|
163
|
-
A crashed or failed tab SHALL show its reason in its own surface with `[r] retry`, `[f] start fresh`, and `[alt+w] close`. When a restarted tab's last user prompt had no settled reply, A1 SHALL offer that prompt back into the editor and SHALL NOT resend it. Other tabs SHALL remain fully operable.
|
|
164
|
-
|
|
165
|
-
##### Scenario: One tab crashes
|
|
166
|
-
- **WHEN** one tab's A1 process exits unexpectedly during a turn
|
|
167
|
-
- **THEN** only that tab SHALL show crash and restart state, and other tabs SHALL keep streaming and accepting input
|
|
168
|
-
|
|
169
|
-
##### Scenario: Restart budget exhausted
|
|
170
|
-
- **WHEN** a tab crashes three times within ten minutes
|
|
171
|
-
- **THEN** it SHALL show failed with retry, fresh, and close actions and SHALL NOT restart automatically again
|
|
172
|
-
|
|
173
162
|
#### Requirement: Tab shortcuts are declared, configurable, and conflict-checked
|
|
174
163
|
Tab shortcuts SHALL be declared with action identities, SHALL be configurable through a keybindings file, SHALL be checked at launch against A1's shortcut registry and user keybindings with conflicts reported, and SHALL appear in `/hotkeys` inside A1 tabs. The attach client SHALL consume a matched tab shortcut before input encoding and SHALL forward every other input to the viewed tab; the only `Ctrl+C` handling SHALL be the double-press detach. Defaults SHALL NOT use `Alt+[`, `Alt+]`, `Alt+Left`, `Alt+Right`, `Ctrl+L`, `Alt+Up`, or `Shift+Tab`.
|
|
175
164
|
|
|
@@ -279,13 +268,6 @@ Viewing a tab SHALL deliver a complete retained surface of cells, attributes, hy
|
|
|
279
268
|
- **WHEN** a client views a tab that produced output for hours while detached
|
|
280
269
|
- **THEN** it SHALL render the tab's current screen immediately without replaying the history
|
|
281
270
|
|
|
282
|
-
#### Requirement: Slow clients never stall tabs
|
|
283
|
-
Each client connection SHALL have a bounded reliable control lane and a single-slot render lane in which newer surface updates replace unsent ones. A client that falls behind SHALL receive a full surface once it drains. The server SHALL NOT block holders, other clients, or registry writes on a slow client, and holders SHALL NOT block children on output.
|
|
284
|
-
|
|
285
|
-
##### Scenario: Suspended terminal
|
|
286
|
-
- **WHEN** one attached terminal stops reading while tabs stream
|
|
287
|
-
- **THEN** tabs and other clients SHALL continue normally and the stalled client SHALL show the current surface when it resumes
|
|
288
|
-
|
|
289
271
|
#### Requirement: The tab bridge reports structured A1 state and controller identity
|
|
290
272
|
Each A1 tab process SHALL receive a derived per-tab/per-incarnation credential and SHALL connect an authenticated bridge to the server that reports sequenced status from engine events, the Pi session file and name, whether its last prompt was interrupted, and semantic requests. Before terminal input from a new controller is accepted, the holder and child SHALL establish a causal input-admission boundary covering previously accepted input in native, PTY, and child buffers and acknowledge the new owner. A sideband marker acknowledgement alone SHALL NOT be treated as proof of ordering across channels. Client-scoped requests SHALL retain immutable controller identity/revision captured at command admission and SHALL be rejected when stale or ambiguous, never rebound to the controller current at execution. The server SHALL send visibility and rename notifications through the bridge, and A1 SHALL reduce animation work while hidden. Bridge messages SHALL NOT carry prompt, transcript, or terminal input content. The child SHALL consume bridge credentials into private memory and remove them from inherited environments before extension loading or descendant spawn; reconnect SHALL NOT restore them to the environment. A missing bridge SHALL degrade status and disable client-scoped child requests without breaking terminal input or attach-local detach.
|
|
291
273
|
|
|
@@ -327,35 +309,6 @@ Clients SHALL authenticate with a random owner-only client token. One random own
|
|
|
327
309
|
- **WHEN** a process of another operating-system user connects
|
|
328
310
|
- **THEN** endpoint access control SHALL refuse it
|
|
329
311
|
|
|
330
|
-
#### Requirement: Crashed and hung tabs restart within a bounded budget
|
|
331
|
-
Holders SHALL detect child exit immediately and the server SHALL detect holder exit and heartbeat hangs within a bounded timeout, terminating verified hung trees gracefully then forcibly. An unrequested exit SHALL restart the tab by resuming its Pi session with increasing backoff; after three restarts within ten minutes the tab SHALL become failed and require retry, fresh start, or close. Restarts SHALL NOT resend an interrupted prompt. If child standard error is separately available, it SHALL be captured only as private bounded recovery data, not as a sanitized diagnostic log, and SHALL be excluded from the doctor bundle.
|
|
332
|
-
|
|
333
|
-
##### Scenario: Tab process killed
|
|
334
|
-
- **WHEN** a tab's A1 process is killed externally
|
|
335
|
-
- **THEN** the holder SHALL restart it from its session and the tab SHALL show its transcript again
|
|
336
|
-
|
|
337
|
-
##### Scenario: Interrupted turn after restart
|
|
338
|
-
- **WHEN** a tab crashed after the user's prompt was persisted but before a reply settled
|
|
339
|
-
- **THEN** the restarted tab SHALL be idle and SHALL offer the prompt without resubmitting it
|
|
340
|
-
|
|
341
|
-
#### Requirement: The server heals itself without losing tabs or creating split brain
|
|
342
|
-
When the server exits unexpectedly, attach clients SHALL show a non-blocking reconnecting indication, and any client or holder MAY start a replacement through the detach routine. The replacement SHALL acquire the released writer lease, increment the durable epoch, derive expected holder credentials, verify native identities/incarnations, and re-admit surviving holders; tabs whose holders are gone SHALL enter crash recovery. A live recorded owner SHALL be terminated only after exact identity verification, and an unverifiable owner or unavailable lease SHALL block replacement. After three starts within sixty seconds, clients SHALL show a stopped state with restart and quit actions, preserving diagnostics.
|
|
343
|
-
|
|
344
|
-
##### Scenario: Server killed with no client attached
|
|
345
|
-
- **WHEN** the server dies while no terminal runs `a1`
|
|
346
|
-
- **THEN** a holder SHALL start the replacement, and the next `a1` SHALL reattach every tab with its current screen
|
|
347
|
-
|
|
348
|
-
#### Requirement: Reboot and logout end tabs without losing sessions
|
|
349
|
-
Resident processes SHALL end with the operating-system session; this version SHALL NOT restore tabs after reboot or logout. When the server starts under a new boot identity, or finds desired-running tabs without live verified holders after a new OS session, it SHALL move the previous tab set to registry history instead of starting those tabs, and bare `a1` SHALL start with one new tab. Every previous Pi session SHALL stay resumable through the normal session picker or `a1 --session`. A pending journaled prompt SHALL be offered, without replay, when its session is next opened in a tab within seven days. A reserved first-turn identity whose journal proves the session file was never created SHALL be recoverable the same way rather than treated as a missing transcript.
|
|
350
|
-
|
|
351
|
-
##### Scenario: Reboot with three tabs
|
|
352
|
-
- **WHEN** the machine reboots with three running tabs and the user runs `a1`
|
|
353
|
-
- **THEN** A1 SHALL start one new tab, and all three previous sessions SHALL be listed in the session picker with every committed transcript entry
|
|
354
|
-
|
|
355
|
-
##### Scenario: First-turn session file does not yet exist
|
|
356
|
-
- **WHEN** a reboot leaves a durable reserved session identity and pending journal but Pi had not created the first session file
|
|
357
|
-
- **THEN** opening that identity SHALL offer the prompt idle rather than treat it as a missing existing transcript or automatically resend it
|
|
358
|
-
|
|
359
312
|
#### Requirement: Updates retain the active resident cohort
|
|
360
313
|
Installing or activating a release SHALL NOT terminate the server, holders, or tab processes. Resident binaries and tab processes SHALL run from immutable release directories, and every release used by a live verified resident process SHALL be retained. In this version a same-generation newer client MAY attach with unsupported optional operations disabled, while the existing resident cohort remains on its release until all tabs stop. A generation mismatch SHALL report that the host must be stopped explicitly and SHALL NOT kill or recycle tabs. Automatic endpoint handoff and idle release recycling require a later change.
|
|
361
314
|
|
|
@@ -388,173 +341,10 @@ The terminal-host binary SHALL ship for Windows x64, Linux x64, and macOS arm64
|
|
|
388
341
|
|
|
389
342
|
### Purpose
|
|
390
343
|
|
|
391
|
-
Defines the reliability
|
|
344
|
+
Defines the remaining reliability verification program that gates preview certification and later default enablement. Milestone 4 delivers crash recovery, liveness/progress supervision, durable recovery data, and diagnostic preservation, but does not implement or certify the `a1 tabs doctor` export; that export remains milestone 6 work.
|
|
392
345
|
|
|
393
346
|
### ADDED Requirements
|
|
394
347
|
|
|
395
|
-
#### Requirement: Failure domains are isolated processes
|
|
396
|
-
The attach client, the resident server, each tab's session holder, and each tab's A1 process SHALL be separate operating-system processes. No process SHALL host another tab's pseudoterminal, terminal model, or A1 runtime. Termination or hang of the server SHALL NOT terminate or stall any holder or tab process; termination or hang of one holder or tab process SHALL NOT affect any other tab, the server, or any client; termination of a client SHALL NOT affect any resident process.
|
|
397
|
-
|
|
398
|
-
##### Scenario: Kill every server process repeatedly
|
|
399
|
-
- **WHEN** the server is killed ten times within one minute while five tabs stream
|
|
400
|
-
- **THEN** all five tab processes SHALL keep running with unchanged process identities and no lost output in their retained screens
|
|
401
|
-
|
|
402
|
-
##### Scenario: One tab's process tree hangs
|
|
403
|
-
- **WHEN** one tab's child stops responding and stops reading its input
|
|
404
|
-
- **THEN** every other tab SHALL keep accepting input and rendering at normal latency
|
|
405
|
-
|
|
406
|
-
#### Requirement: Resident processes are crash-only and fail fast
|
|
407
|
-
Every resident process SHALL be safe to terminate forcibly at any instruction. Its startup path SHALL be its recovery path, reconciling durable desired state with verified actual state. A detected internal invariant violation SHALL terminate only the affected process with a diagnostic record, and SHALL NOT be swallowed so that the process continues in an inconsistent state. Code SHALL NOT be hot-swapped into a running resident process; upgrades SHALL replace processes.
|
|
408
|
-
|
|
409
|
-
##### Scenario: Server invariant violation
|
|
410
|
-
- **WHEN** the server detects registry and topology state that contradict each other
|
|
411
|
-
- **THEN** it SHALL write a crash record and exit, and its replacement SHALL recover from the durable registry and verified holders without affecting tabs
|
|
412
|
-
|
|
413
|
-
##### Scenario: Forced termination during a registry write
|
|
414
|
-
- **WHEN** the server is killed at any point during a registry commit
|
|
415
|
-
- **THEN** the next server SHALL load either the complete prior or the complete new registry and SHALL NOT start empty
|
|
416
|
-
|
|
417
|
-
#### Requirement: Control paths never block on external work
|
|
418
|
-
Each resident role's state machine SHALL run on a single event loop that performs no blocking system call. Process spawn, pseudoterminal creation, process termination, identity inspection, file writes, and synchronization SHALL run off the event loop with explicit deadlines, and a missed deadline SHALL become a typed failure event. Pseudoterminal creation SHALL occur only inside that tab's holder, so a creation that never returns SHALL hang only that holder, which the server SHALL terminate and replace after its deadline. Termination of several tabs SHALL proceed concurrently and SHALL NOT delay unrelated operations.
|
|
419
|
-
|
|
420
|
-
##### Scenario: Pseudoterminal creation never returns
|
|
421
|
-
- **WHEN** pseudoterminal creation blocks indefinitely in a new tab's holder
|
|
422
|
-
- **THEN** the server SHALL remain responsive, SHALL terminate that holder after the spawn deadline, retry within the restart budget, and every other tab SHALL be unaffected
|
|
423
|
-
|
|
424
|
-
##### Scenario: Close a group of busy tabs
|
|
425
|
-
- **WHEN** the user stops six tabs at once
|
|
426
|
-
- **THEN** the server SHALL keep answering clients and heartbeats throughout, and every tab SHALL reach stopped or a reported termination failure within the bounded deadline
|
|
427
|
-
|
|
428
|
-
#### Requirement: Pseudoterminal I/O is flow-controlled and never silently lossy
|
|
429
|
-
Each holder SHALL read its pseudoterminal continuously on a dedicated reader so the child never blocks on output, and SHALL write input from a dedicated writer with a bounded queue so a child that stops reading never blocks the holder. When the input queue is full, A1 SHALL reject further input for that tab with a visible `not accepting input` indication and SHALL NOT silently drop, reorder, or truncate accepted input. Keystrokes sent while a tab is starting SHALL be queued in order up to the bound and delivered when it becomes ready, or rejected visibly. A paste SHALL reserve capacity for its complete bounded payload before any prefix is delivered. Admission atomicity SHALL NOT be described as atomic execution by the child: failure after admission SHALL report uncertain delivery and SHALL NOT trigger automatic replay.
|
|
430
|
-
|
|
431
|
-
##### Scenario: Paste into a stalled child
|
|
432
|
-
- **WHEN** the user pastes into a tab whose child is not reading input and the queue lacks capacity for the entire paste
|
|
433
|
-
- **THEN** admission SHALL reject the paste with a visible indication before delivering any prefix
|
|
434
|
-
|
|
435
|
-
##### Scenario: Child fails after paste admission
|
|
436
|
-
- **WHEN** a paste was admitted but the child dies after reading only part of it
|
|
437
|
-
- **THEN** A1 SHALL report uncertain delivery, SHALL NOT claim transactional child execution, and SHALL NOT replay the paste automatically
|
|
438
|
-
|
|
439
|
-
#### Requirement: Liveness and progress are supervised separately
|
|
440
|
-
Each resident role SHALL run an independent watchdog that detects its own event-loop stall, records diagnostics including thread state, and terminates only that process. The server SHALL supervise holders through five-second heartbeats and treat three missed ticks over a healthy supervision path as a holder timeout. Holders SHALL supervise their A1 process through bridge heartbeats emitted from its event loop. Server or bridge transport loss alone SHALL NOT be classified as a child hang or authorize child termination; child liveness SHALL be re-established before destructive recovery. An A1 process that is alive but has missed bridge heartbeats for 30 seconds SHALL be shown as unresponsive; after `tabsUnresponsiveRestartSeconds` (default 120) it SHALL be restarted from its session with its prompt journal and last screen preserved. A tab that is working but has produced no progress event for `tabsStallNoticeSeconds` (default 300) SHALL be shown as stalled with interrupt and restart actions and SHALL NOT be terminated automatically, because long-running tools are legitimate.
|
|
441
|
-
|
|
442
|
-
##### Scenario: A1 event loop wedges
|
|
443
|
-
- **WHEN** a tab's A1 process stops emitting bridge heartbeats but its process is alive
|
|
444
|
-
- **THEN** its chip SHALL show unresponsive within 30 seconds, and after the configured interval the tab SHALL restart from its session with the pending prompt offered back
|
|
445
|
-
|
|
446
|
-
##### Scenario: Server loss interrupts bridge delivery
|
|
447
|
-
- **WHEN** the server dies or the bridge transport fails while a child remains alive
|
|
448
|
-
- **THEN** holders SHALL keep the child running, report degraded status, and SHALL NOT apply the child heartbeat restart deadline solely to the transport outage
|
|
449
|
-
|
|
450
|
-
##### Scenario: Provider stream stalls
|
|
451
|
-
- **WHEN** a working tab receives no model or tool progress for five minutes
|
|
452
|
-
- **THEN** its chip SHALL show stalled with interrupt and restart actions, and the tab SHALL NOT be killed automatically
|
|
453
|
-
|
|
454
|
-
#### Requirement: Recovery is level-triggered reconciliation
|
|
455
|
-
The server SHALL converge each tab's actual state toward its durable desired state through idempotent reconciliation rather than one-shot event handling. Terminal size, lifecycle, and holder presence SHALL be treated as desired state that is re-applied until observed. Every holder and tab-process incarnation SHALL carry a unique incarnation identity, and events from a superseded incarnation SHALL be discarded. Reconciliation SHALL be gated so that at most one start is in flight per tab.
|
|
456
|
-
|
|
457
|
-
##### Scenario: Late exit event from a replaced child
|
|
458
|
-
- **WHEN** an exit notification for a previous incarnation arrives after the tab was restarted
|
|
459
|
-
- **THEN** the server SHALL discard it and the new incarnation SHALL keep running
|
|
460
|
-
|
|
461
|
-
##### Scenario: Resize lost in transit
|
|
462
|
-
- **WHEN** a resize message is lost or reordered
|
|
463
|
-
- **THEN** the holder's size SHALL still converge to the latest desired size
|
|
464
|
-
|
|
465
|
-
#### Requirement: Stale servers and registry writers are fenced out
|
|
466
|
-
Exactly one server SHALL hold the owner-only operating-system registry-writer lease. A failed endpoint handshake SHALL NOT by itself authorize replacement: the starter SHALL verify the recorded owner's native process identity, terminate that owner, and acquire the released lease, or fail closed when verification or acquisition is unavailable. Each server start SHALL durably increment the registry epoch while holding the lease before it acts. Every registry mutation SHALL verify that the lease is still held and the durable epoch is current. Holders and bridges SHALL accept commands only from the highest epoch they have observed and SHALL reject lower epochs.
|
|
467
|
-
|
|
468
|
-
##### Scenario: A hung server resumes after replacement
|
|
469
|
-
- **WHEN** a verified hung server was terminated, its lease was acquired by a replacement, and stale work from the old incarnation is later delivered
|
|
470
|
-
- **THEN** holders and bridges SHALL reject its epoch and no stale registry mutation SHALL commit
|
|
471
|
-
|
|
472
|
-
##### Scenario: Timed-out owner cannot be verified
|
|
473
|
-
- **WHEN** the endpoint does not answer but the recorded owner cannot be proven and terminated by native identity
|
|
474
|
-
- **THEN** A1 SHALL report host recovery blocked and SHALL NOT start a second registry writer
|
|
475
|
-
|
|
476
|
-
#### Requirement: Durable data is guaranteed per class
|
|
477
|
-
A1 SHALL uphold these guarantees across forced termination of any process, including all resident processes at once:
|
|
478
|
-
- Each submitted prompt SHALL have a stable submission ID bound to its session/incarnation and SHALL be synchronized to an owner-only per-tab journal before agent dispatch. Failed or timed-out journal admission SHALL preserve the editor prompt, report the failure, and dispatch nothing. Asynchronous prompt history SHALL NOT substitute for this barrier. A journal entry SHALL be retired only after the corresponding identified session entry is synchronized; settled completion SHALL also be durably correlated so recovery does not offer a completed submission as unfinished. Recovery SHALL reconcile journal/session records by identity, offer unfinished prompts without automatic resend, and cover the first turn before Pi creates its session file.
|
|
479
|
-
- Committed Pi session entries SHALL never be lost on process termination. A1 SHALL synchronize the session file to stable storage after each settled turn and on graceful stop, so settled turns also survive power loss.
|
|
480
|
-
- A tab's session identity and file path SHALL be durably recorded in the registry before the tab accepts input.
|
|
481
|
-
- The editor draft SHALL be checkpointed periodically with a maximum one-second dirty interval while storage and the event loop are healthy, including continuous typing with no idle interval. A failed or late checkpoint SHALL expose degraded recovery and SHALL NOT silently retain the one-second loss guarantee.
|
|
482
|
-
- When a tab's A1 process dies, its holder SHALL keep the last retained screen visible as a read-only snapshot and SHALL write it with bounded scrollback to an owner-only recovery file, retained for seven days, so streamed but uncommitted output remains readable.
|
|
483
|
-
- Registry mutations SHALL be synchronized with write access sufficient for the platform's flush semantics, SHALL retry transient rename failures with backoff, and SHALL NOT be acknowledged as committed until their durability barrier succeeds. Persistent failure SHALL reject new durable mutations while retaining live observed state in memory, report degraded health, and never rebuild state from an older file over newer memory. Each platform's file and replacement/directory metadata durability primitives and supported-filesystem limits SHALL be specified and tested, including a write-capable flush with write-through replacement on Windows and `F_FULLFSYNC` on macOS; API-call occurrence alone SHALL NOT certify power-loss survival.
|
|
484
|
-
|
|
485
|
-
##### Scenario: Power loss after a settled turn
|
|
486
|
-
- **WHEN** the machine loses power after a turn has settled
|
|
487
|
-
- **THEN** after reboot that session SHALL contain that turn when it is resumed
|
|
488
|
-
|
|
489
|
-
##### Scenario: Crash during the first turn of a new tab
|
|
490
|
-
- **WHEN** a new tab's A1 process is killed before its first reply completes
|
|
491
|
-
- **THEN** the restarted tab SHALL offer the original prompt from the journal even though Pi had not created a session file
|
|
492
|
-
|
|
493
|
-
##### Scenario: Journal admission fails
|
|
494
|
-
- **WHEN** a submitted prompt cannot be durably journaled before dispatch
|
|
495
|
-
- **THEN** the editor SHALL retain it with a visible failure and the agent SHALL receive no submission
|
|
496
|
-
|
|
497
|
-
##### Scenario: Crash between session synchronization and journal retirement
|
|
498
|
-
- **WHEN** a submission's session entry is synchronized but the journal still contains its submission ID at crash time
|
|
499
|
-
- **THEN** recovery SHALL reconcile the records without duplicating the session entry or dispatching the prompt, and SHALL offer it only if the turn remains unfinished
|
|
500
|
-
|
|
501
|
-
##### Scenario: Continuous typing before a crash
|
|
502
|
-
- **WHEN** the user types continuously for thirty seconds with healthy storage and the tab is then killed
|
|
503
|
-
- **THEN** recovery SHALL contain all but at most the last second of draft changes without requiring an inactivity interval
|
|
504
|
-
|
|
505
|
-
##### Scenario: Draft checkpoint stalls
|
|
506
|
-
- **WHEN** the draft checkpoint exceeds its dirty-interval bound because storage fails or blocks
|
|
507
|
-
- **THEN** A1 SHALL report degraded recovery when observable and SHALL NOT claim the one-second draft-loss bound remains satisfied
|
|
508
|
-
|
|
509
|
-
##### Scenario: Crash mid-stream
|
|
510
|
-
- **WHEN** a tab's A1 process dies while a reply streams
|
|
511
|
-
- **THEN** the streamed text SHALL remain visible in the read-only last-screen snapshot and in its recovery file
|
|
512
|
-
|
|
513
|
-
##### Scenario: Antivirus holds the registry file
|
|
514
|
-
- **WHEN** registry rename fails transiently because another process holds the file
|
|
515
|
-
- **THEN** the server SHALL retry, keep serving from memory, report degraded health if the failure persists, and SHALL NOT drop or kill any tab
|
|
516
|
-
|
|
517
|
-
#### Requirement: Session exclusivity is enforced by the operating system
|
|
518
|
-
Every A1-owned runtime that writes a Pi session on a supported platform, whether resident, direct/fallback, or Pi-comparison, SHALL acquire the same profile-neutral native session-writer lease before opening it for writing, regardless of the resident setting. Direct modes SHALL NOT start a resident host, holder, or bridge to perform this check. The lease SHALL be an operating-system lock held by the writer process itself. Lease identity SHALL resolve case, junction/symlink, hard-link and existing-file aliases, and SHALL reserve a canonical parent/name for a new file without a gap when binding its created file identity. Lock custody SHALL follow the actual session writer lifetime; death of the holder alone SHALL NOT release exclusivity while the writer remains alive. Replacement SHALL require lease acquisition and verified exit of the previous writer/tree; unavailable proof SHALL block replacement. Session switching SHALL acquire the target before releasing the previous writer lease and preserve the old session on failed admission. Kernel cleanup SHALL release abandoned leases only once no live owner remains. Unmodified external Pi, older nonparticipating releases, and arbitrary file writers are outside this cooperative contract and SHALL NOT be claimed as covered.
|
|
519
|
-
|
|
520
|
-
##### Scenario: Orphaned child still alive during recovery
|
|
521
|
-
- **WHEN** recovery finds a session whose previous A1 process may still be running but cannot be verified
|
|
522
|
-
- **THEN** the lease SHALL prevent a second process from appending to that session, and the tab SHALL report the conflict instead of starting
|
|
523
|
-
|
|
524
|
-
##### Scenario: Holder dies before its writer exits
|
|
525
|
-
- **WHEN** a holder is killed but its A1 writer has not yet been proven exited
|
|
526
|
-
- **THEN** the writer-bound lease SHALL prevent a replacement from writing the same session, and uncertainty SHALL keep recovery blocked
|
|
527
|
-
|
|
528
|
-
##### Scenario: Direct fallback targets a held session
|
|
529
|
-
- **WHEN** a direct or fallback A1 runtime selects a session held by a resident writer
|
|
530
|
-
- **THEN** admission SHALL fail safely or offer an explicit fork, and SHALL NOT start a second writer or silently attach the direct invocation
|
|
531
|
-
|
|
532
|
-
##### Scenario: Session path alias
|
|
533
|
-
- **WHEN** two A1-owned runtimes select aliases of the same session file
|
|
534
|
-
- **THEN** both SHALL resolve the same lock authority and at most one SHALL open the session for writing
|
|
535
|
-
|
|
536
|
-
##### Scenario: Session switch conflicts
|
|
537
|
-
- **WHEN** a running session attempts to switch to a session already held elsewhere
|
|
538
|
-
- **THEN** the switch SHALL be rejected without losing the old session or its lease
|
|
539
|
-
|
|
540
|
-
#### Requirement: Concurrent tab starts do not corrupt shared profile state
|
|
541
|
-
Tab starts SHALL be limited by `tabsMaxConcurrentStarts` and spaced so that concurrent Pi processes do not contend on profile authentication or settings locks beyond Pi's retry budget. Tab stops SHALL request graceful shutdown before forced termination so profile locks are released normally.
|
|
542
|
-
|
|
543
|
-
##### Scenario: Start ten tabs at once
|
|
544
|
-
- **WHEN** ten tabs start or restart at once
|
|
545
|
-
- **THEN** every tab SHALL start with its configured models available
|
|
546
|
-
|
|
547
|
-
#### Requirement: Diagnostics survive the failures they describe
|
|
548
|
-
Resident logs SHALL rotate by size into bounded retained generations and SHALL never be deleted or truncated at startup. Every crash, watchdog termination, and unrequested child exit SHALL produce a distinct timestamped record containing role, incarnation, reason, recent structured events, and, for native processes, a backtrace, bounded in total size and age. Structured logs and crash records SHALL use allowlisted metadata and SHALL exclude credentials, prompt/transcript/terminal content, raw stderr, and arbitrary exception messages. Journals, last-screen snapshots, and optional separately captured child stderr SHALL be classified as sensitive recovery artifacts rather than sanitized diagnostics, restricted to the owner and bounded by size and age. Optional stderr SHALL retain at most three 5 MiB generations for at most seven days and SHALL NOT be inferred by scraping terminal cells. `a1 tabs doctor` SHALL export only allowlisted diagnostic data with host status, recent structured records, counters for restarts, stalls, resyncs, and degraded states, and platform detachment details; it SHALL exclude recovery content.
|
|
549
|
-
|
|
550
|
-
##### Scenario: Two crashes in a row
|
|
551
|
-
- **WHEN** a tab crashes, restarts, and crashes again
|
|
552
|
-
- **THEN** both crash records SHALL be preserved and distinguishable
|
|
553
|
-
|
|
554
|
-
##### Scenario: Extension writes sensitive stderr
|
|
555
|
-
- **WHEN** a child extension writes a prompt, credential-like text, or terminal control sequence to stderr
|
|
556
|
-
- **THEN** that raw content SHALL NOT appear in structured logs, crash records, or the doctor bundle, and any separately captured copy SHALL remain private bounded recovery data
|
|
557
|
-
|
|
558
348
|
#### Requirement: Reliability evidence matches the enablement stage
|
|
559
349
|
The server state machine SHALL be implemented independently of I/O and SHALL be exercised by deterministic simulation and property tests that inject arbitrary interleavings of process death, message loss, reordering, delay, stale epochs, controller transfer, client churn, and mutations, asserting that no committed mutation is lost, only one registry writer exists, no session gains two live tabs, client-scoped requests remain attributable, and every desired-running tab converges to running or failed. Every persistence and IPC step SHALL expose a failure-injection point exercised by crash-point tests. Protocol decoders and surface encoders SHALL be fuzzed, and bounded chaos/fault-injection suites on each platform SHALL gate the opt-in preview. Implementation SHALL progress through contracts and platform primitives, one persistent tab, failure isolation, crash recovery, complete UX, and packaged certification, each delivered as its own change behind `residentTabs: false`, with evidence at each milestone before dependent behavior is enabled. Intermediate demonstrations SHALL NOT count as shipping acceptance. Historical v2/herdr results, Unix-only tests, and pending 2×2 proof records SHALL NOT substitute for exact-package resident evidence on each platform.
|
|
560
350
|
|
|
@@ -691,29 +481,6 @@ A supported session launch SHALL carry its validated target and effective sessio
|
|
|
691
481
|
|
|
692
482
|
### MODIFIED Requirements
|
|
693
483
|
|
|
694
|
-
#### Requirement: Interactive launch forms are concurrently independent
|
|
695
|
-
A1 SHALL permit multiple simultaneous instances of bare `a1`, prerelease `a1 pi`, or both. Profile selection, profile data, lifecycle state, process containment, and closure SHALL remain scoped to the originating invocation rather than a product-wide foreground slot. When resident tabs are enabled, concurrent bare-A1 instances of the same profile SHALL attach to that profile's single resident terminal host as independent clients; closing one client SHALL NOT affect another client or any resident tab. A1-owned runtimes in either profile SHALL share the native session-writer admission guard only when selecting the same canonical session file, regardless of the resident setting. The guard SHALL be independent of resident initialization: `a1 pi` and direct A1 SHALL start no host, holder, strip or bridge. Different session files SHALL remain independently writable, and unmodified external Pi or older nonparticipating builds SHALL NOT be claimed as covered.
|
|
696
|
-
|
|
697
|
-
##### Scenario: Start the same profile twice
|
|
698
|
-
- **WHEN** the user starts two instances of the same retained profile
|
|
699
|
-
- **THEN** both SHALL launch independently without sharing foreground ownership
|
|
700
|
-
|
|
701
|
-
##### Scenario: Start both profile forms
|
|
702
|
-
- **WHEN** owned A1 or Pi-comparison instances are already active and another supported form is launched
|
|
703
|
-
- **THEN** the new invocation SHALL start independently without requiring an existing instance to exit
|
|
704
|
-
|
|
705
|
-
##### Scenario: Two bare A1 clients share resident tabs
|
|
706
|
-
- **WHEN** two bare `a1` instances of one profile run with resident tabs enabled and one of them exits
|
|
707
|
-
- **THEN** the remaining instance SHALL keep its tabs, active selection, and input unaffected, and every resident tab SHALL keep running
|
|
708
|
-
|
|
709
|
-
##### Scenario: Comparison profile selects a session held by a tab
|
|
710
|
-
- **WHEN** a Pi-comparison runtime selects the canonical file already held by a resident A1 tab
|
|
711
|
-
- **THEN** the shared writer guard SHALL reject duplicate writing without starting resident infrastructure or changing the comparison UI into a tab client
|
|
712
|
-
|
|
713
|
-
##### Scenario: Different session files across profiles
|
|
714
|
-
- **WHEN** bare-A1 and Pi-comparison runtimes select distinct unheld session files
|
|
715
|
-
- **THEN** both SHALL proceed concurrently without a product-wide foreground lock
|
|
716
|
-
|
|
717
484
|
## Capability: `cli-session-resume`
|
|
718
485
|
|
|
719
486
|
### MODIFIED Requirements
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Resident tabs — architecture and roadmap
|
|
2
2
|
|
|
3
|
-
Status: staged implementation.
|
|
3
|
+
Status: staged implementation. Milestones 1–3 are integrated. Milestone 4's crash restart, durable recovery data, liveness/progress supervision, registry recovery, and bounded diagnostics are implemented on its draft change behind the default-off preview setting; the final synchronized head still requires exact-head three-platform CI evidence before acceptance. Windows physical-survival evidence exists for milestone 2 only. macOS and Linux physical survival, complete tab UX, packaging, maintenance commands, and certification remain deferred to later milestones; CI evidence is not a substitute. Discovery or verification failure safely falls back to the direct path. This document is the living design for multi-agent tabs; each milestone change cites the decisions it implements and updates this file when a decision changes. The full target behavior is in [`resident-tabs-requirements.md`](resident-tabs-requirements.md); each milestone moves its slice of those requirements into its own OpenSpec change and removes it from that file.
|
|
4
4
|
|
|
5
5
|
## Context
|
|
6
6
|
|
|
@@ -52,7 +52,7 @@ The read-only review used A1 `develop` at `b42b3c9e`, PR #586 at `8fdb7361`, `E:
|
|
|
52
52
|
|
|
53
53
|
### Milestone 2 pinned launch contract (2026-10-11)
|
|
54
54
|
|
|
55
|
-
- The preview flag is `residentTabs` in
|
|
55
|
+
- The preview flag is `residentTabs` in the flat `a1` object of the global agent `settings.json`, default `false`; pre-UI routing treats absent, unreadable, oversized, and invalid values as off. The former versioned profile document remains a read-only compatibility fallback while that object is absent.
|
|
56
56
|
- The host artifact resolves to `dist/native/<platform>-<arch>/a1-terminal-host[.exe]`, with hermetic `A1_TERMINAL_HOST_PATH`; discovery may use `A1_TABS_ENDPOINT`.
|
|
57
57
|
- Tab children consume and erase `A1_TAB_ID`, `A1_TAB_TOKEN`, and `A1_TAB_ENDPOINT` before loading A1, Pi, extensions, or tools.
|
|
58
58
|
- Client-scoped bridge detach binds `clientId` and `controllerRevision` captured when the command is admitted. The additive generation-1 `attachment` and `bridge.request` fixtures freeze that shape.
|
|
@@ -61,6 +61,26 @@ The read-only review used A1 `develop` at `b42b3c9e`, PR #586 at `8fdb7361`, `E:
|
|
|
61
61
|
- Milestone 2 multiplexes authenticated attach, holder, bridge, and probe roles over the owner endpoint and sends a replaceable full current surface through each client's single-slot render lane. Dedicated holder endpoints and patch deltas remain multi-tab optimizations rather than claims of this one-tab milestone.
|
|
62
62
|
- The native server, holder, attach, bridge reconnect, child containment, and role integration fixture are implemented. Milestone 2 records complete Windows x64 terminal-close and OpenSSH-loss evidence; macOS arm64 and Linux x64 physical terminal/SSH evidence remains uncertified and is an explicit milestone-6 gate rather than an inferred milestone-2 result.
|
|
63
63
|
|
|
64
|
+
### Milestone 3 failure-isolation contract (2026-10-14)
|
|
65
|
+
|
|
66
|
+
- The native `core/server.rs` and `core/holder.rs` state machines are deterministic and I/O-free; the production holder uses the holder core for bounded input admission and ordered writer effects, and the production server uses the server core for heartbeat supervision. Blocking identity/termination work runs through the bounded worker shell with deadlines and stale-incarnation filtering.
|
|
67
|
+
- Every attach, server, and holder role has an independent 15-second watchdog. Watchdog records are bounded, timestamped, owner-only metadata under the profile runtime directory; fault-only role freezes are refused by non-test release builds.
|
|
68
|
+
- Holders read PTY output continuously, use one bounded input authority, reserve complete pastes before delivery, and emit a typed uncertain-delivery result after an admitted write failure. Server-to-client control lanes are frame/byte bounded; render lanes retain one replaceable full current surface. Holders stream surfaces only while at least one client views their tab.
|
|
69
|
+
- Server replacement is serialized by `server-start.lock` in the profile runtime directory. Recovery verifies the recorded native owner before termination, waits boundedly for the registry-writer lease, increments the durable epoch, derives holder credentials, and re-admits only exact holder/child identities and incarnations. A durable three-start/sixty-second budget stops automatic replacement; explicit `--restart` clears it.
|
|
70
|
+
- Registry records now retain holder and child pid/start identities and holder incarnation. Replacement treats unverifiable records as `holder-lost`; it never starts a duplicate writer from uncertain state.
|
|
71
|
+
- `tabsMaxConcurrentStarts` is an owned version-15 setting, default 2 and bounded 1–8. The server also enforces the existing ten-tab hard default where no earlier `tabsMax` setting exists, spaces starts by at least 250 ms, and requests graceful tab shutdown before verified forced termination.
|
|
72
|
+
- All A1-owned Pi runtimes use one profile-neutral session-writer guard regardless of `residentTabs`. A new target is reserved by canonical location, created as an empty owner-only placeholder, bound to stable file identity without a release gap, and only then exposed to Pi for session content. Runtime replacement acquires and binds the target before publishing it or releasing the prior writer; conflict paths preserve the source and may explicitly fork.
|
|
73
|
+
- The generation-1 holder transport continues to use the authenticated owner endpoint and replaceable full surfaces. Dedicated holder endpoints and patch deltas remain later optimizations and are not milestone-3 claims.
|
|
74
|
+
|
|
75
|
+
### Milestone 4 crash-recovery contract (2026-10-12)
|
|
76
|
+
|
|
77
|
+
- The server persists restart intent and the three-in-ten-minute budget before instructing the surviving holder to respawn its child. The holder verifies prior-writer release, preserves its PTY ownership boundary, rotates incarnation credentials, and resumes the recorded session with 1/5/30-second backoff. User-requested restart is explicit and does not consume the crash budget.
|
|
78
|
+
- Child-event-loop heartbeat silence is counted only while server, bridge, holder, and child supervision remains continuously healthy. Transport loss resets the observation window. Progress stalls are advisory and never trigger automatic termination. `tabsUnresponsiveRestartSeconds` and `tabsStallNoticeSeconds` remain advanced controls hidden unless `residentTabs` is enabled.
|
|
79
|
+
- Tab-mode submission is durably journaled before dispatch, correlated with the session entry, synchronized after settlement, and retired idempotently. Recovery reconciles identity and exact text without collapsing duplicate prompts or automatically replaying work. Periodic draft checkpoints expose a degraded state when the one-second healthy-storage envelope cannot be met.
|
|
80
|
+
- Registry replacement retries transient failures, quarantines unreadable state, recovers only from the newest valid bounded history, and fails closed when no valid generation remains. A changed boot or OS-session identity archives the prior tab set instead of restoring it; journals younger than seven days can be adopted when their sessions are explicitly reopened.
|
|
81
|
+
- Last-screen and fixture-only stderr files are private bounded recovery artifacts. Structured server, holder, attach, and child crash records use allowlisted fields, rotate without startup truncation, and remain physically separate from recovery content.
|
|
82
|
+
- Milestone 4 adds only the minimal lifecycle states, failed-tab banner, and retry/fresh/close handling needed to expose recovery. Rich strip behavior, general shortcuts, mouse interactions, naming, prewarm, idle suspension, and two-client UX remain milestone 5. `a1 tabs doctor`, packaging, physical terminal/SSH-loss acceptance, and complete certification remain milestone 6.
|
|
83
|
+
|
|
64
84
|
### Relation to the in-process prep refactors (2026-10-09/10)
|
|
65
85
|
|
|
66
86
|
PRs #729–#736 prepared the owned UI for several sessions in one process. This design runs one A1 process per tab, so it does not depend on the shared helper pools (#733), the engine host's multi-session factory (#734), the terminal-host/presenter split (#735), or the per-agent claim dimension (#736). It does use the lifecycle ordering from #732 (bounded quit, clean disposal), which tab detach and restart rely on, and the unique required session ids from #734. Each tab process must get its own launch runtime id so worktree claims (#736) never collide.
|
|
@@ -137,20 +157,20 @@ Alternatives considered:
|
|
|
137
157
|
- the list of holders and client sessions;
|
|
138
158
|
- fan-out of the active tab's surface to each client;
|
|
139
159
|
- tab-bridge termination, and restore and restart policy.
|
|
140
|
-
It runs no A1 or Pi code and holds no PTY. That keeps it small and hardens it against the herdr single-point-of-failure problem.
|
|
160
|
+
It runs no A1 or Pi code and holds no PTY. That keeps it small and hardens it against the herdr single-point-of-failure problem. Generation 1 forwards replaceable full retained surfaces; patch deltas remain a later optimization.
|
|
141
161
|
- **holder** is resident, one per tab. It owns:
|
|
142
162
|
- exactly one PTY (ConPTY on Windows) and its child process tree;
|
|
143
163
|
- one libghostty-vt retained model with bounded scrollback;
|
|
144
164
|
- input encoding and the per-tab damage state.
|
|
145
165
|
Because ConPTY belongs to its creating process, each tab has its own creator. A server crash therefore does not destroy a tab's ConPTY; holder failure affects only that tab. Actual child/tree exit and writer-lease release still require verification, not inference from the pseudoconsole closing.
|
|
146
|
-
- **Why the server relays surfaces instead of clients connecting to holders directly.** It gives one authenticated endpoint per client, one ordering domain for focus and topology, and simpler multi-client arbitration. Measure the extra local pipe hop in the native hot-path evidence rather than assuming its latency. The server forwards encoded
|
|
166
|
+
- **Why the server relays surfaces instead of clients connecting to holders directly.** It gives one authenticated endpoint per client, one ordering domain for focus and topology, and simpler multi-client arbitration. Measure the extra local pipe hop in the native hot-path evidence rather than assuming its latency. The server forwards encoded holder surfaces and does not re-render them.
|
|
147
167
|
|
|
148
168
|
### 3. Host scope, endpoints, writer authority, and credentials
|
|
149
169
|
|
|
150
170
|
- There is **one server per OS user × canonical A1 profile root**, independent of the release cohort. Tabs must outlive release changes, and the supervisor is forbidden from retaining runtime processes.
|
|
151
171
|
- Windows endpoint: `\\.\pipe\a1-tabs-<sha256(canonicalProfileHome)[0:20]>`.
|
|
152
172
|
- macOS and Linux endpoint: a Unix domain socket `a1-tabs-<same profile hash>.sock` inside an owner-only (`0700`) per-user runtime directory (`$XDG_RUNTIME_DIR` when set, otherwise a private directory under the profile's runtime dir), kept short enough for the platform's socket path limit.
|
|
153
|
-
-
|
|
173
|
+
- Generation 1 admits holders over the authenticated owner endpoint. Dedicated `…-h-<tabId>` endpoints remain an optional later optimization.
|
|
154
174
|
- Hermetic override: `A1_TABS_ENDPOINT`, together with the `A1_*_DIR` overrides.
|
|
155
175
|
- **The endpoint is discovery; the writer lease is authority.** A starting server probes with a real handshake. If a live server answers, it exits as `already-running` and joins the winner. A failed probe does not authorize blind endpoint reclaim: the starter reads the owner marker, verifies pid and native start identity, requests termination, and waits for the owner-only OS-exclusive registry-writer lease. If the owner cannot be verified or the lease cannot be acquired, startup fails closed instead of creating split brain.
|
|
156
176
|
- The ownership marker `{serverId, pid, startIdentity, bootNonce, generation, build}` is written atomically under the writer lease. Every registry mutation rechecks the held lease and current epoch before commit. A server removes an endpoint or marker only while both still identify it.
|
|
@@ -164,7 +184,7 @@ Alternatives considered:
|
|
|
164
184
|
|
|
165
185
|
- **Server start.** The server is started from the Node pre-guardian bootstrap (`ensureTerminalHost()` beside `ensureSupervisor()`), through `a1-terminal-host server --detach`.
|
|
166
186
|
- **No general escape from containment.** On Windows, ordinary launch-instance jobs and holder-owned child jobs retain kill-on-close containment without `JOB_OBJECT_LIMIT_BREAKAWAY_OK` or silent breakaway; a job flag cannot allowlist an executable. On every platform, resident creation is a distinct authenticated fixed-role operation, not an arbitrary executable/argv spawn service.
|
|
167
|
-
- **Authorized launch and recovery.** Initial creation runs before the launch guardian. A contained attach client or surviving holder invokes the native verified `server --detach` recovery path inside the terminal-host executable; there is no arbitrary-spawn IPC method. The routine accepts only a typed `server` or `holder` role and canonical profile, resolves and opens its own terminal-host artifact, constructs a fixed argument grammar, uses an allowlisted environment/cwd with handle inheritance disabled, and verifies the resulting pid/start identity and containment before success. Native tests may compile one feature-gated fixture role, but production accepts no executable or free-form argv. Owner-only credentials prevent cross-user access; this is not a sandbox against arbitrary malicious code already running as the same OS user.
|
|
187
|
+
- **Authorized launch and recovery.** Initial creation runs before the launch guardian. A contained attach client or surviving holder invokes the native verified `server --detach` recovery path inside the terminal-host executable; there is no arbitrary-spawn IPC method. The routine accepts only a typed `server` or `holder` role and canonical profile, resolves and opens its own terminal-host artifact, constructs a fixed argument grammar, uses an allowlisted environment/cwd with handle inheritance disabled, and verifies the resulting pid/start identity and containment before success. On Windows, a contained caller uses the fixed WMI escape, while the holder's fixed recovery invocation launches directly from its already-detached resident boundary; recursively invoking WMI from a detached service can fail in non-interactive sessions. Native tests may compile one feature-gated fixture role, but production accepts no executable or free-form argv. Owner-only credentials prevent cross-user access; this is not a sandbox against arbitrary malicious code already running as the same OS user.
|
|
168
188
|
- **Windows:**
|
|
169
189
|
- Select valid platform creation flags for detached, console-free startup; do not assume combining `DETACHED_PROCESS` and `CREATE_NO_WINDOW` adds a guarantee. Verify resulting process identity and job containment before reporting resident readiness.
|
|
170
190
|
- For a caller in a foreign kill-on-close job that denies breakaway (Windows OpenSSH, some IDE terminals), use WMI `Win32_Process.Create` with an explicit environment block and cwd, bounded startup, and post-launch verification (herdr reference).
|
|
@@ -201,7 +221,7 @@ The channels carry bounded generation-1 frames: a u32 little-endian length follo
|
|
|
201
221
|
- The server sends `bridge.visibility{visible}`, so a hidden A1 throttles animation, and `bridge.rename`, so a strip rename sets the Pi session name.
|
|
202
222
|
- The bridge is advisory. A missing or broken bridge degrades that tab to process-level status and never breaks the tab.
|
|
203
223
|
- **Backpressure:**
|
|
204
|
-
- Each client connection has a reliable, bounded control lane and a **single-slot render lane**. A newer
|
|
224
|
+
- Each client connection has a reliable, bounded control lane and a **single-slot render lane**. A newer full current surface replaces an unsent one, so a client that drains never depends on a dropped intermediate revision.
|
|
205
225
|
- The server never blocks a holder, another client, or registry writes on a slow client.
|
|
206
226
|
- Holders parse their PTY continuously, whether or not the tab is viewed, so a PTY is never throttled and a child never blocks on output.
|
|
207
227
|
|
|
@@ -254,7 +274,7 @@ Tab status is an A1-owned state machine fed by `bridge.status`:
|
|
|
254
274
|
- placement: `order`, `cwd`
|
|
255
275
|
- session: `sessionFile`, `sessionDir`
|
|
256
276
|
- lifecycle: `desired` (`running|stopped`), `lifecycle`, `attentionSeq`, `seenSeq` (volatile status is rebuilt from the bridge and is never persisted)
|
|
257
|
-
- holder: `holderPid`, `holderStartIdentity`, `release`
|
|
277
|
+
- holder: `holderPid`, `holderStartIdentity`, `childPid`, `childStartIdentity`, `incarnation`, `release`
|
|
258
278
|
- restarts: `restarts`, `restartWindowStart`, `lastExit`
|
|
259
279
|
- `registryRevision`, `epoch`, and `bootId`
|
|
260
280
|
- **No per-tab credential is persisted in the registry.** The owner-only profile secret is stored separately and derives per-tab/per-incarnation credentials from recorded non-secret identities. The environment sent with `tab.create` is kept in holder memory only; a tab restarted after a crash reuses its holder's environment.
|
|
@@ -268,7 +288,7 @@ Tab status is an A1-owned state machine fed by `bridge.status`:
|
|
|
268
288
|
|---|---|---|
|
|
269
289
|
| Tab child exits or crashes | holder sees the child exit | If the exit was not requested: `crashed`. The holder respawns `ui.js --tab --session <file>` with backoff 1 s, 5 s, 30 s. After 3 restarts in 10 min: `failed`, with a banner `✗ <reason> — [r] retry · [f] start fresh · [alt+w] close`. An interrupted prompt (reported via the bridge, or detected as a trailing user entry) is offered back into the editor and never resent. Child stderr, if separately available, is a private content-bearing recovery artifact, never an ordinary diagnostic log. |
|
|
270
290
|
| Holder crash | pipe EOF plus verified process identity/exit | Pseudoterminal loss is not proof that every descendant exited. Verify the old writer/tree is gone and acquire its writer lease before resuming in a new holder; otherwise keep the tab blocked without duplicate writers. |
|
|
271
|
-
| Holder hang | holder control heartbeat every 5 s, 3 missed over a healthy supervision path | Terminate only the verified holder/tree within bounded deadlines, then follow the lease-gated recovery path. |
|
|
291
|
+
| Holder hang | holder control heartbeat every 5 s, 3 missed over a healthy supervision path, then one heartbeat of grace for the holder-local watchdog record | Terminate only the verified holder/tree within bounded deadlines, then follow the lease-gated recovery path. |
|
|
272
292
|
| A1 child hang | missing child event-loop heartbeat over a healthy bridge path | Warn at 30 s; restart at `tabsUnresponsiveRestartSeconds` (default 120), preserving journal/screen. A server/bridge transport outage alone is not proof of a child hang. |
|
|
273
293
|
| Server crash | clients and holders see the pipe EOF | Holders keep running. A client or holder starts a replacement, which acquires the released writer lease, increments the epoch, derives expected credentials, and re-admits identity-verified holders. A live but unresponsive recorded owner is terminated only after native identity verification; an unverifiable owner blocks replacement. After 3 starts in 60 s, clients show `✗ tab host stopped — [r] restart · [q] quit`. |
|
|
274
294
|
| Attach client crash or terminal close | the server sees the pipe EOF | Nothing happens to tabs. Pending requests stay `needs-input`. |
|
|
@@ -414,7 +434,7 @@ The v2 daemon was unreliable for structural reasons, and a forensic pass over it
|
|
|
414
434
|
|
|
415
435
|
**Agents that stop making progress.** Liveness and progress are separate signals:
|
|
416
436
|
|
|
417
|
-
- Holder heartbeat: a Rust main-loop tick every 5 s seen by the server; three missed ticks over an otherwise healthy supervision path trigger verified holder recovery.
|
|
437
|
+
- Holder heartbeat: a Rust main-loop tick every 5 s seen by the server; three missed ticks over an otherwise healthy supervision path plus one heartbeat of grace trigger verified holder recovery. The grace keeps external termination behind the holder's 15-second process-local watchdog so its own crash evidence wins despite scheduler jitter.
|
|
418
438
|
- A1 heartbeat: the child's Node event loop, seen through the bridge. After 30 s it shows `unresponsive`; after `tabsUnresponsiveRestartSeconds` (default 120) the tab restarts from its session with its journal and last screen preserved. A missing server or bridge transport degrades status, not proof of a child event-loop stall; reacquire liveness evidence before destructive recovery.
|
|
419
439
|
- Agent progress: model or tool events. After `tabsStallNoticeSeconds` (default 300) it shows `stalled` with interrupt and restart actions. It is never auto-killed, because a legitimate tool can run for a long time.
|
|
420
440
|
|
|
@@ -9,17 +9,17 @@ Version-1 and version-2 deliveries and their existing comments, acceptance PRs,
|
|
|
9
9
|
## Version-3 lifecycle
|
|
10
10
|
|
|
11
11
|
1. **Draft plan:** create one normally named branch/PR such as `feature/...`, `fix/...`, or `chore/...`. Start the body with `## Proposal`, use it for one or two sentences of intent, and follow it with two to ten unchecked, outcome-sized task items under `## Implementation`. Omit generic process tasks, quoted phase lines, and routine validation command lists, and keep machine linkage under final collapsed `Automation`. Keep it draft and include only planning artifacts until the maintainer approves the plan and explicitly requests implementation.
|
|
12
|
-
2. **Same-PR implementation:** continue after explicit approval in the same worktree, branch, history, draft PR, and phase-free body. Check an Implementation item
|
|
13
|
-
3. **Complete evidence:** finish implementation, required tests/evidence, substantive tasks, and explicit known-gap disposition
|
|
14
|
-
4. **Plain acceptance list:** keep the body phase-free and add final `## Acceptance` with one to ten concise implementation-specific behavior-and-result bullets. Do not use checkboxes, generic review/CI/approval/archive statements, URLs, mentions, or automated-test inventory.
|
|
15
|
-
5. **
|
|
12
|
+
2. **Same-PR implementation:** continue after explicit approval in the same worktree, branch, history, draft PR, and phase-free body. Check an Implementation item as soon as its associated implementation, focused pre-ready evidence, and detailed task bookkeeping are complete; an ordinary progress edit changes only `[ ]` to `[x]` and is not deferred until handoff. Adding, removing, reordering, or rewriting an item is a scope refinement requiring explicit approval and coherent planning updates, with affected scope left unchecked. Reconcile approved refinements before corresponding code edits.
|
|
13
|
+
3. **Complete evidence:** finish implementation, required pre-ready tests/evidence, substantive tasks, and explicit known-gap disposition. CI success is later objective evidence, not acceptance, and GitHub check counts are not Implementation task progress.
|
|
14
|
+
4. **Plain acceptance list:** before checking the final item, keep the body phase-free and add final `## Acceptance` with one to ten concise implementation-specific behavior-and-result bullets. Do not use checkboxes, generic review/CI/approval/archive statements, URLs, mentions, or automated-test inventory.
|
|
15
|
+
5. **Automatic readiness and finalization:** reconcile and push current `origin/develop`, then check the final item. That checkbox update completes the agent-owned implementation job; agents never mark implementation PRs ready themselves. Trusted automation revalidates the exact fully complete version-3 task-list snapshot and all pre-finalization inputs, marks the PR ready, and then conservatively synchronizes all deltas, moves the active change into its dated archive, stages the conditional acceptance manifest, commits that to the same branch with the archive App identity, and writes the emitted paths into the body's implementation fence. It never checks tasks or infers completion. Running the [finalization command](#finalization-command) locally first is optional and yields the same bytes.
|
|
16
16
|
6. **Validate:** one normal exact-head workflow validates the finalized head: implementation, synchronized specs, archive, manifest, tasks/evidence, exact PR-body list, and every selected product/governance scope before emitting the stable protected aggregate. A new commit or acceptance-list change re-finalizes automatically when needed and requires full renewed validation; no lifecycle body edit or second workflow run is required.
|
|
17
17
|
7. **Maintainer integration accepts:** after reviewing the finalized candidate, an authorized human either manually merges the exact validated head after the stable protected aggregate succeeds or personally enables GitHub native auto-merge for that unchanged head so protected integration waits for the aggregate. That human action means the listed scenarios are accepted. Agents, Apps, bots, merge queue, automation-owned implementation arms, and documentation integration remain forbidden. A changed head, acceptance list, or finalization invalidates the earlier arm and requires the maintainer to choose again.
|
|
18
18
|
8. **Verify and clean:** trusted post-merge policy derives `Archived` and reports `accepted-and-archived` from committed bytes and immutable GitHub provenance without editing the accepted PR body. It publishes no lifecycle branch or PR. Shared exact-head remote cleanup may delete the unchanged topic ref; local cleanup remains separately ownership-controlled: the agent parks the worktree with `handoff` at step 7, and the next session's `sweep` removes it once the merge, archive, and remote-ref evidence verify (see [local cleanup](local-worktree-cleanup.md)).
|
|
19
19
|
|
|
20
20
|
### Complete-regression evidence ordering
|
|
21
21
|
|
|
22
|
-
PR-attached Full regression is selected only for a repair that the trusted triage created from a failed Full regression: base policy verifies the immutable `openspec-ci` App author, generated candidate identity, and `regression-provenance.json`. Human-authored lookalikes, publishing or validation-authority changes, labels, Publish-only repairs, and successful-run persistent-overrun candidates retain bounded ordinary validation. Generated repair drafts run no Development test suites, including after implementation begins. Finish substantive implementation tasks, focused local evidence, pre-finalization observations, and known-gap disposition before
|
|
22
|
+
PR-attached Full regression is selected only for a repair that the trusted triage created from a failed Full regression: base policy verifies the immutable `openspec-ci` App author, generated candidate identity, and `regression-provenance.json`. Human-authored lookalikes, publishing or validation-authority changes, labels, Publish-only repairs, and successful-run persistent-overrun candidates retain bounded ordinary validation. Generated repair drafts run no Development test suites, including after implementation begins. Finish substantive implementation tasks, focused local evidence, pre-finalization observations, and known-gap disposition before checking the final Implementation item. The ready active head defers testing while trusted finalization publishes the candidate; the finalized head then receives all four native lanes as new full evidence, required by `Development validation required` alongside the existing gates.
|
|
23
23
|
|
|
24
24
|
The final exact-head run is a handoff gate, not a task requiring a future run ID in committed `design.md`. Keep final head/run/selection identity in Actions outcomes and the maintainer handoff; do not invalidate successful evidence with an extra recording commit. Changed code, acceptance/body metadata, selection labels, or target baseline requires fresh evidence. A selected PR success removes the additional mandatory Full regression dispatch, but a standalone/manual run never substitutes for selected PR checks. Before deployment, existing separate-dispatch obligations remain. Neither PR validation nor manual regression proves numbered-package nightly publication recovery.
|
|
25
25
|
|
|
@@ -147,7 +147,7 @@ If the body list changes, candidate validation reruns and compares it with the c
|
|
|
147
147
|
|
|
148
148
|
## Automated finalization
|
|
149
149
|
|
|
150
|
-
The `OpenSpec finalization` workflow (`.github/workflows/openspec-finalization.yml`) runs on `pull_request_target` for `synchronize`, `ready_for_review`, `reopened`, and `edited` events
|
|
150
|
+
The `OpenSpec finalization` workflow (`.github/workflows/openspec-finalization.yml`) runs on `pull_request_target` for `opened`, `synchronize`, `ready_for_review`, `reopened`, and `edited` events targeting `develop`, one event at a time per PR. It checks out default-branch policy, installs the pinned tooling without hooks, and runs `scripts/governance/publish-openspec-finalization.mjs --pr <n>`; the PR head enters that process only as the `openspec/` tree the pinned OpenSpec engine reads. An all-checked version-3 task-list draft with valid Acceptance and complete detailed pre-finalization inputs is re-read as one exact snapshot and marked ready; no content is changed, and incomplete, malformed, legacy, unassociated, forked, or raced drafts remain draft with a stable reason. Closed PRs are skipped. For a ready version-3 candidate the workflow reconciles the head to its finalized form:
|
|
151
151
|
|
|
152
152
|
- **Active and current:** ordinary finalization with today's UTC date; one `docs(openspec): finalize <change>` commit.
|
|
153
153
|
- **Finalized, valid, and current:** nothing is pushed; the run reports `already-finalized`.
|
|
@@ -164,7 +164,7 @@ If an unassociated implementation has already integrated, do not edit its merged
|
|
|
164
164
|
|
|
165
165
|
## Finalization command
|
|
166
166
|
|
|
167
|
-
The local command remains available for inspection or when a developer prefers to finalize before
|
|
167
|
+
The local command remains available for inspection or when a developer prefers to finalize before the automatic ready transition; the workflow then verifies the head and pushes nothing. It has inspection mode by default and an explicit `--write` mode. It never commits, pushes, edits GitHub, marks a PR ready, or merges. Run from the linked worktree and use an ignored artifact body file so the operation can update exact version-3 paths without mutating remote PR state:
|
|
168
168
|
|
|
169
169
|
```bash
|
|
170
170
|
git fetch origin develop
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timurproko/a1",
|
|
3
|
-
"version": "0.2.7-dev.
|
|
3
|
+
"version": "0.2.7-dev.767",
|
|
4
4
|
"description": "Standalone terminal workspace for supervised native and managed agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"privateLaunchContract": "neutral-launch-v1",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"build": "node scripts/development/check-environment.mjs && npm run clean && tsc -p tsconfig.build.json && node scripts/release/generate-release-notes-resource.mjs && node scripts/pi/build-pi-settings-metadata.mjs && node scripts/pi/build-startup-public.mjs && node scripts/development/build-process-guardian.mjs && node scripts/release/generate-runtime-payload-inventory.mjs",
|
|
27
27
|
"build:process-guardian": "node scripts/development/build-process-guardian.mjs",
|
|
28
28
|
"typecheck": "tsgo -p tsconfig.json --noEmit && tsgo -p tsconfig.bin.json",
|
|
29
|
-
"check:architecture": "node scripts/governance/check-architecture.mjs && node scripts/governance/check-product-identity-boundaries.mjs && node scripts/governance/check-package-identity.mjs && node scripts/governance/check-pinned-pi-source-ledger.mjs && node scripts/governance/check-terminal-host-provenance.mjs",
|
|
29
|
+
"check:architecture": "node scripts/governance/check-architecture.mjs && node scripts/governance/check-session-writer-guard.mjs && node scripts/governance/check-product-identity-boundaries.mjs && node scripts/governance/check-package-identity.mjs && node scripts/governance/check-pinned-pi-source-ledger.mjs && node scripts/governance/check-terminal-host-provenance.mjs",
|
|
30
30
|
"check:names": "node scripts/governance/product-identifier-policy.mjs --check",
|
|
31
31
|
"check:names:changed": "node scripts/governance/product-identifier-policy.mjs --check --selection .artifacts/validation/impact.json",
|
|
32
32
|
"check:code-documentation": "node scripts/governance/check-code-documentation.mjs --mode full",
|
|
@@ -65,12 +65,13 @@
|
|
|
65
65
|
"typecheck:bin": "tsgo -p tsconfig.bin.json"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@earendil-works/pi-coding-agent": "1.
|
|
69
|
-
"@earendil-works/pi-tui": "1.
|
|
68
|
+
"@earendil-works/pi-coding-agent": "1.2.0",
|
|
69
|
+
"@earendil-works/pi-tui": "1.2.0",
|
|
70
70
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
71
71
|
"chalk": "5.6.2",
|
|
72
72
|
"cross-spawn": "7.0.6",
|
|
73
73
|
"grok-mermaid": "0.2.2",
|
|
74
|
+
"proper-lockfile": "4.1.2",
|
|
74
75
|
"semver": "7.8.5",
|
|
75
76
|
"undici": "8.9.0"
|
|
76
77
|
},
|
|
@@ -79,6 +80,7 @@
|
|
|
79
80
|
"@lezer/python": "1.1.19",
|
|
80
81
|
"@types/cross-spawn": "6.0.6",
|
|
81
82
|
"@types/node": "24.2.1",
|
|
83
|
+
"@types/proper-lockfile": "4.1.4",
|
|
82
84
|
"@types/semver": "7.8.0",
|
|
83
85
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
84
86
|
"@xterm/headless": "6.0.0",
|