From 0db60249b35f2e4f7f9403da57b5ff8be5a5e77b Mon Sep 17 00:00:00 2001 From: JSap0914 Date: Sun, 28 Jun 2026 01:17:45 +0900 Subject: [PATCH] fix(lcx-doctor): use ${TMPDIR:-/tmp} and fix obsolete hooks/hooks.json check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lcx-doctor skill had two correctness bugs reported in issue #80: 1. Hardcoded /tmp: the skill instructed the agent to sync sources to /tmp/lazycodex-source and /tmp/openai-codex-source. On systems where /tmp is restricted or TMPDIR points elsewhere this fails. Replace every hardcoded /tmp path with ${TMPDIR:-/tmp}, and introduce a SOURCE_ROOT variable in the bash sync snippet so callers only set it once. 2. Obsolete aggregate hook layout check: step 3 told the doctor to verify a hooks/hooks.json file under the installed plugin root. The current aggregate OMO plugin manifest (verified by test/aggregate-manifest.test.mjs) enumerates individual hook files directly in the hooks array — an aggregate hooks.json is not used. Replace the check with the current correct shape: individual hook JSON files under hooks/ as listed in plugin.json. RED->GREEN: added two new assertions to the existing lcx-doctor block in test/lcx-bug-skills.test.mjs. Both failed before this change and pass after. Closes #80 --- plugins/omo/skills/lcx-doctor/SKILL.md | 21 +++++++++++---------- plugins/omo/test/lcx-bug-skills.test.mjs | 6 +++++- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/plugins/omo/skills/lcx-doctor/SKILL.md b/plugins/omo/skills/lcx-doctor/SKILL.md index 1ecbafc..f9e23f7 100644 --- a/plugins/omo/skills/lcx-doctor/SKILL.md +++ b/plugins/omo/skills/lcx-doctor/SKILL.md @@ -7,13 +7,13 @@ metadata: # lcx-doctor -You are a LazyCodex install doctor. Inspect the local installation, compare it against the latest LazyCodex and Codex sources, and return a PASS/WARN/FAIL report where every verdict cites the command output or file that produced it. Diagnose only: the only writes you make are under `/tmp`. Never mutate the user's install, config, or repositories during diagnosis; propose remediations and apply one only when the user explicitly asks afterward. +You are a LazyCodex install doctor. Inspect the local installation, compare it against the latest LazyCodex and Codex sources, and return a PASS/WARN/FAIL report where every verdict cites the command output or file that produced it. Diagnose only: the only writes you make are under `${TMPDIR:-/tmp}`. Never mutate the user's install, config, or repositories during diagnosis; propose remediations and apply one only when the user explicitly asks afterward. Use GPT-5.5 style: outcome first, concise, evidence-bound. ## Required Workflow -1. Materialize the latest sources under `/tmp` first. Every source comparison below reads from these checkouts, never from memory. Re-sync on every run so a cached checkout cannot go stale: +1. Materialize the latest sources under `${TMPDIR:-/tmp}` first. Every source comparison below reads from these checkouts, never from memory. Re-sync on every run so a cached checkout cannot go stale: ```bash sync_latest_source() { @@ -26,18 +26,19 @@ sync_latest_source() { git -C "$DEST" fetch --depth=1 origin "$DEFAULT_BRANCH" git -C "$DEST" checkout -B "$DEFAULT_BRANCH" FETCH_HEAD } -sync_latest_source code-yeongyu/lazycodex /tmp/lazycodex-source -sync_latest_source openai/codex /tmp/openai-codex-source +SOURCE_ROOT="${TMPDIR:-/tmp}" +sync_latest_source code-yeongyu/lazycodex "${SOURCE_ROOT}/lazycodex-source" +sync_latest_source openai/codex "${SOURCE_ROOT}/openai-codex-source" ``` 2. Inventory the installed surface. Resolve `CODEX_HOME` (default `~/.codex`), then collect: - `codex --version` and how `codex` resolves (`command -v codex`). - Installed LazyCodex version: the `version` in the installed plugin manifest, discoverable with `find "${CODEX_HOME:-$HOME/.codex}/plugins" -path '*/.codex-plugin/plugin.json'`. Installed plugins live under `$CODEX_HOME/plugins/cache////`. - - Latest LazyCodex version from `/tmp/lazycodex-source` (release tags or the version stamped in the repo) and latest Codex release (`gh release view --repo openai/codex`). + - Latest LazyCodex version from `${TMPDIR:-/tmp}/lazycodex-source` (release tags or the version stamped in the repo) and latest Codex release (`gh release view --repo openai/codex`). - OS, install method, and `lazycodex` / `lazycodex-ai` bin links resolving (`command -v`). -3. Check config and wiring against the latest installer, not against assumptions. Read what the current installer under `/tmp/lazycodex-source` writes (installer sources live in the omo-codex package, e.g. `scripts/install/`), then verify the local equivalents: +3. Check config and wiring against the latest installer, not against assumptions. Read what the current installer under `${TMPDIR:-/tmp}/lazycodex-source` writes (installer sources live in the omo-codex package, e.g. `scripts/install/`), then verify the local equivalents: - `$CODEX_HOME/config.toml` exists and parses; LazyCodex-managed entries match what the latest installer would write. - - Plugin payload present and non-empty: `hooks/hooks.json`, `skills/`, `.mcp.json`, components under the installed plugin root. + - Plugin payload present and non-empty: individual hook JSON files under `hooks/` as enumerated in the `hooks` array of `plugin.json` (the aggregate OMO plugin lists each hook file path directly; an aggregate hooks manifest is not used), `skills/`, `.mcp.json`, components under the installed plugin root. - Stale project-local leftovers the installer now removes (e.g. `.codex/hooks.json`, `.codex/skills` in the project) are flagged, not deleted. 4. Probe the real surface. Do not invoke `lazycodex doctor`; this skill is already running inside that doctor workflow, so calling it would recurse. Instead run non-recursive probes directly: `codex --version`, `command -v codex`, the bin-link checks above, config/plugin payload inspections, and a trivial non-interactive Codex invocation that loads the plugin. Capture stderr verbatim; a clean exit with warnings is WARN, not PASS. 5. Compare for drift. Where installed bundled files differ from the same files at the installed version, or the latest source renamed or removed something the local config still references, record it with both paths. @@ -67,7 +68,7 @@ sync_latest_source openai/codex /tmp/openai-codex-source | Plugin payload wiring | PASS/WARN/FAIL | [evidence] | | Bin links / aliases | PASS/WARN/FAIL | [evidence] | | Runtime probe | PASS/WARN/FAIL | [evidence] | -| Drift vs latest source | PASS/WARN/FAIL | [evidence, citing /tmp/lazycodex-source or /tmp/openai-codex-source paths] | +| Drift vs latest source | PASS/WARN/FAIL | [evidence, citing ${TMPDIR:-/tmp}/lazycodex-source or ${TMPDIR:-/tmp}/openai-codex-source paths] | ### Remediations 1. [Most important fix first: exact command or config edit, and what it resolves.] @@ -79,7 +80,7 @@ sync_latest_source openai/codex /tmp/openai-codex-source ## Follow-up Routing - Local misconfiguration or stale install: give the remediation; reinstalling via the standard LazyCodex install command is the default fix for payload drift. -- Defect in LazyCodex or Codex product code: recommend `$lcx-report-bug` to file it, or `$lcx-contribute-bug-fix` when the user wants a fix PR. Both reuse the `/tmp` checkouts you already synced. +- Defect in LazyCodex or Codex product code: recommend `$lcx-report-bug` to file it, or `$lcx-contribute-bug-fix` when the user wants a fix PR. Both reuse the `${TMPDIR:-/tmp}` checkouts you already synced. ## Stop Conditions @@ -89,5 +90,5 @@ Do not: - mutate config, installs, or repositories during diagnosis - report a verdict without captured evidence -- compare against remembered source layout instead of `/tmp/lazycodex-source` and `/tmp/openai-codex-source` +- compare against remembered source layout instead of `${TMPDIR:-/tmp}/lazycodex-source` and `${TMPDIR:-/tmp}/openai-codex-source` - declare healthy while any probe output was never captured diff --git a/plugins/omo/test/lcx-bug-skills.test.mjs b/plugins/omo/test/lcx-bug-skills.test.mjs index 0af533c..340e16e 100644 --- a/plugins/omo/test/lcx-bug-skills.test.mjs +++ b/plugins/omo/test/lcx-bug-skills.test.mjs @@ -45,7 +45,7 @@ test("#given synced lcx-contribute-bug-fix skill #when inspected #then it delive assert.match(interfaceMetadata, /- "fix bug pr"/); }); -test("#given synced lcx-doctor skill #when inspected #then it diagnoses installs against latest /tmp sources without mutating them", async () => { +test("#given synced lcx-doctor skill #when inspected #then it uses TMPDIR for source paths and checks current aggregate hook layout", async () => { // given const skillRoot = join(root, "skills", "lcx-doctor"); @@ -55,6 +55,10 @@ test("#given synced lcx-doctor skill #when inspected #then it diagnoses installs // then assert.match(skill, /^---\r?\nname: lcx-doctor\r?\n/m); + assert.match(skill, /\$\{TMPDIR:-\/tmp\}/); + assert.doesNotMatch(skill, /\/tmp\/lazycodex-source/); + assert.doesNotMatch(skill, /\/tmp\/openai-codex-source/); + assert.doesNotMatch(skill, /hooks\/hooks\.json/); assert.match(interfaceMetadata, /display_name: "\(OmO\) lcx-doctor"/); assert.match(interfaceMetadata, /- "lazycodex doctor"/); assert.match(interfaceMetadata, /- "lazycodex health check"/);