Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ data/
# Libretto runtime state. Keep config/skills if setup creates them.
.libretto/sessions/
.libretto/profiles/

# Local design prototypes and visual QA artifacts.
/design-qa.md
/prototypes/
/qa/
161 changes: 161 additions & 0 deletions docs/superpowers/plans/2026-07-18-automation-logging-variants.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Automation Logging Variants Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Simplify parallel sync launch and provide three directly comparable live-log presentations.

**Architecture:** Keep one React app and one parallel-run state. Select `drawer`, `inline`, or `console` from `?logging=`; each presentation renders the same deterministic log event list, so only layout changes between links.

**Tech Stack:** React 19, Vite 6, Phosphor Icons, native CSS, Node test runner, Sites hosting.

## Global Constraints

- Reuse the existing task data, timer, dialogs, sidebar, and three-stage workflow.
- Do not add routes, packages, backend calls, persistence, scheduling, queues, or retry logic.
- Keep Traditional Chinese product copy.
- Keep the existing `.openai/hosting.json` project and workspace-wide access.

---

### Task 1: Shared live-log events

**Files:**
- Modify: `prototypes/automation-guided-flow/src/task-state.test.mjs`
- Modify: `prototypes/automation-guided-flow/src/task-state.mjs`

**Interfaces:**
- Produces: `buildRunLogs(progress: number, elapsedSeconds: number): Array<{time: string, task: string, message: string, level: "info" | "success" | "error"}>`

- [ ] **Step 1: Write the failing test**

Add a test that imports `buildRunLogs`, checks that progress `4` returns only the dispatch event, and checks that progress `60` includes the failed 渣打 event with `level: "error"`.

```js
test("buildRunLogs reveals chronological task events as progress advances", () => {
assert.equal(buildRunLogs(4, 0).length, 1);
const logs = buildRunLogs(60, 18);
assert.equal(logs.at(-1).task, "渣打銀行對帳單");
assert.equal(logs.at(-1).level, "error");
});
```

- [ ] **Step 2: Verify the test fails for the missing export**

Run: `node --test src/task-state.test.mjs`

Expected: FAIL because `buildRunLogs` is not exported.

- [ ] **Step 3: Implement the smallest deterministic event builder**

Use one ordered event array with progress thresholds and return only reached events. Format time from `elapsedSeconds` without timers or I/O.

```js
export function buildRunLogs(progress, elapsedSeconds) {
const now = (offset) => `00:${String(Math.max(0, elapsedSeconds - offset)).padStart(2, "0")}`;
return [
[0, "系統", "已送出 14 個同步任務", "info", 0],
[10, "富邦全部對帳單", "已連線銀行網站", "info", 3],
[24, "玉山信用卡對帳單", "登入完成,開始下載", "info", 7],
[42, "富邦全部對帳單", "已下載 5 個檔案", "success", 12],
[58, "渣打銀行對帳單", "登入逾時,需要重新執行", "error", 18],
].filter(([threshold]) => progress >= threshold).map(([, task, message, level, offset]) => ({ time: now(offset), task, message, level }));
}
```

- [ ] **Step 4: Verify all state tests pass**

Run: `node --test src/task-state.test.mjs`

Expected: 5 tests pass.

### Task 2: Simplified launch and three presentations

**Files:**
- Modify: `prototypes/automation-guided-flow/src/App.jsx`
- Modify: `prototypes/automation-guided-flow/src/styles.css`

**Interfaces:**
- Consumes: `buildRunLogs(progress, elapsedSeconds)` from Task 1.
- Produces: direct variants at `?logging=drawer`, `?logging=inline`, and `?logging=console`.

- [ ] **Step 1: Simplify the idle hero and confirmation sheet**

Change the hero to one heading and one `同步全部` button. Remove summary counts and `調整任務`. Trim `PreflightSheet` to credential readiness, selected tasks, `取消`, and `開始同步`; delete warning and acknowledgement state/props.

```jsx
<section className="hero simple-hero">
<h1>{count} 個任務可以同步執行</h1>
<button className="button primary hero-primary" onClick={onStart}><Play size={18} weight="fill" />同步全部</button>
</section>
```

- [ ] **Step 2: Select the presentation from the query parameter**

Normalize once at module load and default invalid values to `drawer`.

```js
const requestedLoggingMode = new URLSearchParams(window.location.search).get("logging");
const loggingMode = ["drawer", "inline", "console"].includes(requestedLoggingMode) ? requestedLoggingMode : "drawer";
```

