174 lines
8.9 KiB
Markdown
174 lines
8.9 KiB
Markdown
---
|
|
phase: 02-lifecycle-command-safety
|
|
plan: 02
|
|
type: execute
|
|
wave: 2
|
|
depends_on: [02-01]
|
|
files_modified:
|
|
- tauri-app/src/features/runtime/types.ts
|
|
- tauri-app/src/features/runtime/api.ts
|
|
- tauri-app/src/features/runtime/runtime-utils.ts
|
|
- tauri-app/src/features/runtime/useRuntimeManager.ts
|
|
- tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx
|
|
autonomous: true
|
|
requirements: [CTRL-01, CTRL-02, CTRL-03]
|
|
must_haves:
|
|
truths:
|
|
- The runtime manager knows which lifecycle command is active and can expose action-specific feedback instead of one generic busy state.
|
|
- The runtime feature classifies draft changes as immediate, restart-required, or save-before-apply so the UI can explain what happens next.
|
|
- Frontend command guards stay aligned with the backend lifecycle contract from plan 02-01.
|
|
artifacts:
|
|
- path: tauri-app/src/features/runtime/useRuntimeManager.ts
|
|
provides: lifecycle command state, completion feedback, and apply-impact orchestration on top of the Phase 1 draft model
|
|
- path: tauri-app/src/features/runtime/runtime-utils.ts
|
|
provides: reusable lifecycle labels, action guards, and apply-semantics helpers for runtime surfaces
|
|
- path: tauri-app/src/features/runtime/types.ts
|
|
provides: frontend types for active lifecycle commands, command results, and apply-impact values
|
|
- path: tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx
|
|
provides: integrated regression coverage for lifecycle semantics at the React feature layer
|
|
key_links:
|
|
- from: tauri-app/src/features/runtime/api.ts
|
|
to: tauri-app/src/features/runtime/types.ts
|
|
via: typed runtime snapshot fields mirrored from the Tauri backend
|
|
pattern: RuntimeSnapshot|last_error|status
|
|
- from: tauri-app/src/features/runtime/useRuntimeManager.ts
|
|
to: tauri-app/src/features/runtime/runtime-utils.ts
|
|
via: apply-impact classification and lifecycle command label helpers
|
|
pattern: start|stop|restart|required
|
|
---
|
|
|
|
<objective>
|
|
Teach the frontend runtime state layer how to represent lifecycle operations and apply semantics before any surface copy or button behavior changes.
|
|
|
|
Purpose: keep lifecycle trust rules in one manager-owned place, just as Phase 1 centralized draft ownership.
|
|
Output: typed frontend lifecycle state, reusable apply-impact helpers, and test coverage proving the manager exposes the right action-specific states.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@$HOME/.config/opencode/get-shit-done/workflows/execute-plan.md
|
|
@$HOME/.config/opencode/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/REQUIREMENTS.md
|
|
@.planning/phases/02-lifecycle-command-safety/02-RESEARCH.md
|
|
@.planning/phases/02-lifecycle-command-safety/02-01-SUMMARY.md
|
|
@tauri-app/src/features/runtime/types.ts
|
|
@tauri-app/src/features/runtime/api.ts
|
|
@tauri-app/src/features/runtime/runtime-utils.ts
|
|
@tauri-app/src/features/runtime/useRuntimeManager.ts
|
|
@tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx
|
|
|
|
<interfaces>
|
|
From `tauri-app/src/features/runtime/useRuntimeManager.ts`:
|
|
|
|
```ts
|
|
export function useRuntimeManager() {
|
|
return {
|
|
snapshot,
|
|
liveSnapshot,
|
|
savedBaseline,
|
|
draftConfig,
|
|
draftDirty,
|
|
draftOpen,
|
|
draftFields,
|
|
busy,
|
|
refresh,
|
|
saveDraft,
|
|
saveConfig,
|
|
startLocal,
|
|
stopLocal,
|
|
};
|
|
}
|
|
```
|
|
|
|
From `tauri-app/src/features/runtime/types.ts`:
|
|
|
|
```ts
|
|
export interface RuntimeSnapshot {
|
|
status: RuntimeStatus;
|
|
ready: boolean;
|
|
process_running: boolean;
|
|
resolved_url: string;
|
|
binary_path: string | null;
|
|
last_error: RuntimeErrorInfo | null;
|
|
config: RuntimeConfig;
|
|
}
|
|
```
|
|
</interfaces>
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>Task 1: Mirror backend lifecycle metadata and define frontend apply-impact contracts</name>
|
|
<files>tauri-app/src/features/runtime/types.ts, tauri-app/src/features/runtime/api.ts, tauri-app/src/features/runtime/runtime-utils.ts</files>
|
|
<read_first>
|
|
- tauri-app/src/features/runtime/types.ts
|
|
- tauri-app/src/features/runtime/api.ts
|
|
- tauri-app/src/features/runtime/runtime-utils.ts
|
|
- tauri-app/src-tauri/src/runtime/types.rs
|
|
- .planning/phases/02-lifecycle-command-safety/02-RESEARCH.md
|
|
</read_first>
|
|
<behavior>
|
|
- Test 1: the frontend `RuntimeSnapshot` includes the backend lifecycle command fields added in plan 02-01.
|
|
- Test 2: a helper can classify a draft as `immediate`, `restart_required`, or `save_before_apply` from `savedBaseline`, `draftConfig`, and `snapshot.process_running`.
|
|
</behavior>
|
|
<action>Update `tauri-app/src/features/runtime/types.ts` to mirror the new backend lifecycle snapshot fields using concrete frontend unions for active command values `idle | save | start | stop | save_and_start`, command outcomes `succeeded | blocked | failed`, and apply-impact values `immediate | restart_required | save_before_apply`. Update `tauri-app/src/features/runtime/api.ts` to preserve these fields in the local fallback snapshot shape instead of dropping them. Add reusable helpers in `tauri-app/src/features/runtime/runtime-utils.ts` that classify draft impact using the backend restart-impact field list (`connection_mode`, `model_path`, `addr`, `gpu_layers`, `ctx_size`) and current runtime state.</action>
|
|
<acceptance_criteria>
|
|
- `tauri-app/src/features/runtime/types.ts` exports frontend lifecycle command and apply-impact types.
|
|
- `tauri-app/src/features/runtime/api.ts` fallback snapshots include the new lifecycle metadata fields.
|
|
- `tauri-app/src/features/runtime/runtime-utils.ts` contains logic that references `connection_mode`, `model_path`, `addr`, `gpu_layers`, and `ctx_size` when determining restart-required impact.
|
|
</acceptance_criteria>
|
|
<verify>
|
|
<automated>npm test -- RuntimeSurface</automated>
|
|
</verify>
|
|
<done>The frontend type layer can represent both backend lifecycle results and user-facing apply semantics without ad hoc string handling.</done>
|
|
</task>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>Task 2: Replace generic busy handling with action-specific manager state</name>
|
|
<files>tauri-app/src/features/runtime/useRuntimeManager.ts, tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx</files>
|
|
<read_first>
|
|
- tauri-app/src/features/runtime/useRuntimeManager.ts
|
|
- tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx
|
|
- tauri-app/src/features/runtime/runtime-utils.ts
|
|
- tauri-app/src/features/runtime/types.ts
|
|
- .planning/phases/02-lifecycle-command-safety/02-01-SUMMARY.md
|
|
</read_first>
|
|
<behavior>
|
|
- Test 1: starting the runtime exposes an active command of `start` and resolves to a completion result with a stable success message.
|
|
- Test 2: stopping the runtime exposes an active command of `stop` and blocks duplicate lifecycle actions while the command is active.
|
|
- Test 3: when draft changes hit restart-impact fields while the process is running, the manager exposes `restart_required` instead of pretending the save is immediately applied.
|
|
</behavior>
|
|
<action>Refactor `tauri-app/src/features/runtime/useRuntimeManager.ts` so it exposes explicit manager-owned fields for `activeLifecycleCommand`, `lastLifecycleResult`, `lifecycleBusy`, and `applyImpact` rather than relying only on `busy`. Map `saveDraft`, `saveConfig`, `startLocal`, and `stopLocal` to concrete command names `save`, `save_and_start`, `start`, and `stop`. Preserve Phase 1 draft safety: polling must still avoid overwriting dirty draft values. When a command resolves, store a result message based on the backend snapshot metadata or fallback defaults such as `Local API started.`, `Local API stopped.`, `Save completed.`, or the backend-provided blocked/failed message. Update `RuntimeSurface.test.tsx` so the feature harness asserts action-specific state instead of only the generic `busy` boolean.</action>
|
|
<acceptance_criteria>
|
|
- `tauri-app/src/features/runtime/useRuntimeManager.ts` exports `activeLifecycleCommand`, `lastLifecycleResult`, or equivalent explicit action-specific fields.
|
|
- The manager still preserves dirty draft values across polling while lifecycle state changes.
|
|
- `tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx` contains lifecycle assertions for start, stop, blocked duplicates, and restart-required saves.
|
|
</acceptance_criteria>
|
|
<verify>
|
|
<automated>npm test -- RuntimeSurface</automated>
|
|
</verify>
|
|
<done>The runtime manager becomes the single source of truth for lifecycle command progress, completion, and apply semantics.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- `npm test -- RuntimeSurface`
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Frontend state exposes action-specific lifecycle progress and completion information.
|
|
- Apply-impact classification matches backend restart-required rules.
|
|
- Duplicate/conflicting lifecycle actions are blocked at the manager layer before the UI triggers them.
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/02-lifecycle-command-safety/02-02-SUMMARY.md`
|
|
</output>
|