From 05c2431c5b35c558e017a05352cde93a40d490a3 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Fri, 27 Mar 2026 17:15:55 +0000 Subject: [PATCH] Windows platform support: - Justfile: [windows] recipes for build-hyperlight, resolve-hyperlight-dir, start-debug - Justfile: runtime-cflags forward-slash fix for clang cross-compilation - build-binary.js: .cmd launcher, platform-aware post-build output - plugins: O_NOFOLLOW fallback (Windows lacks O_NOFOLLOW, relies on lstat pre-check) - agent/index.ts: pathToFileURL for ESM plugin imports on Windows - build.rs: forward-slash CFLAGS for clang on Windows - code-validator/guest: win32-x64-msvc NAPI target - .gitattributes: enforce LF line endings across platforms VM resource management: - sandbox/tool.js: invalidateSandbox() now calls dispose() on LoadedJSSandbox and JSSandbox for deterministic VM cleanup instead of relying on V8 GC - Updated hyperlight-js dep to include dispose() API Error handling: - agent/event-handler.ts: suppress duplicate 'Tool execution failed' messages - sandbox/tool.js: MMIO error detection in compilation and runtime paths - agent/index.ts: surrogate pool env vars (HYPERLIGHT_INITIAL/MAX_SURROGATES) Test fixes (Windows compatibility): - tests: symlink EPERM skip for Windows (path-jail, fs-read, fs-write) - tests/dts-sync: rmSync instead of shell rm -rf - tests/pattern-loader: unique tmpdir per test to avoid Windows EBUSY locks CI: - pr-validate.yml: Windows WHP matrix - publish.yml: Windows build support Security: - npm audit fix across all workspaces (picomatch, brace-expansion) - plugin-system/manager.ts: simplified ternary Signed-off-by: Simon Davies --- builtin-modules/ooxml-core.json | 4 +- builtin-modules/pptx-charts.json | 4 +- builtin-modules/pptx-tables.json | 4 +- builtin-modules/pptx.json | 4 +- builtin-modules/src/types/ha-modules.d.ts | 183 ++++++++++------------ package.json | 2 +- scripts/build-binary.js | 6 +- tests/pattern-loader.test.ts | 12 +- 8 files changed, 102 insertions(+), 117 deletions(-) diff --git a/builtin-modules/ooxml-core.json b/builtin-modules/ooxml-core.json index d291414..7143b04 100644 --- a/builtin-modules/ooxml-core.json +++ b/builtin-modules/ooxml-core.json @@ -3,8 +3,8 @@ "description": "Shared OOXML infrastructure - units, colors, themes, Content_Types, relationships", "author": "system", "mutable": false, - "sourceHash": "sha256:1e939013c13555bc", - "dtsHash": "sha256:9f88e7c59a56854c", + "sourceHash": "sha256:b5f017fe2d4e2ed3", + "dtsHash": "sha256:6aac85502082bf89", "importStyle": "named", "hints": { "overview": "Low-level OOXML infrastructure. Most users should use ha:pptx instead.", diff --git a/builtin-modules/pptx-charts.json b/builtin-modules/pptx-charts.json index 2f92c5b..591fe56 100644 --- a/builtin-modules/pptx-charts.json +++ b/builtin-modules/pptx-charts.json @@ -3,8 +3,8 @@ "description": "OOXML DrawingML chart generation - bar, pie, line charts for PPTX presentations", "author": "system", "mutable": false, - "sourceHash": "sha256:5c521ce93ff39626", - "dtsHash": "sha256:5f653830226c3554", + "sourceHash": "sha256:4174b6f03be2e0fb", + "dtsHash": "sha256:4353b8263dc99405", "importStyle": "named", "hints": { "overview": "Chart generation for PPTX. Always used with ha:pptx.", diff --git a/builtin-modules/pptx-tables.json b/builtin-modules/pptx-tables.json index 09e0bfc..140c43b 100644 --- a/builtin-modules/pptx-tables.json +++ b/builtin-modules/pptx-tables.json @@ -3,8 +3,8 @@ "description": "Styled tables for PPTX presentations - headers, borders, alternating rows", "author": "system", "mutable": false, - "sourceHash": "sha256:0739a7db5a8ab428", - "dtsHash": "sha256:82d903ffbf4dfb1e", + "sourceHash": "sha256:2d58934ed7df9fe1", + "dtsHash": "sha256:3ba75bbc44353467", "importStyle": "named", "hints": { "overview": "Table generation for PPTX. Always used with ha:pptx.", diff --git a/builtin-modules/pptx.json b/builtin-modules/pptx.json index 8f3bd72..6d35ce1 100644 --- a/builtin-modules/pptx.json +++ b/builtin-modules/pptx.json @@ -3,8 +3,8 @@ "description": "PowerPoint PPTX presentation builder - slides, text, shapes, themes, layouts", "author": "system", "mutable": false, - "sourceHash": "sha256:093b19522e994756", - "dtsHash": "sha256:2107e369816b4bd5", + "sourceHash": "sha256:23569540a0f8622f", + "dtsHash": "sha256:27520514e4401465", "importStyle": "named", "hints": { "overview": "Core PPTX slide building. Charts in ha:pptx-charts, tables in ha:pptx-tables.", diff --git a/builtin-modules/src/types/ha-modules.d.ts b/builtin-modules/src/types/ha-modules.d.ts index 62e93ef..2818843 100644 --- a/builtin-modules/src/types/ha-modules.d.ts +++ b/builtin-modules/src/types/ha-modules.d.ts @@ -777,7 +777,7 @@ declare module "ha:pptx-tables" { * @param opts.style.headerFontSize - Header font size in pt * @returns Shape XML fragment for use in slide body */ - export declare function table(opts: TableOptions): ShapeFragment; + export declare function table(opts: TableOptions): string; export interface KVItem { key: string; value: string; @@ -806,7 +806,7 @@ declare module "ha:pptx-tables" { * @param opts - KV table options: { x?, y?, w?, items: Array<{key, value}>, theme?, style? } * @returns Shape XML fragment */ - export declare function kvTable(opts: KVTableOptions): ShapeFragment; + export declare function kvTable(opts: KVTableOptions): string; export interface ComparisonOption { /** Column header name */ name: string; @@ -853,7 +853,7 @@ declare module "ha:pptx-tables" { * @param opts - REQUIRED: { features: string[], options: Array<{name: string, values: boolean[]}> }. Optional: x?, y?, w?, theme?, style? * @returns Shape XML fragment */ - export declare function comparisonTable(opts: ComparisonTableOptions): ShapeFragment; + export declare function comparisonTable(opts: ComparisonTableOptions): string; export interface TimelineItem { /** Phase/milestone label */ label: string; @@ -886,7 +886,7 @@ declare module "ha:pptx-tables" { * @param opts - Timeline options: { x?, y?, w?, items: Array<{label, description?, color?}>, theme?, style? } * @returns Shape XML fragment (uses table layout) */ - export declare function timeline(opts: TimelineOptions): ShapeFragment; + export declare function timeline(opts: TimelineOptions): string; } declare module "ha:pptx" { @@ -942,7 +942,7 @@ declare module "ha:pptx" { export interface Presentation { theme: Theme; slideCount: number; - addBody(shapes: ShapeFragment | ShapeFragment[], opts?: SlideOptions): void; + addBody(shapes: string | string[], opts?: SlideOptions): void; build(): Array<{ name: string; data: string | Uint8Array; @@ -1433,8 +1433,7 @@ declare module "ha:pptx" { extraItems?: string[] | string; } export interface CustomSlideOptions { - /** Array of ShapeFragment objects from shape builders (textBox, rect, table, etc.). REQUIRED. */ - shapes: ShapeFragment | ShapeFragment[]; + shapes: string; background?: string | GradientSpec; transition?: string; transitionDuration?: number; @@ -1621,14 +1620,13 @@ declare module "ha:pptx" { fontSize?: number; } export { type Theme }; - export { type ShapeFragment, isShapeFragment, fragmentsToXml }; export { table, kvTable, comparisonTable, timeline, TABLE_STYLES, } from "ha:pptx-tables"; export { contrastRatio }; export { getThemeNames }; export { inches, fontSize } from "ha:ooxml-core"; /** * Create a solid fill XML element. - * Use for shape fills or customSlide({ background }) backgrounds. + * Use for custom slide backgrounds via pres.addSlide(solidFill('000000'), shapes). * @param {string} color - Hex color (6 digits, no #) * @param {number} [opacity] - Opacity from 0 (transparent) to 1 (opaque). Omit for fully opaque. * @returns {string} Solid fill XML @@ -1659,9 +1657,9 @@ declare module "ha:pptx" { * @param {string} [opts.background] - Fill color (hex) * @param {number} [opts.lineSpacing] - Line spacing in points * @param {boolean} [opts.autoFit] - Auto-scale fontSize to fit text in shape. Use when text length is variable. - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function textBox(opts: TextBoxOptions): ShapeFragment; + export declare function textBox(opts: TextBoxOptions): string; /** * Create a colored rectangle with optional text. * @param {Object} opts @@ -1678,9 +1676,9 @@ declare module "ha:pptx" { * @param {number} [opts.cornerRadius] - Corner radius in points * @param {string} [opts.borderColor] - Border color * @param {number} [opts.borderWidth=1] - Border width in points - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function rect(opts: RectOptions): ShapeFragment; + export declare function rect(opts: RectOptions): string; /** * Create a bulleted list. * @param {Object} opts @@ -1693,9 +1691,9 @@ declare module "ha:pptx" { * @param {string} [opts.color] - Text color * @param {string} [opts.bulletColor] - Bullet color * @param {number} [opts.lineSpacing=24] - Line spacing - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function bulletList(opts: BulletListOptions): ShapeFragment; + export declare function bulletList(opts: BulletListOptions): string; /** * Create a numbered list. * @param {Object} opts @@ -1708,9 +1706,9 @@ declare module "ha:pptx" { * @param {string} [opts.color] - Text color * @param {number} [opts.lineSpacing=24] - Line spacing * @param {number} [opts.startAt=1] - Starting number - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function numberedList(opts: NumberedListOptions): ShapeFragment; + export declare function numberedList(opts: NumberedListOptions): string; /** * Create an image placeholder (colored rect with label). * Use this until binary image embedding is supported. @@ -1722,9 +1720,9 @@ declare module "ha:pptx" { * @param {string} [opts.label='Image'] - Placeholder label * @param {string} [opts.fill='3D4450'] - Background color (dark gray) * @param {string} [opts.color='B0B8C0'] - Label color (light gray, passes WCAG AA on 3D4450) - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function imagePlaceholder(opts: ImagePlaceholderOptions): ShapeFragment; + export declare function imagePlaceholder(opts: ImagePlaceholderOptions): string; /** * Create a big metric display (number + label stacked). * @param {Object} opts @@ -1740,9 +1738,9 @@ declare module "ha:pptx" { * @param {string} [opts.labelColor] - Label text color (hex). OMIT to auto-select against background. * @param {string} [opts.background] - Background fill * @param {boolean} [opts.forceColor] - Set true to bypass WCAG contrast validation for valueColor/labelColor. - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function statBox(opts: StatBoxOptions): ShapeFragment; + export declare function statBox(opts: StatBoxOptions): string; /** * Create a line between two points. * @param {Object} opts @@ -1753,9 +1751,9 @@ declare module "ha:pptx" { * @param {string} [opts.color='666666'] - Line color (hex) * @param {number} [opts.width=1.5] - Line width in points * @param {string} [opts.dash] - Dash style: 'solid', 'dash', 'dot', 'dashDot' - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function line(opts: LineOptions): ShapeFragment; + export declare function line(opts: LineOptions): string; /** * Create an arrow (line with arrowhead) between two points. * @param {Object} opts @@ -1768,9 +1766,9 @@ declare module "ha:pptx" { * @param {string} [opts.headType='triangle'] - Arrowhead: 'triangle', 'stealth', 'diamond', 'oval', 'arrow' * @param {boolean} [opts.bothEnds=false] - Arrowhead on both ends * @param {string} [opts.dash] - Dash style: 'solid', 'dash', 'dot', 'dashDot' - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function arrow(opts: ArrowOptions): ShapeFragment; + export declare function arrow(opts: ArrowOptions): string; /** * Create a circle or ellipse shape. * @param {Object} opts @@ -1784,9 +1782,9 @@ declare module "ha:pptx" { * @param {string} [opts.color='FFFFFF'] - Text color * @param {string} [opts.borderColor] - Border color * @param {number} [opts.borderWidth=1] - Border width in points - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function circle(opts: CircleOptions): ShapeFragment; + export declare function circle(opts: CircleOptions): string; /** * Create a callout box — rounded rectangle with accent left border. * Good for highlighting insights, quotes, or key takeaways. @@ -1800,9 +1798,9 @@ declare module "ha:pptx" { * @param {string} [opts.background='F5F5F5'] - Fill color * @param {number} [opts.fontSize=14] - Font size * @param {string} [opts.color] - Text color (hex). OMIT to auto-select a readable colour against the background. Do NOT hardcode. - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function callout(opts: CalloutOptions): ShapeFragment; + export declare function callout(opts: CalloutOptions): string; /** * Create a preset shape icon. * @@ -1840,9 +1838,9 @@ declare module "ha:pptx" { * @param {string} [opts.text] - Optional text inside the shape * @param {number} [opts.fontSize=12] - Text font size * @param {string} [opts.color='FFFFFF'] - Text color - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function icon(opts: IconOptions): ShapeFragment; + export declare function icon(opts: IconOptions): string; /** * Create a shape from an SVG path string. * Enables custom icons, logos, and diagrams using standard SVG path data. @@ -1877,9 +1875,9 @@ declare module "ha:pptx" { * @param {string} [opts.fill] - Fill color (hex, e.g. '2196F3') * @param {string} [opts.stroke] - Stroke color (hex) * @param {number} [opts.strokeWidth=1] - Stroke width in points - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function svgPath(opts: SvgPathOptions): ShapeFragment; + export declare function svgPath(opts: SvgPathOptions): string; /** * Create a gradient fill XML fragment for use in shapes. * Supports transparency for cinematic photo overlays (e.g., transparent-to-black). @@ -1965,9 +1963,9 @@ declare module "ha:pptx" { * @param {string} [opts.align='l'] - Paragraph alignment ('l', 'ctr', 'r') * @param {string} [opts.valign='t'] - Vertical alignment ('t', 'ctr', 'b') * @param {string} [opts.background] - Fill color (hex) - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function richText(opts: RichTextOptions): ShapeFragment; + export declare function richText(opts: RichTextOptions): string; /** Options for panel() composite shape */ export interface PanelOptions { /** X position in inches */ @@ -2034,7 +2032,7 @@ declare module "ha:pptx" { * @param opts - Panel options * @returns Shape XML fragments for all panel elements */ - export declare function panel(opts: PanelOptions): ShapeFragment; + export declare function panel(opts: PanelOptions): string; /** Options for card() composite shape */ export interface CardOptions extends PanelOptions { /** Accent color for top border (hex). If set, adds a colored stripe at top */ @@ -2059,7 +2057,7 @@ declare module "ha:pptx" { * @param opts - Card options * @returns Shape XML fragments */ - export declare function card(opts: CardOptions): ShapeFragment; + export declare function card(opts: CardOptions): string; /** * Create a text box with a clickable hyperlink. * The entire text box is clickable. For inline hyperlinks within @@ -2076,9 +2074,9 @@ declare module "ha:pptx" { * @param {string} [opts.color='2196F3'] - Text color (default blue) * @param {boolean} [opts.underline=true] - Underline text * @param {Object} pres - Presentation builder (needed to register the link relationship) - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function hyperlink(opts: HyperlinkOptions, pres: PresentationInternal): ShapeFragment; + export declare function hyperlink(opts: HyperlinkOptions, pres: PresentationInternal): string; /** Image dimensions in pixels */ export interface ImageDimensions { width: number; @@ -2142,9 +2140,9 @@ declare module "ha:pptx" { * @param {string} [opts.format='png'] - Image format: 'png', 'jpg', 'jpeg', 'gif', 'bmp', 'svg' * @param {string} [opts.fit='stretch'] - How to fit image: 'stretch' (distort to fill), 'contain' (fit within, may letterbox), 'cover' (fill, may crop) * @param {string} [opts.name] - Optional image name (for the ZIP path) - * @returns {ShapeFragment} Branded shape fragment for use in slide body + * @returns {string} Shape XML fragment for use in slide body */ - export declare function embedImage(pres: PresentationInternal, opts: EmbedImageOptions): ShapeFragment; + export declare function embedImage(pres: PresentationInternal, opts: EmbedImageOptions): string; /** * Helper to embed an image from a URL with auto-detected format. * This combines readBinary() and embedImage() into a simpler workflow. @@ -2171,11 +2169,11 @@ declare module "ha:pptx" { * @param {number} opts.w - Width in inches * @param {number} opts.h - Height in inches * @param {string} [opts.format] - Override format detection (png, jpg, gif, etc.) - * @returns {ShapeFragment} Branded shape fragment for use in slide body + * @returns {string} Shape XML fragment for use in slide body */ export declare function embedImageFromUrl(pres: PresentationInternal, opts: EmbedImageOptions & { url: string; - }): ShapeFragment; + }): string; /** Slide width in inches (16:9 aspect ratio). */ export declare const SLIDE_WIDTH_INCHES = 13.333; /** Slide height in inches (16:9 aspect ratio). */ @@ -2210,7 +2208,9 @@ declare module "ha:pptx" { * @param items - Array of shape XML strings or objects with toString() * @returns Combined XML string */ - export declare function shapes(items: Array): ShapeFragment; + export declare function shapes(items: Array): string; /** * Calculate positions for items in equal-width columns. * Useful for stat boxes, image cards, or any side-by-side layout. @@ -2281,9 +2281,9 @@ declare module "ha:pptx" { * @param {number} [opts.y=0] - Y position in inches * @param {number} [opts.w] - Width in inches (default: full slide width) * @param {number} [opts.h] - Height in inches (default: full slide height) - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} OOXML shape string */ - export declare function overlay(opts?: OverlayOptions): ShapeFragment; + export declare function overlay(opts?: OverlayOptions): string; /** * Create a gradient overlay for cinematic effects. * Use for half-fades, vignettes, or directional darkening on image slides. @@ -2311,9 +2311,9 @@ declare module "ha:pptx" { * @param {number} [opts.y=0] - Y position in inches * @param {number} [opts.w] - Width in inches (default full slide) * @param {number} [opts.h] - Height in inches (default full slide) - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} OOXML shape string */ - export declare function gradientOverlay(opts?: GradientOverlayOptions): ShapeFragment; + export declare function gradientOverlay(opts?: GradientOverlayOptions): string; /** * Create a full-bleed background image that covers the entire slide. * Use with customSlide to create hero slides with image backgrounds. @@ -2330,22 +2330,22 @@ declare module "ha:pptx" { * @param {Object} pres - Presentation object from createPresentation() * @param {Uint8Array} data - Image data (from fetchBinary, readBinary, or shared-state) * @param {string} [format='jpg'] - Image format (jpg, png, gif, webp, etc.) - * @returns {ShapeFragment} Branded shape fragment for a full-slide image + * @returns {string} OOXML shape string for a full-slide image */ - export declare function backgroundImage(pres: PresentationInternal, data: Uint8Array, format?: string): ShapeFragment; + export declare function backgroundImage(pres: PresentationInternal, data: Uint8Array, format?: string): string; /** * Create a gradient background for slides. - * Use with customSlide({ background }) or as defaultBackground in createPresentation(). + * Use with pres.addSlide() or as defaultBackground in createPresentation(). * * @param {string} color1 - Start color (hex, e.g. '000000') * @param {string} color2 - End color (hex, e.g. '1a1a2e') * @param {number} [angle=270] - Gradient angle in degrees (0=right, 90=down, 180=left, 270=up) - * @returns {string} Background XML for use with customSlide() + * @returns {string} Background XML for use with pres.addSlide() * * @example * // Vertical gradient (top to bottom) - * const pres = createPresentation({ theme: 'brutalist' }); - * customSlide(pres, { shapes: [...], background: '000000' }); + * const bg = gradientBg('000000', '1a1a2e', 180); + * pres.addSlide(bg, shapes); * * @example * // As default background for all slides @@ -2355,19 +2355,6 @@ declare module "ha:pptx" { * }); */ export declare function gradientBg(color1: string, color2: string, angle?: number): string; - export interface ValidationIssue { - code: string; - severity: "error" | "warn"; - message: string; - part?: string; - slideIndex?: number; - hint?: string; - } - export interface ValidationResult { - ok: boolean; - errors: ValidationIssue[]; - warnings: ValidationIssue[]; - } /** * Create a new presentation builder. * @@ -2384,12 +2371,11 @@ declare module "ha:pptx" { * titleSlide(pres, { title: 'My Title' }); * contentSlide(pres, { title: 'Content', bullets: ['Point 1', 'Point 2'] }); * - * // For CUSTOM layouts, use customSlide(): - * customSlide(pres, { - * shapes: [textBox({x: 1, y: 1, w: 8, h: 1, text: 'Custom text'}), - * rect({x: 1, y: 3, w: 4, h: 2, fill: pres.theme.accent1})], - * transition: 'fade' - * }); + * // For CUSTOM layouts, use pres.addSlide() directly: + * const bg = solidFill(pres.theme.bg); + * const shapes = textBox({x: 1, y: 1, w: 8, h: 1, text: 'Custom text'}) + + * rect({x: 1, y: 3, w: 4, h: 2, fill: pres.theme.accent1}); + * pres.addSlide(bg, shapes, { transition: 'fade' }); * * // Build final file * const zip = pres.buildZip(); @@ -2477,19 +2463,12 @@ declare module "ha:pptx" { * pres.addBody(textBox({x:1, y:1, w:8, h:1, text:'Hello'})); * * // With solid background: - * pres.addBody([shape1, shape2], { background: '0D1117', transition: 'fade' }); + * pres.addBody(shapes, { background: '0D1117', transition: 'fade' }); * * // With gradient background: - * pres.addBody([shape1], { background: {color1: '000000', color2: '1a1a2e', angle: 180} }); - */ - addBody(shapesInput: ShapeFragment | ShapeFragment[] | string | string[], slideOpts?: SlideOptions): void; - /** - * Internal: add shapes (as pre-validated XML string) to a new slide. - * Resolves background from per-slide > defaultBackground > theme. - * Not on the Presentation interface — internal use only. - * @internal + * pres.addBody(shapes, { background: {color1: '000000', color2: '1a1a2e', angle: 180} }); */ - _addBodyRaw(shapesStr: string, slideOpts?: SlideOptions): void; + addBody(shapesXml: string | string[], slideOpts?: SlideOptions): void; /** * Insert a slide at a specific index. Existing slides shift right. * @param {number} index - Position to insert (0-based). Clamped to valid range. @@ -2775,18 +2754,17 @@ declare module "ha:pptx" { * Add a blank slide with just the theme background (NO content). * * ⚠️ WARNING: This creates an EMPTY slide. You CANNOT add shapes to it later. - * For custom layouts with shapes, use customSlide() instead: + * For custom layouts with shapes, use pres.addSlide() directly instead: * * @example * // DON'T do this — blankSlide creates empty slide with no way to add content: * blankSlide(pres); // Creates empty slide, cannot add shapes after * - * // DO this instead — use customSlide for custom layouts: - * customSlide(pres, { - * shapes: [textBox({x: 1, y: 1, w: 8, h: 1, text: 'Custom slide'}), - * rect({x: 1, y: 3, w: 4, h: 2, fill: pres.theme.accent1})], - * transition: 'fade' - * }); + * // DO this instead — use addSlide for custom layouts: + * const bg = solidFill(pres.theme.bg); + * const shapes = textBox({x: 1, y: 1, w: 8, h: 1, text: 'Custom slide'}) + + * rect({x: 1, y: 3, w: 4, h: 2, fill: pres.theme.accent1}); + * pres.addSlide(bg, shapes, { transition: 'fade' }); * * @param {Object} pres - Presentation object from createPresentation(). REQUIRED as first param. * @returns {void} @@ -3292,9 +3270,9 @@ declare module "ha:pptx" { * @param {string} [opts.titleColor='8B949E'] - Title color * @param {boolean} [opts.lineNumbers=false] - Show line numbers * @param {number} [opts.cornerRadius=4] - Corner radius in points - * @returns {ShapeFragment} Branded shape fragment + * @returns {string} Shape XML fragment */ - export declare function codeBlock(opts: CodeBlockOptions): ShapeFragment; + export declare function codeBlock(opts: CodeBlockOptions): string; /** * Slide configuration for batch creation. * Each object describes one slide using a declarative config. @@ -3426,21 +3404,20 @@ declare module "ha:pptx" { * * @example * // Single image - * const img = fetchAndEmbed(pres, { + * const imgXml = await fetchAndEmbed(pres, { * url: "https://example.com/photo.jpg", - * x: 1, y: 1, w: 4, h: 3, - * fetchFn: fetchBinary + * x: 1, y: 1, w: 4, h: 3 * }); - * customSlide(pres, { shapes: [img, textBox({...})] }); + * customSlide(pres, { shapes: imgXml + textBox({...}) }); * * @example * // With fetch plugin * import { fetchBinary } from "host:fetch"; - * const img = fetchAndEmbed(pres, { + * const imgXml = await fetchAndEmbed(pres, { * url: "https://cdn.example.com/hero.jpg", * x: 0, y: 0, w: 13.333, h: 7.5, * fit: "cover", - * fetchFn: fetchBinary + * fetchFn: fetchBinary // Pass the fetch function * }); * * @param {Object} pres - Presentation object @@ -3453,7 +3430,7 @@ declare module "ha:pptx" { * @param {string} [opts.format] - Image format (auto-detected from URL if omitted) * @param {string} [opts.fit] - Fit mode: 'stretch', 'contain', 'cover' * @param {Function} opts.fetchFn - Fetch function (e.g., fetchBinary from host:fetch) - * @returns {ShapeFragment} Branded image shape fragment + * @returns {string} Image XML fragment for use in shapes */ export declare function fetchAndEmbed(pres: Pres, opts: { url: string; @@ -3464,7 +3441,7 @@ declare module "ha:pptx" { format?: string; fit?: "stretch" | "contain" | "cover"; fetchFn: (url: string) => Uint8Array; - }): ShapeFragment; + }): string; /** * Fetch multiple images and embed them all, returning XML fragments. * Uses fetchBinaryBatch for efficient parallel downloads when maxParallelFetches > 1. @@ -3479,13 +3456,13 @@ declare module "ha:pptx" { * ], * fetchBatchFn: fetchBinaryBatch * }); - * // images = [{ url, shape }, { url, shape }, { url, shape }] or [{ url, error }, ...] + * // images = [{ url, xml }, { url, xml }, { url, xml }] or [{ url, error }, ...] * * @param {Object} pres - Presentation object * @param {Object} opts - Options * @param {Array} opts.items - Array of {url, x, y, w, h, format?, fit?} * @param {Function} opts.fetchBatchFn - Batch fetch function (fetchBinaryBatch from host:fetch) - * @returns {Array} Array of {url, shape: ShapeFragment} or {url, error} for each item + * @returns {Array} Array of {url, xml} or {url, error} for each item */ export declare function fetchAndEmbedBatch(pres: Pres, opts: { items: Array<{ @@ -3504,7 +3481,7 @@ declare module "ha:pptx" { }>; }): Array<{ url: string; - shape?: ShapeFragment; + xml?: string; error?: string; }>; } diff --git a/package.json b/package.json index fae1070..8527e7b 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "fmt:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\" \"plugins/**/*.ts\" \"builtin-modules/**/*.js\"", "check": "npm run fmt:check && npm run typecheck && npm run test", "prepare": "node -e \"if(require('fs').existsSync('scripts/build-modules.js'))require('child_process').execSync('npm run build:modules',{stdio:'inherit'})\"", - "postinstall": "node -e \"var fs=require('fs'),cp=require('child_process');if(fs.existsSync('scripts/patch-vscode-jsonrpc.js')){cp.execSync('node scripts/patch-vscode-jsonrpc.js',{stdio:'inherit'});cp.execSync('node scripts/check-native-runtime.js',{stdio:'inherit'})}\"" + "postinstall": "node -e \"var fs=require('fs'),cp=require('child_process');if(fs.existsSync('scripts/patch-vscode-jsonrpc.js')){cp.execSync('node scripts/patch-vscode-jsonrpc.js',{stdio:'inherit'});cp.execSync('node scripts/check-native-runtime.js',{stdio:'inherit'});}\"" }, "dependencies": { "@github/copilot-sdk": "^0.1.32", diff --git a/scripts/build-binary.js b/scripts/build-binary.js index 193a04c..469f47d 100644 --- a/scripts/build-binary.js +++ b/scripts/build-binary.js @@ -426,10 +426,10 @@ writeFileSync(launcherCjsPath, launcherCjs); // Node.js launcher (works everywhere, used as npm bin entry) const nodeLauncher = `#!/usr/bin/env node import { join, dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { fileURLToPath, pathToFileURL } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const cjs = join(__dirname, '..', 'lib', 'hyperagent-launcher.cjs'); -await import('file://' + cjs.replace(/\\\\/g, '/')); +await import(pathToFileURL(cjs).href); `; const nodeLauncherPath = join(BIN_DIR, "hyperagent"); writeFileSync(nodeLauncherPath, nodeLauncher); @@ -494,7 +494,7 @@ To run (option 3 - add to PATH permanently via System Properties): ${launcherPath} To run (option 2 - add to PATH): - export PATH="${BIN_DIR}:\\$PATH" + export PATH="${BIN_DIR}:$PATH" hyperagent To run (option 3 - symlink): diff --git a/tests/pattern-loader.test.ts b/tests/pattern-loader.test.ts index 879b89c..a36f3bc 100644 --- a/tests/pattern-loader.test.ts +++ b/tests/pattern-loader.test.ts @@ -23,8 +23,16 @@ describe("pattern-loader", () => { afterEach(() => { try { rmSync(TMP_DIR, { recursive: true, force: true }); - } catch { - // Windows: Defender/indexer may hold a lock — not worth failing the test + } catch (err: unknown) { + // Windows Defender/indexer can hold file locks — only swallow those + const code = (err as NodeJS.ErrnoException).code; + if ( + process.platform === "win32" && + (code === "EBUSY" || code === "EPERM") + ) { + return; + } + throw err; } });