Skip to content

feat(skills): dark-launch office document-generation skills (#1273 PR3) - #1491

Merged
Astro-Han merged 8 commits into
devfrom
feat/1273-office-skills-bundle
Jul 8, 2026
Merged

feat(skills): dark-launch office document-generation skills (#1273 PR3)#1491
Astro-Han merged 8 commits into
devfrom
feat/1273-office-skills-bundle

Conversation

@Astro-Han

@Astro-Han Astro-Han commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Summary

Issue #1273 productization, PR 3 of 4. Bundles the office document-generation skills into the product as a dark launch — the skills ship, are discoverable, and load at runtime, but no default routing/entry is changed and no officecli code is removed (the switch is PR 4).

Four new skills under repo-root skills/ (ships as electron extraResources, scanned by the builtin skill loader, pattern */SKILL.md):

Skill Path Engine
office-pptx skills/office-pptx/ vendored MIT svg_to_pptx (SVG per slide → native editable PPTX)
office-xlsx skills/office-xlsx/ openpyxl
office-docx skills/office-docx/ python-docx
office-pdf skills/office-pdf/ generate via bundled Chromium printToPDF; parse via pdfplumber/pypdf

The PPT skill is productized from codex/i1273-office-eval-baseline: same vendored converter and machine gates, SKILL.md reworded from eval language to a product flow, eval SVG_PPTX_SCRIPT env var replaced by stable in-skill script paths. Upstream LICENSE and VENDORED.md provenance preserved.

Includes one tiny runtime change: packages/opencode/src/tool/skill.ts now prints the skill base directory as a plain filesystem path in addition to the existing file:// URL line (the URL line and its test assertion are unchanged). Bundled skills reference that path in shell commands; the URL form alone broke that contract.

Dark launch — mechanism and known limitation

Skill selection is description-driven: the system prompt advertises every skill with a description and the model self-selects. Each new skill's description is prefixed PREVIEW / dark-launched … NOT the default … keep using officecli-*. Naming is office-* (not officecli-*/morph-ppt*), so the officecli sync/prune script ignores these dirs and the skill-test scope-drift guard does not count them.

Known limitation (explicit, also stated at the top of each SKILL.md): the preview status is enforced only by description text — there is no hard runtime switch, and the four skills appear in the /skills user page like any other skill. Evaluated hard-hide options: (a) a preview frontmatter flag filtered in Skill.available/Skill.fmt plus the app skills page — touches the skill Info schema, system prompt assembly, UI, and their tests; (b) dropping description — hides from the model prompt but makes the route undiscoverable and still shows in the UI. Both exceed this PR's scope; the hard on/off switch belongs to PR 4 with the routing change.

Contract (aligned with PR 2)

Each skill assumes only that:

  • uv is already on the execution environment's PATH.
  • Package-mirror environment variables are already injected by the runtime; the skill never configures the mirror itself.

Every SKILL.md has an explicit uv-missing error contract: if uv --version fails, stop and report an environment error; never fall back to system pip / officecli / an AGPL library. All Python in every skill runs through uv run — including the stdlib-only gates (Windows packaging does not guarantee a python3 binary; uv is the provisioned runtime). office-pdf bans PyMuPDF / fitz (AGPL) outright; allowed parsers are pdfplumber (MIT) and pypdf (BSD), generation uses the bundled Chromium only.

SKILL_DIR contract: SKILL.md instructs the model to use the new plain-filesystem-path line from the skill tool output (never the file:// URL; with a strip-prefix fallback if only the URL is visible).

Key disciplines (machine-check over model judgement)

  • office-pptx: viewBox="0 0 1280 720"; px font floor (title ≥ 60px / body ≥ 24px, title ≥ 2× body); per-line character budget; speaker-note sidecars; native chart via data-pptx-native + JSON metadata; embedded images. Two gates that must print OK, both via uv run: check_text_budget.py (pre-convert; tolerates 60px-style unit suffixes) and check_pptx_assets.py (pre-deliver; slide/notes/chart/media counts plus minimal artifact-summary.json schema: renderer string + non-empty slides array).
  • office-xlsx: real formulas (not baked values), explicit number formats/fonts, native charts, formula-injection rule (user data starting with =/+/-/@ must be force-stored as text; links via cell.hyperlink, never HYPERLINK()). check_xlsx.py gate counts charts from xl/charts/chart*.xml package parts (no reliance on openpyxl's private _charts read-back) and FAILs on injection-style formulas (HYPERLINK/WEBSERVICE/IMPORT*/DDE patterns).
  • office-docx: real Heading styles (not bold body text), explicit fonts, native tables; check_docx.py gate.
  • office-pdf: print-CSS HTML → bundled Chromium; parse via pdfplumber or pypdf (both pinned for offline resolution, one per task suffices); AGPL ban.

Testing evidence

  • office-pptx end-to-end: text-budget gate caught an over-long title (FAIL→OK after shortening); converter produced 3 slides / 2 notes / 1 native chart XML / 1 embedded media; check_pptx_assets.py (via uv run) verified FAIL on missing/invalid artifact-summary.json and OK on a valid deck. Unit-suffixed x="80px" font-size="60px" no longer tracebacks.
  • check_xlsx.py matrix: OK with formula+chart; FAIL on injected =HYPERLINK(...) formula; OK when the same user string is force-stored as text (data_type="s"); FAIL on --require-formula with hard-coded values. Chart round-trip verified for bar/line/pie/area/scatter on openpyxl 3.1.5 before switching to package-part counting.
  • check_docx.py: OK and FAIL paths on constructed good/bad documents.
  • office-pdf parse: pypdf reads a generated PDF; pdfplumber imports (PDFium/pypdfium2 — BSD/Apache, not AGPL).
  • bun test test/tool/skill.test.ts test/skill/skill.test.ts → 21 pass (includes new plain-path assertion and the test scanning the real repo skills/ dir).
  • bun test scripts/sync-officecli-skills.test.ts → 25 pass.
  • packages/opencode bun run typecheck (tsgo) → clean.
  • opencode debug skill lists all four office-* skills next to the untouched officecli-* skills with PREVIEW descriptions.

Not in this PR

  • Flipping default routing / removing officecli, and the hard preview on/off switch (both PR 4).
  • Wiring a Chromium printToPDF tool: no PDF/print tool is exposed yet, so office-pdf's generation path documents the intended bundled-Chromium CDP mechanism and instructs the model to report unavailability rather than shell out to an unbundled browser. The parse path is fully usable today.

Summary by CodeRabbit

  • New Features

    • Added preview support for creating native Word, PowerPoint, and Excel files from project assets.
    • Improved handling of slides, notes, narration, charts, tables, and document validation during export.
  • Bug Fixes

    • Added clearer output for skill paths to help with command-line use.
    • Ignored Python cache artifacts to keep the workspace cleaner.
  • Chores

    • Added package setup and validation checks for the new office workflows.

Astro-Han added 3 commits July 8, 2026 20:06
Productize the svg-pptx native PPT route from the ppt-quality-eval baseline
into a bundled product skill. Vendors the MIT svg_to_pptx converter (LICENSE +
VENDORED.md provenance preserved) plus the two machine gates (check_text_budget
pre-convert, check_pptx_assets pre-deliver). SKILL.md is reworded for the
product flow and uses stable in-skill script paths instead of the eval
SVG_PPTX_SCRIPT env var. Description marks it PREVIEW so it does not compete
with the default officecli-pptx routing.
Native xlsx (openpyxl) and docx (python-docx) generation skills with the same
machine-check-over-model-judgement discipline as office-pptx: real formulas /
Heading styles, explicit fonts and number formats, and a pre-delivery structure
gate (check_xlsx.py / check_docx.py) that must print OK. Descriptions marked
PREVIEW so they do not compete with officecli-xlsx / officecli-docx.
Documents two paths: generate via HTML then PawWork's bundled Chromium
printToPDF (CDP), and parse via uv + pdfplumber (MIT) / pypdf (BSD). Hard rule:
never use PyMuPDF / fitz (AGPL). Marked PREVIEW; no default routing changed.
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Astro-Han, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 29 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c80c5519-e813-427b-b85e-c13f2fe509f7

📥 Commits

Reviewing files that changed from the base of the PR and between e75bf47 and ec4b87f.

📒 Files selected for processing (8)
  • .gitignore
  • skills/office-docx/SKILL.md
  • skills/office-docx/scripts/check_docx.py
  • skills/office-pdf/SKILL.md
  • skills/office-pptx/scripts/check_text_budget.py
  • skills/office-pptx/scripts/svg_to_pptx/animation_config.py
  • skills/office-pptx/scripts/svg_to_pptx/pptx_package/builder.py
  • skills/office-pptx/scripts/svg_to_pptx/pptx_package/media.py
📝 Walkthrough

Walkthrough

This PR adds four new "skill" bundles enabling native document generation/parsing: office-docx (python-docx), office-pdf (Chromium/pdfplumber/pypdf), office-pptx (a vendored SVG-to-PPTX DrawingML converter with animation, native chart/table embedding, and package assembly), and office-xlsx (openpyxl). Each includes SKILL.md documentation, pyproject.toml dependencies, and Python structural validation gate scripts. Also adds a base-directory output line to the skill tool and ignores Python bytecode.

Changes

Core skill tool output

Layer / File(s) Summary
Base directory as plain path
packages/opencode/src/tool/skill.ts, packages/opencode/test/tool/skill.test.ts, .gitignore
SkillTool output now includes the skill base directory as a plain filesystem path; test updated to match; .gitignore excludes Python bytecode.

office-docx Skill

Layer / File(s) Summary
Spec and dependencies
skills/office-docx/SKILL.md, skills/office-docx/pyproject.toml
Documents dark-launched docx generation runtime contract and authoring rules; pins python-docx.
Structure gate
skills/office-docx/scripts/check_docx.py
Validates paragraphs/headings/tables in a produced .docx and reports OK/FAIL.

office-pdf Skill

Layer / File(s) Summary
Spec and dependencies
skills/office-pdf/SKILL.md, skills/office-pdf/pyproject.toml
Documents generate (Chromium printToPDF) and parse (pdfplumber/pypdf) flows with licensing constraints; pins parsing dependencies.

office-pptx Skill

Layer / File(s) Summary
Spec, license, vendoring docs
skills/office-pptx/SKILL.md, skills/office-pptx/LICENSE, skills/office-pptx/VENDORED.md, skills/office-pptx/pyproject.toml
Documents authoring/gate workflow, licenses the bundle, and records vendored converter provenance.
CLI entrypoint and utilities
skills/office-pptx/scripts/svg_to_pptx.py, .../svg_to_pptx/__init__.py, .../console_encoding.py, .../resource_paths.py
Adds CLI wrapper, UTF-8 console setup, and SVG/icon resource path resolution.
SVG preprocessing
skills/office-pptx/scripts/svg_finalize/*, .../tspan_flattener.py, .../use_expander.py
Flattens tspans into text lines/paragraphs and expands icon placeholders in SVG.
Animation config
skills/office-pptx/scripts/svg_to_pptx/animation_config.py
Scans/validates/scaffolds per-slide animation configuration.
DrawingML conversion core
skills/office-pptx/scripts/svg_to_pptx/drawingml/*
Converts SVG shapes/paths/text/images into DrawingML XML with fill/stroke/effect/font handling.
Native table/chart embedding
skills/office-pptx/scripts/svg_to_pptx/native_objects/*
Converts metadata markers into real PPTX tables/charts, including chart data/style/XML and workbook generation.
Package assembly and CLI
skills/office-pptx/scripts/svg_to_pptx/pptx_package/*
Assembles the final .pptx (slides, notes, narration, media) and drives the export CLI.
Validation gates
skills/office-pptx/scripts/check_text_budget.py, .../check_pptx_assets.py
Pre-conversion text overflow check and post-conversion package/asset verification.

office-xlsx Skill

Layer / File(s) Summary
Spec and dependencies
skills/office-xlsx/SKILL.md, skills/office-xlsx/pyproject.toml
Documents openpyxl-based workbook generation rules; pins openpyxl.
Structure/formula/chart gate
skills/office-xlsx/scripts/check_xlsx.py
Validates sheets, cells, real formulas, dangerous patterns, and chart presence.

Estimated code review effort: 5 (Critical) | ~150 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI as pptx_package.cli
  participant Builder as create_pptx_with_native_svg
  participant Converter as convert_svg_to_slide_shapes
  participant Native as native_objects
  participant Notes as notes.py
  participant Narration as narration.py

  CLI->>Builder: invoke with SVG files and options
  Builder->>Converter: convert each SVG to slide shape XML
  Converter->>Native: convert_native_object for chart/table markers
  Native-->>Converter: ShapeResult (table/chart XML + assets)
  Converter-->>Builder: slide XML + media/relationships
  Builder->>Notes: create_notes_slide_xml per slide
  Builder->>Narration: inject_narration and apply_recorded_timing
  Builder-->>CLI: final .pptx package
Loading

Suggested labels: platform, task

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the change, but it omits required template sections like Human Review Status, Review Focus, Risk Notes, How To Verify, and the checklist. Reformat the PR body to match the template and fill in all required sections, including review status, risks, verification, and the checklist.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and matches the main change: dark-launching the office document-generation skills.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/1273-office-skills-bundle

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the P2 Medium priority label Jul 8, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested priority: P2 (includes non-doc, non-test paths outside the low-risk bucket).

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.

Astro-Han added 3 commits July 8, 2026 20:08
…e pyc

The pre-commit smoke test ran the vendored converter in place, which wrote
CPython bytecode into skills/office-pptx/scripts/**/__pycache__/. Remove those
31 tracked .pyc files and add a repo-wide Python bytecode ignore so bundled
skill sources stay source-only.
The skill tool only printed the base directory as a file:// URL, but bundled
skills instruct the model to reuse that directory in shell commands (cp, uv
run script paths), where a file:// URL breaks. Add one output line with the
plain path; the existing URL line is unchanged.
P1:
- SKILL_DIR contract: all four SKILL.md now tell the model to use the new
  plain-filesystem-path line from the skill tool output (never the file://
  URL, with a strip-prefix fallback).
- office-pptx Gate 2 now runs via 'uv run python' like every other command,
  instead of a bare python3 that Windows packaging does not guarantee.

P2:
- office-xlsx: formula-injection rule — only model-authored computed cells
  may be formulas; user data starting with =/+/-/@ must be force-stored as
  text; links via cell.hyperlink, never HYPERLINK(). check_xlsx.py adds a
  tripwire (HYPERLINK/WEBSERVICE/IMPORT*/DDE-style) and counts formulas by
  data_type=='f' only, so force-texted user data no longer false-FAILs.
- check_xlsx.py --require-chart now counts xl/charts/chart*.xml package
  parts instead of relying on openpyxl's private ws._charts read-back
  (round-trip verified for bar/line/pie/area/scatter on openpyxl 3.1.5).
- check_text_budget.py: tolerate unit suffixes like '60px' in x/font-size
  and add future annotations import (mirrors eval-side commit 95f30f4).
- Dark-launch limitation stated at the top of each SKILL.md: preview is
  description-enforced only, hard switch belongs to PR 4.

P3:
- check_pptx_assets.py: minimal artifact-summary.json schema check
  (renderer string + non-empty slides array) and honest docstring scope
  (mirrors eval-side wording).
- office-pdf SKILL.md: both parsers pinned for offline resolution, but one
  per task is enough.
@github-actions github-actions Bot added the harness Model harness, prompts, tool descriptions, and session mechanics label Jul 8, 2026
@Astro-Han Astro-Han added the enhancement New feature or request label Jul 8, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (2)
skills/office-pptx/scripts/svg_to_pptx/animation_config.py (1)

191-201: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider warning on non-dict transition/animation values in _validate_scope_effects.

Non-dict transition or animation fields are silently skipped rather than flagged. For example, "transition": "fade" (a string instead of an object) would produce no warning, leaving the user unaware their config is malformed. A brief type check with a warning would improve the validation surface.

♻️ Optional: add type warnings for non-dict transition/animation
 def _validate_scope_effects(scope: dict[str, Any], label: str, warnings: list[str]) -> None:
     transition = scope.get('transition', {})
+    if transition and not isinstance(transition, dict):
+        warnings.append(f'animations.json {label} "transition" must be an object')
     if isinstance(transition, dict):
         effect = transition.get('effect')
         if effect is not None and not _valid_transition_effect(str(effect)):
             warnings.append(f'animations.json {label} has unknown transition effect: {effect}')
     animation = scope.get('animation', {})
+    if animation and not isinstance(animation, dict):
+        warnings.append(f'animations.json {label} "animation" must be an object')
     if isinstance(animation, dict):
         effect = animation.get('effect')
         if effect is not None and not _valid_animation_effect(str(effect)):
             warnings.append(f'animations.json {label} has unknown animation effect: {effect}')
🤖 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 `@skills/office-pptx/scripts/svg_to_pptx/animation_config.py` around lines 191
- 201, The _validate_scope_effects helper currently skips malformed
transition/animation values when they are not dicts, so add explicit type
warnings for those fields before checking effects. Update
_validate_scope_effects in animation_config.py to detect non-dict
scope['transition'] and scope['animation'] values and append a warning that
includes the label and the unexpected type/value, while keeping the existing
unknown-effect validation for valid dicts.
skills/office-pptx/scripts/svg_to_pptx/pptx_package/cli.py (1)

45-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated trigger/effect-resolution logic vs. builder._slide_animation_settings.

_recorded_narration_on_click_slides re-derives the effective animation effect/trigger from animation_config + CLI overrides independently of builder.py's _slide_animation_settings. If the config schema or override precedence changes in one place, this on-click validation can silently drift out of sync and let narration+on-click conflicts through undetected.

Consider extracting the shared "resolve effective animation setting from CLI arg + config + overrides" logic into a single helper both files call.

🤖 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 `@skills/office-pptx/scripts/svg_to_pptx/pptx_package/cli.py` around lines 45 -
71, The on-click narration check in _recorded_narration_on_click_slides is
duplicating the same effective animation resolution logic that already exists in
builder._slide_animation_settings, so the two paths can drift. Refactor the
shared CLI/config/override precedence into a single helper and have both
_recorded_narration_on_click_slides and _slide_animation_settings call it to
resolve the effective effect and trigger consistently. Keep the helper
responsible for interpreting animation_config, animation_cli_overrides, and the
animation/animation_trigger inputs so validation stays aligned with the builder
behavior.
🤖 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 `@skills/office-docx/scripts/check_docx.py`:
- Around line 39-53: The paragraph-count gate in check_docx.py is treating
headings as body text, so a document with only Heading styles can incorrectly
pass. Update the counting logic around non_empty, headings, and the
min_paragraphs check so --min-paragraphs is based on real body paragraphs only
(exclude paragraphs whose style.name starts with "Heading"), while keeping the
existing heading and table checks unchanged.

In `@skills/office-docx/SKILL.md`:
- Around line 17-25: The uv check in the office-docx skill does not match the
required contract message. Update the shell snippet in the skill setup block so
the fallback path for the `uv --version` failure prints the exact required
string, and keep the rest of the flow unchanged; use the `SKILL_DIR` setup and
`uv --version` guard as the place to fix it.

In `@skills/office-pdf/SKILL.md`:
- Line 43: The missing-uv check in SKILL.md does not match the documented
runtime-contract message exactly because the current `uv --version` fallback
emits shell noise and a different string. Update the setup check so it
explicitly verifies `uv` without triggering `uv: command not found`, and make
the failure path in the relevant setup section print the exact contract message
referenced by the office-pdf runtime contract.

In `@skills/office-pptx/scripts/check_text_budget.py`:
- Around line 40-42: The attr() helper in check_text_budget.py can match short
attribute names inside longer ones, so update the regex in attr() to require a
word boundary before the attribute name for both search patterns. Keep the
existing fallback logic, but make sure names like x, y, dx, dy, and rx only
match exact attributes when parsing source in attr().

In `@skills/office-pptx/scripts/svg_to_pptx/animation_config.py`:
- Around line 204-233: The default transition in build_scaffold is hardcoded to
a value that can fail validation when pptx_animations is unavailable and
TRANSITIONS is empty. Update the defaults block in build_scaffold to choose a
safe fallback transition effect (for example, none) whenever TRANSITIONS has no
supported entries, while keeping fade only when it is actually valid. Use the
build_scaffold function and the TRANSITIONS availability check to locate and
adjust the scaffold’s default transition settings.

In `@skills/office-pptx/scripts/svg_to_pptx/pptx_package/builder.py`:
- Around line 222-243: The icacls subprocess invocation in builder.py can hang
indefinitely during export, so add a timeout to the subprocess.run call in the
ACL-adjustment logic and handle subprocess.TimeoutExpired alongside OSError.
Update the warning path in the same helper that builds the warnings list so a
timeout records a clear message for output_path, then returns warnings instead
of blocking the export.
- Around line 482-514: The relationship matcher in _REL_TARGET_RE is too
restrictive and fails to capture normal OOXML self-closing Relationship elements
because it excludes any slash in the attributes. Update the regex in builder.py
so _verify_internal_rels_targets() can iterate over all <Relationship .../>
entries, then keep the existing Target and TargetMode handling unchanged so
dangling internal targets are still detected correctly.

In `@skills/office-pptx/scripts/svg_to_pptx/pptx_package/media.py`:
- Around line 147-160: The cache write path in media handling discards a
successfully rendered PNG when `os.replace(tmp_path, cached)` fails, because the
temp file is then unlinked and `shutil.copy(cached, png_path)` may run with no
cached file available. Update the logic in the PNG caching flow to preserve the
rendered output by falling back to copying from `tmp_path` directly to
`png_path` when the cache move fails, and only delete the temp file after a
successful copy. Keep the fix localized around the `os.replace`,
`tmp_path.unlink`, and `shutil.copy` sequence in the PNG render/caching
function.

---

Nitpick comments:
In `@skills/office-pptx/scripts/svg_to_pptx/animation_config.py`:
- Around line 191-201: The _validate_scope_effects helper currently skips
malformed transition/animation values when they are not dicts, so add explicit
type warnings for those fields before checking effects. Update
_validate_scope_effects in animation_config.py to detect non-dict
scope['transition'] and scope['animation'] values and append a warning that
includes the label and the unexpected type/value, while keeping the existing
unknown-effect validation for valid dicts.

In `@skills/office-pptx/scripts/svg_to_pptx/pptx_package/cli.py`:
- Around line 45-71: The on-click narration check in
_recorded_narration_on_click_slides is duplicating the same effective animation
resolution logic that already exists in builder._slide_animation_settings, so
the two paths can drift. Refactor the shared CLI/config/override precedence into
a single helper and have both _recorded_narration_on_click_slides and
_slide_animation_settings call it to resolve the effective effect and trigger
consistently. Keep the helper responsible for interpreting animation_config,
animation_cli_overrides, and the animation/animation_trigger inputs so
validation stays aligned with the builder behavior.
🪄 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: f56c4125-4f92-42d6-a0cd-8ff40ce91c3d

📥 Commits

Reviewing files that changed from the base of the PR and between 4bc3294 and e75bf47.

📒 Files selected for processing (50)
  • .gitignore
  • packages/opencode/src/tool/skill.ts
  • packages/opencode/test/tool/skill.test.ts
  • skills/office-docx/SKILL.md
  • skills/office-docx/pyproject.toml
  • skills/office-docx/scripts/check_docx.py
  • skills/office-pdf/SKILL.md
  • skills/office-pdf/pyproject.toml
  • skills/office-pptx/LICENSE
  • skills/office-pptx/SKILL.md
  • skills/office-pptx/VENDORED.md
  • skills/office-pptx/pyproject.toml
  • skills/office-pptx/scripts/check_pptx_assets.py
  • skills/office-pptx/scripts/check_text_budget.py
  • skills/office-pptx/scripts/console_encoding.py
  • skills/office-pptx/scripts/resource_paths.py
  • skills/office-pptx/scripts/svg_finalize/__init__.py
  • skills/office-pptx/scripts/svg_finalize/flatten_tspan.py
  • skills/office-pptx/scripts/svg_to_pptx.py
  • skills/office-pptx/scripts/svg_to_pptx/__init__.py
  • skills/office-pptx/scripts/svg_to_pptx/animation_config.py
  • skills/office-pptx/scripts/svg_to_pptx/drawingml/__init__.py
  • skills/office-pptx/scripts/svg_to_pptx/drawingml/context.py
  • skills/office-pptx/scripts/svg_to_pptx/drawingml/converter.py
  • skills/office-pptx/scripts/svg_to_pptx/drawingml/elements.py
  • skills/office-pptx/scripts/svg_to_pptx/drawingml/paths.py
  • skills/office-pptx/scripts/svg_to_pptx/drawingml/styles.py
  • skills/office-pptx/scripts/svg_to_pptx/drawingml/utils.py
  • skills/office-pptx/scripts/svg_to_pptx/native_objects/__init__.py
  • skills/office-pptx/scripts/svg_to_pptx/native_objects/chart_data.py
  • skills/office-pptx/scripts/svg_to_pptx/native_objects/chart_style.py
  • skills/office-pptx/scripts/svg_to_pptx/native_objects/chart_xml.py
  • skills/office-pptx/scripts/svg_to_pptx/native_objects/chartex.py
  • skills/office-pptx/scripts/svg_to_pptx/native_objects/marker_common.py
  • skills/office-pptx/scripts/svg_to_pptx/native_objects/table.py
  • skills/office-pptx/scripts/svg_to_pptx/native_objects/workbook.py
  • skills/office-pptx/scripts/svg_to_pptx/pptx_package/__init__.py
  • skills/office-pptx/scripts/svg_to_pptx/pptx_package/builder.py
  • skills/office-pptx/scripts/svg_to_pptx/pptx_package/cli.py
  • skills/office-pptx/scripts/svg_to_pptx/pptx_package/dimensions.py
  • skills/office-pptx/scripts/svg_to_pptx/pptx_package/discovery.py
  • skills/office-pptx/scripts/svg_to_pptx/pptx_package/media.py
  • skills/office-pptx/scripts/svg_to_pptx/pptx_package/narration.py
  • skills/office-pptx/scripts/svg_to_pptx/pptx_package/notes.py
  • skills/office-pptx/scripts/svg_to_pptx/pptx_package/slide_xml.py
  • skills/office-pptx/scripts/svg_to_pptx/tspan_flattener.py
  • skills/office-pptx/scripts/svg_to_pptx/use_expander.py
  • skills/office-xlsx/SKILL.md
  • skills/office-xlsx/pyproject.toml
  • skills/office-xlsx/scripts/check_xlsx.py

Comment thread skills/office-docx/scripts/check_docx.py Outdated
Comment thread skills/office-docx/SKILL.md
Comment thread skills/office-pdf/SKILL.md Outdated
Comment thread skills/office-pptx/scripts/check_text_budget.py
Comment thread skills/office-pptx/scripts/svg_to_pptx/animation_config.py
Comment thread skills/office-pptx/scripts/svg_to_pptx/pptx_package/builder.py
Comment thread skills/office-pptx/scripts/svg_to_pptx/pptx_package/builder.py Outdated
Comment thread skills/office-pptx/scripts/svg_to_pptx/pptx_package/media.py
Astro-Han added 2 commits July 8, 2026 21:21
- check_text_budget: anchor attr() on a word boundary so "x" no longer
  matches inside dx=/rx= and returns the wrong overflow position
- builder: fix _REL_TARGET_RE ([^/] stopped at the first slash, so the
  internal-rels verification never matched real <Relationship .../> elements
  and silently passed); add a 10s timeout to the icacls ACL grant
- media: on cache-write failure, deliver the rendered PNG from the temp
  file instead of discarding it
- check_docx: count body paragraphs excluding Heading styles so a
  heading-only doc cannot satisfy --min-paragraphs
- animation_config: scaffold default transition falls back to 'none' when
  pptx_animations is absent and TRANSITIONS is empty
- office-docx/office-pdf SKILL.md: emit the exact documented missing-uv
  contract string and suppress the shell's own command-not-found noise
@Astro-Han
Astro-Han merged commit 03762e9 into dev Jul 8, 2026
42 checks passed
@Astro-Han
Astro-Han deleted the feat/1273-office-skills-bundle branch July 8, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request harness Model harness, prompts, tool descriptions, and session mechanics P2 Medium priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant