refactor(office): retire bundled OfficeCLI for native office-* skills (#1273 PR4) - #1494
Conversation
|
Warning Review limit reached
Next review available in: 30 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR removes OfficeCLI-specific workflows, scripts, eval routes, and reference assets, while switching shell artifact handling to generic office output paths, renaming bundled skills to ChangesOfficeCLI cutover and office- migration*
Shell office output migration
Eval routes and reference removals
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related issues
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Suggested priority: P2 (includes user-path files (packages/app/src/pages/skills/skill-presentation.ts)).
P1/P0 are reserved for maintainer confirmation. Please relabel manually if this is a release blocker, security issue, data-loss risk, or updater/runtime failure.
|
To use Codex here, create a Codex account and connect to github. |
…skill bundle Promote the native python office-* skills (office-docx/xlsx/pptx/pdf) from dark-launched preview to the default route: rewrite their SKILL.md descriptions and the core pawwork.txt guidance to point at them directly, and delete the upstream-synced officecli-* skill bundle plus the coupled morph-ppt / morph-ppt-3d skills, which cannot function without the officecli binary. Update the skill discovery test to assert the office-* skills are present and to guard that no officecli-*/morph-ppt skill can be re-vendored by a future sync.
… steps Remove the officecli entry from bundled-tools.json and its download/prepare path, delete prepare-officecli and sync-officecli-skills (plus tests), and drop the officecli-bump auto-sync workflow. Remove the Prepare OfficeCLI steps and bundle smoke assertions from build.yml and desktop-smoke.yml, and retarget the release and workflow contract tests to the remaining bundled tool (uv). uv stays bundled as the Python runtime the office-* skills depend on.
The shell artifact-capture subsystem special-cased officecli commands to infer .docx/.xlsx/.pptx write targets. With officecli gone, that branch is dead: drop the officecli command matchers, target inference, and OFFICECLI_SKIP_UPDATE env wiring, keeping only the generic write-detection helpers the office-* skills rely on through declared outputs and auto-discovery. Rename isOfficeCliOutputPath to isOfficeOutputPath and prune the now-unused deps from the orchestrator. Update the shell/env/heuristic tests accordingly and delete the tests that only covered the removed officecli behavior.
PawWork still handles Word/Excel/PowerPoint locally, now through the native office-* skills instead of the bundled OfficeCLI binary. Update the README, CN README, marketing site copy, comparison table, and llms.txt to state local Office handling without the OfficeCLI attribution, and remove the OfficeCLI section and its copyright line from THIRD_PARTY_NOTICES.md since it is no longer bundled. Rename the officecli-* seeds in the skills-surface snap fixture and its comment to office-* so the gallery fixture stays representative; rendering logic is unchanged.
e66003e to
2feb4fb
Compare
The office-* SKILL.md bodies still told the model 'dark-launched preview / does not replace the default path / only run when explicitly routed here / hard switch lands with PR 4'. With this PR being that routing switch, those guards contradict the promoted frontmatter and pawwork.txt and would make the model avoid the only remaining Office route. Drop the preview paragraphs from all four skills and the dark-launch caveat from office-pdf's print-fallback note. Surfaced by Codex, Pi (GLM-5.2), and ChatGPT code review.
- office-route-eval read manifest.officecli.version, which throws now that the officecli entry is gone; degrade to "removed" so the retained evidence eval still runs. - .pdf is a promoted Office deliverable (already listed in the expected_outputs description), so add it to officeOutputExtensions for consistent artifact detection and binary handling. - rewrap a uv-mirror comment that split 'explicitly configured' across lines. Surfaced by Codex, Pi (GLM-5.2), and ChatGPT code review.
office-* skills generate files via `uv run python ... -o out.pptx`, which isLikelyWriteCommand did not flag (no shell redirect). With officecli's exact-target capture removed, those artifacts escaped turn-file / artifact tracking unless the model happened to set expected_outputs. Treat a named office output path (.docx/.xlsx/.pptx/.pdf) on a python/uv/uvx command as the write signal so artifact auto-discovery runs; test/lint commands like `uv run pytest` name no such path and stay read-only. Closes the last shared P2 from Codex / Pi (GLM-5.2) / ChatGPT review.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/opencode/script/office-route-eval/eval.ts (1)
37-41: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUpdate
OfficeRouteManifesttype to reflect optionalofficecli.The runtime code now safely handles a missing
officeclikey (lines 259), but the type definition at lines 37–41 still declaresofficeclias a required field. SinceJSON.parsereturnsany, this won't cause a compile error, but the type is now misleading and could cause confusion for future maintainers.♻️ Make the
officeclifield optional in the manifest typeofficecli: { manifestVersion: string binaryPath: string binaryVersion?: string - } + }?Also applies to: 254-260
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/opencode/script/office-route-eval/eval.ts` around lines 37 - 41, Update the OfficeRouteManifest type so officecli is optional instead of required, matching the runtime handling in the manifest parsing logic. Adjust the type definition near OfficeRouteManifest and keep the existing fallback behavior in the JSON.parse-based code path that checks for a missing officecli key, so the type accurately reflects the shape accepted by OfficeRouteEval.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/opencode/script/office-route-eval/eval.ts`:
- Around line 37-41: Update the OfficeRouteManifest type so officecli is
optional instead of required, matching the runtime handling in the manifest
parsing logic. Adjust the type definition near OfficeRouteManifest and keep the
existing fallback behavior in the JSON.parse-based code path that checks for a
missing officecli key, so the type accurately reflects the shape accepted by
OfficeRouteEval.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: a9420cb1-d0d3-45eb-a903-fcaa28c239f9
⛔ Files ignored due to path filters (27)
skills/morph-ppt/reference/styles/bw--brutalist-raw/bw__brutalist_raw.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/bw--mono-line/bw__mono_line.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/bw--swiss-bauhaus/bw__swiss_bauhaus.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--architectural-plan/dark__architectural_plan.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--blueprint-grid/dark__blueprint_grid.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--circle-digital/dark__circle_digital.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--cosmic-neon/dark__cosmic_neon.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--cyber-future/dark__cyber_future.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--diagonal-cut/dark__diagonal_cut.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--editorial-story/dark__editorial_story.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--investor-pitch/template.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--liquid-flow/dark__liquid_flow.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--luxury-minimal/dark__luxury_minimal.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--neon-productivity/dark__neon_productivity.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--premium-navy/dark__premium_navy.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--space-odyssey/dark__space_odyssey.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/dark--spotlight-stage/dark__spotlight_stage.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/light--bold-type/light__bold_type.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/light--isometric-clean/light__isometric_clean.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/light--minimal-product/light__minimal_product.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/light--watercolor-wash/light__watercolor_wash.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/mixed--duotone-split/mixed__duotone_split.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/vivid--candy-stripe/vivid__candy_stripe.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/vivid--playful-marketing/vivid__playful_marketing.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/warm--brand-refresh/warm__brand_refresh.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/warm--earth-organic/warm__earth_organic.pptxis excluded by!**/*.pptxskills/morph-ppt/reference/styles/warm--playful-organic/Cat-Secret-Life.pptxis excluded by!**/*.pptx
📒 Files selected for processing (141)
.github/workflows/build.yml.github/workflows/desktop-smoke.yml.github/workflows/officecli-bump.ymlREADME.mdREADME_CN.mdTHIRD_PARTY_NOTICES.mdpackages/app/e2e/snap/skills-surface.snap.tspackages/app/src/pages/skills/skill-presentation.tspackages/desktop-electron/bundled-tools.jsonpackages/desktop-electron/package.jsonpackages/desktop-electron/scripts/prepare-officecli.test.tspackages/desktop-electron/scripts/prepare-officecli.tspackages/desktop-electron/scripts/prepare-uv.tspackages/desktop-electron/scripts/release-workflow-contract.test.tspackages/desktop-electron/scripts/sync-officecli-skills.test.tspackages/desktop-electron/scripts/sync-officecli-skills.tspackages/desktop-electron/tsconfig.release.jsonpackages/opencode/script/office-route-eval/eval.tspackages/opencode/src/session/prompt.tspackages/opencode/src/session/prompt/pawwork.txtpackages/opencode/src/tool/shell-artifact-orchestrator.tspackages/opencode/src/tool/shell-office-artifacts.tspackages/opencode/src/tool/shell-output-capture.tspackages/opencode/src/tool/shell-write-heuristic.tspackages/opencode/src/tool/shell.tspackages/opencode/src/tool/shell/prompt.tspackages/opencode/src/util/env.tspackages/opencode/src/util/uv-mirror.tspackages/opencode/test/github/bun-version-workflow.test.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/opencode/test/github/officecli-bump-workflow.test.tspackages/opencode/test/github/pr-triage-workflow.test.tspackages/opencode/test/session/session-skill.test.tspackages/opencode/test/skill/skill.test.tspackages/opencode/test/tool/shell-artifact-orchestrator.test.tspackages/opencode/test/tool/shell-env-source.test.tspackages/opencode/test/tool/shell-office-artifacts.test.tspackages/opencode/test/tool/shell-prompt.test.tspackages/opencode/test/tool/shell-write-heuristic.test.tspackages/opencode/test/tool/shell.test.tspackages/opencode/test/util/env.test.tssite/public/llms.txtsite/src/components/Home.astrosite/src/i18n.tsskills/morph-ppt-3d/SKILL.mdskills/morph-ppt/SKILL.mdskills/morph-ppt/reference/decision-rules.mdskills/morph-ppt/reference/morph-helpers.pyskills/morph-ppt/reference/morph-helpers.shskills/morph-ppt/reference/pptx-design.mdskills/morph-ppt/reference/styles/INDEX.mdskills/morph-ppt/reference/styles/bw--brutalist-raw/build.shskills/morph-ppt/reference/styles/bw--brutalist-raw/style.mdskills/morph-ppt/reference/styles/bw--mono-line/build.shskills/morph-ppt/reference/styles/bw--mono-line/style.mdskills/morph-ppt/reference/styles/bw--swiss-bauhaus/build.shskills/morph-ppt/reference/styles/bw--swiss-bauhaus/style.mdskills/morph-ppt/reference/styles/bw--swiss-system/style.mdskills/morph-ppt/reference/styles/dark--architectural-plan/build.shskills/morph-ppt/reference/styles/dark--architectural-plan/style.mdskills/morph-ppt/reference/styles/dark--aurora-softedge/style.mdskills/morph-ppt/reference/styles/dark--blueprint-grid/build.shskills/morph-ppt/reference/styles/dark--blueprint-grid/style.mdskills/morph-ppt/reference/styles/dark--circle-digital/build.shskills/morph-ppt/reference/styles/dark--circle-digital/style.mdskills/morph-ppt/reference/styles/dark--cosmic-neon/build.shskills/morph-ppt/reference/styles/dark--cosmic-neon/style.mdskills/morph-ppt/reference/styles/dark--cyber-future/build.shskills/morph-ppt/reference/styles/dark--cyber-future/style.mdskills/morph-ppt/reference/styles/dark--diagonal-cut/build.shskills/morph-ppt/reference/styles/dark--diagonal-cut/style.mdskills/morph-ppt/reference/styles/dark--editorial-story/build.shskills/morph-ppt/reference/styles/dark--editorial-story/style.mdskills/morph-ppt/reference/styles/dark--investor-pitch/build.shskills/morph-ppt/reference/styles/dark--investor-pitch/style.mdskills/morph-ppt/reference/styles/dark--liquid-flow/build.shskills/morph-ppt/reference/styles/dark--liquid-flow/style.mdskills/morph-ppt/reference/styles/dark--luxury-minimal/build.shskills/morph-ppt/reference/styles/dark--luxury-minimal/style.mdskills/morph-ppt/reference/styles/dark--midnight-blueprint/style.mdskills/morph-ppt/reference/styles/dark--neon-productivity/build.shskills/morph-ppt/reference/styles/dark--neon-productivity/style.mdskills/morph-ppt/reference/styles/dark--obsidian-amber/style.mdskills/morph-ppt/reference/styles/dark--premium-navy/build.shskills/morph-ppt/reference/styles/dark--premium-navy/style.mdskills/morph-ppt/reference/styles/dark--sage-grain/style.mdskills/morph-ppt/reference/styles/dark--space-odyssey/build.shskills/morph-ppt/reference/styles/dark--space-odyssey/style.mdskills/morph-ppt/reference/styles/dark--spotlight-stage/build.shskills/morph-ppt/reference/styles/dark--spotlight-stage/style.mdskills/morph-ppt/reference/styles/dark--velvet-rose/style.mdskills/morph-ppt/reference/styles/light--bold-type/build.shskills/morph-ppt/reference/styles/light--bold-type/style.mdskills/morph-ppt/reference/styles/light--firmwise-saas/style.mdskills/morph-ppt/reference/styles/light--fluid-gradient/style.mdskills/morph-ppt/reference/styles/light--glassmorphism-vc/style.mdskills/morph-ppt/reference/styles/light--isometric-clean/build.shskills/morph-ppt/reference/styles/light--isometric-clean/style.mdskills/morph-ppt/reference/styles/light--minimal-corporate/style.mdskills/morph-ppt/reference/styles/light--minimal-product/build.shskills/morph-ppt/reference/styles/light--minimal-product/style.mdskills/morph-ppt/reference/styles/light--project-proposal/style.mdskills/morph-ppt/reference/styles/light--spring-launch/style.mdskills/morph-ppt/reference/styles/light--training-interactive/style.mdskills/morph-ppt/reference/styles/light--watercolor-wash/build.shskills/morph-ppt/reference/styles/light--watercolor-wash/style.mdskills/morph-ppt/reference/styles/mixed--bauhaus-blocks/style.mdskills/morph-ppt/reference/styles/mixed--chromatic-aberration/style.mdskills/morph-ppt/reference/styles/mixed--duotone-split/build.shskills/morph-ppt/reference/styles/mixed--duotone-split/style.mdskills/morph-ppt/reference/styles/mixed--spectral-grid/style.mdskills/morph-ppt/reference/styles/vivid--bauhaus-electric/style.mdskills/morph-ppt/reference/styles/vivid--candy-stripe/build.shskills/morph-ppt/reference/styles/vivid--candy-stripe/style.mdskills/morph-ppt/reference/styles/vivid--energy-neon/style.mdskills/morph-ppt/reference/styles/vivid--pink-editorial/style.mdskills/morph-ppt/reference/styles/vivid--playful-marketing/build.shskills/morph-ppt/reference/styles/vivid--playful-marketing/style.mdskills/morph-ppt/reference/styles/warm--bloom-academy/style.mdskills/morph-ppt/reference/styles/warm--brand-refresh/build.shskills/morph-ppt/reference/styles/warm--brand-refresh/style.mdskills/morph-ppt/reference/styles/warm--coral-culture/style.mdskills/morph-ppt/reference/styles/warm--earth-organic/build.shskills/morph-ppt/reference/styles/warm--earth-organic/style.mdskills/morph-ppt/reference/styles/warm--monument-editorial/style.mdskills/morph-ppt/reference/styles/warm--playful-organic/build.shskills/morph-ppt/reference/styles/warm--playful-organic/style.mdskills/morph-ppt/reference/styles/warm--sunset-mosaic/style.mdskills/morph-ppt/reference/styles/warm--vital-bloom/style.mdskills/office-docx/SKILL.mdskills/office-pdf/SKILL.mdskills/office-pptx/SKILL.mdskills/office-xlsx/SKILL.mdskills/officecli-academic-paper/SKILL.mdskills/officecli-data-dashboard/SKILL.mdskills/officecli-docx/SKILL.mdskills/officecli-financial-model/SKILL.mdskills/officecli-pitch-deck/SKILL.mdskills/officecli-pptx/SKILL.mdskills/officecli-word-form/SKILL.mdskills/officecli-xlsx/SKILL.md
💤 Files with no reviewable changes (98)
- skills/morph-ppt/reference/styles/light--firmwise-saas/style.md
- skills/morph-ppt/reference/styles/light--isometric-clean/style.md
- skills/morph-ppt/reference/styles/bw--swiss-system/style.md
- skills/morph-ppt/reference/styles/dark--spotlight-stage/style.md
- skills/morph-ppt/reference/styles/light--bold-type/style.md
- skills/morph-ppt/reference/styles/bw--mono-line/style.md
- skills/morph-ppt/reference/styles/light--minimal-corporate/style.md
- skills/morph-ppt/reference/styles/dark--premium-navy/style.md
- skills/morph-ppt/reference/styles/dark--luxury-minimal/style.md
- packages/desktop-electron/scripts/prepare-officecli.test.ts
- skills/morph-ppt/reference/styles/light--training-interactive/style.md
- skills/morph-ppt/reference/styles/warm--brand-refresh/style.md
- skills/morph-ppt/reference/styles/warm--monument-editorial/style.md
- skills/morph-ppt/reference/styles/dark--velvet-rose/style.md
- skills/morph-ppt/reference/styles/vivid--bauhaus-electric/style.md
- skills/morph-ppt/reference/styles/dark--neon-productivity/style.md
- skills/morph-ppt/reference/styles/dark--cosmic-neon/build.sh
- skills/morph-ppt/reference/styles/mixed--duotone-split/build.sh
- skills/morph-ppt/reference/styles/light--glassmorphism-vc/style.md
- skills/morph-ppt/reference/styles/dark--aurora-softedge/style.md
- skills/morph-ppt/reference/styles/dark--editorial-story/style.md
- skills/morph-ppt/reference/styles/dark--cosmic-neon/style.md
- skills/morph-ppt/reference/styles/vivid--energy-neon/style.md
- skills/morph-ppt/reference/styles/dark--liquid-flow/style.md
- skills/morph-ppt/reference/styles/mixed--chromatic-aberration/style.md
- skills/morph-ppt/reference/styles/warm--coral-culture/style.md
- skills/morph-ppt/reference/styles/light--isometric-clean/build.sh
- skills/morph-ppt/reference/styles/dark--neon-productivity/build.sh
- skills/morph-ppt/reference/styles/vivid--playful-marketing/style.md
- packages/opencode/test/tool/shell-env-source.test.ts
- skills/morph-ppt/reference/styles/warm--playful-organic/build.sh
- skills/morph-ppt/reference/styles/light--watercolor-wash/style.md
- skills/morph-ppt/reference/decision-rules.md
- skills/morph-ppt/reference/styles/mixed--spectral-grid/style.md
- skills/morph-ppt/reference/styles/vivid--pink-editorial/style.md
- skills/morph-ppt/reference/styles/dark--cyber-future/style.md
- skills/morph-ppt/reference/styles/dark--spotlight-stage/build.sh
- skills/morph-ppt/reference/styles/INDEX.md
- packages/opencode/test/github/officecli-bump-workflow.test.ts
- skills/morph-ppt/reference/styles/dark--space-odyssey/style.md
- skills/morph-ppt/reference/styles/bw--swiss-bauhaus/build.sh
- skills/morph-ppt/reference/styles/light--minimal-product/build.sh
- skills/morph-ppt/reference/styles/dark--obsidian-amber/style.md
- skills/morph-ppt/reference/styles/warm--earth-organic/style.md
- skills/morph-ppt/reference/styles/bw--brutalist-raw/build.sh
- skills/morph-ppt/reference/styles/light--watercolor-wash/build.sh
- skills/morph-ppt/reference/styles/dark--diagonal-cut/style.md
- skills/morph-ppt/reference/styles/bw--swiss-bauhaus/style.md
- skills/morph-ppt/reference/styles/light--minimal-product/style.md
- skills/morph-ppt/reference/pptx-design.md
- skills/morph-ppt/reference/styles/mixed--bauhaus-blocks/style.md
- skills/morph-ppt/reference/styles/mixed--duotone-split/style.md
- skills/morph-ppt/reference/styles/dark--blueprint-grid/style.md
- packages/desktop-electron/bundled-tools.json
- skills/morph-ppt/reference/styles/light--fluid-gradient/style.md
- skills/morph-ppt/reference/styles/dark--architectural-plan/style.md
- .github/workflows/officecli-bump.yml
- skills/morph-ppt/reference/styles/warm--bloom-academy/style.md
- skills/morph-ppt/reference/styles/dark--circle-digital/style.md
- skills/morph-ppt-3d/SKILL.md
- skills/morph-ppt/reference/styles/vivid--candy-stripe/style.md
- skills/morph-ppt/reference/styles/dark--premium-navy/build.sh
- skills/morph-ppt/SKILL.md
- packages/desktop-electron/scripts/sync-officecli-skills.test.ts
- skills/morph-ppt/reference/styles/vivid--playful-marketing/build.sh
- skills/morph-ppt/reference/styles/dark--space-odyssey/build.sh
- skills/morph-ppt/reference/styles/bw--mono-line/build.sh
- skills/morph-ppt/reference/styles/light--project-proposal/style.md
- skills/morph-ppt/reference/styles/dark--blueprint-grid/build.sh
- skills/morph-ppt/reference/styles/dark--midnight-blueprint/style.md
- skills/morph-ppt/reference/styles/bw--brutalist-raw/style.md
- skills/morph-ppt/reference/styles/light--bold-type/build.sh
- skills/morph-ppt/reference/styles/light--spring-launch/style.md
- skills/morph-ppt/reference/styles/dark--circle-digital/build.sh
- skills/morph-ppt/reference/styles/dark--liquid-flow/build.sh
- packages/opencode/test/tool/shell-office-artifacts.test.ts
- skills/morph-ppt/reference/styles/dark--luxury-minimal/build.sh
- skills/morph-ppt/reference/styles/dark--investor-pitch/build.sh
- packages/desktop-electron/scripts/sync-officecli-skills.ts
- skills/morph-ppt/reference/styles/dark--sage-grain/style.md
- skills/morph-ppt/reference/styles/dark--cyber-future/build.sh
- packages/desktop-electron/package.json
- skills/morph-ppt/reference/styles/vivid--candy-stripe/build.sh
- skills/morph-ppt/reference/styles/dark--diagonal-cut/build.sh
- skills/morph-ppt/reference/styles/dark--architectural-plan/build.sh
- skills/morph-ppt/reference/styles/dark--editorial-story/build.sh
- skills/morph-ppt/reference/styles/warm--brand-refresh/build.sh
- skills/morph-ppt/reference/styles/dark--investor-pitch/style.md
- packages/desktop-electron/scripts/prepare-officecli.ts
- .github/workflows/build.yml
- skills/morph-ppt/reference/styles/warm--earth-organic/build.sh
- skills/morph-ppt/reference/morph-helpers.py
- packages/opencode/src/session/prompt.ts
- packages/opencode/src/tool/shell.ts
- .github/workflows/desktop-smoke.yml
- packages/opencode/test/github/bun-version-workflow.test.ts
- packages/opencode/test/tool/shell.test.ts
- skills/morph-ppt/reference/morph-helpers.sh
The prior heuristic flagged any python/uv command containing an office extension as a write, so parse commands like `uv run python read_docx.py input.docx` recorded false uncaptured-change markers, and quoted outputs like `-o "report.docx"` were missed (words came from quote-stripped text). Instead match the raw command for an -o/--out/--output/--outfile flag naming an office output path, so read/parse commands stay read-only and quoted outputs are caught. Surfaced by Codex round-2 review.
office-route-eval and ppt-quality-eval were one-off harnesses comparing the officecli route against the native python routes. With officecli fully retired they can no longer run — office:eval schedules the removed officecli binary and ppt:eval copies a deleted morph-ppt template fixture — and the routing decision they informed lives in the decision doc. Remove both harnesses and their package scripts. officecli is now gone repo-wide except the skill.test.ts removal guard. Surfaced by Codex round-2 review.
The raw-command regex matched -o/--out inside quoted literals, so read-only commands like `echo "usage: -o report.docx"` and `grep "-o report.docx" file` were flagged as writes and triggered office auto-discovery (recording a false uncaptured-change signal). Detect the flag as a real shell token via tokenWords, which respects quoting: quoted output paths with spaces are still captured, but office-looking text inside an outer quote is not.
Drive the real isLikelyWriteCommand through the orchestrator so a real `-o <office file>` generator with no declared expected_outputs flows heuristic -> auto-discovery -> captured binary artifact, replacing the coverage the removed OfficeCLI E2E gave the office output path.
office-pptx only documented SVG-authored generation, so routing an existing-deck read/edit request there left no instructions, while pawwork.txt and the sibling docx/xlsx skills promise read+parse. Add a python-pptx read/edit section and broaden the description, matching office-docx/xlsx.
The description both claimed "any PDF request" and gated generation on a print entry point that no tool currently exposes. Scope parsing as the unconditional path and mark generation best-effort with graceful degradation, so the promoted default route does not overclaim generation.
Round-4 review of the -o output-flag heuristic surfaced three capture bugs: - The parsed -o path was discarded and capture fell back to a cwd scan, so a nested / `../` target (or one lost to discovery overflow) went unrecorded even though the command named it. Carry parsed output paths into artifact tracking. - The -o check fired on any tool, so `grep -o report.docx file` (grep's only-matching flag) was read as a write. Gate detection to python / uv generators. - .pdf counted toward the discovery capture budget, so a folder of ambient PDFs overflowed the scan and dropped real .docx/.xlsx/.pptx captures. Exclude .pdf from the cwd scan (PDF generation is unwired; an explicit -o out.pdf is still tracked and .pdf still reads as a binary artifact).
…ve()
Round-5 review found two capture bugs in the -o backstop:
- Parsed -o outputs were fed through the auto-discovery path, which always appends
an uncaptured marker even after the exact file is recorded, so a normal
`... -o deck.pptx` turn was reported mixed/uncaptured despite full capture. Treat
parsed outputs like declared expected_outputs: exact, shown regardless of change,
never flagged uncaptured, and captured without a cwd scan.
- docx/xlsx generation saves via `doc.save("out.docx")` with no -o flag, so the
deliverable was neither captured nor marked uncaptured when expected_outputs was
omitted. officeOutputPaths now also recognizes the python `.save(...)` call.
Also drops the now-dead Segment.delimiter field left over from the removed OfficeCLI
batch parsing.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
packages/opencode/test/tool/shell-artifact-orchestrator.test.ts (1)
385-397: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the repo’s Effect test runner instead of manual
Effect.runPromise.These tests exercise an Effect-based workflow, so wrap them with the file’s
testEffect(...).live/it.livepattern rather than manually running the Effect in each test. As per coding guidelines, tests that exercise Effect services or Effect-based workflows should usetestEffect(...); based on learnings, tool tests underpackages/opencode/test/tool/should usetestEffect(...).live/it.livefor tool initialization/execution scenarios.Also applies to: 427-439, 473-485, 515-527
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/opencode/test/tool/shell-artifact-orchestrator.test.ts` around lines 385 - 397, The tests in orchestrateArtifacts are manually invoking Effect workflows with Effect.runPromise, but they should use the repo’s Effect test harness instead. Update the affected test cases in shell-artifact-orchestrator.test.ts to follow the existing testEffect(...).live / it.live pattern used for Effect-based tool initialization and execution, and keep the assertions inside that Effect-aware test wrapper.Sources: Coding guidelines, Learnings
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/opencode/src/tool/shell-artifact-orchestrator.ts`:
- Around line 89-116: The parsed Office output path is being treated as exact
even when the command changes directories, which can cause artifacts to be
missed. In shell-artifact-orchestrator, update the flow around
parseOfficeOutputs, resolveTrackedInput, and shouldAutoDiscover so relative
parsed outputs are resolved against the command’s active shell cwd at the point
of generation, not the original cwd. Detect cwd-changing segments like cd before
the generator, and if a relative parsed output depends on that changed
directory, either adjust the resolution or allow cwd discovery instead of
suppressing it.
In `@packages/opencode/src/tool/shell-office-artifacts.ts`:
- Around line 142-147: The `.save()` extraction in `shell-office-artifacts.ts`
is too broad because `isGeneratorCommand` is command-wide, so non-generator
segments can contribute phantom artifacts. Update the parsing logic around the
`matchAll` loop so `.save()` is only extracted from the actual generator
segment(s), not from arbitrary later segments like `node -e` or `ruby -e`, and
keep the existing `isOfficeOutputPath`/`isStaticOutputValue` checks intact. Use
the `isGeneratorCommand`, `saveScanSkipHeads`, and `commandHead(words)` gate as
the place to narrow scope before pushing into `paths`.
- Around line 87-89: The isStaticOutputValue helper is too permissive because it
only rejects $, backticks, *, and ?, but still treats shell-expanded literals
like brace expansion, character classes, and leading tilde as exact output.
Update isStaticOutputValue in shell-office-artifacts.ts to reject any value that
could be expanded by the shell before exact-output handling, including brace
patterns, bracket patterns, and ~-prefixed paths, so downstream discovery
doesn’t miss the real file.
---
Nitpick comments:
In `@packages/opencode/test/tool/shell-artifact-orchestrator.test.ts`:
- Around line 385-397: The tests in orchestrateArtifacts are manually invoking
Effect workflows with Effect.runPromise, but they should use the repo’s Effect
test harness instead. Update the affected test cases in
shell-artifact-orchestrator.test.ts to follow the existing testEffect(...).live
/ it.live pattern used for Effect-based tool initialization and execution, and
keep the assertions inside that Effect-aware test wrapper.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: c34cd863-f72c-491a-ac79-1006936510f2
📒 Files selected for processing (5)
packages/opencode/src/tool/shell-artifact-orchestrator.tspackages/opencode/src/tool/shell-office-artifacts.tspackages/opencode/src/tool/shell.tspackages/opencode/test/tool/shell-artifact-orchestrator.test.tspackages/opencode/test/tool/shell-office-artifacts.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/opencode/test/tool/shell-office-artifacts.test.ts
- packages/opencode/src/tool/shell.ts
Codex R8 flagged two capture gaps in the native office route: 1. isStaticOutputValue missed Windows cmd variables — `-o "%OUT%.docx"` was tracked as the literal `%OUT%.docx` (never expanded), so a parsed output existed, discovery was skipped, and the real file was lost. Reject `%` alongside the POSIX/glob metacharacters. 2. The no-exact-output fallback keyed on "is a python/uv generator", so a read-only `uv run pytest` or `uv run python read_docx.py input.docx` in an office-heavy workspace triggered a cwd scan and, on discovery overflow, a false uncaptured marker. Replace hasOfficeGenerator with hasOfficeOutputIntent: the fallback fires only when the command NAMED an office output it couldn't resolve to an exact path (a dynamic `-o "$OUT.docx"` / `%OUT%.docx`), which still captures the real dynamic file while leaving read-only invocations untouched. A bare generator whose only write is an internal doc.save() is captured via the model-declared expected_outputs, the instructed primary path.
.save(r'out.docx') / .save(f'report.docx') were missed because the regex expected a quote immediately after an optional backslash. Allow the r/b/u/f python string prefixes so raw and f-string save calls are captured too.
Codex R9 / Pi R9 flagged two more backstop gaps: 1. An output flag holding the whole filename in a variable — `-o "$OUT"` — has no visible office extension, so intent detection returned false and the cwd scan was skipped. Trigger the scan when the value is a discoverable office extension OR a dynamic value whose extension is hidden in a variable. Align intent with what discovery can find (drop .pdf, which discovery excludes) so a dynamic .pdf no longer triggers a futile scan. 2. nonOfficeGeneratorText dropped the ENTIRE generator segment, discarding a redirect attached to it — `uv run python analyze.py > results.txt` or `... -o report.docx > log.txt` lost the redirected write, so it was neither scanned nor flagged uncaptured. Preserve write-redirections (quote-aware, so a `>` inside a python string is not mistaken for one) while still dropping the generator command whose -o/.save is captured exactly. Also match `.save (` with whitespace before the paren.
Two edge cases in the undeclared-office-write backstop, found in review:
- A dynamic office output the command clearly intended (`-o "$OUT.docx"`)
that the cwd scan cannot find — it expanded outside cwd or deeper than
the scan reaches — silently vanished from the audit. Now flag the turn
uncaptured when `dynamicOfficeOutput` intent fired but no office artifact
actually changed, so an attempted write is never lost.
- `nonOfficeGeneratorText` split a command on newlines and stripped every
generator segment independently. A heredoc body line `prs.save('deck.pptx')`
was kept as its own segment and re-read as a write, double-flagging a
purely-captured office deck as uncaptured. It also stripped `python setup.py
build`, hiding a real non-office write. Now only segments whose write IS a
captured office output (static -o/.save, dynamic office intent, or a
generator's heredoc .save body) are dropped; a python segment that named no
office output is kept so the write heuristic still judges it.
…options Two more office-capture gaps found in review: - A command mixing an exact office output with a dynamic one (`... -o a.docx && ... -o "$OUT.docx"`) suppressed the cwd scan for the dynamic sibling: the `parsed.length === 0` gate fired only when NO exact output existed. hasOfficeOutputIntent now reports only UNRESOLVED outputs (it excludes the ones officeOutputPaths captures exactly, via a shared isExactlyCapturableOutput helper), so the mixed command still scans for the dynamic one. The uncaptured decision now clears only on a DISCOVERED (non-parsed) office change, so an exact sibling changing cannot mask a lost dynamic output. - uv permits global options before the `run` subcommand (`uv --directory work run python build.py -o report.docx`), which pushed `run` past the immediate next token and made isOfficeGeneratorSegment read the command as non-python / read-only. It now also detects a `run python` pair anywhere in a uv invocation.
Follow-ups to the uv-global-options handling: - `uv --directory <dir>` changes the working directory before running, so a relative `-o report.docx` names `<dir>/report.docx`, not the shell cwd. The exact parser was still tracking the phantom cwd path (and, being an exact parse, skipping discovery). A new uvChangesDirectory() marks a relative output unresolved when the segment carries `--directory`, deferring to the discovery backstop; an absolute output and `--project` (which does not chdir) stay exactly captured. - Unify the two uv branches in isOfficeGeneratorSegment: the immediate-next check accepted `uv run <anything>` while the global-options path required `run python`, so `uv run pytest` and `uv --offline run pytest` classified differently. Both now key on the presence of the `run` subcommand token, which also keeps `uv run script.py` (bare script, no explicit python) recognized. The office-output value gates still prevent a non-office `uv run <tool>` from producing a phantom capture.
Two more uv --directory edge cases from review:
- `--directory` is valid both as a global option (`uv --directory x run ...`)
and as a `uv run` option (`uv run --directory x python ...`); both chdir.
uvChangesDirectory() broke at the `run` token and missed the latter. It now
scans up to the executed python command, so `--directory` in either position
is detected while a `--directory` among the script's own args (after python)
is correctly ignored.
- A heredoc `.save('out.docx')` sits in a later newline-split segment with no
uv prefix, so its relativeUnresolved was computed without the generator's
--directory. A `uv --directory` now propagates to the following segments (it
sets the persistent cwd-changed flag, like `cd`), so a heredoc body's save
correctly defers to discovery under work/ instead of tracking a phantom cwd
path.
…dows .save Three office-capture gaps from review: - uv --directory over-propagated: the persistent cwd flag leaked the chdir across `&&`/`;` into the next command (`uv --directory work run ... && uv run python b.py -o b.docx` wrongly deferred b.docx to discovery). Track two separate scopes: a persistent `cd` (crosses separators) and a command-scoped `uv --directory` that carries into a heredoc body (newline continuation) but resets at the next command separator. commandSegments now records each segment's trailing delimiter to distinguish the two. - Shell line continuations (`\<newline>`) split a single generator into two segments, orphaning the `-o` flag. stripLineContinuations() collapses them (quote-aware: literal inside single quotes) before segmenting. - A `.save(r"C:\dir\out.docx")` Windows path was truncated at `C:` by the capture regex's `[^"'\\]` class, silently losing the artifact. The shared saveOutputValues() helper now allows backslash path separators while still ending at an escaped closing quote, and de-duplicates the three previously copy-pasted .save regexes.
uvChangesDirectory() stopped at the first python-ish token, but in `uv run --python python3 --directory work python build.py -o report.docx` the `python3` is the value of uv's `--python`/`-p` interpreter selector, not the executed command — so the scan broke before reaching `--directory` and tracked a phantom cwd path. A python-ish token preceded by `--python`/`-p` no longer stops the scan, so the later `--directory` is detected and the relative output correctly defers to discovery.
Two more office-capture gaps from review: - A newline separates independent commands too, not just a heredoc body, so scoping `uv --directory` to "newline = continuation" leaked the chdir across `uv --directory ... run <newline> uv run python b.py -o b.docx`. commandSegments is now heredoc-aware: a `<<DELIM ... DELIM` body (including `<<-` and quoted delimiters) stays in one segment, so a newline OUTSIDE a heredoc is a normal command separator. This lets `--directory` be judged per segment with no cross-command propagation — dropping the fragile delimiter/scope tracking. - A cwd-relative static `.pdf` (`cd reports && ... -o report.pdf`) was neither exactly capturable (cwd changed) nor discoverable (.pdf excluded from the cwd scan), so it vanished with no uncaptured mark. A new unresolvedOfficeIntent() treats any unresolved STATIC office path (known filename, incl. .pdf) as intent, so the turn is flagged uncaptured instead of losing the deliverable; a dynamic visible .pdf (`-o "$OUT.pdf"`, no concrete name) still stays out.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/opencode/src/tool/shell-office-artifacts.ts`:
- Around line 22-55: The continuation stripping in stripLineContinuations is
removing backslash-newline sequences inside heredoc bodies, which can break
commandSegments by swallowing the heredoc terminator and merging following
commands. Update the parsing flow in shell-office-artifacts so heredoc spans are
preserved before calling stripLineContinuations, or make stripLineContinuations
skip content inside heredocs while keeping its existing behavior elsewhere.
- Around line 253-265: Update isOfficeGeneratorSegment so that `uv` is only
treated as an office generator when `run` is the actual subcommand immediately
after any global options, not just any token in `rest`; the current
`rest.some(...)` check is too broad and can misclassify commands like `uv pip
install run ...`. Adjust the `commandHead`/`rest` handling in
`isOfficeGeneratorSegment` to validate the first non-option subcommand token is
`run`, keeping the existing `python` and `python3` cases unchanged.
- Around line 88-94: The heredoc delimiter parser in shell-office-artifacts.ts
only scans alphanumeric and underscore characters, so it truncates valid
delimiter words like PY-END and breaks matching of the closing marker. Update
the delimiter parsing logic in the heredoc handling code (the block that builds
delimiter and checks delimiterQuote) to consume the full delimiter word using
the same terminator rules that apply to heredoc tokens, including hyphens and
other valid delimiter characters, so the parsed delimiter matches the closing
marker correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: a6f60cb0-6455-4230-93fa-101fff045df4
📒 Files selected for processing (3)
packages/opencode/src/tool/shell-office-artifacts.tspackages/opencode/test/tool/shell-artifact-orchestrator.test.tspackages/opencode/test/tool/shell-office-artifacts.test.ts
…y redirects isOfficeGeneratorSegment now matches a versioned python interpreter head (python3.12 / python2 via /^python\d/, consistent with isPythonCommandToken) so a direct `python3.12 build.py -o report.docx` is captured instead of silently lost. segmentWriteRedirects skips `<<` heredoc bodies so ordinary python code (`if total > 0:`, SVG/HTML `>` literals) inside a captured generator's heredoc is not misread as a shell redirect and falsely marked as an uncaptured side-effect write.
The R17 heredoc-body skip jumped from `<<` straight to the closing delimiter, swallowing a real redirect on the opener line (`uv run python <<'PY' > log.txt`) so that side-effect write vanished from turn-change auditing. Advance only past the `<<` operator and skip the body at the opener line's newline, so opener-line redirects are still captured while the stdin body is not misread as one.
…etection `... -o report.docx >/dev/null` (or `2>/dev/null`, Windows `>NUL`) discards output — it is not a file write. segmentWriteRedirects now drops null-device targets so silencing a cleanly-captured office generator no longer leaves a phantom redirect that makes isLikelyWriteCommand flag the turn as an uncaptured non-office side effect.
…ubcommand - skipHeredocBody now reads the whole delimiter word (quote-aware) so a valid hyphenated/dotted delimiter (`<<PY-END`, `<<'EOF.1'`) is matched instead of being truncated at the first hyphen, which left the closing marker unmatched and swallowed the rest of the command (hiding trailing side-effect writes). - isOfficeGeneratorSegment treats `uv` as an office generator only when `run` is the actual subcommand, bailing when a different uv subcommand (pip/tool/...) precedes it, so `uv pip install run -o report.docx` is not misclassified. Both from CodeRabbit review of PR #1494.
…iteral % - uvRunsSubcommand now skips value-taking option values (`--directory build`, `--python python3`), so a directory/project name that collides with a uv subcommand name no longer hides the real `run` and drops the office output. - isStaticOutputValue only treats a paired `%NAME%` Windows variable as dynamic, not any lone `%`, so a literal business filename (`Growth 20%.pptx`, `100%.docx`) stays static and is captured exactly. Both from ChatGPT review of PR #1494.
Codex R20 + ChatGPT R20 each surfaced two real gaps in the office artifact-capture path. All four are fixed with regression tests. - Multiple dynamic outputs (`... -o "$A.docx" && ... -o "$B.docx"`): discovering one changed file no longer clears the uncaptured flag for its siblings. `unresolvedOfficeOutputCount` counts the intended dynamic outputs and the audit now requires one discovered file per output before treating them all as captured; `hasOfficeOutputIntent` delegates to it. - Backslash-quoted heredoc delimiter (`<<\PY`): the closing line is `PY`, so the parser strips the quoting backslash instead of reading `\PY` and swallowing the rest of the command as heredoc body. - Unquoted POSIX escaped space in an output path (`-o Quarterly\ Report.docx`): `shellWords` now binds `\<space>`/`\<tab>` into one token so the real filename is captured. Only whitespace is unescaped, so a Windows `C:\out\report.docx` keeps its separators. - Trailing backslash inside a heredoc body (`# \` before the closing delimiter): `stripLineContinuations` is now heredoc-aware (reusing `skipHeredocBody`), so a body-internal `\`-newline is not collapsed into a line continuation that fuses the closing delimiter into the body and hides the following command from the side-effect audit.
One inline ArtifactDeps object in the orchestrator test still set the old `hasOfficeOutputIntent` key after it was renamed to `unresolvedOfficeOutputCount`, breaking `tsgo` typecheck. Update the key so the deps object matches the type.
- uvChangesDirectory now skips every uv value-option's value (not just --python/-p), so a python-like --project value no longer hides a later --directory chdir and mistracks a relative office output as exact. - shellWords unescapes unquoted backslash-escaped shell metacharacters (& ; | ( ) ' ") into literal filename chars; commandSegments no longer splits on an escaped delimiter, so R\&D.docx / report\;q.docx capture the real name instead of a phantom literal-backslash path or a torn segment. Windows-style C:\out\report.docx separators stay literal.
shellWords dropped a backslash before ANY char inside double quotes, so a quoted Windows path `-o "C:\\Users\\me\\deck.pptx"` tokenized to `C:Usersmedeck.pptx` and the office artifact was tracked at the wrong path and lost. POSIX keeps a backslash special inside double quotes only before " \\ $ `; before other chars it is literal. Restrict the unescape to that set so Windows separators survive while an escaped quote in `...save(\"x.docx\")` still resolves. Adds regression tests.
Two parser-completeness fixes surfaced by review: - commandSegments skipped the whole heredoc span at `<<`, burying a command chained on the OPENER line (`uv run python <<'PY'; touch x` / `&& rm y`) inside the captured office segment, so a non-office side-effect write vanished from the audit. Now only the body is skipped: the opener line keeps splitting on ;/&&/|| and the body is re-attached to the generator segment, so the trailing write becomes its own auditable segment while office capture is kept. - uvValueOptions missed several value-taking `uv run` options (--package, --extra, --group, --no-group, --only-group, and more), so a python-shaped value there (`uv run --package python --directory work ...`) stopped the uvChangesDirectory/uvRunsSubcommand scan early and hid a later --directory chdir, mistracking a relative office output as an exact shell-cwd path. Completed and centralized the table as the single maintenance point. Adds regression tests for both.
Windows PowerShell 5.1 has no `&&`, so the shell-tool prompt instructs agents
to chain dependent commands as `cmd1; if ($?) { cmd2 }`. commandSegments never
descended into the `{ }` block, so a generator wrapped in it
(`... ; if ($?) { uv run python build.py -o report.docx }`) had segment head
`if`, was not recognized as an office generator, and its deliverable was neither
captured nor flagged uncaptured unless expected_outputs was set.
Treat a STANDALONE `{`/`}` (whitespace/`)`/`;`-bounded) as a command separator so
the wrapped generator becomes its own segment with the real command as its head.
A brace glued to `$` (${VAR}), `@` (hashtable), or a word (brace-expansion
`report{1,2}.docx`) is left intact. Also unwraps a bash `{ cmd; }` group. Adds
regression tests.
…kens uvChangesDirectory only stopped at python/pythonN/*.py tokens, so a `uv run` that executes a console script (`uv run render-pdf --directory inputs -o report.pdf`) scanned past the command and read the script's own `--directory` arg as uv's chdir. The relative output was then demoted from exact capture to unresolved; since discovery excludes .pdf, a real cwd `report.pdf` produced only an uncaptured mark with no downloadable artifact (and .docx/.xlsx/.pptx lost exact-capture overflow protection). Rewrite uvChangesDirectory as a uv-run option parser: skip uv global options to `run`, then skip run options and their values until the first positional (the executed command) or `--`; a `--directory` beyond that point is the command's own argument. Handles console-script commands, not just python. Drops the now-unused isPythonCommandToken. Adds regression tests.
…i/-f aliases The artifact-capture cwd backstop parses uv run options to find where the executed COMMAND starts, so a value-option value (e.g. `-w python-docx`) is not mistaken for the command and does not hide a later `--directory` chdir. The table was missing the short aliases -w/-i/-f and several long value options, so `uv run -w pkg --directory work python make.py -o report.docx` mis-captured the relative output as an exact shell-cwd file. Sync uvValueOptions to `uv run --help` (uv 0.11.28) as the source of truth: add -w/-i/-f plus --allow-insecure-host, --no-extra, --upgrade-group, --exclude-newer-package, --config-settings-package, --no-editable-package, --no-sources-package. Future uv versions adding a value option is a known limitation, documented at the table; resync on uv bump. Add -w/-i/-f regression tests (discovery when hiding --directory, exact when not).
Summary
Full retirement of the bundled OfficeCLI in favor of the native python
office-*skills (office-docx/office-xlsx/office-pptx/office-pdf). This is the switchover that follows PR3's dark-launch (#1491).The change lands as four atomic concerns, one per commit, plus follow-up commits that harden the shell artifact-capture parser in response to the multi-reviewer rounds:
office-*from preview to default in the corepawwork.txtguidance and each SKILL.md; delete the upstream-syncedofficecli-*skill bundle and the coupledmorph-ppt/morph-ppt-3dskills (which cannot run without the officecli binary).officeclibundled-tool entry,prepare-officecli/sync-officecli-skills(+ tests), theofficecli-bumpauto-sync workflow, and the Prepare OfficeCLI steps / bundle smoke assertions inbuild.ymlanddesktop-smoke.yml. Retarget the release and workflow contract tests to the remaining bundled tool,uv.OFFICECLI_SKIP_UPDATEwiring), keeping only the generic write-detection helpers theoffice-*path uses via declared outputs and auto-discovery.llms.txt/ THIRD_PARTY_NOTICES while keeping the "handles Office files locally" capability claim.Because commit 3 makes the generic shell artifact-capture path the sole route for office deliverables, the review rounds focused on its parser edge cases. Follow-up commits close the gaps that surfaced: versioned
python3.12generators, heredoc body vs. opener-line redirects, null-device redirects, hyphenated and backslash-quoted heredoc delimiters (<<PY-END,<<\PY),uv runsubcommand gating that skips option values (--directory build), literal%filenames vs.%VAR%, unquoted POSIX escaped-space output paths (-o Quarterly\ Report.docx) while preserving WindowsC:\out\report.docxseparators, per-output counting so capturing one of several dynamic outputs cannot mask a sibling that escaped the cwd scan, and a heredoc-aware line-continuation strip so a trailing\inside a heredoc body cannot swallow the following command from the side-effect audit. Each fix ships with a regression test.Why
The
office-*skills reach the same Word/Excel/PPT capability with thin, native python tooling (python-docx, openpyxl, an svg→pptx converter, bundled Chromium printToPDF) and no vendored binary or upstream sync contract. Keeping officecli in parallel is exactly the "stand up a parallel system" debt the project guards against. This is a deliberate, accepted regression: the ~5,300 lines of themed design knowledge that shipped insideofficecli-pitch-deck/financial-model/academic-paper/word-form/data-dashboardgo away with the bundle. The office-route and ppt-quality eval harnesses underpackages/opencode/script/are kept intact as the evidence base for choosing native over officecli.Related Issue
#1273
Human Review Status
Pending
Review Focus
office-*declared-output and auto-discovery paths now that the officecli-specific inference is gone, and that the parser edge-case fixes hold together (heredoc bounds,uv/python generator detection, dynamic-output counting, escaped-space paths).officecliare intentional (decision evidence), not a missed removal.Risk Notes
build.ymlanddesktop-smoke.ymlno longer prepare or smoke-check an officecli binary;uvremains bundled and its Prepare step / release contract are unchanged in behavior.office-pdfdegrades gracefully where printToPDF isn't wired; that wiring is a separate follow-up PR, out of scope here.How To Verify
skills-surface snap fixture: rename only (synthetic seed names, unchanged rendering logic and DOM assertions) — no product UI change, no snap regen needed.
Screenshots or Recordings
No product UI change. Site comparison-table cell swaps the "OfficeCLI" label for the same checkmark pattern the other capability rows already use.
Summary by CodeRabbit
office-*skill naming.uvinstead.