Skip to content

feat(mt#1144): cockpit v0 shell + widget framework with placeholder widgets#1017

Merged
edobry merged 10 commits into
mainfrom
task/mt-1144
May 9, 2026
Merged

feat(mt#1144): cockpit v0 shell + widget framework with placeholder widgets#1017
edobry merged 10 commits into
mainfrom
task/mt-1144

Conversation

@minsky-ai
Copy link
Copy Markdown
Contributor

@minsky-ai minsky-ai Bot commented May 9, 2026

Summary

Completes the cockpit v0 frontend shell and CLI wiring for mt#1144. The backend widget framework (types, config, widget-registry, server, attention-stub, basic-health widgets, 8 integration tests) shipped in prior session commits. This PR adds the CLI command, Vite/Tailwind build tooling, and the React SPA frontend.

Stack

Pinned via mt#1518 (DONE 2026-05-08): Express + Vite + React + TypeScript + Tailwind + minimal hand-rolled shadcn-shape Card. Aligns with Fractal accelerator curriculum and agentic-FE meta. No shadcn CLI install.

Key Changes

CLI command (src/commands/cockpit/)

  • index.ts: createCockpitCommand() returning Commander.js Command("cockpit")
  • start-command.ts: createStartCommand() with --port option (default 3737); uses fileURLToPath(import.meta.url) for cross-runtime safe path resolution; checks for built dist/index.html before starting, exits with actionable error if missing; starts Express app via createCockpitServer()
  • src/cli.ts: lazy-import cockpit command wired alongside mcp/compile

Backend (src/cockpit/)

  • types.ts: WidgetModule, WidgetData, WidgetUpdateMode, WidgetContext, CockpitConfig, WidgetMeta interfaces
  • config.ts: cockpit.json loader with isValidConfig() type guard — falls back to default if file is malformed (PR feat(mt#1144): cockpit v0 shell + widget framework with placeholder widgets #1017 R1 fix)
  • widget-registry.ts: static registry mapping IDs to WidgetModules
  • server.ts: createCockpitServer factory; routes for /api/health (returns uptimeSec field for naming consistency), /api/widgets, /api/widget/:id/data (try/catch returns degraded on throw), /, /assets/*
  • widgets/attention-stub.ts: degraded placeholder (pending mt#1034)
  • widgets/basic-health.ts: ok placeholder with uptime/version/loaded count
  • cockpit.test.ts: 8 integration tests

Build tooling

  • vite.config.ts: root at src/cockpit/web, plugin-react, build.outDir = "dist", dev proxy /api → http://localhost:3737
  • tailwind.config.ts: shadcn CSS variable color tokens
  • postcss.config.js: tailwindcss + autoprefixer
  • package.json: cockpit:build script; react/react-dom/clsx/tailwind-merge in dependencies; vite/@vitejs/plugin-react/@types/react/@types/react-dom/tailwindcss/postcss/autoprefixer in devDependencies
  • tsconfig.json: exclude src/cockpit/web from tsgo (vite/client types conflict with project ProcessEnv)
  • eslint.config.js: add **/dist/** to ignores so Vite build output is not linted

Frontend SPA (src/cockpit/web/)

  • index.html, index.css, main.tsx: entry point with Tailwind base + shadcn CSS vars
  • lib/cn.ts: clsx + twMerge helper
  • lib/widget-client.ts: fetchWidgets() / fetchWidgetData() with inline types
  • components/Card.tsx: hand-rolled shadcn-API Card/CardHeader/CardTitle/CardContent with forwardRef
  • components/ErrorBoundary.tsx: React class component; renders crash card on widget error
  • components/Layout.tsx: responsive CSS grid (1/2/3 columns)
  • widgets/AttentionStub.tsx: attention widget; shows degraded reason when state=degraded
  • widgets/BasicHealth.tsx: health widget with uptime (Xm Ys), version, widget count
  • App.tsx: fetchWidgets on mount, setInterval for polling-mode widgets, WIDGET_RENDERERS dispatch, ErrorBoundary per widget, Loading/fallback states

Reviewer service typecheck regression fix (services/reviewer/)

  • src/logger.ts:233 — TS2352 fix: insert as unknown intermediate cast for ReviewerLogger Proxy passthrough; suppress no-excessive-as-unknown warning with explanation
  • src/server.test.ts:117 — TS2322 fix: align process.stdout.write override callback signature with Node's Error | undefined (not Error | null)

These two fixes are pre-existing CI failures from mt#1255 (commit 8eab052) — main has been broken since. Fixed inline rather than blocking on a separate PR; no behavior change, type alignment only.

Test Plan

Execution evidence:

$ bun test src/cockpit/cockpit.test.ts
bun test v1.2.21 (7c45ed97)

src/cockpit/cockpit.test.ts:
(pass) Cockpit server > GET /api/health returns 200 and status ok with uptimeSec [6.91ms]
(pass) Cockpit server > GET /api/widgets returns both enabled widgets [2.83ms]
(pass) Cockpit server > GET /api/widget/attention-stub/data returns degraded with pending reason [3.02ms]
(pass) Cockpit server > GET /api/widget/basic-health/data returns ok with health payload [2.79ms]
(pass) Cockpit server > Widget that throws returns degraded with 'widget crashed' reason [2.70ms]
(pass) Cockpit server > Disabling attention-stub via overrideConfig excludes it from /api/widgets [2.91ms]
(pass) Cockpit server > Malformed overrideConfig does not crash; /api/widgets returns empty list [3.19ms]
(pass) Cockpit server > Adding third widget via overrideRegistry adds 3 entries to /api/widgets [2.93ms]

 8 pass
 0 fail
 29 expect() calls
Ran 8 tests across 1 file. [114.00ms]

Test cases:

  1. GET /api/health returns 200 and status ok with uptimeSec — asserts new uptimeSec field present and old uptime absent
  2. GET /api/widgets returns both enabled widgets
  3. GET /api/widget/attention-stub/data returns degraded with pending reason
  4. GET /api/widget/basic-health/data returns ok with health payload
  5. Widget that throws returns degraded with 'widget crashed' reason
  6. Disabling attention-stub via overrideConfig excludes it from /api/widgets
  7. Malformed overrideConfig does not crash; /api/widgets returns empty list (PR feat(mt#1144): cockpit v0 shell + widget framework with placeholder widgets #1017 R1 regression test)
  8. Adding third widget via overrideRegistry adds 3 entries to /api/widgets

Frontend smoke

bun run cockpit:build succeeds, produces src/cockpit/web/dist/index.html + hashed CSS/JS assets. Manual browser smoke (placeholder widgets render, error boundary contains crashes) pending main-agent or operator post-build verification.

Live verification

Manual browser smoke pending — to verify post-merge:

  1. bun install
  2. bun run cockpit:build
  3. bun src/cli.ts cockpit start
  4. Open http://localhost:3737 → verify two placeholder cards render (Attention "Pending mt#1034", Basic Health with uptime/version)

Concurrency analysis

N/A — no check-then-act pattern introduced. The CLI existsSync check before server start is a startup guard with no concurrent writer; idempotent on failure.

Out of scope

  • Server-side polling loop / SSE (mt#1148)
  • shadcn CLI install (defer until a widget actually needs Button/Dialog)
  • Cockpit dev workflow (cockpit:dev script with vite dev + express in parallel) — production-mode only for v0
  • Real Agents / Tasks / Attention widgets (mt#1145, mt#1146, mt#1147)
  • Dark mode / theme switching
  • Authentication on the cockpit HTTP endpoint
  • Frontend unit tests (requires additional Vite/React test harness)

edobry added 8 commits May 8, 2026 20:30
…ceholder server modules

- src/cockpit/types.ts: WidgetModule, WidgetData, WidgetUpdateMode, WidgetContext, CockpitConfig, WidgetMeta interfaces
- src/cockpit/config.ts: cockpit.json loading with default both-enabled config
- src/cockpit/widget-registry.ts: static registry mapping IDs to WidgetModules
- src/cockpit/widgets/attention-stub.ts: degraded placeholder (pending mt#1034)
- src/cockpit/widgets/basic-health.ts: ok placeholder with uptime/version/loaded count

Subagent dispatch checkpoint. Remaining: server.ts, cockpit.test.ts,
src/commands/cockpit/, src/cockpit/web/ frontend, vite/tailwind/postcss config,
package.json deps, src/cli.ts wiring.
…assing

- src/cockpit/server.ts: createCockpitServer factory; routes for /api/health, /api/widgets, /api/widget/:id/data, /, /assets/*; overrideConfig + overrideRegistry options for tests; per-widget try/catch returns degraded state on throw
- src/cockpit/cockpit.test.ts: 7 integration tests (health, widget metadata, ok+degraded paths, crash containment, config-driven enable/disable, runtime widget addition) — all passing
- src/cockpit/widget-registry.ts: minor adjustment for server consumption

Test results: 7 pass / 0 fail / 23 expect() calls (112ms)

Remaining: src/commands/cockpit/, src/cli.ts wiring, src/cockpit/web/ frontend, vite/tailwind/postcss config, package.json deps.
- src/commands/cockpit/index.ts: createCockpitCommand() returns Command cockpit
- src/commands/cockpit/start-command.ts: createStartCommand() with --port option,
  checks for built dist/index.html, starts Express app on listen
- src/cli.ts: lazy-import cockpit command following mcp/compile pattern
…ckage.json

- vite.config.ts: root=src/cockpit/web, plugin-react, build outDir=dist, dev proxy /api
- tailwind.config.ts: content glob for cockpit/web, shadcn CSS variable color tokens
- postcss.config.js: tailwindcss + autoprefixer plugins
- package.json: add react/react-dom/clsx/tailwind-merge/express to dependencies;
  add vite/@vitejs/plugin-react/@types/react/@types/react-dom/tailwindcss/postcss/autoprefixer to devDependencies;
  add cockpit:build script
…om tsgo

- src/cockpit/web/index.html: SPA entry point
- src/cockpit/web/index.css: @tailwind directives + shadcn CSS variable defaults
- src/cockpit/web/main.tsx: ReactDOM.createRoot entry
- src/cockpit/web/lib/cn.ts: clsx + twMerge helper
- src/cockpit/web/lib/widget-client.ts: fetchWidgets/fetchWidgetData API client
- src/cockpit/web/components/Card.tsx: shadcn-API Card/CardHeader/CardTitle/CardContent
- src/cockpit/web/components/ErrorBoundary.tsx: class component wrapping crashed widgets
- src/cockpit/web/components/Layout.tsx: responsive CSS grid layout
- src/cockpit/web/widgets/AttentionStub.tsx: attention widget renderer
- src/cockpit/web/widgets/BasicHealth.tsx: health widget with uptime/version/count
- src/cockpit/web/App.tsx: orchestrates fetch, polling intervals, renderer dispatch
- tsconfig.json: exclude src/cockpit/web (Vite handles it; vite/client types conflict)
- Regenerated bun.lock from main's baseline to keep typescript@5.8.3 (5.9.x
  breaks existing Process casts; @typescript-eslint requires <5.9.0)
- Added cockpit frontend packages: react/react-dom/clsx/tailwind-merge,
  vite/@vitejs/plugin-react/@types/react/@types/react-dom/tailwindcss/postcss/autoprefixer
- eslint.config.js: add **/dist/** to ignores (covers src/cockpit/web/dist/assets/)
- Prettier-formatted start-command.ts and session-merge-operations.ts (dynamic
  import spacing that prettier normalizes differently cross-session)
Start from main's bun.lock baseline (preserving typescript@5.8.3) and
add only the new cockpit packages incrementally:
- react@18.3.1, react-dom@18.3.1, clsx@2.1.1, tailwind-merge@2.6.0
- vite@5.x, @vitejs/plugin-react@4.x, @types/react@18.x, @types/react-dom@18.x
- tailwindcss@3.x, postcss@8.x, autoprefixer@10.x
@minsky-ai minsky-ai Bot added the authorship/co-authored Co-authored by human and AI agent label May 9, 2026
Copy link
Copy Markdown

@minsky-reviewer minsky-reviewer Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: unknown


Solid scaffolding for the cockpit CLI, server, and SPA. However, a few correctness and robustness issues block merge: (1) the server assumes config.widgets exists and is an array — a malformed cockpit.json will crash startup; add validation/defaulting. (2) the CLI’s preflight bundle path uses import.meta.dir with fragile ../../ traversal; align with fileURLToPath or centralize resolution to avoid false negatives. (3) the /api/health response uses uptime instead of uptimeSec, diverging from other uptime fields and inviting confusion; make the naming consistent or document and test it. Address these and the rest looks coherent and on-spec.

Findings

  • [BLOCKING] src/cockpit/server.ts:35 — Server assumes config.widgets exists; malformed cockpit.json will crash the server on startup/request.
    At src/cockpit/server.ts:35, the code iterates for (const entry of config.widgets) without validating that config.widgets is defined and an array. loadCockpitConfig() (src/cockpit/config.ts) returns the raw parsed JSON (or default) with no schema validation. If a user has an existing ~/.config/minsky/cockpit.json that is empty, missing widgets, or otherwise malformed, the server will throw (e.g., TypeError: Cannot read properties of undefined (reading 'Symbol(Symbol.iterator)')) during startup or on first request.

Suggested fix: validate/normalize the loaded config in loadCockpitConfig() (e.g., if not an object with an array widgets, fall back to the default), or defensively default in the server (const widgets = Array.isArray(config.widgets) ? config.widgets : []). Add tests for a malformed config file path via overrideConfig that mimics this condition.

  • [BLOCKING] src/commands/cockpit/start-command.ts:28 — Path to built index.html uses import.meta.dir and relative ../../ which can be incorrect; may fail to find bundle.
    At src/commands/cockpit/start-command.ts:28, the code builds distIndexHtml as path.join(import.meta.dir, "../../cockpit/web/dist/index.html"). Two issues:

  • import.meta.dir is non-standard; in native ESM, import.meta.url should be used with fileURLToPath to derive a directory path. In Bun, import.meta.dir exists but can be brittle across runtime and tooling; elsewhere in the repo you use fileURLToPath (e.g., src/cockpit/server.ts). This inconsistency increases cross-runtime breakage risk.

  • The ../../ hop assumes the compiled JS file layout remains exactly as in TS sources. If the CLI is executed from a different cwd or via a bundler/packager, this relative traversal may not point to src/cockpit/web/dist/index.html and will cause a false negative prompting users to run cockpit:build even when already built.

Suggested fix: compute the path relative to server.ts (which already resolves WEB_DIST_DIR) or share a helper in src/cockpit/server.ts exporting the resolved INDEX_HTML path. Alternatively, resolve fileURLToPath(import.meta.url) here and join to the known location, ensuring the path matches the server’s logic, or—better—let the server itself check for the asset and return a helpful error, removing this preflight from the CLI to avoid duplication.

  • [BLOCKING] src/cockpit/server.ts:76 — Health endpoint schema mismatch with frontend expectation (uptime field name differs).
    The health widget’s frontend BasicHealth expects a payload { uptimeSec, version, loadedWidgetCount } coming from /api/widget/basic-health/data — that’s fine. However, the general health endpoint /api/health at src/cockpit/server.ts:76-89 responds with { status: "ok", version, uptime } (field uptime not uptimeSec). This inconsistency is an easy source of confusion and breaks the stated PR summary that the endpoint returns "health + version + uptime" in the same shape as used elsewhere. If any future client or widget tries to consume /api/health to render uptime in seconds as uptimeSec, it will fail or require bespoke mapping.

Suggested fix: rename the field to uptimeSec for consistency, or document the discrepancy and ensure consumers use the correct key. Ideally add a test that asserts the /api/health response property names and units.

…ge.json key

- BLOCKING (config.ts): added isValidConfig() type-narrowing guard.
  loadCockpitConfig() now falls back to default when parsed JSON is missing
  the widgets array or has malformed entries, instead of crashing the server
  on startup. Test added (test 8) — malformed overrideConfig produces empty
  widget list rather than 500.

- BLOCKING (start-command.ts): replaced brittle  +
   traversal with  pattern matching
  the resolution in . Cross-runtime safe.

- BLOCKING (server.ts): renamed  21:09  up 6 days, 21:43, 22 users, load averages: 4.31 3.51 3.45 field to
  for naming consistency with the basic-health widget's
  . Test 1 expanded to assert the new field name and
  that the old 21:09  up 6 days, 21:43, 22 users, load averages: 4.31 3.51 3.45 key is absent.

- CI build fix: removed duplicate  entry from
  package.json (was at lines 100 + 106 — added by the third subagent dispatch).
  CI's frozen-lockfile install now succeeds.

Test result: 8 pass / 0 fail / 29 expect() calls.
Copy link
Copy Markdown

@minsky-reviewer minsky-reviewer Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: unknown


The previously blocking issues have been addressed: the server now validates and defaults malformed configs, /api/health uses uptimeSec, and the CLI path resolution uses fileURLToPath rather than import.meta.dir. I found no new critical defects introduced by the fixes. Minor nits include duplicated bundle-existence checks between CLI and server and an exact TypeScript peer pin that may be unnecessarily strict. Overall, functionality matches the PR description and tests back the behavior — approving to proceed.

… from mt#1255

Pre-existing typecheck failures on main (since mt#1255, commit 8eab052).
Both main commits 4d95241 and 8eab052 have failed CI on this same step;
this PR rebased on top of them, inheriting the failure. Fixing inline rather
than blocking on a separate PR.

- services/reviewer/src/logger.ts:233 — TS2352 on  Proxy cast.
  Inserted  intermediate cast and suppressed the
  'no-excessive-as-unknown' lint warning with explanation.

- services/reviewer/src/server.test.ts:117 — TS2322 on process.stdout.write
  override. Node's WriteStream.write callback uses
  (not ). Aligned the test override.

Both fixes scoped tightly: no behavior change, just type alignment.
Copy link
Copy Markdown

@minsky-reviewer minsky-reviewer Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: unknown


The previously blocking issues from R1 were addressed: config handling now validates and defaults malformed widgets, /api/health returns uptimeSec, and the CLI uses fileURLToPath for robust path resolution. The new cockpit CLI, server, and React SPA integrate coherently, and integration tests cover key server behaviors including malformed configs and widget failures. I see no new critical defects introduced by these changes — approving to merge.

@minsky-ai minsky-ai Bot dismissed minsky-reviewer[bot]’s stale review May 9, 2026 01:17

Stale review on commit e0f982c. All 3 BLOCKING findings (config validation, fileURLToPath migration, /api/health uptimeSec naming) were addressed in commit 4d463ec with corresponding test additions; subsequent APPROVE reviews 4256263079 and 4256278058 confirm resolution.

Copy link
Copy Markdown

@minsky-reviewer minsky-reviewer Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: structured Chinese-wall review for mt#1144 cockpit shell + widget framework

CI status: 2 passed, 0 failed (build + Prevent Placeholder Tests both green on commit 9f40424).
Smoke: pass — bun src/cli.ts --version exits 0; bun test src/cockpit/cockpit.test.ts passes 8/8 / 29 expect() calls / 114ms; bun run cockpit:build produces src/cockpit/web/dist/index.html + hashed assets.

Summary

The PR ships the cockpit v0 shell + widget framework end-to-end. After R1 BLOCKING findings (config validation, fileURLToPath migration, /api/health uptimeSec naming), the second review round APPROVED with no new defects. The third commit (CI fix for the pre-existing mt#1255 services/reviewer typecheck regression) was also APPROVED with no new findings.

This review supplements minsky-reviewer[bot]'s APPROVE (reviewId 4256278058) on the latest commit with the spec verification + documentation impact sections required by the merge gate.

Coverage: 100% of diff reviewed via the bot's R1 + R2 + R3 reviews and the structured review-context fetch.

No BLOCKING or NON-BLOCKING findings remain.

Spec verification

Task: mt#1144 (Cockpit: shell + widget framework)

Criterion Status Evidence
minsky cockpit command starts a local HTTP server on a durable port; URL printed to stdout Met src/commands/cockpit/start-command.ts:36-38app.listen(port, () => console.log(\Cockpit running at http://localhost:${port}\`))`, default port 3737, --port override
Widget registry loads modules declared in ~/.config/minsky/cockpit.json Met src/cockpit/config.ts:loadCockpitConfig reads ~/.config/minsky/cockpit.json; src/cockpit/server.ts:50-58 iterates enabled entries against WIDGET_REGISTRY
Shell provides a stable widget contract (TypeScript types) Met src/cockpit/types.ts exports WidgetModule, WidgetData, WidgetUpdateMode, WidgetContext, CockpitConfig, WidgetMeta
Polling loop dispatches updates to each widget on its declared interval Met Client-side polling in src/cockpit/web/App.tsx via widget-client.tssetInterval(intervalMs) per polling-mode widget. Server-side polling deferred to mt#1148 (per spec §Out of scope: SSE transport)
Pending/disabled widgets render an explanatory state that names the blocker Met Server: enabled-only filter at server.ts:53 excludes disabled widgets. Frontend: widgets/AttentionStub.tsx renders data.reason when state === "degraded"
Adding a new widget = implementing the contract + registering in config. No shell changes Met Documented in src/cockpit/widget-registry.ts — three steps: implement WidgetModule, add import + entry to builtinWidgets, enable in config
Graceful error boundaries: one widget failing does not blank the page Met Server: per-widget try/catch at server.ts:101-107 returns degraded state on throw (test #5). Frontend: components/ErrorBoundary.tsx React class component wraps each rendered widget
Placeholder widgets ship: at minimum, an "Attention (pending mt#1034)" stub and a basic-health widget Met src/cockpit/widgets/attention-stub.ts (degraded with "Pending mt#1034" reason) and src/cockpit/widgets/basic-health.ts (ok with uptime/version/loadedWidgetCount); 8 integration tests pass

Action required: None. All criteria met.

Adoption sweep

Symbol / command Consumers found Classification
createCockpitCommand() Wired into src/cli.ts alongside mcp/compile Adopted
createStartCommand() Called by createCockpitCommand Adopted
createCockpitServer() Called by start-command.ts action handler; tested by 8 integration tests in cockpit.test.ts Adopted
WidgetModule, WidgetData, WidgetUpdateMode types Used by attention-stub.ts, basic-health.ts, widget-registry.ts, server.ts, cockpit.test.ts Adopted
loadCockpitConfig() Called by createCockpitServer() (when no overrideConfig) Adopted
WIDGET_REGISTRY (static map) Spread into effective registry in createCockpitServer() Adopted
setLoadedWidgetCount() Called by createCockpitServer() after resolving enabled set Adopted
cockpit:build package.json script New script — adoption pending main-agent or operator post-merge invocation (bun run cockpit:build) Adopted (script self-contained; no internal callers expected)
Frontend components (Card, ErrorBoundary, Layout) and widgets (AttentionStub, BasicHealth) All consumed by App.tsx via WIDGET_RENDERERS dispatch Adopted

No adoption gap. All new exports are wired into either the runtime path or the integration test suite.

Documentation impact

No update needed — this PR introduces a new optional minsky cockpit subcommand with placeholder widgets only. The cockpit subsystem itself is documented inline (JSDoc in each module) and via the mt#1143 parent task spec. No changes to architectural docs (docs/architecture.md), theory-of-operation docs, CONTRIBUTING.md, or README.md are warranted at this v0 stage. When real widgets ship (mt#1145/1146/1147) and the cockpit becomes user-visible default infrastructure, README/CONTRIBUTING references should be added then.

(Had Claude look into this — AI-assisted Chinese-wall review supplementing the auto-firing reviewer-bot's APPROVE.)

@minsky-reviewer minsky-reviewer Bot added the review:bot-approved Reviewer bot has approved this PR label May 9, 2026
@edobry edobry merged commit 0e274c4 into main May 9, 2026
2 checks passed
@edobry edobry deleted the task/mt-1144 branch May 9, 2026 01:21
edobry added a commit that referenced this pull request May 9, 2026
…already applied via mt#1144)

## Summary

This PR closes out mt#1694, which tracked the two TypeScript errors in `services/reviewer/` introduced by the mt#1255 winston logger merge (PR #1014, merged 2026-05-09 00:18:28Z).

The fixes were applied inline as part of the mt#1144 cockpit PR (commit `9f40424c9`, "fix(mt#1144): unblock CI — fix services/reviewer typecheck regression from mt#1255") before this session was started. Both acceptance criteria are met on the current HEAD.

This PR adds only a bun.lock housekeeping fix: a duplicate `"@minsky/shared": "workspace:*"` entry that was left over from the mt#1144 merge.

## Motivation & Context

Two TypeScript errors broke CI for all PRs after 2026-05-09 00:18:28Z:

1. `services/reviewer/src/logger.ts:233` — TS2352: `ReviewerLogger` → `Record<string|symbol, unknown>` cast lacked the intermediate `unknown` step
2. `services/reviewer/src/server.test.ts:117` — TS2322: `process.stdout.write` mock used `Error | null` but Bun's WriteFunction expects `Error | undefined`

Both were fixed in commit `9f40424c9` (part of PR #1017, mt#1144):
- `logger.ts`: double-cast via `as unknown as Record<string | symbol, unknown>` with ESLint suppression comment explaining intent
- `server.test.ts`: callback signature aligned to `(err?: Error) => void` (no `null`)

## Key Changes

- `bun.lock`: remove duplicate `"@minsky/shared": "workspace:*"` entry (cleanup only)

## Testing

Verified in session workspace (HEAD = `0e274c429`, same as origin/main after mt#1144 merge):

```
$ cd services/reviewer && bun run typecheck
$ tsc --noEmit
exit 0

$ cd services/reviewer && bun test --preload ../../tests/setup.ts --timeout=15000 src/
786 pass, 0 fail, 1683 expect() calls
```

Both acceptance tests from the spec pass.

## Concurrency analysis

N/A — no check-then-act pattern introduced. This is a bun.lock dedup only.

Co-Authored-By: minsky-ai[bot] <minsky-ai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

authorship/co-authored Co-authored by human and AI agent review:bot-approved Reviewer bot has approved this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant