@eigenpal/cli 0.13.0 → 0.13.2

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.
@@ -23,7 +23,7 @@ implement at runtime. Server-side validation errors point you here.
23
23
 
24
24
  - `ai.*` — model-backed processing (parse, extract, classify). Cost + latency depend on the model.
25
25
  - `transform.*` — deterministic data transforms (set, remove, combine, split, merge,
26
- script, template, pdf-embed, xlsx-to-json). WASM sandboxed where applicable.
26
+ script, template, pdf-embed, xlsx-to-json, json-to-xlsx). WASM sandboxed where applicable.
27
27
  - `action.*` — external side effects (HTTP, invoke another workflow, website reader).
28
28
  - `control.*` — flow control (if, foreach, parallel, parallel_map, wait, fail).
29
29
 
@@ -35,13 +35,16 @@ the catalog tells you what fields it takes.
35
35
 
36
36
  | Use case | Step |
37
37
  | --------------------------------- | ------------------------------------------------- |
38
- | Read a PDF / DOCX / image | `ai.parse` |
38
+ | Read a PDF / DOCX / image (native-first) | `ai.parse` with `parseMode: native` or `native-or-ocr` |
39
+ | Read a PDF / DOCX / image (full OCR/vision) | `ai.parse` with `parseMode: ocr` or `vision` |
39
40
  | Pull a typed object from text | `ai.extract` with `config.schema` |
40
41
  | Pick one label from a fixed set | `ai.classify` with `config.labels` |
41
42
  | Reject bad inputs with a 4xx code | `control.fail` (often after `ai.classify`) |
42
43
  | Sum / filter / regex | `transform.script` (NOT Liquid) |
43
- | Render a DOCX template | `transform.template` |
44
+ | Render a DOCX or XLSX template (YAML workflow) | `transform.template` with `tmpl_...` or `./file.xlsx` |
45
+ | Fill a DOCX or XLSX template (runtime agent) | fill-template platform skill |
44
46
  | Convert XLSX to JSON | `transform.xlsx-to-json` |
47
+ | Convert JSON rows to XLSX | `transform.json-to-xlsx` |
45
48
  | Merge or combine objects | `transform.combine` / `transform.merge` |
46
49
  | Conditional execution | `if:` on the step (Liquid) or `control.if` |
47
50
  | Map over an input array | `forEach:` on the step or `control.foreach` |
@@ -51,6 +54,59 @@ the catalog tells you what fields it takes.
51
54
  | Call another workflow | `action.invoke-workflow` |
52
55
  | Fetch a webpage as markdown | `action.website-reader` |
53
56
 
57
+ ## Workspace vs Git templates
58
+
59
+ Two separate template systems share DOCX/XLSX placeholder syntax but not
60
+ references:
61
+
62
+ | Goal | Mechanism |
63
+ | --- | --- |
64
+ | YAML workflow produces a filled DOCX/XLSX | `transform.template` with `templateId: tmpl_...` or `template: ./templates/foo.xlsx` (CLI push uploads) |
65
+ | Runtime agent produces a filled DOCX/XLSX | fill-template platform skill against Git templates |
66
+
67
+ Git templates (`agents/<agent>/templates/<slug>/`, shared
68
+ `resources/templates/<slug>/`) never receive a `tmpl_...` ID and cannot be
69
+ used in `transform.template`. Manage Git templates through the agent source
70
+ loop — see the eigenpal skill's **Agent templates (Git source)** section.
71
+
72
+ Workspace templates are tenant-scoped `tmpl_...` resources with immutable
73
+ `tmpr_...` revisions. Manage them from the CLI (preferred) or Studio:
74
+
75
+ ```bash
76
+ eigenpal workflow templates upload ./templates/roster.xlsx --json
77
+ eigenpal workflow templates list --json
78
+ eigenpal workflow templates get tmpl_... --json
79
+ eigenpal workflow templates smoke ./templates/roster.xlsx --data ./fixture.json --out ./filled.xlsx
80
+ eigenpal workflow validate ./workflow.yaml --online
81
+ eigenpal workflow push --file workflow.yaml
82
+ ```
83
+
84
+ Author YAML with either a live id or a source-controlled path. Push uploads
85
+ the file (skipped when the SHA-256 still matches) and sends `templateId` +
86
+ current `templateRevisionId` to the server without rewriting the file on disk.
87
+
88
+ `templateId` must be `tmpl_...` when not using a local path; file IDs
89
+ (`file_...`) are rejected at validate/push.
90
+
91
+ In the Office file itself use `{placeholder}` and, for XLSX row expansion,
92
+ `{table:array.prop}`. `{{placeholder}}` is Liquid for YAML `data` mapping
93
+ only — putting it in an XLSX file fails at fill. Example prototype row:
94
+
95
+ ```yaml
96
+ - name: fill-roster
97
+ type: transform.template
98
+ with:
99
+ templateId: tmpl_...
100
+ data:
101
+ report_title: "{{ steps.extract.output.title }}"
102
+ subjects: "{{ steps.extract.output.subjects }}"
103
+ ```
104
+
105
+ Spreadsheet cells: `{report_title}`, `{table:subjects.first_name}`,
106
+ `{table:subjects.last_name}`. Null/blank cells stay empty; numbers and
107
+ booleans keep spreadsheet types; every sheet is filled; existing formulas
108
+ stay formulas.
109
+
54
110
  ## Liquid vs `transform.script`
