# Repository Guidelines

## Project Structure & Module Organization
This repo is a Windows-first `pnpm` workspace. Core app code lives in `apps/` and shared libraries live in `packages/`.

- `apps/desktop`: Electron main process, preload bridge, packaging config, and desktop services.
- `apps/ui`: Vite + React renderer.
- `packages/shared-types`: shared IPC contracts and DTOs.
- `packages/gateway-client`: Gateway/WebSocket client logic.
- `packages/runtime-manager`: bundled runtime lifecycle management.
- `build/scripts`: PowerShell packaging and smoke-test scripts.
- `vendor/openclaw-runtime`: generated runtime payload placeholder; generated contents should not be committed.
- `dist/`: installer output and other generated artifacts.

## Build, Test, and Development Commands
Use Corepack so the workspace stays on the pinned `pnpm` version.

- `corepack pnpm install`: install workspace dependencies.
- `corepack pnpm dev`: start the UI and Electron shell together for local development.
- `corepack pnpm build`: build all workspace packages in dependency order.
- `corepack pnpm typecheck`: run `tsc --noEmit` across the workspace.
- `corepack pnpm package`: materialize the runtime payload, build packages, and create the macOS DMG.
- `corepack pnpm smoke:installer`: run the packaged installer smoke test.

## macOS Packaging Notes
Current unsigned and unnotarized handoff builds should be packaged as the larger uncompressed DMG first. The reason is: 因为现在没有公证和签名，先打包成比较大的 dmg. Use `compression: store` / `dmg.format=UDRO` for that temporary handoff path.

After signing and notarization are ready, customer releases should be distributed as a compressed `.dmg`, not as a zipped DMG and not as an uncompressed DMG. The desktop electron-builder config normally keeps `compression: maximum`; using `compression: store` produces an uncompressed APFS DMG around 1.95 GB for the bundled runtime payload.

Run `corepack pnpm run package:mac` first so the runtime is materialized and `dist/installer/mac-arm64/千匠问天.app` is rebuilt from the latest code. If electron-builder finishes the `.app` but fails while creating the DMG with `hdiutil create`, do not ship a quick `UDZO` fallback. Create a bzip2-compressed DMG and then rewrite it with `hdiutil convert` so wasted image bytes are removed:

```sh
hdiutil create -srcfolder dist/installer/mac-arm64/千匠问天.app -volname "千匠问天 0.1.0" -format UDBZ dist/installer/千匠问天-0.1.0-mac-arm64-latest.tmp.dmg
hdiutil convert dist/installer/千匠问天-0.1.0-mac-arm64-latest.tmp.dmg -format UDBZ -o dist/installer/千匠问天-0.1.0-mac-arm64-latest.dmg
```

Before handing off a temporary unsigned/unnotarized DMG, run `hdiutil imageinfo <dmg>` and confirm `Format: UDRO` and `Compressed: false`. Before handing off a compressed release DMG, confirm `Format: UDBZ`, `Compressed: true`, and `CUDIFEncoding-bytes-wasted: 0`. For either path, run `hdiutil verify <dmg>` and `corepack pnpm run smoke:mac:package`. A larger DMG does not automatically mean extra app content; compare mounted `.app` size and file counts if needed.

## Coding Style & Naming Conventions
The codebase uses strict TypeScript, ESM modules, and 2-space indentation. Prefer double quotes and trailing semicolon-free style, matching existing files.

- Use `PascalCase` for React components and service classes.
- Use `camelCase` for functions, variables, and helpers.
- Keep shared contracts in `packages/shared-types`.
- Keep renderer code behind the preload bridge; do not access secrets, runtime files, or child processes directly from `apps/ui`.

There is no separate ESLint/Prettier config at the root; `lint` currently maps to TypeScript type-checking.

## Testing Guidelines
Primary validation is workspace type-checking plus targeted PowerShell smoke scripts in `build/scripts/`.

- Run `corepack pnpm typecheck` before opening a PR.
- Run the relevant smoke script when touching packaging, startup, routing, or runtime bootstrap paths.
- Name new smoke scripts descriptively, following the existing `*-smoke.ps1` pattern.

## Commit & Pull Request Guidelines
Recent history follows Conventional Commits with scopes, for example `fix(desktop): ...` and `feat(desktop): ...`. Keep messages imperative and scoped to the area changed.