- [ ] **Step 3: Add one shared log renderer**

Render time, task, message, and error/success color from `buildRunLogs`. Keep the markup reusable in all three surfaces.

```jsx
function LogEntries({ logs }) {
return <ol className="log-entries">{logs.map((log) => <li className={log.level} key={`${log.time}-${log.task}`}><time>{log.time}</time><div><strong>{log.task}</strong><span>{log.message}</span></div></li>)}</ol>;
}
```

- [ ] **Step 4: Add drawer, inline, and console wrappers**

- Drawer: fixed right panel with aggregate progress, `LogEntries`, close, and stop-all.
- Inline: add a unique `日誌` button per included task row and expand the selected row directly beneath it.
- Console: fixed bottom panel with chronological `LogEntries`, collapse, and stop-all.

All three wrappers receive only `run`, `logs`, visibility callbacks, and `onStop`; they do not own run state.

- [ ] **Step 5: Connect launch and visibility**

On confirm, start the existing parallel run, close confirmation, then open the selected log surface. During a run, the hero contains `查看日誌` and `停止全部`; `查看日誌` reopens the relevant surface.

- [ ] **Step 6: Style only the new surfaces and delete obsolete rules**

Remove `.preflight-warning`, `.acknowledge`, and unused multi-check spacing. Add `.live-log-drawer`, `.inline-log`, `.log-console`, and shared `.log-entries` rules using existing colors and borders. Keep the drawer responsive and the console above the 64px sidebar breakpoint.

- [ ] **Step 7: Build and verify**

Run: `node --test src/task-state.test.mjs && npm run build && git diff --check`

Expected: tests pass, Vite emits `dist/server/index.js`, and diff check is clean.

### Task 3: Browser QA and existing Sites deployment

**Files:**
- Modify: `prototypes/automation-guided-flow/design-qa.md`
- Generated build output only: `prototypes/automation-guided-flow/dist/**`

**Interfaces:**
- Consumes the three query-parameter variants from Task 2.
- Produces an updated version at the existing Sites URL.

- [ ] **Step 1: Verify all three local variants**

For each query parameter, launch sync and confirm the expected logging surface appears. Check that removed copy and controls are absent, `同步全部` is present, and the browser console has no fresh errors.

- [ ] **Step 2: Verify responsive layout**

At the existing narrow browser viewport, confirm no document-level horizontal overflow and that the active logging surface can be closed and reopened.

- [ ] **Step 3: Update design QA**

Record the simplified launch flow, three tested variants, interaction checks, browser-console result, and `final result: passed` in `design-qa.md`.

- [ ] **Step 4: Publish the validated source**

Push the exact source state to the existing Sites source repository, package the current `dist`, save version 2 with the pushed commit SHA, deploy it, poll to `succeeded`, and retain `workspace_all` access.

- [ ] **Step 5: Return three direct links**

Return the same deployed base URL with `?logging=drawer`, `?logging=inline`, and `?logging=console` so the user can compare without a new route or selector UI.
53 changes: 53 additions & 0 deletions docs/superpowers/plans/2026-07-19-automation-active-task-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Automation Active Task Jump Prototype Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Build one isolated Automation prototype where active tasks in the running summary navigate to their inline logs.

**Architecture:** Create one self-contained HTML prototype with realistic mock data and native browser behavior. Keep all presentation and interaction local to the prototype; add one source-level Node check for the required interaction contract.

**Tech Stack:** HTML, CSS, browser JavaScript, Node.js assertions.

## Global Constraints

- Do not modify the production app.
- Remove the 「查看日誌」 action from the prototype.
- Task start and polling never cause automatic expansion or scrolling.
- Preserve other manually opened inline logs.
- Use no new dependencies.

---

### Task 1: Active-task summary and inline-log navigation

**Files:**
- Create: `prototypes/automation-active-task-jump/index.html`
- Create: `prototypes/automation-active-task-jump/active-task-jump.check.mjs`

**Interfaces:**
- Consumes: browser `scrollIntoView`, `focus`, `matchMedia`, and DOM events.
- Produces: `revealTaskLog(taskId)` in the prototype script.

- [ ] **Step 1: Write the failing source contract check**

Assert that the prototype contains active-task buttons, no 「查看日誌」 button, `revealTaskLog`, `scrollIntoView`, focus transfer, reduced-motion handling, and multiple independently open inline logs.

- [ ] **Step 2: Run the check to verify it fails**

