implements PLN-0062 native shell lifecycle wiring
This commit is contained in:
parent
f62be06dc5
commit
edfac5a99b
@ -171,6 +171,7 @@ impl Firmware {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::firmware::firmware_state::HubHomeStep;
|
||||||
use prometeu_bytecode::assembler::assemble;
|
use prometeu_bytecode::assembler::assemble;
|
||||||
use prometeu_bytecode::model::{BytecodeModule, FunctionMeta, SyscallDecl};
|
use prometeu_bytecode::model::{BytecodeModule, FunctionMeta, SyscallDecl};
|
||||||
use prometeu_drivers::hardware::Hardware;
|
use prometeu_drivers::hardware::Hardware;
|
||||||
@ -281,6 +282,14 @@ mod tests {
|
|||||||
(firmware, hardware, signals, task_id)
|
(firmware, hardware, signals, task_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hub_home_firmware() -> (Firmware, Hardware) {
|
||||||
|
let mut firmware = Firmware::new(None);
|
||||||
|
firmware.state = FirmwareState::HubHome(HubHomeStep);
|
||||||
|
firmware.state_initialized = false;
|
||||||
|
|
||||||
|
(firmware, Hardware::new())
|
||||||
|
}
|
||||||
|
|
||||||
fn focus_window(firmware: &mut Firmware, owner: WindowOwner) {
|
fn focus_window(firmware: &mut Firmware, owner: WindowOwner) {
|
||||||
let mut windows = firmware.os.windows();
|
let mut windows = firmware.os.windows();
|
||||||
windows.remove_all_windows();
|
windows.remove_all_windows();
|
||||||
@ -406,6 +415,65 @@ mod tests {
|
|||||||
assert_eq!(firmware.os.vm().tick_index(), tick_index_before_system_update + 1);
|
assert_eq!(firmware.os.vm().tick_index(), tick_index_before_system_update + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hub_home_launches_shell_a_as_native_shell_task_window() {
|
||||||
|
let (mut firmware, mut hardware) = hub_home_firmware();
|
||||||
|
let signals = InputSignals { a_signal: true, ..Default::default() };
|
||||||
|
|
||||||
|
firmware.tick(&signals, &mut hardware);
|
||||||
|
|
||||||
|
let task_id = match &firmware.state {
|
||||||
|
FirmwareState::ShellRunning(step) => step.task_id,
|
||||||
|
other => panic!("expected ShellRunning state, got {:?}", other),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(firmware.os.windows().focused_window_belongs_to_task(task_id));
|
||||||
|
assert_eq!(firmware.os.windows().window_count(), 1);
|
||||||
|
assert_eq!(firmware.os.windows().windows()[0].title, "ShellA");
|
||||||
|
assert_eq!(firmware.os.lifecycle().task_state(task_id), Some(TaskState::Foreground));
|
||||||
|
assert_eq!(
|
||||||
|
firmware.os.lifecycle().process_state_for_task(task_id),
|
||||||
|
Ok(ProcessState::Running)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hub_home_launches_shell_b_as_native_shell_task_window() {
|
||||||
|
let (mut firmware, mut hardware) = hub_home_firmware();
|
||||||
|
let signals = InputSignals { b_signal: true, ..Default::default() };
|
||||||
|
|
||||||
|
firmware.tick(&signals, &mut hardware);
|
||||||
|
|
||||||
|
let task_id = match &firmware.state {
|
||||||
|
FirmwareState::ShellRunning(step) => step.task_id,
|
||||||
|
other => panic!("expected ShellRunning state, got {:?}", other),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(firmware.os.windows().focused_window_belongs_to_task(task_id));
|
||||||
|
assert_eq!(firmware.os.windows().window_count(), 1);
|
||||||
|
assert_eq!(firmware.os.windows().windows()[0].title, "ShellB");
|
||||||
|
assert_eq!(firmware.os.lifecycle().task_state(task_id), Some(TaskState::Foreground));
|
||||||
|
assert_eq!(
|
||||||
|
firmware.os.lifecycle().process_state_for_task(task_id),
|
||||||
|
Ok(ProcessState::Running)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shell_running_start_close_uses_lifecycle_and_returns_hub_home() {
|
||||||
|
let (mut firmware, mut hardware, _signals, task_id) = load_shell_running_firmware();
|
||||||
|
let close_signals = InputSignals { start_signal: true, ..Default::default() };
|
||||||
|
|
||||||
|
firmware.tick(&close_signals, &mut hardware);
|
||||||
|
|
||||||
|
assert!(matches!(firmware.state, FirmwareState::HubHome(_)));
|
||||||
|
assert_eq!(firmware.os.lifecycle().task_state(task_id), Some(TaskState::Closed));
|
||||||
|
assert_eq!(
|
||||||
|
firmware.os.lifecycle().process_state_for_task(task_id),
|
||||||
|
Ok(ProcessState::Stopped)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn shell_running_closes_task_and_returns_hub_home_without_focused_window() {
|
fn shell_running_closes_task_and_returns_hub_home_without_focused_window() {
|
||||||
let (mut firmware, mut hardware, signals, task_id) = load_shell_running_firmware();
|
let (mut firmware, mut hardware, signals, task_id) = load_shell_running_firmware();
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
use crate::firmware::firmware_state::{AppCrashesStep, FirmwareState};
|
use crate::firmware::firmware_state::{AppCrashesStep, FirmwareState, ShellRunningStep};
|
||||||
use crate::firmware::prometeu_context::PrometeuContext;
|
use crate::firmware::prometeu_context::PrometeuContext;
|
||||||
use prometeu_hal::log::{LogLevel, LogSource};
|
use prometeu_hal::log::{LogLevel, LogSource};
|
||||||
|
use prometeu_hal::primitives::Rect;
|
||||||
|
use prometeu_system::SystemProfileAction;
|
||||||
|
use prometeu_system::windows::WindowOwner;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct HubHomeStep;
|
pub struct HubHomeStep;
|
||||||
@ -16,6 +19,18 @@ impl HubHomeStep {
|
|||||||
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(SystemProfileAction::LaunchNativeShell(app)) = outcome.action {
|
||||||
|
let task_id = ctx.os.sessions().create_native_shell_task(app.app_id(), app.title());
|
||||||
|
let id = ctx.os.windows().add_window(
|
||||||
|
app.title().to_string(),
|
||||||
|
WindowOwner::Task(task_id),
|
||||||
|
Rect { x: 40, y: 20, w: 400, h: 220 },
|
||||||
|
app.color(),
|
||||||
|
);
|
||||||
|
ctx.os.windows().set_focus(id);
|
||||||
|
return Some(FirmwareState::ShellRunning(ShellRunningStep::new(task_id)));
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use crate::firmware::firmware_state::{AppCrashesStep, FirmwareState, HubHomeStep};
|
use crate::firmware::firmware_state::{AppCrashesStep, FirmwareState, HubHomeStep};
|
||||||
use crate::firmware::prometeu_context::PrometeuContext;
|
use crate::firmware::prometeu_context::PrometeuContext;
|
||||||
use prometeu_hal::log::LogSource;
|
use prometeu_hal::log::LogSource;
|
||||||
use prometeu_system::CrashReport;
|
|
||||||
use prometeu_system::task::{TaskId, TaskState};
|
use prometeu_system::task::{TaskId, TaskState};
|
||||||
|
use prometeu_system::{CrashReport, SystemProfileAction};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ShellRunningStep {
|
pub struct ShellRunningStep {
|
||||||
@ -66,6 +66,16 @@ impl ShellRunningStep {
|
|||||||
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if outcome.action == Some(SystemProfileAction::CloseShell) {
|
||||||
|
if let Err(error) = ctx.os.lifecycle().close_task(self.task_id) {
|
||||||
|
ctx.os.error(
|
||||||
|
LogSource::Hub,
|
||||||
|
format!("Failed to close shell task {:?}: {:?}", self.task_id, error),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Some(FirmwareState::HubHome(HubHomeStep));
|
||||||
|
}
|
||||||
|
|
||||||
if !ctx.os.windows().focused_window_belongs_to_task(self.task_id) {
|
if !ctx.os.windows().focused_window_belongs_to_task(self.task_id) {
|
||||||
ctx.os.info(
|
ctx.os.info(
|
||||||
LogSource::Hub,
|
LogSource::Hub,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ mod services;
|
|||||||
|
|
||||||
pub use crash_report::CrashReport;
|
pub use crash_report::CrashReport;
|
||||||
pub use os::{LifecycleError, LifecycleOperation, SystemOS};
|
pub use os::{LifecycleError, LifecycleOperation, SystemOS};
|
||||||
pub use programs::PrometeuHub;
|
pub use programs::{NativeShellApp, PrometeuHub, SystemProfileAction, SystemProfileUpdate};
|
||||||
pub use services::fs;
|
pub use services::fs;
|
||||||
pub use services::process;
|
pub use services::process;
|
||||||
pub use services::task;
|
pub use services::task;
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
mod prometeu_hub;
|
mod prometeu_hub;
|
||||||
|
|
||||||
pub use prometeu_hub::PrometeuHub;
|
pub use prometeu_hub::{NativeShellApp, PrometeuHub, SystemProfileAction, SystemProfileUpdate};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#[allow(clippy::module_inception)]
|
#[allow(clippy::module_inception)]
|
||||||
mod prometeu_hub;
|
mod prometeu_hub;
|
||||||
|
|
||||||
pub use prometeu_hub::PrometeuHub;
|
pub use prometeu_hub::{NativeShellApp, PrometeuHub, SystemProfileAction, SystemProfileUpdate};
|
||||||
|
|||||||
@ -1,16 +1,49 @@
|
|||||||
use crate::windows::WindowOwner;
|
|
||||||
use crate::{CrashReport, SystemOS};
|
use crate::{CrashReport, SystemOS};
|
||||||
use prometeu_hal::color::Color;
|
use prometeu_hal::color::Color;
|
||||||
use prometeu_hal::log::{LogLevel, LogSource};
|
|
||||||
use prometeu_hal::primitives::Rect;
|
|
||||||
use prometeu_hal::{HardwareBridge, InputSignals};
|
use prometeu_hal::{HardwareBridge, InputSignals};
|
||||||
use prometeu_vm::VirtualMachine;
|
use prometeu_vm::VirtualMachine;
|
||||||
|
|
||||||
/// PrometeuHub: Launcher and system UI environment.
|
/// PrometeuHub: Launcher and system UI environment.
|
||||||
pub struct PrometeuHub;
|
pub struct PrometeuHub;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum NativeShellApp {
|
||||||
|
ShellA,
|
||||||
|
ShellB,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NativeShellApp {
|
||||||
|
pub fn app_id(self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::ShellA => 10_001,
|
||||||
|
Self::ShellB => 10_002,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn title(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::ShellA => "ShellA",
|
||||||
|
Self::ShellB => "ShellB",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn color(self) -> Color {
|
||||||
|
match self {
|
||||||
|
Self::ShellA => Color::GREEN,
|
||||||
|
Self::ShellB => Color::BLUE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum SystemProfileAction {
|
||||||
|
LaunchNativeShell(NativeShellApp),
|
||||||
|
CloseShell,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SystemProfileUpdate {
|
pub struct SystemProfileUpdate {
|
||||||
pub crash: Option<CrashReport>,
|
pub crash: Option<CrashReport>,
|
||||||
|
pub action: Option<SystemProfileAction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PrometeuHub {
|
impl Default for PrometeuHub {
|
||||||
@ -28,43 +61,19 @@ impl PrometeuHub {
|
|||||||
// Initializes the Window System and lists apps
|
// Initializes the Window System and lists apps
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gui_update(&mut self, os: &mut SystemOS, hw: &mut dyn HardwareBridge) {
|
pub fn gui_update(
|
||||||
|
&mut self,
|
||||||
|
_os: &mut SystemOS,
|
||||||
|
hw: &mut dyn HardwareBridge,
|
||||||
|
) -> Option<SystemProfileAction> {
|
||||||
hw.gfx_mut().clear(Color::BLACK);
|
hw.gfx_mut().clear(Color::BLACK);
|
||||||
|
|
||||||
let mut next_window = None;
|
|
||||||
|
|
||||||
if hw.pad().a().pressed {
|
if hw.pad().a().pressed {
|
||||||
os.log(LogLevel::Debug, LogSource::Hub, 0, "window A opened".to_string());
|
Some(SystemProfileAction::LaunchNativeShell(NativeShellApp::ShellA))
|
||||||
next_window = Some((
|
|
||||||
"Green Window".to_string(),
|
|
||||||
Rect { x: 0, y: 0, w: 160, h: 90 },
|
|
||||||
Color::GREEN,
|
|
||||||
));
|
|
||||||
} else if hw.pad().b().pressed {
|
} else if hw.pad().b().pressed {
|
||||||
os.log(LogLevel::Debug, LogSource::Hub, 0, "window B opened".to_string());
|
Some(SystemProfileAction::LaunchNativeShell(NativeShellApp::ShellB))
|
||||||
next_window = Some((
|
} else {
|
||||||
"Indigo Window".to_string(),
|
None
|
||||||
Rect { x: 160, y: 0, w: 160, h: 90 },
|
|
||||||
Color::INDIGO,
|
|
||||||
));
|
|
||||||
} else if hw.pad().x().pressed {
|
|
||||||
os.log(LogLevel::Debug, LogSource::Hub, 0, "window X opened".to_string());
|
|
||||||
next_window = Some((
|
|
||||||
"Yellow Window".to_string(),
|
|
||||||
Rect { x: 0, y: 90, w: 160, h: 90 },
|
|
||||||
Color::YELLOW,
|
|
||||||
));
|
|
||||||
} else if hw.pad().y().pressed {
|
|
||||||
os.log(LogLevel::Debug, LogSource::Hub, 0, "window Y opened".to_string());
|
|
||||||
next_window =
|
|
||||||
Some(("Red Window".to_string(), Rect { x: 160, y: 90, w: 160, h: 90 }, Color::RED));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((title, rect, color)) = next_window {
|
|
||||||
let mut window = os.windows();
|
|
||||||
window.remove_all_windows();
|
|
||||||
let id = window.add_window(title, WindowOwner::Hub, rect, color);
|
|
||||||
window.set_focus(id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,12 +97,11 @@ impl PrometeuHub {
|
|||||||
hw: &mut dyn HardwareBridge,
|
hw: &mut dyn HardwareBridge,
|
||||||
) -> SystemProfileUpdate {
|
) -> SystemProfileUpdate {
|
||||||
let mut crash = None;
|
let mut crash = None;
|
||||||
|
let mut action = self.gui_update(os, hw);
|
||||||
|
|
||||||
self.gui_update(os, hw);
|
if os.windows().focused_window().is_some() {
|
||||||
|
|
||||||
if let Some(focused_id) = os.windows().focused_window() {
|
|
||||||
if hw.pad().start().down {
|
if hw.pad().start().down {
|
||||||
os.windows().close_window(focused_id);
|
action = Some(SystemProfileAction::CloseShell);
|
||||||
} else {
|
} else {
|
||||||
crash = os.vm().tick(vm, signals, hw);
|
crash = os.vm().tick(vm, signals, hw);
|
||||||
}
|
}
|
||||||
@ -102,6 +110,6 @@ impl PrometeuHub {
|
|||||||
self.render(os, hw);
|
self.render(os, hw);
|
||||||
hw.gfx_mut().present();
|
hw.gfx_mut().present();
|
||||||
|
|
||||||
SystemProfileUpdate { crash }
|
SystemProfileUpdate { crash, action }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,4 +34,4 @@
|
|||||||
{"type":"discussion","id":"DSC-0031","status":"done","ticket":"runtime-mode-separation-game-system","title":"Agenda - Runtime Mode Separation: Game and System","created_at":"2026-05-11","updated_at":"2026-05-14","tags":["runtime","firmware","hub","system-apps","game-mode","scheduler"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0040","file":"discussion/lessons/DSC-0031-runtime-mode-separation-game-system/LSN-0040-system-pipeline-separation.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14"}]}
|
{"type":"discussion","id":"DSC-0031","status":"done","ticket":"runtime-mode-separation-game-system","title":"Agenda - Runtime Mode Separation: Game and System","created_at":"2026-05-11","updated_at":"2026-05-14","tags":["runtime","firmware","hub","system-apps","game-mode","scheduler"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0040","file":"discussion/lessons/DSC-0031-runtime-mode-separation-game-system/LSN-0040-system-pipeline-separation.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14"}]}
|
||||||
{"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
|
{"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
|
||||||
{"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
|
{"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
|
||||||
{"type":"discussion","id":"DSC-0036","status":"in_progress","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[{"id":"AGD-0036","file":"AGD-0036-prometeu-hub-ui-direction.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15"}],"decisions":[{"id":"DEC-0028","file":"DEC-0028-prometeu-hub-initial-retro-shell-ui-slice.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15","ref_agenda":"AGD-0036"}],"plans":[{"id":"PLN-0062","file":"PLN-0062-native-shell-launch-and-lifecycle-wiring.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0063","file":"PLN-0063-hub-mouse-input-and-click-routing.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0064","file":"PLN-0064-retro-hub-home-and-fake-shell-ui.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0065","file":"PLN-0065-pixel-operator-font-integration.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0066","file":"PLN-0066-hub-ui-slice-validation-and-lesson.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]}],"lessons":[]}
|
{"type":"discussion","id":"DSC-0036","status":"in_progress","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[{"id":"AGD-0036","file":"AGD-0036-prometeu-hub-ui-direction.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15"}],"decisions":[{"id":"DEC-0028","file":"DEC-0028-prometeu-hub-initial-retro-shell-ui-slice.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15","ref_agenda":"AGD-0036"}],"plans":[{"id":"PLN-0062","file":"PLN-0062-native-shell-launch-and-lifecycle-wiring.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0063","file":"PLN-0063-hub-mouse-input-and-click-routing.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0064","file":"PLN-0064-retro-hub-home-and-fake-shell-ui.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0065","file":"PLN-0065-pixel-operator-font-integration.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0066","file":"PLN-0066-hub-ui-slice-validation-and-lesson.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]}],"lessons":[]}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
id: PLN-0062
|
id: PLN-0062
|
||||||
ticket: prometeu-hub-ui-direction
|
ticket: prometeu-hub-ui-direction
|
||||||
title: Native Shell Launch and Lifecycle Wiring
|
title: Native Shell Launch and Lifecycle Wiring
|
||||||
status: open
|
status: done
|
||||||
created: 2026-05-15
|
created: 2026-05-15
|
||||||
ref_decisions: [DEC-0028]
|
ref_decisions: [DEC-0028]
|
||||||
tags: [hub, ui, shell, system-apps, lifecycle, design-system]
|
tags: [hub, ui, shell, system-apps, lifecycle, design-system]
|
||||||
@ -82,13 +82,13 @@ Make the launch/close path architecturally correct before the visual slice depen
|
|||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
- [ ] Launching `ShellA` creates a native Shell task/process.
|
- [x] Launching `ShellA` creates a native Shell task/process.
|
||||||
- [ ] Launching `ShellB` creates a native Shell task/process.
|
- [x] Launching `ShellB` creates a native Shell task/process.
|
||||||
- [ ] Each launched Shell app receives a focused `WindowOwner::Task(task_id)` window.
|
- [x] Each launched Shell app receives a focused `WindowOwner::Task(task_id)` window.
|
||||||
- [ ] Closing the Shell app closes lifecycle state through `os.lifecycle().close_task(task_id)`.
|
- [x] Closing the Shell app closes lifecycle state through `os.lifecycle().close_task(task_id)`.
|
||||||
- [ ] Closing the Shell app returns firmware to `HubHome`.
|
- [x] Closing the Shell app returns firmware to `HubHome`.
|
||||||
- [ ] Hub visual code does not directly mutate task/process managers.
|
- [x] Hub visual code does not directly mutate task/process managers.
|
||||||
- [ ] Existing shell liveness behavior remains intact.
|
- [x] Existing shell liveness behavior remains intact.
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user