Commit Graph

193 Commits

Author SHA1 Message Date
Codex Agent 9840dcc269 fix: add cloud web access route alias 2026-06-05 09:54:11 +08:00
Lyon 412f95f1a5 fix(v02): unify web trace markdown rendering (#858)
Co-authored-by: Codex Agent <codex@hwlab.local>
2026-06-04 21:33:01 +08:00
Lyon 2129cebfef fix(v02): improve trace and sidebar web ui (#854)
Co-authored-by: Codex Agent <codex@hwlab.local>
2026-06-04 20:56:43 +08:00
Lyon 10c03e6c32 fix(web): v0.2 unify Code Agent trace polling path + persist fail (HWLAB #802) (#806)
Follow-up to PR #798 (#795 final). PR #798 closed the total-timeout /
hard-cap issue, but left two residual code-path inconsistencies that
#802 captures:

- Submit path and refresh path used different trace-polling code:
  submitMessage called `pollRunnerTrace` + `waitForAgentResult` (a
  dual function pair from pre-#798), while hydrate() never subscribed
  to the running trace at all. After a page refresh, the user saw
  the cloud-api "running" state but no live trace events.
- The submit fail branch only dispatched a local "Code Agent 超时"
  message; it never called `persistConversation`, so the failure was
  invisible after F5 — the cloud-api conversation would show
  "running" forever from the user's perspective.

This PR collapses both into a single `subscribeToTrace` entry point
and wires the refresh path into the same active subscription:

- `state/runner-trace.ts` — replace `waitForAgentResult` +
  `pollRunnerTrace` with a single `subscribeToTrace(config)` that
  handles both the result endpoint and the trace endpoint in one
  `for(;;)` loop. Calls `onActivity` on EVERY successful poll (not
  just on new events) so the per-poll inactivity window in
  `fetchJson` does not fire on a healthy polling loop. Terminal
  status -> `onComplete`; 5xx -> keep polling, no activity; 4xx ->
  `onInfrastructureError`; `signal.aborted` -> silent return. The
  hard-cap / 4x / `TRACE_HARD_CAP_ATTEMPTS` machinery is gone (was
  already removed by #798).
- `state/trace-reattach.ts` — new `useTraceReattach` hook that
  subscribes to the running trace on hydrate (same `subscribeToTrace`
  call as submitMessage). Reuses an existing agent message slot for
  the traceId if one exists; otherwise creates a placeholder. Persists
  on both onComplete and onInfrastructureError. Path unification
  achieved: one entry, two callers.
- `state/workbench.ts`:
  - `submitMessage` calls `subscribeToTrace` directly with a
    single-line `onActivity: () => updateActivity()` plus
    `onComplete` / `onInfrastructureError` callbacks. The
    `onInfrastructureError` branch now ALSO calls
    `persistConversation`, persisting the fail state to cloud-api.
  - The re-attach useEffect is replaced with a one-liner
    `useTraceReattach({...})` call (workbench.ts stays under the
    400-line guard).
- `scripts/fetchJson-inactivity.test.ts` — third case tightened:
  200ms-cadence activity for 10s with `timeoutMs: 3000`; the
  request must live the full 10s and abort only after activity
  stops. Asserts `elapsed >= 10_000`.
- `docs/reference/spec-v02-hwlab-cloud-web.md` — the "Code Agent
  Timeout Model" section is renamed "Code Agent Timeout Model 与
  Path Unification" and now also pins: (a) `subscribeToTrace` is
  the only entry; `waitForAgentResult` / `pollRunnerTrace` /
  `TRACE_HARD_CAP_ATTEMPTS` MUST NOT exist; (b) `useTraceReattach`
  MUST be wired in; (c) `persistConversation` is required in both
  onComplete and onInfrastructureError; (d) `state.workspace.activeTraceId`
  changes MUST re-attach. Includes a distilled history of
  #775 / #777 / #791 / #795 / #797 / #798 / #802.

Verification
- `bun run scripts/tsc-check.ts` → strict React TSX, 0 explicit any
- `bun run check` → 5 pass / 0 fail (3 inactivity + 2 dist-contract)
- `bun run build` → 9 dist files verified fresh; `app.js`
  238460 → 240990 B
- `state/trace-reattach.ts` is now wired in; `state/runner-trace.ts`
  exports only `subscribeToTrace` (verified by tsc + grep)
- `workbench.ts` line count 400 (under the 400-line guard)
- New 200ms-cadence 10s test passes; old 100ms-cadence 2s test
  and total-timeout 200ms test still pass.

Refs: HWLAB #802, #795, #777, #791, #798

Co-authored-by: Codex Agent <codex@hwlab.local>
2026-06-04 11:08:20 +08:00
Lyon f7731d1421 fix(web): v0.2 remove all total-timeout / hard cap on Code Agent turn (HWLAB #795 final) (#798)
Follow-up to PR #797: drop every wall-clock or attempt-count ceiling from
`state/runner-trace.ts` so the Web UI's Code Agent inactivity-timeout
contract is total-cap-free. The previous PR kept a
`max(totalTimeoutMs * 4, totalTimeoutMs + 60s)` outer-loop safety net
plus a `TRACE_HARD_CAP_ATTEMPTS = 120` poll-count cap, which would
re-introduce the same regression class that #795 was filed against: a
long-running operation that keeps emitting trace events could still be
killed by the outer ceiling even with an active `activityRef`. The
"Code Agent Timeout Model" section of
`docs/reference/spec-v02-hwlab-cloud-web.md` now pins the contract:

- The sole abort signal is per-poll `fetchJson` inactivity-timeout,
  driven by `activityRef`.
- The outer `waitForAgentResult` / `pollRunnerTrace` loops are
  `for (;;)`. They only exit when the upstream returns a terminal
  status, the request fails with a non-5xx, or the inactivity window
  fires inside `fetchJson`.
- The per-poll `getAgentChatResult` call passes the full
  `totalTimeoutMs`; the inactivity window is **not** shrunk by
  wall-clock elapsed time.
- `TRACE_HARD_CAP_ATTEMPTS` and the 4x / +60s outer cap are deleted.
- Runaway protection is the caller's responsibility: Web users have
  cancel / steer / close-tab; CLI has `--timeout-ms`. The browser does
  not introduce an implicit cap.

Changes

- `web/hwlab-cloud-web/src/state/runner-trace.ts`:
  - Drop `const hardCapMs = Math.max(totalTimeoutMs * 4, totalTimeoutMs + 60_000)`
    and the `if (Date.now() - startedAt >= hardCapMs) break;` checks in
    both `waitForAgentResult` and `pollRunnerTrace`.
  - Replace `while (Date.now() - startedAt < hardCapMs)` with
    `for (;;)`. Drop the now-unused `startedAt` locals and the
    `let attempt = 0; attempt > TRACE_HARD_CAP_ATTEMPTS` guard.
  - Pass `totalTimeoutMs` directly to `api.getAgentChatResult` instead
    of `totalTimeoutMs - (Date.now() - startedAt)` so the per-poll
    inactivity window is stable.
  - Delete `const TRACE_HARD_CAP_ATTEMPTS = 120;` (no longer referenced).

- `web/hwlab-cloud-web/scripts/fetchJson-inactivity.test.ts`:
  - Replace the "1.5s cadence 6.5s" case with a stricter "200ms cadence
    10s" case: `timeoutMs=3000` inactivity window, continuous 200ms
    activity for 10s, then stop. Assert `elapsed >= 10_000` and that
    the abort is the inactivity-timeout error. This pins the
    `elapsed >= 10000` invariant in the spec.

- `docs/reference/spec-v02-hwlab-cloud-web.md`:
  - Strengthen the existing bullet in "在系统中的职责划分" to
    explicitly forbid total-timeout, hard cap, `codeAgentTimeoutMs * N`,
    poll-count cap, and wall-clock-shrunk per-poll windows.
  - Add a dedicated "Code Agent Timeout Model" section after "## 内部架构"
    that distils the contract, lists the three invariants, and records
    the history of #775 / #777 / #791 / #795 leading to the final state.

Verification

- `bun run scripts/tsc-check.ts` → strict React TSX, 0 explicit any
- `bun run check` → 5 pass / 0 fail (3 inactivity + 2 dist-contract)
- `bun run build` → 9 dist files verified fresh; `app.js` 241802 → 238460 B
  (delta reflects the deleted hardCap / TRACE_HARD_CAP_ATTEMPTS code)
- New 200ms-cadence 10s inactivity test runs for ~13s and asserts the
  request lives the full window — proving the outer cap is gone.

Refs: HWLAB #795 (final), #777, #791, #775

Co-authored-by: Codex <codex@local>
2026-06-04 09:36:29 +08:00
Lyon 909715c335 fix(web): v0.2 wire workbench activityRef end-to-end (HWLAB #795) (#797)
The React migration (#756) and the 7-round #775 patch left the
`fetchJson` inactivity-timeout surface half-wired: `client.ts` and the
`api.*` helpers accepted an `ActivityRef`, but `state/workbench.ts`
`submitMessage` and `state/runner-trace.ts` `waitForAgentResult` /
`pollRunnerTrace` never built or forwarded one. The Web UI was therefore
falling back to a **total** timeout: a long-running Code Agent operation
(e.g. `bootsharp` that finished in ~9.7s but the assistant message
chain took ~37s) was killed at `codeAgentTimeoutMs` even while trace
events kept flowing, producing "Code Agent 在超时内未返回可显示正文".
User-facing symptom in #795 is exactly this: the 4th turn on
`D601-F103-V2 bootshar[p]` timed out in the Web UI while the
backend completed the work and emitted `agentrun:result:completed`.

Changes

- `state/workbench.ts` adds a `useRef<number>`-backed `lastActivityAtRef`,
  `updateActivity`, `buildActivityRef` and exposes `recordActivity` on the
  store. `submitMessage` now bumps activity on the initial submit, on
  every trace snapshot, and threads a single `submitActivityRef` through
  `api.sendAgentMessage` / `api.steerAgentMessage`, `pollRunnerTrace`,
  and `waitForAgentResult`.
- `state/runner-trace.ts` `waitForAgentResult` and `pollRunnerTrace`
  accept an `ActivityRefSource`, pass it to `api.getAgentChatResult` so
  each per-poll `fetchJson` uses the inactivity-timeout branch, and
  `pollRunnerTrace` mutates the ref's `lastActivityAt` / `lastEventLabel`
  / `waitingFor` whenever a fresh snapshot arrives. The outer
  `while`-loop hard ceiling becomes `max(totalTimeoutMs * 4, totalTimeoutMs + 60s)`
  as a safety net for runaway operations; the per-request
  inactivity-timeout (driven by `activityRef`) is the primary abort
  signal, matching the pre-React `app-device-pod.ts:fetchJson` contract.
- `components/command-bar/CommandBar.tsx` adds an `onTyping` prop and
  fires it from the textarea `onChange` so user-typing resets the
  inactivity clock.
- `App.tsx` adds a stable `noteActivity` (`useCallback`) wired to
  `store.recordActivity` and passes it as `onTyping` to `<CommandBar>`.

Test

- `scripts/fetchJson-inactivity.test.ts` adds three cases:
  1. `fetchJson` without `activityRef` honours the total window.
  2. `fetchJson` with 100ms-cadence activity survives the configured
     window and aborts ~1-2s after activity stops with the
     "无新活动" error (the HWLAB #795 regression assertion).
  3. `fetchJson` with 1.5s-cadence activity (the actual
     `pollRunnerTrace` interval) survives past the 5s window and only
     aborts after activity stops at 6.5s.

Verification

- `bun run scripts/tsc-check.ts` passes (strict React TSX, 0 explicit any)
- `bun run check` 5 pass / 0 fail (3 new + 2 dist-contract)
- `bun run build` 9 dist files verified fresh; `app.js` 234676 → 238740 B
- orphan-listener check (per HWLAB #748): no `el.X.addEventListener`
  in `*.tsx` whose X is not in the `el` literal.

Refs

- HWLAB #795 (this issue)
- HWLAB #775 round 1 #777 added the `fetchJson` `activityRef` plumbing
  in `client.ts` but stopped short of the workbench / runner-trace layer
- HWLAB #756 React migration baseline

Co-authored-by: Codex <codex@local>
2026-06-04 09:01:42 +08:00
Codex d11c91d36e fix(web): avoid live 404 probes 2026-06-03 18:47:42 +08:00
Codex deb99ec1c9 fix(web): defer workbench fetches until auth ready 2026-06-03 18:33:50 +08:00
Codex 58b06fcd17 fix(web): enforce React TypeScript single path 2026-06-03 17:47:27 +08:00
Lyon 6ecfe015cf fix(web): ensure web deps installed before vite build in runtime (#768)
Co-authored-by: Codex <codex@local>
2026-06-03 17:28:30 +08:00
Lyon a78a4199a8 fix(web): use local node_modules/.bin/vite in dist-contract (#767)
Co-authored-by: Codex <codex@local>
2026-06-03 17:15:54 +08:00
Lyon 0d06a4c5fe fix(web): migrate Cloud Web from vanilla DOM to React + TypeScript + Vite (#756) (#764)
- Replace monolithic app.ts / app-conversation.ts / app-device-pod.ts /
  app-skills.ts / app-helpers.ts / app-session-tabs.ts / auth.ts and the
  364-line index.html with a Vite-built React + TypeScript SPA.
- New src/ module tree: main.tsx, App.tsx, components/{layout,auth,
  conversation,command-bar,device-pod,skills,settings,help},
  hooks/, services/api, services/auth, state, types, logic/ (pure
  helpers from the old tree), styles/.
- Pure-logic modules (composer-policy, code-agent-facts, code-agent-
  status, live-status, message-markdown, app-trace, app-session-tabs,
  runtime) move to src/logic/ with their tests preserved; tests still
  auto-discover.
- Build pipeline switches from Bun.build to Vite: vite.config.ts
  inlines everything into a single app.js + app-assets/ for the dist;
  scripts/dist-contract.ts now runs vite build and asserts the dist
  against a fresh build instead of comparing dist to source.
- scripts/check.ts now verifies the React entry, the mount-only
  index.html, Vite dist, the composer / session / device pod / skills
  / settings / help contracts, the React state shape, and the new
  test file locations. It also refuses to run if any legacy app-*.ts
  or auth.ts survives at the top level.
- New scripts/frontend-guard.ts enforces the 400-line migration target,
  refuses the legacy el map and document.getElementById markers,
  refuses to keep app-*.ts / auth.ts at the top level, and verifies
  the required module directory layout.
- Update scripts/src/dev-cloud-workbench-smoke-lib.mjs to read the new
  src/services/, src/logic/ paths and refresh cloudWebModuleSourceFiles.
- index.html is now a mount shell only (no login shell, no workbench
  shell, no device pod sidebar markup). React renders the full UI from
  src/main.tsx, satisfying the issue-756 migration goal of catching
  unclosed tags at the TypeScript/JSX compile step instead of relying
  on browser DOM healing.
- web:check (now: check + frontend-guard + tsc-check + bun test) is
  green: 51 pass / 0 fail, Vite build produces dist/app.js (379 kB)
  + dist/index.html + dist/app-assets/. Vite build is reproducible;
  dist freshness is verified against a fresh Vite build.
- Grandfathered pure-logic files (> 600 lines): src/logic/app-trace.ts
  (1367), src/logic/live-status.ts (1006), src/logic/code-agent-facts.ts
  (548), src/logic/code-agent-status.ts (572). Reason: each is a tested
  pure-logic classifier with a public contract consumed by both the
  CLI renderer and the Web renderer; splitting now would fork the
  public function shape across two PRs and the migration target is the
  React entry + module split, not a pure-logic refactor.

Refs #756. Closes #756 once merged + deployed to hwlab-v02.

Co-authored-by: Codex <codex@local>
2026-06-03 16:53:25 +08:00
Codex 2fa23bd71d fix(web): restore v02 workbench layout 2026-06-03 15:49:52 +08:00
Lyon 10906ec726 fix(issue751): add web-types.d.ts + tsconfig + tsc-check baseline (#754)
为 issue #751 的 TypeScript 收紧建基线:
- 新增 web/hwlab-cloud-web/tsconfig.json(strict family 全部开启、noImplicitAny
  默认关、allowImportingTsExtensions 打开、types=[bun-types, node])
- 新增 web/hwlab-cloud-web/web-types.d.ts(ElMap + WorkbenchState + 跨文件
  function/lifecycle/constant 的 ambient declarations;用 WorkbenchUnknown
  接口避开 any 字面量,同时保留索引签名允许任意属性访问)
- 新增 web/hwlab-cloud-web/scripts/tsc-check.ts:web:check 的并行 type gate,
  显式 untyped 注解(项目源码 + web-types.d.ts)直接 exit 2;residual type
  错误按 issue #751 follow-up 处理
- web/hwlab-cloud-web/package.json:加 typescript@5.6.3 / @types/node@22.7.5
  / bun-types@1.1.33;check / check:tsc / check:tsc-strict 入口
- byId/query 加显式 : HTMLElement 返回类型(不再返回 HTMLElement | null)
- app-conversation.ts 中 captureConversationScrollPosition 加 : void 注解

web:check(54 tests / 0 fail)+ web:build(12 dist files)通过;tsc-check
报告 0 explicit untyped,residual type 错误(property access / strict null
等)作为 issue #751 后续轮次跟踪,不阻塞 build。

Refs: pikasTech/HWLAB#751

Co-authored-by: Codex <codex@noreply.local>
2026-06-03 15:21:03 +08:00
Lyon 2168ad2ad7 fix(web): HWLAB #744 WebUI v0.2 改进 (#746)
- 问题1: 修复重复 session - 按 threadId 去重 conversation
- 问题2: session sidebar 默认宽度改为150% (330px),移除上限
- 问题3: 删除重复的命令栏「新建 Session」按钮
- 问题4: session 报错(status=failed/error/canceled/timeout)后允许继续重试
- 问题5: session tabs 上方显示当前模型通道
- 问题6: 所有时间统一使用北京时间(UTC+8),移除「北京时间」字样
- 问题7: 注销按钮移入 activity-rail 设置标签

Closes #744

Co-authored-by: Codex <codex@local>
2026-06-03 13:13:23 +08:00
Codex 94b9df822c feat: 手动化 Code Agent session 管理 2026-06-03 10:40:50 +08:00
Codex da25cb4c02 feat: align session sidebar and cli management 2026-06-03 09:47:52 +08:00
Codex 5b1c9eb5dd feat: add session tabs to cloud web 2026-06-03 08:37:07 +08:00
Codex 90c5dad065 feat: show prompt assembly in skills panel 2026-06-03 08:03:04 +08:00
Codex 66282ba80f fix: unlock cloud web composer steer 2026-06-02 12:25:16 +08:00
Codex c1bf4f0a59 fix: 收紧 v0.2 Device Pod 右栏首屏布局 2026-05-31 16:53:56 +08:00
Codex 6af815bda1 fix: 修复 v0.2 Device Pod 右栏与助手消息 2026-05-31 16:24:44 +08:00
Codex c462122ad7 fix: refine v02 workbench layout 2026-05-31 13:58:51 +08:00
Codex 70ebd1689c feat: add uploaded skills management 2026-05-31 11:45:10 +08:00
Codex d269dd52bf fix: enforce v02 cloud web validation 2026-05-31 11:39:18 +08:00
Codex 7cafb70d9a fix: absorb v02 web trace layout updates 2026-05-31 10:58:23 +08:00
Codex b99c663614 feat: enforce v02 runtime authority 2026-05-29 08:10:19 +08:00
Codex ba9daf7e03 fix: resolve bun command from ci path 2026-05-29 03:34:56 +08:00
Codex 03c09f5c94 refactor: migrate v0.2 runtime services to TypeScript 2026-05-29 02:09:35 +08:00
Codex e2c206aab4 Merge remote-tracking branch 'origin/v0.2' into codex/v02-cloud-api-ts-migration
# Conflicts:
#	package.json
#	scripts/src/artifact-runtime-readiness-guard.mjs
#	scripts/src/m3-io-control-e2e.mjs
#	web/hwlab-cloud-web/scripts/check.ts
2026-05-29 00:59:52 +08:00
Codex a0869c5afa refactor: migrate v02 cloud api to TypeScript 2026-05-29 00:33:22 +08:00
Codex b7f7299056 feat: migrate v0.2 cloud web to TypeScript 2026-05-28 21:33:33 +08:00
Codex 81d7242a69 fix: compact device pod sidebar 2026-05-28 09:16:13 +08:00
Codex 02c9fea329 fix: keep cloud web rollout scoped 2026-05-28 08:32:58 +08:00
Codex 1c44ce671b fix: stabilize cloud web restored status 2026-05-28 08:06:24 +08:00
Codex 297206b695 feat: add fake device pod sidebar service 2026-05-28 01:39:03 +08:00
Codex 35b1445b76 fix: preserve inner trace scroll 2026-05-27 14:50:19 +08:00
Codex 2a22359865 feat: preload gateway tran helper 2026-05-27 12:31:37 +08:00
Codex a163789586 fix: decouple trace updates from scroll 2026-05-27 12:02:00 +08:00
Codex 8d533cb736 Merge remote-tracking branch 'origin/G14' into fix/code-agent-timeout-control-20260527004132
# Conflicts:
#	deploy/deploy.json
2026-05-27 08:11:49 +08:00
Codex a56ea7e33e fix: extend code agent timeout recovery 2026-05-27 07:46:24 +08:00
Codex a452c14983 fix: show command execution summaries in trace 2026-05-27 07:45:54 +08:00
Codex 1db095bfdc feat: render final response markdown 2026-05-27 00:25:15 +08:00
Codex 58468159c3 fix: keep assistant stream chunks out of trace events 2026-05-26 21:32:24 +08:00
Lyon 6a849596ed Merge pull request #488 from pikasTech/fix/code-agent-partial-result-tests
fix: harden Code Agent result lifecycle
2026-05-26 15:37:01 +08:00
Codex e6ac2898fe refactor: remove legacy dev cd scripts 2026-05-26 05:31:57 +08:00
Codex 7969de24c7 test: make legacy auth browser fixture diagnostic 2026-05-26 02:45:02 +08:00
Codex 78da29d781 fix: keep quick prompts in composer flow 2026-05-26 02:24:45 +08:00
Codex cdb70b12b2 fix: keep command composer hit targets above summaries 2026-05-26 02:07:54 +08:00
Codex 83cf496fcd feat: add code agent provider profiles 2026-05-26 01:47:11 +08:00