Run: `node prototypes/automation-active-task-jump/active-task-jump.check.mjs`
Expected: FAIL because `index.html` does not exist.

- [ ] **Step 3: Implement the self-contained prototype**

Build the existing Automation shell, running summary task buttons, three workflow stages, and inline log panels. Selecting an active task opens its stage and log, scrolls to it, focuses its heading, and applies a temporary highlight.

- [ ] **Step 4: Run the source check**

Run: `node prototypes/automation-active-task-jump/active-task-jump.check.mjs`
Expected: PASS.

- [ ] **Step 5: Render and visually verify**

Render at 1600 × 1000. Confirm typography, layout, active-task scanability, target highlight, and narrow responsiveness. Start a local-only static server and provide the prototype URL.

**Repository note:** Keep the existing dirty worktree uncommitted and preserve unrelated user changes.
86 changes: 86 additions & 0 deletions docs/superpowers/plans/2026-07-19-automation-disclosure-motion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Automation Disclosure Motion Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Animate automation stage, inline-log, and show-all disclosures without changing their layout or state model.

**Architecture:** Reuse Svelte's installed `slide` transition through one local reduced-motion-aware wrapper in `AutomationDashboard.svelte`. Apply it to the three existing conditional surfaces and add a CSS transition to the existing caret.

**Tech Stack:** Svelte 5, TypeScript, native CSS, Node assertion checks, Electron CDP.

## Global Constraints

- No new dependency, route, data state, or visual redesign.
- Expansion and collapse duration is 220 ms; caret rotation is 180 ms.
- `prefers-reduced-motion: reduce` changes disclosure duration to 0 ms.
- Preserve table semantics, fixed column widths, labels, and controls.

---

### Task 1: Disclosure transitions

**Files:**
- Modify: `src/lib/automation/AutomationDashboard.check.ts`
- Modify: `src/lib/automation/AutomationDashboard.svelte`

**Interfaces:**
- Consumes: Svelte `slide(node, { duration })`.
- Produces: `disclosureSlide(node: Element)` transition used by stage bodies, inline logs, and task rows.

- [ ] **Step 1: Write the failing source regression checks**

Add assertions for the `slide` import, reduced-motion wrapper, three transition directives, and caret transition:

```ts
assert.match(source, /import \{ slide \} from "svelte\/transition"/);
assert.match(source, /function disclosureSlide\(node: Element\)/);
assert.match(source, /matchMedia\("\(prefers-reduced-motion: reduce\)"\)\.matches \? 0 : 220/);
assert.match(source, /class="stage-body"[^>]*transition:disclosureSlide/);
assert.match(source, /class="task-row"[^>]*transition:disclosureSlide/);
assert.match(source, /class="inline-log-panel"[^>]*transition:disclosureSlide/);
assert.match(source, /transition: transform 180ms ease/);
```

- [ ] **Step 2: Run the focused check and confirm the new assertions fail**

Run: `node --no-warnings --experimental-strip-types --test src/lib/automation/AutomationDashboard.check.ts`

Expected: FAIL on the missing `svelte/transition` import.

- [ ] **Step 3: Add the smallest implementation**

Import `slide`, add the local wrapper, apply `transition:disclosureSlide` to the existing stage body, keyed task rows, and inline log panel, and add `transition: transform 180ms ease` to `.stage-caret`.

```svelte
<script lang="ts">
import { slide } from "svelte/transition";

function disclosureSlide(node: Element) {
return slide(node, {
duration: matchMedia("(prefers-reduced-motion: reduce)").matches ? 0 : 220,
});
}
</script>
```

- [ ] **Step 4: Run focused and project verification**

Run: `node --no-warnings --experimental-strip-types --test src/lib/automation/AutomationDashboard.check.ts`

Expected: PASS.

Run: `npm run typecheck`

Expected: exit 0 with no Svelte or TypeScript errors.

Run: `npm run build`

Expected: exit 0 and renderer/electron bundles emitted.

- [ ] **Step 5: Verify the live Electron interactions**

Connect to `http://127.0.0.1:9222`, reload the built page, and verify stage collapse/expand, inline-log collapse/expand, and show-all/collapse. Capture the implementation at the same desktop viewport and confirm there are no fresh console errors.

- [ ] **Step 6: Record design QA**

Update `design-qa.md` with the source screenshot paths, implementation screenshot path, viewport/state, the three interactions, console result, focused comparison, and `final result: passed` only when no actionable P0/P1/P2 mismatch remains.
Loading
Loading