[codex] 修复 Windows Coding Agents 安装状态检测 (#1126)

* fix windows coding agent status detection

* fix windows coding agents detection and terminal launch

- Fix Claude Code status detection on Windows by prioritizing .cmd files over unix-style scripts when using 'where' command
- Fix command execution logic for .cmd/.bat files to use proper cmd.exe quoting instead of complex cmdQuote function
- Fix native terminal launch on Windows by properly escaping shellCommand in PowerShell Start-Process instead of using empty $args[0]

These changes resolve issues where Claude Code was incorrectly detected as uninstalled on Windows and native terminal launch failed with PowerShell argument errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix claude code custom model launch

* fix windows filename sanitization for coding agent config paths

- Replace invalid filename characters (< > : " / \ | ? *) with underscores in provider/profile names
- Prevents ENOENT errors when provider names contain Windows-invalid characters like colons
- Fixes issue where 'custom:glm-coding-plan' provider would fail to create config directory on Windows

This change ensures that coding agent configuration paths are valid on all platforms while preserving the semantic meaning of provider names.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* remove stale planning docs

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ekko
2026-05-29 20:26:02 +08:00
committed by GitHub
parent 9838173365
commit e3359c671c
4 changed files with 68 additions and 673 deletions
-158
View File
@@ -1,158 +0,0 @@
# Codex Config And Proxy Plan
## Goals
- Launch Codex from Hermes without mutating the user's real `~/.codex`.
- Keep model/provider config isolated by Hermes profile and provider.
- Support OpenAI Responses providers directly.
- Add a local adapter for providers that only expose OpenAI Chat Completions.
- Keep Codex resume/history stable by using a consistent model provider id.
## Directory Layout
All generated Codex state should live under the Web UI home:
```text
~/.hermes-web-ui/coding-agent/
model/{profile}/{provider}/codex/
config.toml
auth.json
AGENTS.md
workspace/{profile}/{provider}/
```
Launch command shape:
```bash
cd ~/.hermes-web-ui/coding-agent/workspace/{profile}/{provider} \
&& CODEX_HOME=~/.hermes-web-ui/coding-agent/model/{profile}/{provider}/codex \
codex --model {model}
```
## Current MVP Config
For Responses-compatible providers, generate:
```toml
model_provider = "custom"
model = "provider-model-id"
disable_response_storage = true
[model_providers.custom]
name = "provider-id"
base_url = "https://provider.example/v1"
wire_api = "responses"
requires_openai_auth = false
experimental_bearer_token = "provider-api-key"
```
Keep `auth.json` empty for third-party providers:
```json
{}
```
Reason: avoid overwriting the user's official Codex / ChatGPT login cache.
## Stable Provider Id
Use `model_provider = "custom"` for third-party providers.
Codex history and resume behavior can depend on provider identity. Keeping a stable provider id avoids making history appear to move between provider-specific ids.
Provider identity remains visible in:
- `[model_providers.custom].name`
- the generated directory path
- the UI launch result
## Local Proxy Plan
Some providers expose only OpenAI Chat Completions:
```text
/v1/chat/completions
```
Codex prefers Responses:
```text
/v1/responses
```
Add a local proxy endpoint:
```text
/api/codex-proxy/{routeKey}/v1/responses
```
The `routeKey` should encode:
```text
profile + "\0" + provider + "\0" + model
```
Authentication should use a generated `hwui_...` token, not the upstream provider key.
## Responses To Chat Mapping
When the upstream provider is Chat Completions only:
- Convert Responses `input` items to Chat `messages`.
- Convert Responses `tools` to Chat `tools`.
- Convert `max_output_tokens` to `max_tokens`.
- Preserve `stream: true`.
- Map function calls and function outputs both ways.
Response event mapping for streaming:
```text
chat delta.content -> response.output_text.delta
chat delta.tool_calls -> response.function_call_arguments.delta
finish -> response.completed
```
Non-streaming mapping:
```text
chat.choices[0].message.content -> output message/content
chat.choices[0].message.tool_calls -> output function_call items
chat.usage -> response.usage
```
## Config Generation With Proxy
For Chat-only providers, generated Codex config should point at Hermes:
```toml
model_provider = "custom"
model = "provider-model-id"
disable_response_storage = true
[model_providers.custom]
name = "provider-id"
base_url = "http://127.0.0.1:{serverPort}/api/codex-proxy/{routeKey}/v1"
wire_api = "responses"
requires_openai_auth = false
experimental_bearer_token = "hwui_generated_route_token"
```
The proxy then forwards to the real provider with the real provider key.
## Implementation Tasks
1. Add a Codex proxy service parallel to the Claude Code proxy service.
2. Register route targets in memory for launch-time provider/model selection.
3. Add `/api/codex-proxy/:key/v1/responses`.
4. Implement Responses to Chat conversion.
5. Implement Chat to Responses conversion for streaming and non-streaming.
6. Add launch-time api mode selection for Codex providers.
7. Generate Codex `base_url` against the local proxy when api mode is Chat Completions.
8. Add server tests for config generation, auth rejection, streaming conversion, tool call conversion, and error passthrough.
## Open Questions
- Whether to expose Codex protocol selection in the UI immediately or infer it from provider preset metadata.
- Whether to persist proxy targets or require relaunch after server restart.
- Whether model catalog generation is needed for the first Codex MVP.
- Whether MCP and `AGENTS.md` should be copied from a template or edited only through the advanced config editor.
-491
View File
@@ -1,491 +0,0 @@
# LaTeX Rendering Implementation Plan
> **For Hermes:** Use subagent-driven-development skill to implement this plan task-by-task.
**Goal:** Add reliable LaTeX/math rendering to Hermes Web UI chat Markdown messages so formulas render visually instead of appearing as raw TeX, including explicit fenced math blocks like ```latex.
**Architecture:** Keep the existing `markdown-it` renderer in `MarkdownRenderer.vue` and add a KaTeX-backed math plugin there, plus a small fence override for explicit LaTeX code fences. Load KaTeX styles globally once, cover inline, display, and fenced math in component tests, then verify with a production build and a local Web UI smoke test.
**Tech Stack:** Vue 3, TypeScript, Vite, markdown-it, KaTeX, Vitest, @vue/test-utils.
---
## Acceptance Criteria
- Chat messages render inline math like `$x^2 + y^2 = z^2$` as KaTeX HTML.
- Chat messages render block math like `$$\n\\int_0^1 x^2 dx = \\frac{1}{3}\n$$` as display KaTeX HTML.
- Chat messages render explicit fenced math blocks like <code>```latex</code>, <code>```tex</code>, or <code>```math</code> as display KaTeX HTML.
- Existing Markdown features still work: code fences, Mermaid fences, headings, local file links, mentions.
- Ordinary fenced code blocks stay literal and are not rendered as math.
- Invalid/unsupported math syntax does not crash the chat renderer.
- `npm run test -- tests/client/markdown-rendering.test.ts` passes.
- `npm run build` passes.
- Local `hermes-web-ui.service` can be restarted onto the built fork and displays formulas in the real panel.
## Recommended Dependency Choice
Use `markdown-it-katex` + `katex` because the app already uses `markdown-it`, and this is the smallest change surface.
Install as runtime dependencies, not dev-only, because the renderer runs in the browser bundle:
```bash
npm install katex markdown-it-katex
npm install -D @types/katex
```
If TypeScript reports no module declaration for `markdown-it-katex`, add a local declaration file instead of weakening `tsconfig`.
---
## Task 1: Add KaTeX dependencies
**Objective:** Make the required renderer and styles available to the client bundle.
**Files:**
- Modify: `package.json`
- Modify: `package-lock.json` or lockfile generated by npm if present
**Step 1: Install packages**
Run from repo root:
```bash
cd /home/werserk/2-kira/hermes-web-ui
npm install katex markdown-it-katex
npm install -D @types/katex
```
**Expected:** `package.json` includes `katex` and `markdown-it-katex`; lockfile is updated.
**Step 2: Verify dependency tree**
```bash
npm ls katex markdown-it-katex
```
**Expected:** both packages resolve without `UNMET DEPENDENCY`.
**Step 3: Commit**
```bash
git add package.json package-lock.json
git commit -m "chore: add latex rendering dependencies"
```
---
## Task 2: Add TypeScript module declaration if needed
**Objective:** Keep TypeScript strict and avoid `any` leaking into the renderer setup.
**Files:**
- Create if needed: `packages/client/src/types/markdown-it-katex.d.ts`
**Step 1: Run typecheck to discover whether declaration is needed**
```bash
npm run build
```
**Expected before implementation:** build may still fail later because code is not changed yet. For this task, only check whether TypeScript knows the `markdown-it-katex` module after it is imported in Task 3.
**Step 2: If TS2307/TS7016 appears, create declaration**
Create `packages/client/src/types/markdown-it-katex.d.ts`:
```ts
declare module 'markdown-it-katex' {
import type MarkdownIt from 'markdown-it'
interface MarkdownItKatexOptions {
throwOnError?: boolean
errorColor?: string
strict?: boolean | string | ((errorCode: string) => boolean | string)
output?: 'html' | 'mathml' | 'htmlAndMathml'
trust?: boolean | ((context: unknown) => boolean)
macros?: Record<string, string>
}
const markdownItKatex: MarkdownIt.PluginWithOptions<MarkdownItKatexOptions>
export default markdownItKatex
}
```
**Step 3: Commit only if file was needed**
```bash
git add packages/client/src/types/markdown-it-katex.d.ts
git commit -m "chore: add markdown-it-katex types"
```
---
## Task 3: Wire KaTeX into MarkdownRenderer
**Objective:** Render math in the same path that currently renders Markdown chat messages.
**Files:**
- Modify: `packages/client/src/components/hermes/chat/MarkdownRenderer.vue`
**Step 1: Import the plugin**
Near existing Markdown imports:
```ts
import markdownItKatex from 'markdown-it-katex'
```
**Step 2: Register the plugin after creating `md`**
After the `new MarkdownItConstructor(...)` block and before custom fence renderer setup:
```ts
md.use(markdownItKatex, {
throwOnError: false,
errorColor: '#cc3344',
output: 'htmlAndMathml',
})
```
**Step 3: Preserve existing Mermaid fence behavior**
Do not move or remove this existing code:
```ts
const defaultFenceRenderer = md.renderer.rules.fence?.bind(md.renderer.rules)
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
const token = tokens[idx]
if (isMermaidFence(token.info)) {
return renderMermaidPlaceholder(token.content)
}
if (defaultFenceRenderer) {
return defaultFenceRenderer(tokens, idx, options, env, self)
}
return self.renderToken(tokens, idx, options)
}
```
**Step 4: Run focused test suite**
```bash
npm run test -- tests/client/markdown-rendering.test.ts
```
**Expected:** existing tests still pass or only fail because new math tests are not yet added.
**Step 5: Commit**
```bash
git add packages/client/src/components/hermes/chat/MarkdownRenderer.vue
git commit -m "feat: enable latex rendering in chat markdown"
```
---
## Task 4: Load and tune KaTeX CSS
**Objective:** Ensure rendered math is visually correct in the Web UI.
**Files:**
- Modify: `packages/client/src/main.ts`
- Optionally modify: `packages/client/src/styles/global.scss`
**Step 1: Import KaTeX CSS once globally**
In `packages/client/src/main.ts`, add after global styles import:
```ts
import 'katex/dist/katex.min.css'
```
Current import area should become:
```ts
import App from './App.vue'
import './styles/global.scss'
import 'katex/dist/katex.min.css'
```
**Step 2: Add Hermes-specific layout tweaks only if needed**
If visual smoke test shows cramped block equations, append to `packages/client/src/styles/global.scss`:
```scss
.markdown-body {
.katex-display {
overflow-x: auto;
overflow-y: hidden;
padding: 0.25rem 0;
}
}
```
Do not restyle KaTeX itself unless there is a concrete visual bug.
**Step 3: Commit**
```bash
git add packages/client/src/main.ts packages/client/src/styles/global.scss
git commit -m "style: load katex styles for markdown math"
```
---
## Task 5: Add regression tests for math rendering
**Objective:** Prove formulas render, code fences stay literal, and malformed math is safe.
**Files:**
- Modify: `tests/client/markdown-rendering.test.ts`
**Step 1: Add inline math test**
Inside `describe('MarkdownRenderer', () => { ... })`:
```ts
it('renders inline latex math with katex', () => {
const wrapper = mount(MarkdownRenderer, {
props: {
content: 'Pythagoras: $x^2 + y^2 = z^2$.',
},
})
const body = wrapper.find('.markdown-body')
expect(body.find('.katex').exists()).toBe(true)
expect(body.html()).toContain('x')
expect(body.html()).toContain('z')
expect(body.text()).not.toContain('$x^2 + y^2 = z^2$')
})
```
**Step 2: Add block math test**
```ts
it('renders display latex math with katex', () => {
const wrapper = mount(MarkdownRenderer, {
props: {
content: '$$\n\\int_0^1 x^2 dx = \\frac{1}{3}\n$$',
},
})
const body = wrapper.find('.markdown-body')
expect(body.find('.katex-display').exists()).toBe(true)
expect(body.find('.katex').exists()).toBe(true)
expect(body.text()).not.toContain('$$')
})
```
**Step 3: Add fenced-code non-rendering test**
```ts
it('does not render latex inside fenced code blocks', () => {
const wrapper = mount(MarkdownRenderer, {
props: {
content: '```md\n$x^2 + y^2 = z^2$\n```',
},
})
expect(wrapper.find('.markdown-body').find('.katex').exists()).toBe(false)
expect(wrapper.find('code.hljs').text()).toContain('$x^2 + y^2 = z^2$')
})
```
**Step 4: Add invalid math safety test**
```ts
it('keeps rendering when latex syntax is invalid', () => {
const wrapper = mount(MarkdownRenderer, {
props: {
content: 'Before $\\notacommand{ after',
},
})
expect(wrapper.find('.markdown-body').text()).toContain('Before')
})
```
**Step 5: Run focused tests**
```bash
npm run test -- tests/client/markdown-rendering.test.ts
```
**Expected:** all tests in the file pass.
**Step 6: Commit**
```bash
git add tests/client/markdown-rendering.test.ts
git commit -m "test: cover latex rendering in markdown"
```
---
## Task 6: Run build and broader regression checks
**Objective:** Catch TypeScript, Vite, and existing client regressions before deploying locally.
**Files:**
- No source changes expected unless checks fail.
**Step 1: Run focused tests**
```bash
npm run test -- tests/client/markdown-rendering.test.ts tests/client/markdown-rendering-mermaid-import-timeout.test.ts
```
**Expected:** pass.
**Step 2: Run all tests if practical**
```bash
npm run test
```
**Expected:** pass. If unrelated pre-existing failures appear, record them in the PR body with evidence.
**Step 3: Run production build**
```bash
npm run build
```
**Expected:** pass and update `dist/` only as build output. Do not commit `dist/` unless the package/release workflow requires it.
**Step 4: Commit fixes only if needed**
```bash
git add <fixed-files>
git commit -m "fix: stabilize latex markdown rendering"
```
---
## Task 7: Deploy to Maxim's local Hermes Web UI instance
**Objective:** Start using the feature on `https://hermes.kiraproject.ru/` before upstream PR review completes.
**Files:**
- Local runtime install under npm/global prefix may change outside the repo.
- Do not commit generated deployment artifacts unless intentionally part of the repo.
**Step 1: Build from the fork checkout**
```bash
cd /home/werserk/2-kira/hermes-web-ui
npm run build
```
**Step 2: Replace currently installed package using npm link or local global install**
Preferred reversible approach:
```bash
cd /home/werserk/2-kira/hermes-web-ui
npm install -g --prefix /home/werserk/.npm-global .
```
**Step 3: Restart the Web UI service**
```bash
systemctl --user restart hermes-web-ui.service
systemctl --user status hermes-web-ui.service --no-pager --lines=20
```
**Step 4: Smoke test HTTP response**
```bash
curl -sS -I --max-time 5 http://127.0.0.1:8648/ | head -20
```
**Expected:** HTTP 200/304 or another successful static response, not connection refused.
**Step 5: Browser smoke test**
Open the chat panel and send/render a message containing:
```md
Inline: $x^2 + y^2 = z^2$
Block:
$$
\\int_0^1 x^2 dx = \\frac{1}{3}
$$
Code fence should stay literal:
```md
$x^2 + y^2 = z^2$
```
```
**Expected:** first two formulas render visually; fenced formula stays literal.
---
## Task 8: Prepare upstream PR
**Objective:** Make the contribution easy for upstream maintainers to review.
**Files:**
- No code changes required unless PR polish finds an issue.
**Step 1: Push branch**
```bash
git push origin feat/latex-rendering
```
**Step 2: Create PR draft**
```bash
gh pr create \
--repo EKKOLearnAI/hermes-web-ui \
--head kira-project-lab:feat/latex-rendering \
--base main \
--title "feat(chat): render LaTeX math in Markdown messages" \
--body "$(cat <<'EOF'
## Summary
- Adds KaTeX-backed LaTeX rendering to chat Markdown messages.
- Supports inline `$...$` and display `$$...$$` math.
- Keeps math inside fenced code blocks literal.
## Test Plan
- [ ] npm run test -- tests/client/markdown-rendering.test.ts
- [ ] npm run test -- tests/client/markdown-rendering-mermaid-import-timeout.test.ts
- [ ] npm run build
- [ ] Manual browser smoke test with inline, block, and fenced math
## Notes
This uses the existing markdown-it rendering path and keeps HTML disabled.
EOF
)" \
--draft
```
**Step 3: Attach visual proof**
Add before/after screenshots in the PR body or a PR comment:
- Before: raw `$...$` / `$$...$$` text.
- After: rendered KaTeX inline and display equations.
---
## Risks and Guardrails
- **Delimiter ambiguity:** `$` is common in shell snippets and prices. The fenced-code test protects code blocks, but inline text like `cost is $5 and $6` may be parsed depending on plugin behavior. If this is noisy, switch to `markdown-it-texmath` with explicit delimiter options or configure delimiters to prioritize `\(...\)` / `\[...\]`.
- **Security:** keep `html: false` in `markdown-it`; do not enable arbitrary HTML. KaTeX should run with `trust: false` unless a clear need appears.
- **Bundle size:** KaTeX adds client bundle weight. Acceptable for this feature, but mention it in PR if maintainers ask.
- **CSS scope:** KaTeX CSS is global. Import once in `main.ts`; avoid duplicating it inside component styles.
- **Invalid math:** `throwOnError: false` should prevent chat crashes. Regression test required.
## Definition of Done
- Branch `feat/latex-rendering` contains committed implementation.
- Local Web UI renders inline and block formulas.
- Focused Markdown tests pass.
- Production build passes.
- PR draft exists against `EKKOLearnAI/hermes-web-ui:main` or is ready to create.