PRs should include a short summary, linked issue if applicable, validation commands run, and screenshots for visible UI changes. Call out packaging or runtime prerequisites when a reviewer needs a Windows machine or local OpenClaw setup to verify the change.

## UI Layout Guardrails
When editing `apps/ui/src/App.tsx` and `apps/ui/src/styles.css`, keep the renderer layout on a single, stable skeleton system.

- Do not mix two layout systems in the main renderer shell. The main workspace skeleton must be driven by stable semantic class names, not large Tailwind utility overrides in `App.tsx`.
- Keep the conversation workspace wired through the same structural classes every time: `conversation-shell`, `conversation-main-layout`, `conversation-content-area`, and `conversation-panel`.
- Do not redefine core layout classes multiple times in `styles.css`. In particular, keep only one final definition for `shell`, `sidebar`, `main-shell`, `page-topbar`, `content-area`, `conversation-panel`, `message-list`, and `composer-shell`.
- Scope conversation-only styling under `.conversation-shell ...` so chat-specific rules do not leak into plugins or settings pages.
- Preserve the two-column desktop structure: left sidebar, right workspace. Changes must not collapse the right workspace into a sidebar-like single-column page.
- Before removing or hiding UI controls, check whether smoke helpers, automation hooks, or renderer-side test utilities depend on those DOM nodes or selectors.
- Be careful with Chinese text encoding in UI files. Avoid introducing BOM or accidental encoding changes when patching `App.tsx`, `styles.css`, or other renderer text files.
- For UI skeleton changes, validate with `corepack pnpm typecheck` and `corepack pnpm build`, and manually confirm chat, experts, plugins, and settings still render with correct height and scrolling behavior.

## Chinese Encoding Safety

When editing `apps/ui/src/App.tsx`, avoid whole-file rewrites. This file contains Chinese UI copy and has previously been corrupted by PowerShell encoding conversion.

- Prefer `apply_patch` for small targeted edits.
- Do not use `Set-Content`, `Out-File`, or raw `WriteAllText` on `App.tsx` unless explicitly writing UTF-8 without BOM and after checking the diff.
- After edits, verify the file does not start with UTF-8 BOM bytes `239,187,191`.
- Inspect `git diff -- apps/ui/src/App.tsx` before validation; Chinese text must not become mojibake or `�`.
- If Chinese text is corrupted, compare against the already pushed version with `git show HEAD:apps/ui/src/App.tsx` or the target remote branch, and restore only the corrupted text/sections.
- If corruption is widespread, restore `App.tsx` from the pushed version first, then reapply intended logic changes as small patches.
- Always run `corepack pnpm --filter @qjclaw/ui typecheck` after touching `App.tsx`.

## Response Style (Strict Rules)

You MUST follow these rules:

1. **Answer only the core question**
- Focus on the single question asked
- No extra explanations, assumptions, or added topics
- If unclear, ask a clarification question instead of guessing

2. **Be extremely concise**
- Default to minimal wording (prefer 3–5 sentences)
- Avoid long paragraphs and repetition
- If one sentence is enough, don’t use two

3. **No unnecessary expansion**
- Do NOT include background, theory, or history unless explicitly asked
- No extra analysis, comparisons, or suggestions

4. **Single-question rule**
- Handle only ONE question at a time
- If multiple questions are asked, answer the most important one and ask the user to split the rest

5. **Structured when helpful**
- Prefer short bullet points or steps
- Avoid verbose explanations

6. **User-controlled depth**
- Optionally end with:
  “Let me know if you want more detail on any part.”

---
## Example Style

✔ Good:
- “Two reasons: 1) xxx 2) xxx”
- “Do these 3 steps: …”

✘ Avoid:
- Long explanations
- Extra background info
- Covering multiple directions at once

## OpenAI Responses Tool-Call Safety

Avoid the API error `No tool call found for function call output with call_id ...` by treating tool calls as a strict request/response state machine.

- Only send a `function_call_output` for a `call_id` that appeared in the immediately preceding model response.
- Send each tool result exactly once. Never replay old `call_id` values after retrying, resuming, or branching a conversation.
- Do not mix `call_id` values across different Responses, sessions, tabs, workers, or parallel agent branches.
- When continuing a Responses API chain, keep the correct `previous_response_id` and append only the pending tool outputs for that response.
- On retry after a transport or 400 error, rebuild the request from the last confirmed model response instead of reusing buffered tool outputs blindly.
