@office-kit/pptx-editor 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -194,7 +194,8 @@ tool with the next release.
194
194
 
195
195
  - **Names** are the export names (`setShapeFill`, `addSlideShape`, …), sorted.
196
196
  Four tools are the editor's own, for finding what the others take:
197
- `listSlides`, `listShapes` (refs, kind, bounds and text of each shape),
197
+ `listSlides`, `listShapes` (refs, kind, bounds and text of each shape, and a
198
+ chart's kind, title, categories and series values),
198
199
  `listLayouts` and `listComments`.
199
200
  - **Descriptions** are the exports' TSDoc. **Input schemas** are JSON Schema
200
201
  (draft 2020-12) generated from the functions' TypeScript signatures, one
@@ -326,6 +327,38 @@ The merge itself is `mergeDecks(base, ours, theirs)` from
326
327
  `@office-kit/pptx-editor/merge`. It has no DOM dependency, for hosts that merge
327
328
  on a server, and returns `{ ok: true, bytes }` or `{ ok: false, conflicts }`.
328
329
 
330
+ ### Small edits without the editor
331
+
332
+ `@office-kit/pptx-editor/headless` gives an agent that has no editor (on a
333
+ server, say) nine edits for small revisions, as one tool: `setShapeText`,
334
+ `setTableCellText`, `setChartData`, `setShapeTextFormat` (size, bold, italic,
335
+ color of a shape's whole text), `setShapeFill`, `setShapeBounds`,
336
+ `removeShape`, `moveSlide` and `removeSlide`, in one compact schema. Text edits always keep the formatting of the text they do not change.
337
+ It has no DOM dependency and runs in Node.
338
+
339
+ ```ts
340
+ import { loadPresentation, savePresentation } from '@office-kit/pptx';
341
+ import {
342
+ agentEditSchema,
343
+ applyAgentEdits,
344
+ decodeAgentEdits,
345
+ readForAgent,
346
+ } from '@office-kit/pptx-editor/headless';
347
+
348
+ const deck = await loadPresentation(bytes);
349
+ const context = readForAgent(deck, null); // slides, notes, shapes, chart values
350
+ // Give the model `agentEditSchema` as one tool's input schema; it answers `{ edits }`.
351
+ const { edits, touchedSlides } = decodeAgentEdits(input.edits);
352
+ await applyAgentEdits(deck, edits);
353
+ const revised = await savePresentation(deck);
354
+ ```
355
+
356
+ `decodeAgentEdits` checks the whole batch without a presentation and throws an
357
+ `AgentEditError` (`index: null`) naming every problem by its JSON Pointer.
358
+ `applyAgentEdits` applies the edits in order; when one fails it rejects with
359
+ that edit's `index`, and the edits before it have been applied, so discard
360
+ the presentation.
361
+
329
362
  ## Behaviour on your page
330
363
 
331
364
  - **Styles are isolated.** The editor renders inside a shadow root on an
@@ -1,5 +1,17 @@
1
- import { r as shapeRef } from "./src-BrBOgen_.js";
1
+ import { i as shapeRef } from "./shape-ref-B5iNfYWh.js";
2
2
  import * as pptx from "@office-kit/pptx";
3
+ //#region \0rolldown/runtime.js
4
+ var __defProp = Object.defineProperty;
5
+ var __exportAll = (all, no_symbols) => {
6
+ let target = {};
7
+ for (var name in all) __defProp(target, name, {
8
+ get: all[name],
9
+ enumerable: true
10
+ });
11
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
12
+ return target;
13
+ };
14
+ //#endregion
3
15
  //#region src/manifest/tools.generated.ts
4
16
  const generatedTools = {
5
17
  notTools: {
@@ -1995,10 +2007,6 @@ const generatedTools = {
1995
2007
  type: "string",
1996
2008
  enum: ["in", "out"]
1997
2009
  },
1998
- AnimationInOutOrString: { anyOf: [{ $ref: "#/$defs/AnimationInOut" }, {
1999
- type: "string",
2000
- enum: ["none", "cross"]
2001
- }] },
2002
2010
  Bar3DShape: {
2003
2011
  type: "string",
2004
2012
  enum: [
@@ -2074,7 +2082,7 @@ const generatedTools = {
2074
2082
  type: "string",
2075
2083
  enum: ["none", "cross"]
2076
2084
  }],
2077
- description: "Major-tick mark mode on the category axis (`<c:catAx><c:majorTickMark>`)."
2085
+ description: "Major-tick mark mode on the category axis (`<c:catAx><c:majorTickMark>`).\nDefault: `'none'` on bar / column charts, `'out'` otherwise."
2078
2086
  },
2079
2087
  CategoryAxisMinorGridlineColor: {
2080
2088
  type: "string",
@@ -2093,7 +2101,7 @@ const generatedTools = {
2093
2101
  type: "string",
2094
2102
  enum: ["none", "cross"]
2095
2103
  }],
2096
- description: "Minor-tick mark mode on the category axis (`<c:catAx><c:minorTickMark>`)."
2104
+ description: "Minor-tick mark mode on the category axis (`<c:catAx><c:minorTickMark>`); default `'none'`."
2097
2105
  },
2098
2106
  CategoryAxisNoMultiLevelLabel: {
2099
2107
  type: "boolean",
@@ -2429,8 +2437,20 @@ const generatedTools = {
2429
2437
  type: "number",
2430
2438
  description: "Axis line width in EMU, the mirror of `ChartSpec.valueAxisLineWidthEmu`."
2431
2439
  },
2432
- majorTickMark: { $ref: "#/$defs/AnimationInOutOrString" },
2433
- minorTickMark: { $ref: "#/$defs/AnimationInOutOrString" },
2440
+ majorTickMark: {
2441
+ anyOf: [{ $ref: "#/$defs/AnimationInOut" }, {
2442
+ type: "string",
2443
+ enum: ["none", "cross"]
2444
+ }],
2445
+ description: "Major tick marks; default `'out'`."
2446
+ },
2447
+ minorTickMark: {
2448
+ anyOf: [{ $ref: "#/$defs/AnimationInOut" }, {
2449
+ type: "string",
2450
+ enum: ["none", "cross"]
2451
+ }],
2452
+ description: "Minor tick marks; default `'none'`."
2453
+ },
2434
2454
  tickLabelPos: {
2435
2455
  type: "string",
2436
2456
  enum: [
@@ -2865,7 +2885,7 @@ const generatedTools = {
2865
2885
  PointDataLabels: {
2866
2886
  type: "array",
2867
2887
  items: { anyOf: [{ type: "null" }, { $ref: "#/$defs/ChartDataLabels" }] },
2868
- description: "Optional per-data-point data-label overrides\n(`<c:dLbls><c:dLbl><c:idx val=\"N\"/>…`). Sparse — `null` slots fall back\nto the series-level `dataLabels`. The reference desktop app draws the per-point element\nover the series defaults, which is how pie / doughnut exporters give each\nslice its own label content and font."
2888
+ description: "Optional per-data-point data-label overrides\n(`<c:dLbls><c:dLbl><c:idx val=\"N\"/>…`). Sparse — `null` slots fall back\nto the series-level `dataLabels`, else the chart-level `dataLabels`, else\nno label. That fallback is written as the series' own `<c:dLbls>`, so\nreading the chart back reports it as the series' `dataLabels`. The\nreference desktop app draws the per-point element\nover the series defaults, which is how pie / doughnut exporters give each\nslice its own label content and font."
2869
2889
  },
2870
2890
  PointExplosions: {
2871
2891
  type: "array",
@@ -3064,7 +3084,7 @@ const generatedTools = {
3064
3084
  type: "string",
3065
3085
  enum: ["none", "cross"]
3066
3086
  }],
3067
- description: "Minor-tick mark mode on the value axis (`<c:valAx><c:minorTickMark>`)."
3087
+ description: "Minor-tick mark mode on the value axis (`<c:valAx><c:minorTickMark>`); default `'none'`."
3068
3088
  },
3069
3089
  ValueAxisOrientation: {
3070
3090
  type: "string",
@@ -4560,7 +4580,7 @@ const generatedTools = {
4560
4580
  },
4561
4581
  {
4562
4582
  name: "compactPackage",
4563
- description: "Removes media parts that no rels graph references. Returns the\nlist of removed part names. Useful after a sequence of slide\nremovals leaves orphan images behind.\n\nOnly `/ppt/media/...` parts are considered. The check walks every\n`.rels` part in the package and resolves each internal rel target\nagainst its source part name to build the live media set.",
4583
+ description: "Removes every part that cannot be reached from the package root\n(`/_rels/.rels`) through internal relationships, together with its\n`.rels` part and its `[Content_Types].xml` override. Returns the\nremoved part names.\n\n`removeSlide` removes only the slide and its `.rels`, so the slide's\ncharts, embedded workbooks, notes slide, tags and media stay in the\npackage until this runs. Parts still in use — including layouts no\nslide uses, which their master references — are kept. Any other part\nnothing points at, such as custom data added without a relationship, is\nremoved too. When `/_rels/.rels` does not reach `/ppt/presentation.xml`,\nnothing is removed.",
4564
4584
  args: [null],
4565
4585
  input_schema: {
4566
4586
  type: "object",
@@ -5072,7 +5092,7 @@ const generatedTools = {
5072
5092
  },
5073
5093
  {
5074
5094
  name: "removeSlide",
5075
- description: "Removes the given slide from the deck. Removes the `<p:sldId>`, the\n`presentation.xml.rels` entry, and the slide part + its `.rels` part.\nLinks to this slide from other slides are cleared to prevent accidental\nretargeting when a slide part name is reused.\n\nMedia parts are intentionally NOT cleaned up — they may be shared\nwith other slides. The freed `sldId` is NOT reused on subsequent\n`addSlide` calls (the reference desktop app's quirk, see plan §Risks).",
5095
+ description: "Removes the given slide from the deck. Removes the `<p:sldId>`, the\n`presentation.xml.rels` entry, and the slide part + its `.rels` part.\nLinks to this slide from other slides are cleared to prevent accidental\nretargeting when a slide part name is reused.\n\nParts the slide referenced (media, charts and their workbooks, the notes\nslide, tags) are left in place because other slides may share them; call\n`compactPackage` afterwards to drop the ones nothing references any more.\nThe freed `sldId` is NOT reused on subsequent `addSlide` calls (the\nreference desktop app's quirk, see plan §Risks).",
5076
5096
  args: [null, "slide"],
5077
5097
  input_schema: {
5078
5098
  type: "object",
@@ -5685,6 +5705,87 @@ const generatedTools = {
5685
5705
  },
5686
5706
  output: { type: "null" }
5687
5707
  },
5708
+ {
5709
+ name: "setChartData",
5710
+ description: "Replaces the data of a bar, column, line, area, pie or doughnut chart.\n\nWhen `kind` is the chart's own and `series` names the same series (in any\norder), only the values change: everything else in the chart, its\nformatting included, is kept. Changing `kind`, or adding, removing or\nrenaming a series, builds the chart again from its title, axis titles,\nlegend, series names and colors, and the rest of its formatting returns\nto the defaults; to keep it, copy the series names exactly as they are\nread. Each series needs one value per category: when changing\n`categories`, pass every series with values of the same length. A pie or\ndoughnut chart takes exactly one series. On a date axis the categories\nare read as date serial numbers (days since 1899-12-30, e.g. `\"45292\"`\nfor 2024-01-01) and must be passed the same way. The embedded workbook\nis rewritten with the new data.\n\nThrows when the chart is of another kind (scatter, bubble, stock,\nsurface, radar, or one this library cannot read), when `categories` or\n`series` is empty, when a series has more or fewer values than there are\ncategories, when a date-axis category is not a number, and when\ncategories change on a chart whose categories have several levels.",
5711
+ args: ["chart", "data"],
5712
+ input_schema: {
5713
+ type: "object",
5714
+ properties: {
5715
+ chart: { $ref: "#/$defs/ChartRef" },
5716
+ data: {
5717
+ type: "object",
5718
+ properties: {
5719
+ kind: {
5720
+ type: "string",
5721
+ enum: [
5722
+ "bar",
5723
+ "column",
5724
+ "line",
5725
+ "pie",
5726
+ "doughnut",
5727
+ "area"
5728
+ ]
5729
+ },
5730
+ categories: {
5731
+ type: "array",
5732
+ items: { type: "string" }
5733
+ },
5734
+ series: {
5735
+ type: "array",
5736
+ items: {
5737
+ type: "object",
5738
+ properties: {
5739
+ name: { type: "string" },
5740
+ values: {
5741
+ type: "array",
5742
+ items: { type: ["null", "number"] },
5743
+ description: "One value per category; `null` leaves the point empty."
5744
+ }
5745
+ },
5746
+ required: ["name", "values"],
5747
+ additionalProperties: false
5748
+ },
5749
+ description: "Every series of the chart, in order."
5750
+ }
5751
+ },
5752
+ additionalProperties: false
5753
+ }
5754
+ },
5755
+ required: ["chart", "data"],
5756
+ additionalProperties: false,
5757
+ $defs: {
5758
+ ChartRef: {
5759
+ $ref: "#/$defs/ShapeRef",
5760
+ description: "A chart, by the ShapeRef of the graphic frame that holds it."
5761
+ },
5762
+ ShapeRef: {
5763
+ type: "object",
5764
+ description: "A shape, by its slide and id, as `listShapes` or the user's selection reports it. `slideIndex` and `name` are informational.",
5765
+ properties: {
5766
+ slide: { $ref: "#/$defs/SlideRef" },
5767
+ shapeId: {
5768
+ type: "integer",
5769
+ minimum: 0
5770
+ },
5771
+ slideIndex: {
5772
+ type: "integer",
5773
+ minimum: 0
5774
+ },
5775
+ name: { type: "string" }
5776
+ },
5777
+ required: ["slide", "shapeId"],
5778
+ additionalProperties: false
5779
+ },
5780
+ SlideRef: {
5781
+ type: "string",
5782
+ pattern: "^/ppt/slides/[^/]+\\.xml$",
5783
+ description: "A slide, by its part name as `listSlides` reports it, e.g. \"/ppt/slides/slide1.xml\"."
5784
+ }
5785
+ }
5786
+ },
5787
+ output: { type: "null" }
5788
+ },
5688
5789
  {
5689
5790
  name: "setChartSpec",
5690
5791
  description: "Replaces the chart definition on an existing graphic-frame chart\nshape. Updates the inline `<c:strCache>` / `<c:numCache>` blocks so\nthe reference desktop app renders the new data without opening the embedded\nworkbook. The shape's geometry (position / size / rotation) is\npreserved verbatim.\n\nThe embedded xlsx is re-written too — it's what the \"Edit data\"\naffordance opens. The previous workbook is replaced wholesale (no\nattempt to preserve styles a user added in a spreadsheet app).\n\nPass any `ChartSpec`, including a different `kind` from the\noriginal; this acts as \"change my column chart to a line chart with\nfresh data.\"",
@@ -7416,10 +7517,6 @@ const generatedTools = {
7416
7517
  type: "string",
7417
7518
  enum: ["in", "out"]
7418
7519
  },
7419
- AnimationInOutOrString: { anyOf: [{ $ref: "#/$defs/AnimationInOut" }, {
7420
- type: "string",
7421
- enum: ["none", "cross"]
7422
- }] },
7423
7520
  Bar3DShape: {
7424
7521
  type: "string",
7425
7522
  enum: [
@@ -7495,7 +7592,7 @@ const generatedTools = {
7495
7592
  type: "string",
7496
7593
  enum: ["none", "cross"]
7497
7594
  }],
7498
- description: "Major-tick mark mode on the category axis (`<c:catAx><c:majorTickMark>`)."
7595
+ description: "Major-tick mark mode on the category axis (`<c:catAx><c:majorTickMark>`).\nDefault: `'none'` on bar / column charts, `'out'` otherwise."
7499
7596
  },
7500
7597
  CategoryAxisMinorGridlineColor: {
7501
7598
  type: "string",
@@ -7514,7 +7611,7 @@ const generatedTools = {
7514
7611
  type: "string",
7515
7612
  enum: ["none", "cross"]
7516
7613
  }],
7517
- description: "Minor-tick mark mode on the category axis (`<c:catAx><c:minorTickMark>`)."
7614
+ description: "Minor-tick mark mode on the category axis (`<c:catAx><c:minorTickMark>`); default `'none'`."
7518
7615
  },
7519
7616
  CategoryAxisNoMultiLevelLabel: {
7520
7617
  type: "boolean",
@@ -7854,8 +7951,20 @@ const generatedTools = {
7854
7951
  type: "number",
7855
7952
  description: "Axis line width in EMU, the mirror of `ChartSpec.valueAxisLineWidthEmu`."
7856
7953
  },
7857
- majorTickMark: { $ref: "#/$defs/AnimationInOutOrString" },
7858
- minorTickMark: { $ref: "#/$defs/AnimationInOutOrString" },
7954
+ majorTickMark: {
7955
+ anyOf: [{ $ref: "#/$defs/AnimationInOut" }, {
7956
+ type: "string",
7957
+ enum: ["none", "cross"]
7958
+ }],
7959
+ description: "Major tick marks; default `'out'`."
7960
+ },
7961
+ minorTickMark: {
7962
+ anyOf: [{ $ref: "#/$defs/AnimationInOut" }, {
7963
+ type: "string",
7964
+ enum: ["none", "cross"]
7965
+ }],
7966
+ description: "Minor tick marks; default `'none'`."
7967
+ },
7859
7968
  tickLabelPos: {
7860
7969
  type: "string",
7861
7970
  enum: [
@@ -8286,7 +8395,7 @@ const generatedTools = {
8286
8395
  PointDataLabels: {
8287
8396
  type: "array",
8288
8397
  items: { anyOf: [{ type: "null" }, { $ref: "#/$defs/ChartDataLabels" }] },
8289
- description: "Optional per-data-point data-label overrides\n(`<c:dLbls><c:dLbl><c:idx val=\"N\"/>…`). Sparse — `null` slots fall back\nto the series-level `dataLabels`. The reference desktop app draws the per-point element\nover the series defaults, which is how pie / doughnut exporters give each\nslice its own label content and font."
8398
+ description: "Optional per-data-point data-label overrides\n(`<c:dLbls><c:dLbl><c:idx val=\"N\"/>…`). Sparse — `null` slots fall back\nto the series-level `dataLabels`, else the chart-level `dataLabels`, else\nno label. That fallback is written as the series' own `<c:dLbls>`, so\nreading the chart back reports it as the series' `dataLabels`. The\nreference desktop app draws the per-point element\nover the series defaults, which is how pie / doughnut exporters give each\nslice its own label content and font."
8290
8399
  },
8291
8400
  PointExplosions: {
8292
8401
  type: "array",
@@ -8503,7 +8612,7 @@ const generatedTools = {
8503
8612
  type: "string",
8504
8613
  enum: ["none", "cross"]
8505
8614
  }],
8506
- description: "Minor-tick mark mode on the value axis (`<c:valAx><c:minorTickMark>`)."
8615
+ description: "Minor-tick mark mode on the value axis (`<c:valAx><c:minorTickMark>`); default `'none'`."
8507
8616
  },
8508
8617
  ValueAxisOrientation: {
8509
8618
  type: "string",
@@ -22957,6 +23066,12 @@ const generatedTools = {
22957
23066
  };
22958
23067
  //#endregion
22959
23068
  //#region src/core/agent-tools.ts
23069
+ var agent_tools_exports = /* @__PURE__ */ __exportAll({
23070
+ editorTools: () => editorTools,
23071
+ runTool: () => runTool,
23072
+ schemaErrors: () => schemaErrors,
23073
+ shapeSummary: () => shapeSummary
23074
+ });
22960
23075
  const library = pptx;
22961
23076
  const DEFS = "#/$defs/";
22962
23077
  function slideByPartName(presentation, partName) {
@@ -23206,6 +23321,7 @@ const NO_INPUT = {
23206
23321
  properties: {},
23207
23322
  additionalProperties: false
23208
23323
  };
23324
+ /** A shape as `listShapes` reports it. */
23209
23325
  function shapeSummary(presentation, shape) {
23210
23326
  const bounds = pptx.getShapeBoundsResolved(presentation, shape);
23211
23327
  const summary = {
@@ -23222,6 +23338,17 @@ function shapeSummary(presentation, shape) {
23222
23338
  if (pptx.isTableShape(shape)) {
23223
23339
  const { rows, cols } = pptx.getTableDimensions(shape);
23224
23340
  summary.cells = Array.from({ length: rows }, (_, row) => Array.from({ length: cols }, (_, col) => pptx.getTableCellText(pptx.getTableCell(shape, row, col))));
23341
+ } else if (pptx.isChartShape(shape)) {
23342
+ const spec = pptx.getShapeChartSpec(shape);
23343
+ summary.chart = spec && {
23344
+ kind: spec.kind,
23345
+ title: spec.title ?? null,
23346
+ categories: spec.categories,
23347
+ series: spec.series.map(({ name, values }) => ({
23348
+ name,
23349
+ values
23350
+ }))
23351
+ };
23225
23352
  } else if (pptx.hasShapeText(shape)) summary.text = pptx.getShapeText(shape);
23226
23353
  return summary;
23227
23354
  }
@@ -23243,7 +23370,7 @@ const readTools = [
23243
23370
  },
23244
23371
  {
23245
23372
  name: "listShapes",
23246
- description: `Lists the shapes on a slide, back to front: each shape's ref (which other tools take as "shape", or with "row" and "col" added as a table "cell"), its kind, placeholder type, bounds and text (for a table, the text of every cell). Bounds are in EMU: 914400 per inch, 360000 per cm, 12700 per point.`,
23373
+ description: `Lists the shapes on a slide, back to front: each shape's ref (which other tools take as "shape", or with "row" and "col" added as a table "cell"), its kind, placeholder type, bounds and text (for a table, the text of every cell; for a chart, its kind, title, categories and series values, or null when its kind cannot be read; date-axis categories are date serial numbers). Bounds are in EMU: 914400 per inch, 360000 per cm, 12700 per point.`,
23247
23374
  input_schema: SLIDE_INPUT,
23248
23375
  read: (presentation, input) => pptx.getSlideShapes(input.slide).map((shape) => shapeSummary(presentation, shape))
23249
23376
  },
@@ -23284,6 +23411,18 @@ function defsOf(schema) {
23284
23411
  return schema.$defs ?? {};
23285
23412
  }
23286
23413
  /**
23414
+ * The problems with `value` against `schema`, a root schema with its own
23415
+ * `$defs`, each named by its JSON Pointer; empty when it matches.
23416
+ */
23417
+ function schemaErrors(schema, value) {
23418
+ const checking = {
23419
+ defs: defsOf(schema),
23420
+ errors: []
23421
+ };
23422
+ decode(schema, value, "", checking);
23423
+ return checking.errors;
23424
+ }
23425
+ /**
23287
23426
  * Runs tool `name` with the model's `input`. Rejects, editing nothing, when
23288
23427
  * there is no such tool or the input does not match its schema; the message
23289
23428
  * lists each problem by its JSON Pointer, for the model to correct.
@@ -23292,12 +23431,8 @@ async function runTool(host, name, input) {
23292
23431
  const tool = byName.get(name);
23293
23432
  if (!tool) throw new Error(`There is no tool ${JSON.stringify(name)}. Call one of the tools listed.`);
23294
23433
  const defs = defsOf(tool.input_schema);
23295
- const checking = {
23296
- defs,
23297
- errors: []
23298
- };
23299
- decode(tool.input_schema, input, "", checking);
23300
- if (checking.errors.length > 0) throw new Error(`Invalid input for ${name}:\n${checking.errors.map((error) => `- ${error}`).join("\n")}`);
23434
+ const errors = schemaErrors(tool.input_schema, input);
23435
+ if (errors.length > 0) throw new Error(`Invalid input for ${name}:\n${errors.map((error) => `- ${error}`).join("\n")}`);
23301
23436
  const resolve = (presentation) => decode(tool.input_schema, input, "", {
23302
23437
  defs,
23303
23438
  errors: [],
@@ -23318,6 +23453,6 @@ async function runTool(host, name, input) {
23318
23453
  return result;
23319
23454
  }
23320
23455
  //#endregion
23321
- export { editorTools, runTool };
23456
+ export { generatedTools as a, shapeSummary as i, runTool as n, schemaErrors as r, agent_tools_exports as t };
23322
23457
 
23323
- //# sourceMappingURL=agent-tools-CEZAOXNe.js.map
23458
+ //# sourceMappingURL=agent-tools-EU7Eb-FV.js.map