55
111
 
56
112
  | Logic shape | Use |
@@ -356,7 +412,7 @@ _Generated from `STEP_SCHEMAS` in `@eigenpal/types/src/workflow/step-configs.ts`
356
412
 
357
413
  #### `ai.parse` — Parse Document
358
414
 
359
- Extract text from documents (PDF, DOCX, images) using OCR or vision models
415
+ Extract text from documents (PDF, DOCX, images) using native extraction, OCR, or vision models
360
416
 
361
417
  **Durable retry:** Provider request retries are separate; the workflow engine does not durably retry this step.
362
418
 
@@ -365,7 +421,7 @@ Extract text from documents (PDF, DOCX, images) using OCR or vision models
365
421
  | Field | Type | Required | Default | Description |
366
422
  | --- | --- | --- | --- | --- |
367
423
  | `input` | string | yes | | Storage reference or template expression for the document |
368
- | `parseMode` | `"ocr"` \| `"vision"` | no | | Base parser for PDF/image inputs. OCR is the default; vision uses the selected LLM. Text and Office files always use native parsing. |
424
+ | `parseMode` | `"ocr"` \| `"vision"` \| `"native"` \| `"native-or-ocr"` | no | | Base parser for PDF/image inputs. OCR is the default; vision uses the selected LLM. `native` extracts PDF embedded text only and never calls OCR or vision. `native-or-ocr` extracts native text, runs page-quality diagnostics, and requests OCR when pages have detectable anomalies (empty, U+FFFD, lone surrogates, forbidden controls, unassigned/noncharacter, heavy PUA). Page selection, subset egress, and billing are provider-dependent. Valid-looking wrong text and literal "?" are not flagged. Text and Office files always use local parsing. |
369
425
  | `ocrModel` | string | no | | OCR provider ID for PDF/image parsing |
370
426
  | `llmModel` | string | no | | LLM provider ID for vision-based parsing |
371
427
  | `figureModel` | string | no | | Vision model used only for the optional figure-description pass |
@@ -391,6 +447,7 @@ Extract text from documents (PDF, DOCX, images) using OCR or vision models
391
447
  | `parserType` | `"plaintext"` \| `"office"` \| `"llm-vision"` \| `"ocr"` | yes | | |
392
448
  | `parserVersion` | string | no | | |
393
449
  | `model` | string | no | | Model used (for LLM/OCR parsers) |
450
+ | `processingStrategy` | `"native"` \| `"ocr"` \| `"vision"` \| `"hybrid"` | no | | How this result was produced: `native` (local PDF text only), `ocr`, `vision`, or `hybrid` (native pages merged with OCR on fallback pages). |
394
451
  | `structured` | record<string, unknown> | no | | Canonical structured document with ordered blocks, regions, bounding boxes, tables, figures, and chunks when supported by the parser |
395
452
 
396
453
  #### `ai.extract` — Extract Data
@@ -637,7 +694,7 @@ Merge multiple named inputs into a single output
637
694
 
638
695
  #### `transform.template` — Fill Template
639
696
 
640
- Fill a DOCX template with data from previous steps. Select a template in the workflow builder or provide a template ID from your workspace.
697
+ Fill a DOCX or XLSX workspace template with data from previous steps. Reference a tmpl_... id, or a local ./templates/file.xlsx path (CLI push uploads it). Git agent templates use the fill-template skill instead and cannot be referenced here. File IDs (file_...) are not accepted. Placeholders are auto-detected. In the Office file use {placeholder} and {table:array.prop}; {{placeholder}} in an XLSX file is rejected ({{ }} is YAML Liquid only).
641
698
 
642
699
  **Durable retry:** Transforms, including those that write files, are not durably retried.
643
700
 
@@ -645,11 +702,13 @@ Fill a DOCX template with data from previous steps. Select a template in the wor
645
702
 
646
703
  | Field | Type | Required | Default | Description |
647
704
  | --- | --- | --- | --- | --- |
