Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "designmd-pptx",
"version": "2.1.1",
"version": "2.1.2",
"description": "Compile awesome-design-md / Stitch DESIGN.md into officecli PPTX tokens, ordered decks, and staging-safe apply.",
"author": {
"name": "Min-Gul Kim",
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

All notable changes to designmd-pptx are documented here.

## [2.1.2] — 2026-07-15

Residual fixes after Codex **re-verify** of v2.1.1 (still flagged generative body loss,
placement NaN, Windows uninstall fail-open, methodology honesty).

### Fixed
- Generative recipe maps preserve card bodies (`title — body`) + `overflow.cards`
- Placement validation: finite coords, min size, non-empty text, identical-box reject
- Windows uninstall fail-closed on missing/invalid/mismatched manifest; SHA warn + `DESIGNMD_REQUIRE_OFFICECLI_SHA=1`
- Generated public benchmark METHODOLOGY honesty banner
- VS Code shared OutputChannel (no per-command leak)
- `generate --layout-cmd`; docs: pulse removed; smoke checklist

### Smoke
- `scripts/smoke-v2.1.1.sh` (version gate 2.1.2) track A PASS on Darwin
- Windows install + real PPT open: manual (docs/smoke-v2.1.1.md B/C)

## [2.1.1] — 2026-07-15

Adversarial review follow-up (Codex gpt-5.6-sol@high **BLOCK** findings).
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# designmd-pptx

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Version](https://img.shields.io/badge/version-2.1.1-brightgreen)](plugin.json)
[![Release](https://img.shields.io/badge/release-v2.1.1-blue)](https://github.com/kimmingul/designmd-pptx/releases/tag/v2.1.1)
[![Version](https://img.shields.io/badge/version-2.1.2-brightgreen)](plugin.json)
[![Release](https://img.shields.io/badge/release-v2.1.2-blue)](https://github.com/kimmingul/designmd-pptx/releases/tag/v2.1.2)

**awesome-design-md / Stitch `DESIGN.md` → [OfficeCLI](https://github.com/officecli/officecli) PPTX** — packaged for **Claude Code, OpenAI Codex, and Grok Build** (**v2.1**).

Expand Down
9 changes: 5 additions & 4 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,10 @@ python -m designmd_pptx scaffold default -o out/v2 \
--content generated/content.generated.deck.json
```

Freeform placements are validated by `layout.solve_adaptive` before emission
so title/body floors still hold. Optional external layout generator:
`DESIGNMD_LAYOUT_CMD` / vision contact sheet via `--contact`.
Freeform placements are validated (finite cm, on-canvas, non-empty text) before
emission. Optional external layout generator: env `DESIGNMD_LAYOUT_CMD` or
`--layout-cmd` (JSON placements/preset on stdout). Vision contact sheet via
`--contact`.

## animate (#40)

Expand All @@ -93,7 +94,7 @@ animation:
transition: fade # none | fade | push | wipe | cut | cover
transition_speed: med
stagger_ms: 150
emphasis: none # none | pulse
emphasis: none # only 'none' is implemented
```

```bash
Expand Down
2 changes: 1 addition & 1 deletion docs/design-md-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ animation:
transition: fade # none | fade | push | wipe | cut | cover
transition_speed: med # slow | med | fast
stagger_ms: 150
emphasis: none # none | pulse
emphasis: none # only 'none' implemented (v2.1.x)
---
```

Expand Down
154 changes: 154 additions & 0 deletions docs/smoke-v2.1.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Smoke checklist — designmd-pptx v2.1.2

Post-adversarial (Codex BLOCK → 2.1.2 fixes). Two tracks:

1. **Automated local smoke** (any OS with Python 3.10+) — `scripts/smoke-v2.1.2.sh`
2. **Windows bootstrap smoke** (Windows 10/11 + PowerShell 5.1+) — section B
3. **PowerPoint / LibreOffice animation smoke** — section C

Exit criteria for “production announce ready”:

| Gate | Pass condition |
|---|---|
| A Automated | `scripts/smoke-v2.1.2.sh` exit 0 |
| B Windows | install → doctor → scaffold → uninstall without leftover product root |
| C Animation | animate → open in PPT/LO; transitions present; no repair dialog |

---

## A. Automated local smoke

```bash
# from repo root
./scripts/smoke-v2.1.2.sh
# or:
bash scripts/smoke-v2.1.2.sh
```

Covers:

- version == 2.1.2 + `npm run check` exact equality
- unit suite (or fast subset if `SMOKE_FAST=1`)
- refine multi-slide split stability
- extract `barDir=col` → column
- generative overflow preserve + placement reject
- animation CT_Slide order + force required
- public synthetic suite (`--public-n 30`) with recipe smoke notes
- windows installer structural markers (`windows-install --check-script`)
- VS Code cli.js argv injection resistance (node)

---

## B. Windows bootstrap smoke (manual / VM)

**Host:** clean Windows 10/11 user (no admin required).

```powershell
# 1) Clone or download Install-DesignmdPptx.ps1 from v2.1.2 tag
cd path\to\designmd-pptx
powershell -ExecutionPolicy Bypass -File packaging\windows\Install-DesignmdPptx.ps1 -DryRun

# 2) Real install (network: winget/PyPI/GitHub)
powershell -ExecutionPolicy Bypass -File packaging\windows\Install-DesignmdPptx.ps1

# 3) New terminal — shim on PATH
designmd-pptx --help
designmd-pptx doctor
designmd-pptx scaffold default -o $env:TEMP\dmd-smoke --content python\examples\content.deck.json

# 4) Safe-root guard (must FAIL)
powershell -ExecutionPolicy Bypass -File packaging\windows\Install-DesignmdPptx.ps1 `
-Uninstall -InstallRoot C:\Windows\Temp\evil
# expect: InstallRoot must be under ...\designmd-pptx

# 5) Uninstall
powershell -ExecutionPolicy Bypass -File packaging\windows\Install-DesignmdPptx.ps1 -Uninstall
# product root gone; officecli-official may remain (documented)
```

Optional integrity:

```powershell
# If you have the expected tarball hash:
$env:DESIGNMD_OFFICECLI_SHA256 = "<sha256 of officecli_0.2.117_windows_amd64.tar.gz>"
powershell -ExecutionPolicy Bypass -File packaging\windows\Install-DesignmdPptx.ps1
```

**Record:** OS build, Python source (existing vs winget), doctor output, any PATH issues.

---

## C. PowerPoint / LibreOffice animation smoke

Requires a materialised `.pptx` (legacy OfficeCLI `apply` or an existing deck).

```bash
# After scaffold --apply (legacy binary) OR any valid deck.pptx:
PYTHONPATH=python python -m designmd_pptx animate path/to/deck.pptx \
-o /tmp/deck.animated.pptx --entrance fade --transition fade --force

# Inspect OOXML order without Office:
python - <<'PY'
import zipfile
from lxml import etree
from pathlib import Path
p = Path("/tmp/deck.animated.pptx")
with zipfile.ZipFile(p) as z:
xml = z.read("ppt/slides/slide1.xml")
root = etree.fromstring(xml)
locals_ = [c.tag.split("}")[-1] for c in root]
print(locals_)
assert "transition" in locals_ and "timing" in locals_
assert locals_.index("transition") < locals_.index("timing")
if "extLst" in locals_:
assert locals_.index("timing") < locals_.index("extLst")
print("order OK")
PY
```

**In PowerPoint / LibreOffice Impress:**

1. Open `deck.animated.pptx` — no repair / “unreadable content” dialog.
2. Slide Show → transitions visible (fade).
3. Select title shape → Animation pane shows entrance effect (or equivalent).
4. Save-as new file succeeds.

**In-place force guard:**

```bash
# must refuse without --force
PYTHONPATH=python python -m designmd_pptx animate deck.pptx -o deck.pptx --entrance fade
# expect: error/notes about --force
```

---

## D. Sign-off template

```text
Date:
Operator:
Commit/tag:
A automated smoke: PASS / FAIL (log: )
B Windows install: PASS / FAIL / SKIP (reason: )
C PPT/LO animation: PASS / FAIL / SKIP (reason: )
Notes:
Announce: YES / NO
```

---

## E. Recorded run (this environment)

```text
Date: 2026-07-15
Operator: agent (macOS Darwin)
Commit/tag: v2.1.2 (b6ba429)
A automated smoke: PASS — bash scripts/smoke-v2.1.2.sh
B Windows install: SKIP — no Windows/pwsh on host (manual VM required)
C PPT/LO animation: PARTIAL — OOXML order verified programmatically
tags: cSld, clrMapOvr, transition, timing
officecli/soffice/libreoffice: not on PATH (no real slideshow open)
Codex re-verify (gpt-5.6-sol@high): see .grok/artifacts/verify/codex-gpt-5.6-sol-reverify-v2.1.2.md
Announce: conditional on B+C human sign-off if claiming full production Windows/PPT
```
2 changes: 1 addition & 1 deletion docs/windows-installer.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ powershell -ExecutionPolicy Bypass -File Install-DesignmdPptx.ps1 -DryRun
| `-DryRun` | Print actions only |
| `-SkipOfficeCli` | Skip pinned OfficeCLI download |
| `-SkipPath` | Do not modify user PATH |
| `-PackageSource X` | default `designmd-pptx==2.1.1` (pinned); or local path/wheel |
| `-PackageSource X` | default `designmd-pptx==2.1.2` (pinned); or local path/wheel |
| `-OfficeCliSha256` | Optional expected SHA-256 of the officecli-dist tarball |
| `-InstallRoot PATH` | Must stay under `%LOCALAPPDATA%\designmd-pptx` |

Expand Down
7 changes: 6 additions & 1 deletion editor/vscode/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@ const { resolveCli: resolveCliPure, diagnosticsFromReport } = require("./cli");
const DIAG_COLLECTION = "designmd-pptx";

/** @param {vscode.ExtensionContext} context */
/** @type {vscode.OutputChannel | undefined} */
let sharedOutput;

function activate(context) {
const diagnostics = vscode.languages.createDiagnosticCollection(DIAG_COLLECTION);
context.subscriptions.push(diagnostics);
sharedOutput = vscode.window.createOutputChannel("designmd-pptx");
context.subscriptions.push(sharedOutput);

const explorer = new DesignmdExplorer();
context.subscriptions.push(
Expand Down Expand Up @@ -109,7 +114,7 @@ function resolveCli(args) {
function runCli(args, opts = {}) {
const { argv, cwd, env, display } = resolveCli(args);
const name = opts.title || `designmd-pptx ${args[0] || ""}`.trim();
const out = vscode.window.createOutputChannel("designmd-pptx", { log: true });
const out = sharedOutput || vscode.window.createOutputChannel("designmd-pptx");
if (opts.reveal !== false) {
out.show(true);
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "designmd-pptx",
"version": "2.1.1",
"version": "2.1.2",
"description": "DESIGN.md → officecli PPTX compiler, packaged for Claude Code / Codex / Grok Build (v2.1)",
"license": "MIT",
"private": true,
Expand Down
36 changes: 21 additions & 15 deletions packaging/windows/Install-DesignmdPptx.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ param(
[switch]$SkipOfficeCli,
[switch]$SkipPath,
# Pin package by default (adversarial #35) — override with -PackageSource for editable installs
[string]$PackageSource = "designmd-pptx==2.1.1",
[string]$PackageSource = "designmd-pptx==2.1.2",
[string]$InstallRoot = "",
[string]$OfficeCliPin = "", # empty → read from embedded default / env
[string]$OfficeCliSha256 = "", # optional expected SHA-256 of the tarball
Expand Down Expand Up @@ -236,8 +236,10 @@ function Install-OfficeCliPin {
throw "OfficeCLI tarball SHA-256 mismatch: got $hash expected $expectSha"
}
Write-Ok "SHA-256 verified"
} elseif ($env:DESIGNMD_REQUIRE_OFFICECLI_SHA -eq "1") {
throw "DESIGNMD_REQUIRE_OFFICECLI_SHA=1 but no -OfficeCliSha256 / DESIGNMD_OFFICECLI_SHA256 provided"
} else {
Write-Info "No DESIGNMD_OFFICECLI_SHA256 / -OfficeCliSha256 set — skipping hash verify (pin URL only)"
Write-Host " WARN pin URL only — set DESIGNMD_OFFICECLI_SHA256 for supply-chain verify" -ForegroundColor Yellow
}
# tar is available on Windows 10+; extract only under our temp root (path safety)
$extract = Join-Path $env:TEMP "designmd-officecli-extract-$pin"
Expand Down Expand Up @@ -390,26 +392,30 @@ function Remove-UserPathEntry {
function Invoke-Uninstall {
Write-Step "Uninstall $ProductName from $InstallRoot"
Assert-SafeInstallRoot $InstallRoot
# Require product marker unless dry-run of empty tree
if (-not $DryRun -and (Test-Path $InstallRoot) -and -not (Test-Path $Manifest)) {
throw "Refusing uninstall: $Manifest missing (not a designmd-pptx install root)"
}
if ($DryRun) {
Write-Info "dry-run: remove $InstallRoot and PATH entry"
return
}
$pathModified = $false
if (Test-Path $Manifest) {
try {
$m = Get-Content $Manifest -Raw | ConvertFrom-Json
$pathModified = [bool]$m.path_modified
if ($m.product -and $m.product -ne $ProductName) {
throw "Refusing uninstall: manifest product is $($m.product)"
}
} catch {
if ("$_" -match "Refusing") { throw }
if (-not (Test-Path $Manifest)) {
throw "Refusing uninstall: $Manifest missing (not a designmd-pptx install root)"
}
try {
$m = Get-Content $Manifest -Raw | ConvertFrom-Json
} catch {
throw "Refusing uninstall: manifest is not valid JSON: $_"
}
if (-not $m.product -or $m.product -ne $ProductName) {
throw "Refusing uninstall: manifest product is '$($m.product)' (want $ProductName)"
}
if ($m.paths -and $m.paths.root) {
$manifestRoot = [System.IO.Path]::GetFullPath([string]$m.paths.root)
$wantRoot = [System.IO.Path]::GetFullPath($InstallRoot)
if (-not $manifestRoot.Equals($wantRoot, [System.StringComparison]::OrdinalIgnoreCase)) {
throw "Refusing uninstall: manifest root $manifestRoot != InstallRoot $wantRoot"
}
}
$pathModified = [bool]$m.path_modified
if ($pathModified -or -not $SkipPath) {
Remove-UserPathEntry
}
Expand Down
2 changes: 1 addition & 1 deletion packaging/windows/designmd-pptx.iss
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
; with -Uninstall.

#define MyAppName "designmd-pptx"
#define MyAppVersion "2.1.1"
#define MyAppVersion "2.1.2"
#define MyAppPublisher "designmd-pptx contributors"
#define MyAppURL "https://github.com/kimmingul/designmd-pptx"

Expand Down
2 changes: 1 addition & 1 deletion plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "designmd-pptx",
"version": "2.1.1",
"version": "2.1.2",
"description": "DESIGN.md → officecli PPTX compiler for agentic AI: compose markdown briefs into decks, extract/restyle existing decks, brand slide masters, Gate 3 screenshot QA. Grok Build manifest of the multi-platform (Claude Code / Codex / Grok) plugin.",
"author": {
"name": "Min-Gul Kim",
Expand Down
2 changes: 1 addition & 1 deletion python/designmd_pptx/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""DESIGN.md (awesome-design-md / Stitch) → officecli PPTX slide tokens & recipes."""

__version__ = "2.1.1"
__version__ = "2.1.2"
7 changes: 7 additions & 0 deletions python/designmd_pptx/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,10 @@ def cmd_generate(args: argparse.Namespace) -> int:
tokens = compile_design_md(_resolve_design(args.design))

directive = args.directive or args.style
layout_cmd = getattr(args, "layout_cmd", None)
if layout_cmd:
import os
os.environ["DESIGNMD_LAYOUT_CMD"] = str(layout_cmd)
if args.profile:
report = gen.generate_deck_layout(
deck,
Expand Down Expand Up @@ -1362,6 +1366,9 @@ def build_parser() -> argparse.ArgumentParser:
help="Contact-sheet PNG for vision-driven re-layout")
gn.add_argument("--vision-plan", type=Path, default=None)
gn.add_argument("--vision-cmd", default=None)
gn.add_argument("--layout-cmd", default=None,
help="External layout generator command (or set DESIGNMD_LAYOUT_CMD); "
"stdin JSON content, stdout {placements|preset}")
gn.add_argument("--rounds", type=int, default=2,
help="Max generate+refine rounds (default 2)")
gn.set_defaults(func=cmd_generate)
Expand Down
2 changes: 1 addition & 1 deletion python/designmd_pptx/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ def _ensure_proc(self) -> subprocess.Popen:
daemon=True,
).start()
init = self._call("initialize", {
"clientInfo": {"name": "designmd-pptx", "version": "2.1.1"},
"clientInfo": {"name": "designmd-pptx", "version": "2.1.2"},
})
self._caps = None
self._server = init
Expand Down
2 changes: 1 addition & 1 deletion python/designmd_pptx/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from .colors_parse import collect_css_vars
from .validate import validate_content_overlay, validate_tokens_against_schema_file

COMPILER_VERSION = "2.1.1"
COMPILER_VERSION = "2.1.2"

DEFAULT_PATTERNS = [
"cover",
Expand Down
Loading
Loading