@eigenpal/cli 0.20.44 → 0.20.46

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @eigenpal/cli
2
2
 
3
+ ## 0.20.45
4
+
5
+ ### Minor Changes
6
+
7
+ - 0be0b92: The CLI now follows the chunked Files upload transport, so large on-prem file uploads work without browser-reachable object storage.
8
+
9
+ ## 0.20.45
10
+
11
+ ### Patch Changes
12
+
13
+ - ded47bf: Clarify how to flag specific dataset review fields and attach field comments with current workflow values. Agent guidance now keeps expected outputs aligned with the full intended workflow output and leaves comparison rules to evaluators.
14
+
3
15
  ## 0.20.42
4
16
 
5
17
  ### Patch Changes
package/dist/cli.js CHANGED
@@ -15494,7 +15494,7 @@ var init_human_review = __esm(() => {
15494
15494
  }).refine((value) => value.slice(1).split("/").every((segment) => segment === "*" || !segment.includes("*")), { message: "A wildcard must occupy an entire JSON Pointer segment" });
15495
15495
  HumanReviewCategoricalConfidenceSchema = _enum(["low", "medium", "high"]);
15496
15496
  HumanReviewNumericConfidenceSchema = number2().finite().min(0).max(1);
15497
- HumanReviewMetadataFromSchema = _enum(["ai.extract"]).describe("Producer adapter. `ai.extract` derives field confidence from `_grounding` and strips that reserved key from review data. Grounding is not stripped unless this is set.");
15497
+ HumanReviewMetadataFromSchema = _enum(["ai.extract"]).describe("Producer adapter. `ai.extract` derives categorical field confidence from `_grounding`, copies valid numeric grounding scores into fieldMetadata.display.score, and strips that reserved key from review data. Grounding is not stripped unless this is set.");
15498
15498
  HumanReviewResolvedConfidenceSchema = union([
15499
15499
  HumanReviewNumericConfidenceSchema,
15500
15500
  HumanReviewCategoricalConfidenceSchema,
@@ -15505,11 +15505,11 @@ var init_human_review = __esm(() => {
15505
15505
  HumanReviewCategoricalConfidenceSchema
15506
15506
  ]);
15507
15507
  HumanReviewFieldMetadataSchema = object({
15508
- confidence: HumanReviewResolvedConfidenceSchema.optional().describe("Producer-supplied confidence: 0–1 numeric (legacy) or categorical low|medium|high from ai.extract grounding. Not calibrated by Eigenpal."),
15508
+ confidence: HumanReviewResolvedConfidenceSchema.optional().describe("Routing confidence: categorical low|medium|high from ai.extract grounding, or legacy 0–1 numeric when authored. Numeric grounding scores from extract land in display.score instead. Not calibrated by Eigenpal."),
15509
15509
  label: string2().max(500).optional().describe("Short label shown in the review UI"),
15510
15510
  description: string2().max(5000).optional().describe("Longer reviewer guidance for this field"),
15511
15511
  review: _enum(["auto", "always", "never"]).default("auto").optional().describe("Legacy per-field override kept for existing tasks. Prefer selection.fields.review."),
15512
- display: record(string2(), unknown()).optional().describe("Opaque display metadata preserved for the review UI")
15512
+ display: record(string2(), unknown()).optional().describe("Opaque display metadata preserved for the review UI. When metadataFrom is ai.extract, numeric grounding scores are copied here as display.score; routing confidence stays on confidence as categorical low|medium|high.")
15513
15513
  }).strict();
15514
15514
  HumanReviewFieldPolicySchema = object({
15515
15515
  review: _enum(["always", "never", "skip"]).optional().describe("Always require review, or never/skip review for matching paths"),
@@ -56616,6 +56616,9 @@ var init_eval = __esm(() => {
56616
56616
  });
56617
56617
 
56618
56618
  // ../types/src/git-source/grammar.ts
56619
+ function qualifyRunTargetName(name) {
56620
+ return /^wf_[A-Za-z0-9_-]+$/.test(name) ? `workflows.${name}` : name;
56621
+ }
56619
56622
  function parseAutomationTarget(target) {
56620
56623
  const parsed = AutomationTargetSchema.parse(target);
56621
56624
  const [rawPackageName, rawRef] = parsed.split("@");
@@ -56634,7 +56637,7 @@ function parseRunTarget(target) {
56634
56637
  const parsed = RunTargetSchema.parse(target);
56635
56638
  if (typeof parsed === "string") {
56636
56639
  const [name, rawRef] = parsed.split("@");
56637
- const [root, ...segments] = name.split(".");
56640
+ const [root, ...segments] = qualifyRunTargetName(name).split(".");
56638
56641
  const slug = segments.join("/");
56639
56642
  if (root === "agents") {
56640
56643
  return {
@@ -56855,11 +56858,11 @@ var init_grammar = __esm(() => {
56855
56858
  ctx.addIssue({ code: "custom", message: "Run target must be <target> or <target>@<version>" });
56856
56859
  return;
56857
56860
  }
56858
- const parts = name.split(".");
56861
+ const parts = qualifyRunTargetName(name).split(".");
56859
56862
  if (parts.length < 2) {
56860
56863
  ctx.addIssue({
56861
56864
  code: "custom",
56862
- message: "Run target must start with agents. or workflows. followed by a slug or id"
56865
+ message: "Run target must be a wf_ id or start with agents. or workflows. followed by a slug or id"
56863
56866
  });
56864
56867
  return;
56865
56868
  }
@@ -207667,10 +207670,29 @@ function resolveRequestUrl(baseUrl, path) {
207667
207670
  return `${base.origin}${requestPath}`;
207668
207671
  return `${base.origin}${basePath}${requestPath}`;
207669
207672
  }
207673
+
207674
+ // src/lib/fetch-body.ts
207675
+ function isNodeReadableStream(body) {
207676
+ return typeof body.pipe === "function";
207677
+ }
207678
+ function byteViewToArrayBuffer(view) {
207679
+ if (view.buffer instanceof ArrayBuffer && view.byteOffset === 0 && view.byteLength === view.buffer.byteLength) {
207680
+ return view.buffer;
207681
+ }
207682
+ const copy = new Uint8Array(view.byteLength);
207683
+ copy.set(view);
207684
+ return copy.buffer;
207685
+ }
207686
+ function toPutBody(body) {
207687
+ if (isNodeReadableStream(body)) {
207688
+ return body;
207689
+ }
207690
+ return byteViewToArrayBuffer(body);
207691
+ }
207670
207692
  // package.json
207671
207693
  var package_default = {
207672
207694
  name: "@eigenpal/cli",
207673
- version: "0.20.44",
207695
+ version: "0.20.46",
207674
207696
  description: "Eigenpal CLI — author and run document workflows from your terminal. Agent-ready.",
207675
207697
  keywords: [
207676
207698
  "eigenpal",
@@ -207863,6 +207885,18 @@ class ApiClient {
207863
207885
  });
207864
207886
  return this.handleResponse(res, url);
207865
207887
  }
207888
+ async putBytes(path, body) {
207889
+ const url = this.buildUrl(path);
207890
+ const stream = isNodeReadableStream(body);
207891
+ const init = {
207892
+ method: "PUT",
207893
+ headers: this.headers({ "Content-Type": "application/octet-stream" }),
207894
+ body,
207895
+ ...stream ? { duplex: "half" } : {}
207896
+ };
207897
+ const res = await fetch(url, init);
207898
+ return this.handleResponse(res, url);
207899
+ }
207866
207900
  async patch(path, body) {
207867
207901
  const url = this.buildUrl(path);
207868
207902
  const res = await fetch(url, {
@@ -211510,7 +211544,7 @@ function registerDatasetReviewRequestCommands(dataset, resolveAutomation) {
211510
211544
  { key: "createdAt", header: "createdAt", format: formatTimestamp }
211511
211545
  ], { ...opts, entityLabel: "review request" });
211512
211546
  }));
211513
- addJsonFlag(withBaseUrl(reviewRequest.command("create <automation-id>"))).description("Request human review of dataset ground truth. Snapshot examples and poll progress until review is complete.").requiredOption("--title <title>", "Review request title").requiredOption("--example-name <name>", "Example folder name to include (repeatable)", collectRepeatable, []).option("--instructions <text>", "Note shown to the reviewer for the whole request").option("--focus <path>", "Expected-output path to highlight (repeatable)", collectRepeatable, []).option("--focus-reason <spec>", "Reason a focus path needs review, as path=reason (repeatable)", collectRepeatable, []).option("--ignore <path>", "Expected-output path reviewers can skip (repeatable)", collectRepeatable, []).option("--item-note <spec>", "Example-level note seeded at create time, as exampleName=comment (repeatable)", collectRepeatable, []).option("--field-note <spec>", "Field-level note seeded at create time, as exampleName.path=comment (repeatable)", collectRepeatable, []).option("--focus-json <json>", "JSON array of { path, reason? } focus fields").option("--notes-json <json>", "JSON array of { exampleName, comment?, fields?: [{ path, comment }] }").option("--status <draft|open|paused>", "Initial lifecycle status (default: draft)").addHelpText("after", `
211547
+ addJsonFlag(withBaseUrl(reviewRequest.command("create <automation-id>"))).description("Request human review of dataset ground truth. Snapshot examples and poll progress until review is complete.").requiredOption("--title <title>", "Review request title").requiredOption("--example-name <name>", "Example folder name to include (repeatable)", collectRepeatable, []).option("--instructions <text>", "Note shown to the reviewer for the whole request").option("--focus <path>", "Expected-output leaf path to flag across selected examples; parent paths flag every descendant (repeatable)", collectRepeatable, []).option("--focus-reason <spec>", "Reason a focus path needs review, as path=reason (repeatable)", collectRepeatable, []).option("--ignore <path>", "Expected-output path reviewers can skip (repeatable)", collectRepeatable, []).option("--item-note <spec>", "Example-level note seeded at create time, as exampleName=comment (repeatable)", collectRepeatable, []).option("--field-note <spec>", "Field comment only, as exampleName.path=comment; does not flag the field (repeatable)", collectRepeatable, []).option("--focus-json <json>", "JSON array of { path, reason? } focus fields").option("--notes-json <json>", "JSON array of { exampleName, comment?, fields?: [{ path, comment }] }").option("--status <draft|open|paused>", "Initial lifecycle status (default: draft)").addHelpText("after", `
211514
211548
  Examples:
211515
211549
  $ eigenpal workflow dataset review-request create wf_abc123 \\
211516
211550
  --title "Q1 invoice GT review" \\
@@ -211518,12 +211552,21 @@ Examples:
211518
211552
  --instructions "Check IBAN checksums and totals." \\
211519
211553
  --focus vendor.iban --focus-reason 'vendor.iban=OCR often mangles IBANs' \\
211520
211554
  --ignore currency \\
211521
- --field-note 'invoice-foo.total=off by 0.01 last run' \\
211555
+ --field-note 'invoice-foo.vendor.iban=Workflow currently returns SK12; expected SK34. Verify against the document.' \\
211522
211556
  --status open --json
211523
211557
 
211524
211558
  $ eigenpal workflow dataset review-request list wf_abc123 --status open --json
211525
211559
  $ eigenpal workflow dataset review-request get wf_abc123 dsr_... --json
211526
211560
 
211561
+ Keep expected.json one-to-one with the complete intended workflow output,
211562
+ including nested objects, arrays, types, and expected file references. Evaluators
211563
+ define which values to compare and how; never reshape ground truth for scoring.
211564
+ Review snapshots must keep that full dataset shape. Flag only uncertain or
211565
+ incorrect leaf paths (for example items.3.amount), not every field or a whole
211566
+ array unless every descendant needs review. Focus applies to all selected
211567
+ examples. A field note adds context without flagging: include the workflow's
211568
+ current value, the expected value, and what the reviewer should verify.
211569
+
211527
211570
  Agent loop: create with focus/ignore and per-example notes → poll \`get --json\`
211528
211571
  until \`.progress.complete\` → record per-field decisions and per-example
211529
211572
  approve/remove with comments → \`pull --out <dir>\` to fetch expected files
@@ -244453,25 +244496,6 @@ import { createReadStream } from "node:fs";
244453
244496
  import { stat as stat3 } from "node:fs/promises";
244454
244497
  import path17 from "node:path";
244455
244498
 
244456
- // src/lib/fetch-body.ts
244457
- function isNodeReadableStream(body) {
244458
- return typeof body.pipe === "function";
244459
- }
244460
- function byteViewToArrayBuffer(view) {
244461
- if (view.buffer instanceof ArrayBuffer && view.byteOffset === 0 && view.byteLength === view.buffer.byteLength) {
244462
- return view.buffer;
244463
- }
244464
- const copy = new Uint8Array(view.byteLength);
244465
- copy.set(view);
244466
- return copy.buffer;
244467
- }
244468
- function toPutBody(body) {
244469
- if (isNodeReadableStream(body)) {
244470
- return body;
244471
- }
244472
- return byteViewToArrayBuffer(body);
244473
- }
244474
-
244475
244499
  // src/lib/upload-presigned-multipart.ts
244476
244500
  var MULTIPART_UPLOAD_CONCURRENCY = 4;
244477
244501
  var MULTIPART_PART_MAX_RETRIES = 4;
@@ -244645,6 +244669,79 @@ async function uploadPresignedMultipartParts(options) {
244645
244669
  }
244646
244670
  }
244647
244671
 
244672
+ // src/lib/upload-app-chunked.ts
244673
+ var HTTP_CHUNKED_MAX_RETRIES = 4;
244674
+ var HTTP_CHUNKED_RETRY_BASE_MS = 250;
244675
+ function expectedHttpChunkByteLength(totalSize, chunkSizeBytes, chunkIndex, chunkCount) {
244676
+ if (!Number.isInteger(chunkIndex) || chunkIndex < 0 || chunkIndex >= chunkCount) {
244677
+ throw new Error(`chunkIndex must be an integer in [0, ${chunkCount})`);
244678
+ }
244679
+ if (totalSize === 0)
244680
+ return 0;
244681
+ if (chunkIndex < chunkCount - 1)
244682
+ return chunkSizeBytes;
244683
+ const remainder = totalSize % chunkSizeBytes;
244684
+ return remainder === 0 ? chunkSizeBytes : remainder;
244685
+ }
244686
+ function chunkByteOffset(chunkSizeBytes, chunkIndex) {
244687
+ return chunkIndex * chunkSizeBytes;
244688
+ }
244689
+ function shouldAbortHttpChunkedUploadSession(options) {
244690
+ return !options.chunksReady;
244691
+ }
244692
+ function httpChunkedCompleteRetryHint(uploadId) {
244693
+ return `Uploaded chunks remain stored for ${uploadId}; retry complete and do not abort the session.`;
244694
+ }
244695
+ function annotateHttpChunkedCompleteFailure(uploadId, error) {
244696
+ const hint = httpChunkedCompleteRetryHint(uploadId);
244697
+ if (error instanceof Error) {
244698
+ if (!error.message.includes("retry complete")) {
244699
+ error.message = `${error.message} ${hint}`;
244700
+ }
244701
+ return error;
244702
+ }
244703
+ return new Error(`${String(error)} ${hint}`);
244704
+ }
244705
+
244706
+ class ChunkUploadHttpError extends Error {
244707
+ status;
244708
+ constructor(status) {
244709
+ super(`Chunk upload failed (${status})`);
244710
+ this.status = status;
244711
+ this.name = "ChunkUploadHttpError";
244712
+ }
244713
+ }
244714
+ function isRetryableChunkError(error) {
244715
+ if (error instanceof ChunkUploadHttpError)
244716
+ return isTransientHttpStatus(error.status);
244717
+ return true;
244718
+ }
244719
+ async function uploadHttpChunks(options) {
244720
+ for (let chunkIndex = 0;chunkIndex < options.chunkCount; chunkIndex++) {
244721
+ const length = expectedHttpChunkByteLength(options.totalSize, options.chunkSizeBytes, chunkIndex, options.chunkCount);
244722
+ const start = chunkByteOffset(options.chunkSizeBytes, chunkIndex);
244723
+ let lastError;
244724
+ for (let attempt = 0;attempt <= HTTP_CHUNKED_MAX_RETRIES; attempt++) {
244725
+ try {
244726
+ await options.putChunk({ chunkIndex, start, length });
244727
+ lastError = undefined;
244728
+ break;
244729
+ } catch (error) {
244730
+ lastError = error;
244731
+ if (!isRetryableChunkError(error) || attempt === HTTP_CHUNKED_MAX_RETRIES) {
244732
+ throw error;
244733
+ }
244734
+ await sleep2(HTTP_CHUNKED_RETRY_BASE_MS * 2 ** attempt);
244735
+ }
244736
+ }
244737
+ if (lastError)
244738
+ throw lastError;
244739
+ }
244740
+ }
244741
+ function sleep2(ms) {
244742
+ return new Promise((resolve) => setTimeout(resolve, ms));
244743
+ }
244744
+
244648
244745
  // src/lib/upload-reusable-file.ts
244649
244746
  function newIdempotencyKey() {
244650
244747
  return randomUUID();
@@ -244673,6 +244770,9 @@ async function uploadReusableFile(client, input) {
244673
244770
  if (negotiation.transport === "presigned-multipart") {
244674
244771
  return uploadPresignedMultipart(client, source, negotiation);
244675
244772
  }
244773
+ if (negotiation.transport === "http-chunked") {
244774
+ return uploadHttpChunked(client, source, negotiation);
244775
+ }
244676
244776
  let putReady = false;
244677
244777
  try {
244678
244778
  const putBody = source.kind === "buffer" ? toPutBody(new Uint8Array(source.content)) : toPutBody(createReadStream(source.filePath));
@@ -244724,6 +244824,38 @@ async function resolveUploadSource(input) {
244724
244824
  contentType
244725
244825
  };
244726
244826
  }
244827
+ async function uploadHttpChunked(client, source, session) {
244828
+ const chunksPath = apiPath(session.chunksUrl);
244829
+ const completePath = apiPath(session.completeUrl);
244830
+ let chunksReady = false;
244831
+ try {
244832
+ await uploadHttpChunks({
244833
+ chunkCount: session.chunkCount,
244834
+ chunkSizeBytes: session.chunkSizeBytes,
244835
+ totalSize: source.size,
244836
+ putChunk: async ({ chunkIndex, start, length }) => {
244837
+ const body = source.kind === "buffer" ? toPutBody(source.content.subarray(start, start + length)) : length === 0 ? toPutBody(new Uint8Array) : toPutBody(createReadStream(source.filePath, { start, end: start + length - 1 }));
244838
+ try {
244839
+ await client.putBytes(`${chunksPath}/${chunkIndex}`, body);
244840
+ } catch (error) {
244841
+ if (error instanceof ApiError)
244842
+ throw new ChunkUploadHttpError(error.status);
244843
+ throw error;
244844
+ }
244845
+ }
244846
+ });
244847
+ chunksReady = true;
244848
+ return await client.post(completePath, {});
244849
+ } catch (error) {
244850
+ if (shouldAbortHttpChunkedUploadSession({ chunksReady })) {
244851
+ await client.delete(apiPath(`/files/uploads/${session.uploadId}`)).catch(() => {
244852
+ return;
244853
+ });
244854
+ throw error;
244855
+ }
244856
+ throw annotateHttpChunkedCompleteFailure(session.uploadId, error);
244857
+ }
244858
+ }
244727
244859
  async function uploadPresignedMultipart(client, source, session) {
244728
244860
  const partsPath = apiPath(session.partsUrl);
244729
244861
  const completePath = apiPath(session.completeUrl);