648
- | `templateId` | string | yes | | ID of the template from templates table |
649
- | `data` | record<string, unknown> | yes | | Data object to merge into template. Each key must be explicitly defined - cannot pass a whole object as single expression |
650
- | `outputFilename` | string | no | | Output filename - supports {{field}} syntax |
651
- | `highlightNotFound` | boolean | no | `true` | Highlight missing variables with red-colored text in the output document |
652
- | `notFoundText` | string | no | `"NOT FOUND"` | Text to display for missing variables when highlightNotFound is enabled |
705
+ | `templateId` | string | no | | Workspace template ID (tmpl_...) from the Templates table (DOCX or XLSX). Git agent templates cannot be referenced here. File IDs (file_...) are not accepted. Mutually exclusive with `template`. |
706
+ | `template` | string | no | | Local DOCX or XLSX path relative to the workflow YAML (e.g. ./templates/foo.xlsx). CLI push keeps the real path inside the workflow project unless you pass --allow-external-templates, uploads unmatched files as new tmpl_ resources, and does not rewrite the source YAML. Mutually exclusive with templateId. |
707
+ | `templateRevisionId` | string | no | | Immutable template revision ID (tmpr_...). Pin this when executions must keep using the same template bytes after replacements. Requires templateId; local `template` paths are pinned automatically on push. |
708
+ | `data` | record<string, unknown> | yes | | Data object to merge into template. Each key must be explicitly defined - cannot pass a whole object as single expression. |
709
+ | `outputFilename` | string | no | | Output filename - supports {{field}} syntax; .docx or .xlsx extension is added if omitted |
710
+ | `highlightNotFound` | boolean | no | `true` | Highlight missing variables with red-colored text in the output document (DOCX only; ignored for XLSX) |
711
+ | `notFoundText` | string | no | `"NOT FOUND"` | Text to display for missing variables when highlightNotFound is enabled (DOCX only; ignored for XLSX) |
653
712
 
654
713
  **Output:** `object`
655
714
 
@@ -703,6 +762,31 @@ Convert XLSX spreadsheet to JSON array of row objects for use in scripts or down
703
762
  | `rows` | array<record<string, unknown>> | yes | | Array of row objects (first row = headers as keys) |
704
763
  | `fileId` | string | no | | File ID of stored CSV when outputCsv is true |
705
764
 
765
+ #### `transform.json-to-xlsx` — JSON to XLSX
766
+
767
+ Convert JSON rows into an XLSX spreadsheet. Pair with transform.xlsx-to-json. Formula-looking strings stay text; nested cell values are rejected.
768
+
769
+ **Durable retry:** Transforms, including those that write files, are not durably retried.
770
+
771
+ **Config** (in `step.with`):
772
+
773
+ | Field | Type | Required | Default | Description |
774
+ | --- | --- | --- | --- | --- |
775
+ | `filename` | string | no | | Output filename — supports LiquidJS; .xlsx is added if omitted |
776
+ | `columns` | array<object> | no | | Ordered columns for a single-sheet workbook. Use sheets for multiple sheets. |
777
+ | `rows` | string \| array<record<string, unknown>> | no | | Array of row objects, or a template expression that resolves to one |
778
+ | `sheets` | array<object> | no | | Multiple sheets. Do not combine with top-level columns/rows. |
779
+ | `limits` | object | no | | Optional workload caps that can only lower the server defaults. Omitted fields use the server defaults. |
780
+
781
+ **Output:** `object`
782
+
783
+ | Field | Type | Required | Default | Description |
784
+ | --- | --- | --- | --- | --- |
785
+ | `fileId` | string | yes | | File ID from the files table |
786
+ | `filename` | string | yes | | Sanitized output filename including .xlsx |
787
+ | `sheetCount` | integer | yes | | Number of sheets in the workbook |
788
+ | `sheets` | array<object> | yes | | Per-sheet name and row count |
789
+
706
790
  #### `transform.script` — Script
707
791
 
708
792
  Execute a TypeScript function in a QuickJS sandbox. Input keys become the function's parameter list, in declaration order, and the required `: R` return-type annotation IS this step's output schema: `inputs: { items, taxRate }` ⇒ `function script(items: …, taxRate: …): R { … }`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eigenpal/cli",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "description": "Eigenpal CLI — author and run document workflows from your terminal. Agent-ready.",
5
5
  "keywords": [
6
6
  "eigenpal",
@@ -50,18 +50,9 @@
50
50
  "lint": "eslint src/",
51
51
  "typecheck": "tsc --noEmit"
52
52
  },
53
- "dependencies": {
54
- "@clack/prompts": "^1.3.0",
55
- "ajv": "^8.17.1",
56
- "commander": "^14.0.3",
57
- "fflate": "0.8.2",
58
- "openai": "^6.27.0",
59
- "picocolors": "^1.1.1",
60
- "quickjs-emscripten": "^0.32.0",
61
- "yaml": "^2.7.0",
62
- "zod": "^4.4.3"
63
- },
53
+ "dependencies": {},
64
54
  "devDependencies": {
55
+ "@eigenpal/common": "workspace:*",
65
56
  "@eigenpal/types": "workspace:*",
66
57
  "@eigenpal/workflow-yaml": "workspace:*",
67
58
  "@t3-oss/env-core": "^0.13.11",