open-design/apps/daemon/tests/pitch-deck-manifest-required-inputs.test.ts
lefarcen c80acfefeb
fix(daemon,web): block pitch-deck placeholder publishes and unbreak framework decks (#2384)
Two preview-time bugs surfaced ahead of 0.8.0:

1. Pitch-deck example (#2215): the official html-ppt-pitch-deck prompt asked
   the agent to confirm three facts first, but the manifest had no
   structured `od.inputs`, so the platform's required-input gate had no
   fields to enforce and the run could publish HTML that still contained
   unresolved fundraising placeholders (`Name to confirm`, `$X.XM`,
   `Replace this panel with`, ...). Add structured required inputs to the
   manifest and a daemon-side publication guard that rejects HTML/deck
   artifact writes whose body still contains those placeholders. Scope is
   the file-write boundary only (no assistant-text scanning), so the
   guard cannot trip on the agent's chat prose mid-clarification.

2. Framework deck preview off-screen: `injectDeckBridge` injected
   `place-content: center !important` on `.deck-shell` for every deck-mode
   srcdoc, which forced the framework's `display: grid` shell to re-center
   its implicit track. The framework's `fit()` already centers a
   `transform-origin: top left` stage with an explicit `translate(tx, ty)`
   that assumes the stage's natural layout position is (0, 0); the two
   centerings stacked and the scaled stage landed ~1000px off-screen, so
   the preview showed a sliver of slide content in the top-left with the
   rest black. Skip the override when the framework's `id="deck-stage"`
   marker is in the doc, and drop the dead `display: grid; place-items:
   center` from the deck framework template so future drift can't
   re-introduce the same stack.
2026-05-20 16:20:34 +08:00

57 lines
2.1 KiB
TypeScript

import { readFile } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import { parseManifest } from '@open-design/plugin-runtime';
// The pitch-deck example's prompt instructs the agent to "confirm three
// things first" — name + one-line pitch, key traction numbers, ask + use
// of funds — but until #2215 those facts existed only as English prose
// inside the prompt. The platform's required-input gate at apply time
// (apps/daemon/src/plugins/apply.ts:validateInputs) has nothing structured
// to enforce in that shape, so an agent could route through od-default
// and start generating with no facts collected. This test pins the three
// facts as structured `od.inputs` fields so the gate fires before any
// HTML/deck artifact is written.
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(__dirname, '../../..');
const manifestPath = path.join(
repoRoot,
'plugins/_official/examples/html-ppt-pitch-deck/open-design.json',
);
describe('html-ppt-pitch-deck manifest inputs', () => {
it('declares the financing facts the example prompt says must be confirmed first', async () => {
const parsed = parseManifest(await readFile(manifestPath, 'utf8'));
expect(parsed.ok).toBe(true);
if (!parsed.ok) return;
const inputs = parsed.manifest.od?.inputs ?? [];
const requiredNames = inputs
.filter((input) => input.required === true)
.map((input) => input.name);
expect(requiredNames).toEqual(
expect.arrayContaining([
'one_line_pitch',
'key_traction_numbers',
'ask_and_use_of_funds',
]),
);
for (const name of [
'one_line_pitch',
'key_traction_numbers',
'ask_and_use_of_funds',
]) {
const input = inputs.find((candidate) => candidate.name === name);
expect(input).toMatchObject({
type: 'text',
required: true,
});
expect(input?.label).toEqual(expect.any(String));
expect(input?.label?.trim()).not.toBe('');
}
});
});