markform 0.1.27 → 0.1.29

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/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
 
2
- import { t as runCli } from "./cli-yBrJefDI.mjs";
2
+ import { t as runCli } from "./cli-DVAFMui4.mjs";
3
3
 
4
4
  export { runCli };
package/dist/index.d.mts CHANGED
@@ -1176,6 +1176,18 @@ interface FillOptions {
1176
1176
  * @default 'required'
1177
1177
  */
1178
1178
  toolChoice?: 'auto' | 'required';
1179
+ /**
1180
+ * Maximum retries for transient API errors (429, 503, etc.).
1181
+ * Passed to the AI SDK's `generateText()` which handles exponential backoff.
1182
+ *
1183
+ * Set to 0 to disable AI SDK retries and handle retries externally
1184
+ * (recommended for production harnesses that need full control over retry behavior).
1185
+ *
1186
+ * **Required** — must be set explicitly.
1187
+ * The Vercel AI SDK's own default is 2. Common values: 0 (no retries / tests),
1188
+ * 2–3 (production).
1189
+ */
1190
+ maxRetries: number;
1179
1191
  }
1180
1192
  /**
1181
1193
  * Progress information for each turn.
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  import { $ as SetStringPatchSchema, A as MarkformSectionInputSchema, At as WireResponseStepSchema, B as ProgressCountsSchema, C as HarnessConfigSchema, Ct as UrlListValueSchema, D as IssueReasonSchema, Dt as WireFormatSchema, E as InspectResultSchema, Et as ValidatorRefSchema, F as NumberValueSchema, G as SessionTranscriptSchema, H as ProgressSummarySchema, I as OptionIdSchema, J as SetDatePatchSchema, K as SessionTurnSchema, L as OptionSchema, M as MultiSelectFieldSchema, Mt as WireToolResultSchema, N as MultiSelectValueSchema, Nt as YearFieldSchema, O as IssueScopeSchema, Ot as WireRequestFormatSchema, P as NumberFieldSchema, Pt as YearValueSchema, Q as SetStringListPatchSchema, R as PatchSchema, S as FormSchemaSchema, St as UrlListFieldSchema, T as InspectIssueSchema, Tt as ValidationIssueSchema, U as RunModeSchema, V as ProgressStateSchema, W as SessionFinalSchema, X as SetNumberPatchSchema, Y as SetMultiSelectPatchSchema, Z as SetSingleSelectPatchSchema, _ as FieldKindSchema, _t as TableFieldSchema, a as CheckboxProgressCountsSchema, at as SimpleCheckboxStateSchema, b as FieldSchema, bt as TableValueSchema, c as CheckboxesValueSchema, ct as SourcePositionSchema, d as DateFieldSchema, dt as StringFieldSchema, et as SetTablePatchSchema, f as DateValueSchema, ft as StringListFieldSchema, g as FieldGroupSchema, gt as TableColumnSchema, h as ExplicitCheckboxValueSchema, ht as StructureSummarySchema, i as CheckboxModeSchema, it as SeveritySchema, j as MultiCheckboxStateSchema, jt as WireToolCallSchema, k as MarkformFrontmatterSchema, kt as WireResponseFormatSchema, l as ClearFieldPatchSchema, lt as SourceRangeSchema, m as DocumentationTagSchema, mt as StringValueSchema, n as ApplyResultSchema, nt as SetUrlPatchSchema, o as CheckboxValueSchema, ot as SingleSelectFieldSchema, p as DocumentationBlockSchema, pt as StringListValueSchema, q as SetCheckboxesPatchSchema, r as CellResponseSchema, rt as SetYearPatchSchema, s as CheckboxesFieldSchema, st as SingleSelectValueSchema, t as AnswerStateSchema, tt as SetUrlListPatchSchema, u as ColumnTypeNameSchema, ut as StepResultSchema, v as FieldProgressSchema, vt as TableRowPatchSchema, w as IdSchema, wt as UrlValueSchema, x as FieldValueSchema, xt as UrlFieldSchema, y as FieldResponseSchema, yt as TableRowResponseSchema } from "./coreTypes-DIv9Aabl.mjs";
3
- import { At as isParseError, C as isFormComplete, Ct as MarkformPatchError, Dt as isConfigError, E as serializeReport, Et as isAbortError, Mt as isRetryableError, Nt as isValidationError, Ot as isLlmError, S as computeStructureSummary, St as MarkformParseError, Tt as ParseError, _ as inspect, b as computeFormState, bt as MarkformError, d as coerceInputContext, f as coerceToFieldPatch, jt as isPatchError, kt as isMarkformError, m as applyPatches, p as findFieldById, v as validate, vt as MarkformAbortError, w as serializeForm, wt as MarkformValidationError, x as computeProgressSummary, xt as MarkformLlmError, y as computeAllSummaries, yt as MarkformConfigError } from "./prompts-CwEV0X5z.mjs";
4
- import { A as MockAgent, B as fieldToJsonSchema, F as isCellRef, G as injectHeaderIds, H as parseForm, I as isFieldRef, J as parseCellValue, K as findAllHeadings, L as isQualifiedRef, M as FormHarness, N as createHarness, O as FillRecordCollector, P as getFieldId, R as parseScopeRef, S as BUILT_IN_PROVIDERS, U as findAllCheckboxes, V as formToJsonSchema, W as injectCheckboxIds, X as parseRawTable, Y as parseMarkdownTable, _ as resolveHarnessConfig, a as ExecutionMetadataSchema, b as createParallelHarness, c as TimelineEntrySchema, d as ToolCallRecordSchema, f as ToolStatsSchema, g as formatFillRecordSummary, i as runResearch, j as createMockAgent, l as TimingBreakdownItemSchema, n as isResearchForm, o as FillRecordSchema, p as ToolSummarySchema, q as findEnclosingHeadings, r as validateResearchForm, s as FillRecordStatusSchema, t as VERSION, u as TimingBreakdownSchema, v as fillForm, x as scopeIssuesForItem, y as ParallelHarness, z as serializeScopeRef } from "./src-DMIq0BFC.mjs";
3
+ import { At as isAbortError, C as isFormComplete, Ct as MarkformConfigError, Dt as MarkformPatchError, E as serializeReport, Et as MarkformParseError, Ft as isPatchError, It as isRetryableError, Lt as isValidationError, M as parseMarkdownTable, Mt as isLlmError, N as parseRawTable, Nt as isMarkformError, Ot as MarkformValidationError, Pt as isParseError, S as computeStructureSummary, St as MarkformAbortError, Tt as MarkformLlmError, _ as inspect, b as computeFormState, d as coerceInputContext, f as coerceToFieldPatch, j as parseCellValue, jt as isConfigError, kt as ParseError, m as applyPatches, p as findFieldById, v as validate, w as serializeForm, wt as MarkformError, x as computeProgressSummary, y as computeAllSummaries } from "./prompts-BR5xYbvY.mjs";
4
+ import { A as MockAgent, B as fieldToJsonSchema, F as isCellRef, G as injectHeaderIds, H as parseForm, I as isFieldRef, K as findAllHeadings, L as isQualifiedRef, M as FormHarness, N as createHarness, O as FillRecordCollector, P as getFieldId, R as parseScopeRef, S as BUILT_IN_PROVIDERS, U as findAllCheckboxes, V as formToJsonSchema, W as injectCheckboxIds, _ as resolveHarnessConfig, a as ExecutionMetadataSchema, b as createParallelHarness, c as TimelineEntrySchema, d as ToolCallRecordSchema, f as ToolStatsSchema, g as formatFillRecordSummary, i as runResearch, j as createMockAgent, l as TimingBreakdownItemSchema, n as isResearchForm, o as FillRecordSchema, p as ToolSummarySchema, q as findEnclosingHeadings, r as validateResearchForm, s as FillRecordStatusSchema, t as VERSION, u as TimingBreakdownSchema, v as fillForm, x as scopeIssuesForItem, y as ParallelHarness, z as serializeScopeRef } from "./src-eBNM0w2R.mjs";
5
5
  import { n as serializeSession, t as parseSession } from "./session-BW9jtYNV.mjs";
6
6
 
7
7
  export { AnswerStateSchema, ApplyResultSchema, BUILT_IN_PROVIDERS, CellResponseSchema, CheckboxModeSchema, CheckboxProgressCountsSchema, CheckboxValueSchema, CheckboxesFieldSchema, CheckboxesValueSchema, ClearFieldPatchSchema, ColumnTypeNameSchema, DateFieldSchema, DateValueSchema, DocumentationBlockSchema, DocumentationTagSchema, ExecutionMetadataSchema, ExplicitCheckboxValueSchema, FieldGroupSchema, FieldKindSchema, FieldProgressSchema, FieldResponseSchema, FieldSchema, FieldValueSchema, FillRecordCollector, FillRecordSchema, FillRecordStatusSchema, FormHarness, FormSchemaSchema, HarnessConfigSchema, IdSchema, InspectIssueSchema, InspectResultSchema, IssueReasonSchema, IssueScopeSchema, MarkformAbortError, MarkformConfigError, MarkformError, MarkformFrontmatterSchema, MarkformLlmError, MarkformParseError, MarkformPatchError, MarkformSectionInputSchema, MarkformValidationError, MockAgent, MultiCheckboxStateSchema, MultiSelectFieldSchema, MultiSelectValueSchema, NumberFieldSchema, NumberValueSchema, OptionIdSchema, OptionSchema, ParallelHarness, ParseError, PatchSchema, ProgressCountsSchema, ProgressStateSchema, ProgressSummarySchema, RunModeSchema, SessionFinalSchema, SessionTranscriptSchema, SessionTurnSchema, SetCheckboxesPatchSchema, SetDatePatchSchema, SetMultiSelectPatchSchema, SetNumberPatchSchema, SetSingleSelectPatchSchema, SetStringListPatchSchema, SetStringPatchSchema, SetTablePatchSchema, SetUrlListPatchSchema, SetUrlPatchSchema, SetYearPatchSchema, SeveritySchema, SimpleCheckboxStateSchema, SingleSelectFieldSchema, SingleSelectValueSchema, SourcePositionSchema, SourceRangeSchema, StepResultSchema, StringFieldSchema, StringListFieldSchema, StringListValueSchema, StringValueSchema, StructureSummarySchema, TableColumnSchema, TableFieldSchema, TableRowPatchSchema, TableRowResponseSchema, TableValueSchema, TimelineEntrySchema, TimingBreakdownItemSchema, TimingBreakdownSchema, ToolCallRecordSchema, ToolStatsSchema, ToolSummarySchema, UrlFieldSchema, UrlListFieldSchema, UrlListValueSchema, UrlValueSchema, VERSION, ValidationIssueSchema, ValidatorRefSchema, WireFormatSchema, WireRequestFormatSchema, WireResponseFormatSchema, WireResponseStepSchema, WireToolCallSchema, WireToolResultSchema, YearFieldSchema, YearValueSchema, applyPatches, coerceInputContext, coerceToFieldPatch, computeAllSummaries, computeFormState, computeProgressSummary, computeStructureSummary, createHarness, createMockAgent, createParallelHarness, fieldToJsonSchema, fillForm, findAllCheckboxes, findAllHeadings, findEnclosingHeadings, findFieldById, formToJsonSchema, formatFillRecordSummary, getFieldId, injectCheckboxIds, injectHeaderIds, inspect, isAbortError, isCellRef, isConfigError, isFieldRef, isFormComplete, isLlmError, isMarkformError, isParseError, isPatchError, isQualifiedRef, isResearchForm, isRetryableError, isValidationError, parseCellValue, parseForm, parseMarkdownTable, parseRawTable, parseScopeRef, parseSession, resolveHarnessConfig, runResearch, scopeIssuesForItem, serializeForm, serializeReport, serializeScopeRef, serializeSession, validate, validateResearchForm };
@@ -3,7 +3,7 @@ import { n as formatUrlAsMarkdownLink } from "./urlFormat-lls7CsEP.mjs";
3
3
  import YAML from "yaml";
4
4
 
5
5
  //#region src/errors.ts
6
- const VERSION = "0.1.27";
6
+ const VERSION = "0.1.29";
7
7
  /**
8
8
  * Base error class for all markform errors.
9
9
  * Consumers can catch this to handle any markform error.
@@ -512,18 +512,21 @@ const DEFAULT_MAX_ISSUES_PER_TURN = 10;
512
512
  */
513
513
  const DEFAULT_MAX_PARALLEL_AGENTS = 4;
514
514
  /**
515
- * Default maximum AI SDK retries for transient API errors (429, 503, etc.).
516
- * The Vercel AI SDK handles retry with exponential backoff automatically.
517
- * Set to 0 to disable retries (useful for fast tests).
518
- */
519
- const DEFAULT_MAX_RETRIES = 3;
520
- /**
521
515
  * Default maximum AI SDK steps (tool call rounds) per harness turn.
522
516
  * Matches AI SDK's ToolLoopAgent default of 20.
523
517
  * @see https://ai-sdk.dev/docs/agents/loop-control
524
518
  */
525
519
  const DEFAULT_MAX_STEPS_PER_TURN = 20;
526
520
  /**
521
+ * Default maximum retries for transient API errors in CLI commands.
522
+ *
523
+ * This is the single source of truth for the CLI retry default.
524
+ * The Vercel AI SDK's own default is 2; we use 3 for slightly more resilience
525
+ * in CLI usage. The TypeScript API (`FillOptions`, `LiveAgentConfig`) has no
526
+ * default — callers must provide `maxRetries` explicitly.
527
+ */
528
+ const CLI_DEFAULT_MAX_RETRIES = 3;
529
+ /**
527
530
  * Default maximum issues to show per turn in research mode.
528
531
  * Lower than general fill to keep research responses focused.
529
532
  */
@@ -910,7 +913,7 @@ function detectSentinel(value) {
910
913
  * Formats: `%SKIP%`, `%SKIP% (reason text)`, `%ABORT%`, `%ABORT% (reason text)`
911
914
  * Returns null if the content is not a valid sentinel format.
912
915
  */
913
- function parseSentinel(content) {
916
+ function parseSentinel$1(content) {
914
917
  if (!content) return null;
915
918
  const trimmed = content.trim();
916
919
  const reasonPattern = /^\((.+)\)$/s;
@@ -948,7 +951,7 @@ function parseSentinel(content) {
948
951
  function tryParseSentinelResponse(node, fieldId, required) {
949
952
  const fenceContent = extractFenceValue(node);
950
953
  const stateAttr = getStringAttr(node, "state");
951
- const sentinel = parseSentinel(fenceContent);
954
+ const sentinel = parseSentinel$1(fenceContent);
952
955
  if (!sentinel) return null;
953
956
  if (sentinel.type === "skip") {
954
957
  if (stateAttr !== void 0 && stateAttr !== "skipped") throw new MarkformParseError(`Field '${fieldId}' has conflicting state='${stateAttr}' with %SKIP% sentinel`);
@@ -968,6 +971,250 @@ function tryParseSentinelResponse(node, fieldId, required) {
968
971
  return null;
969
972
  }
970
973
 
974
+ //#endregion
975
+ //#region src/engine/table/parseTable.ts
976
+ /** Sentinel pattern: %SKIP% or %SKIP:reason% or %SKIP(reason)% */
977
+ const SKIP_PATTERN = /^%SKIP(?:[:(](.*))?[)]?%$/i;
978
+ /** Sentinel pattern: %ABORT% or %ABORT:reason% or %ABORT(reason)% */
979
+ const ABORT_PATTERN = /^%ABORT(?:[:(](.*))?[)]?%$/i;
980
+ /** Markdown link pattern: [text](url) */
981
+ const MARKDOWN_LINK_PATTERN = /^\[([^\]]*)\]\(([^)]+)\)$/;
982
+ /**
983
+ * Extract URL from markdown link format if present.
984
+ * Returns the URL part from [text](url) format, or the original value if not a markdown link.
985
+ */
986
+ function extractUrlFromMarkdownLink(value) {
987
+ const match = MARKDOWN_LINK_PATTERN.exec(value);
988
+ if (match) return match[2];
989
+ return value;
990
+ }
991
+ /**
992
+ * Detect if a cell value is a sentinel.
993
+ */
994
+ function parseSentinel(value) {
995
+ const trimmed = value.trim();
996
+ const skipMatch = SKIP_PATTERN.exec(trimmed);
997
+ if (skipMatch) return {
998
+ type: "skip",
999
+ reason: skipMatch[1]
1000
+ };
1001
+ const abortMatch = ABORT_PATTERN.exec(trimmed);
1002
+ if (abortMatch) return {
1003
+ type: "abort",
1004
+ reason: abortMatch[1]
1005
+ };
1006
+ return null;
1007
+ }
1008
+ /**
1009
+ * Parse a cell value according to its column type.
1010
+ * Returns a CellResponse with appropriate state.
1011
+ */
1012
+ function parseCellValue(rawValue, columnType) {
1013
+ const trimmed = rawValue.trim();
1014
+ if (!trimmed) return { state: "skipped" };
1015
+ const sentinel = parseSentinel(trimmed);
1016
+ if (sentinel) return {
1017
+ state: sentinel.type === "skip" ? "skipped" : "aborted",
1018
+ reason: sentinel.reason
1019
+ };
1020
+ const unescaped = trimmed.replace(/\\[|]/g, "|").replace(/<br\s*\/?>/gi, "\n");
1021
+ switch (columnType) {
1022
+ case "string": return {
1023
+ state: "answered",
1024
+ value: unescaped
1025
+ };
1026
+ case "number": {
1027
+ const num = parseFloat(trimmed);
1028
+ if (isNaN(num)) return {
1029
+ state: "answered",
1030
+ value: trimmed
1031
+ };
1032
+ return {
1033
+ state: "answered",
1034
+ value: num
1035
+ };
1036
+ }
1037
+ case "url": return {
1038
+ state: "answered",
1039
+ value: extractUrlFromMarkdownLink(trimmed)
1040
+ };
1041
+ case "date": return {
1042
+ state: "answered",
1043
+ value: trimmed
1044
+ };
1045
+ case "year": {
1046
+ const year = parseInt(trimmed, 10);
1047
+ if (isNaN(year) || !Number.isInteger(year)) return {
1048
+ state: "answered",
1049
+ value: trimmed
1050
+ };
1051
+ return {
1052
+ state: "answered",
1053
+ value: year
1054
+ };
1055
+ }
1056
+ }
1057
+ }
1058
+ /**
1059
+ * Check if a single cell is empty.
1060
+ * Used by both row normalization and validation to ensure consistent logic.
1061
+ *
1062
+ * - Skipped cells are empty
1063
+ * - Aborted cells are NOT empty (they carry intentional signal)
1064
+ * - Answered cells are empty only if value is undefined/null/empty string
1065
+ * - Unknown states are treated conservatively as NOT empty
1066
+ */
1067
+ function isCellEmpty(cell) {
1068
+ if (!cell || cell.state === "skipped") return true;
1069
+ if (cell.state === "aborted") return false;
1070
+ if (cell.state === "answered") return cell.value === void 0 || cell.value === null || cell.value === "";
1071
+ return false;
1072
+ }
1073
+ /**
1074
+ * Check if a table row is fully empty (all cells skipped/empty).
1075
+ * Used during normalization to drop rows that carry no data.
1076
+ */
1077
+ function isRowFullyEmpty(row) {
1078
+ return Object.values(row).every(isCellEmpty);
1079
+ }
1080
+ /**
1081
+ * Parse a table row into cell values.
1082
+ * Handles leading/trailing pipes and cell trimming.
1083
+ */
1084
+ function parseTableRow(line) {
1085
+ let trimmed = line.trim();
1086
+ if (trimmed.startsWith("|")) trimmed = trimmed.slice(1);
1087
+ if (trimmed.endsWith("|")) trimmed = trimmed.slice(0, -1);
1088
+ return trimmed.split("|").map((cell) => cell.trim());
1089
+ }
1090
+ /**
1091
+ * Extract header labels from table content.
1092
+ * Returns array of header labels from the first row, or empty array if no valid header.
1093
+ */
1094
+ function extractTableHeaderLabels(content) {
1095
+ if (!content || content.trim() === "") return [];
1096
+ const lines = content.trim().split("\n").filter((line) => line.trim());
1097
+ if (lines.length === 0) return [];
1098
+ return parseTableRow(lines[0]);
1099
+ }
1100
+ /**
1101
+ * Check if a line is a valid table separator row.
1102
+ * Each cell should contain only dashes and optional colons for alignment.
1103
+ */
1104
+ function isValidSeparator(line, expectedCols) {
1105
+ const cells = parseTableRow(line);
1106
+ if (cells.length !== expectedCols) return false;
1107
+ const separatorPattern = /^:?-+:?$/;
1108
+ return cells.every((cell) => separatorPattern.test(cell.trim()));
1109
+ }
1110
+ /**
1111
+ * Parse a markdown table with column schema for type coercion.
1112
+ *
1113
+ * @param content - The markdown table content
1114
+ * @param columns - Column definitions from the table field schema
1115
+ * @param dataStartLine - Optional line index where data rows start (skips header validation)
1116
+ * @returns Parsed table value with typed cells
1117
+ */
1118
+ function parseMarkdownTable(content, columns, dataStartLine) {
1119
+ const lines = content.trim().split("\n").filter((line) => line.trim());
1120
+ if (lines.length === 0) return {
1121
+ ok: true,
1122
+ value: {
1123
+ kind: "table",
1124
+ rows: []
1125
+ }
1126
+ };
1127
+ if (lines.length < 2) return {
1128
+ ok: false,
1129
+ error: "Table must have at least a header and separator row"
1130
+ };
1131
+ const headerLine = lines[0];
1132
+ const headers = parseTableRow(headerLine);
1133
+ const separatorLine = lines[1];
1134
+ if (!isValidSeparator(separatorLine, headers.length)) return {
1135
+ ok: false,
1136
+ error: "Invalid table separator row"
1137
+ };
1138
+ if (dataStartLine !== void 0) {
1139
+ const rows = [];
1140
+ for (let i = dataStartLine; i < lines.length; i++) {
1141
+ const rawCells = parseTableRow(lines[i]);
1142
+ const row = {};
1143
+ for (let j = 0; j < columns.length; j++) {
1144
+ const column = columns[j];
1145
+ const rawValue = rawCells[j] ?? "";
1146
+ row[column.id] = parseCellValue(rawValue, column.type);
1147
+ }
1148
+ rows.push(row);
1149
+ }
1150
+ return {
1151
+ ok: true,
1152
+ value: {
1153
+ kind: "table",
1154
+ rows: rows.filter((r) => !isRowFullyEmpty(r))
1155
+ }
1156
+ };
1157
+ }
1158
+ const columnIdToIndex = /* @__PURE__ */ new Map();
1159
+ for (let i = 0; i < headers.length; i++) {
1160
+ const header = headers[i];
1161
+ const column = columns.find((c) => c.id === header || c.label === header);
1162
+ if (column) columnIdToIndex.set(column.id, i);
1163
+ }
1164
+ const rows = [];
1165
+ for (let i = 2; i < lines.length; i++) {
1166
+ const rawCells = parseTableRow(lines[i]);
1167
+ const row = {};
1168
+ for (const column of columns) {
1169
+ const cellIndex = columnIdToIndex.get(column.id);
1170
+ const rawValue = cellIndex !== void 0 ? rawCells[cellIndex] ?? "" : "";
1171
+ row[column.id] = parseCellValue(rawValue, column.type);
1172
+ }
1173
+ rows.push(row);
1174
+ }
1175
+ return {
1176
+ ok: true,
1177
+ value: {
1178
+ kind: "table",
1179
+ rows: rows.filter((r) => !isRowFullyEmpty(r))
1180
+ }
1181
+ };
1182
+ }
1183
+ /**
1184
+ * Parse just the raw table structure without schema.
1185
+ * Useful for validation and error reporting.
1186
+ */
1187
+ function parseRawTable(content) {
1188
+ const lines = content.trim().split("\n").filter((line) => line.trim());
1189
+ if (lines.length === 0) return {
1190
+ ok: true,
1191
+ headers: [],
1192
+ rows: []
1193
+ };
1194
+ if (lines.length < 2) return {
1195
+ ok: false,
1196
+ error: "Table must have at least a header and separator row"
1197
+ };
1198
+ const headers = parseTableRow(lines[0]);
1199
+ const separatorLine = lines[1];
1200
+ if (!isValidSeparator(separatorLine, headers.length)) return {
1201
+ ok: false,
1202
+ error: "Invalid table separator row"
1203
+ };
1204
+ const rows = [];
1205
+ for (let i = 2; i < lines.length; i++) {
1206
+ const row = parseTableRow(lines[i]);
1207
+ while (row.length < headers.length) row.push("");
1208
+ if (row.length > headers.length) row.length = headers.length;
1209
+ rows.push(row);
1210
+ }
1211
+ return {
1212
+ ok: true,
1213
+ headers,
1214
+ rows
1215
+ };
1216
+ }
1217
+
971
1218
  //#endregion
972
1219
  //#region src/engine/preprocess.ts
973
1220
  const MARKFORM_TAGS = new Set([
@@ -3495,12 +3742,20 @@ function validateCellValue(cell, column, fieldId, rowIndex) {
3495
3742
  /**
3496
3743
  * Validate a table row.
3497
3744
  */
3498
- function validateTableRow(row, columns, fieldId, rowIndex) {
3745
+ function validateTableRow(row, columns, fieldId, rowIndex, fieldLabel) {
3499
3746
  const issues = [];
3500
3747
  for (const column of columns) {
3501
3748
  const cell = row[column.id] ?? { state: "skipped" };
3502
3749
  issues.push(...validateCellValue(cell, column, fieldId, rowIndex));
3503
3750
  }
3751
+ const totalCells = columns.length;
3752
+ const filledCells = columns.filter((col) => !isCellEmpty(row[col.id])).length;
3753
+ if (filledCells > 0 && filledCells < totalCells && totalCells - filledCells > totalCells / 2) issues.push({
3754
+ severity: "warning",
3755
+ message: `Row ${rowIndex + 1} of "${fieldLabel}" has most cells empty (${filledCells} of ${totalCells} filled).`,
3756
+ ref: `${fieldId}[${rowIndex}]`,
3757
+ source: "builtin"
3758
+ });
3504
3759
  return issues;
3505
3760
  }
3506
3761
  /**
@@ -3519,20 +3774,20 @@ function validateTableField(field, value) {
3519
3774
  });
3520
3775
  return issues;
3521
3776
  }
3522
- if (isEmpty) return issues;
3523
- if (field.minRows !== void 0 && rows.length < field.minRows) issues.push({
3777
+ if (field.minRows !== void 0 && field.minRows > 0 && rows.length < field.minRows) issues.push({
3524
3778
  severity: "error",
3525
3779
  message: `"${field.label}" must have at least ${field.minRows} row(s) (has ${rows.length})`,
3526
3780
  ref: field.id,
3527
3781
  source: "builtin"
3528
3782
  });
3783
+ if (isEmpty) return issues;
3529
3784
  if (field.maxRows !== void 0 && rows.length > field.maxRows) issues.push({
3530
3785
  severity: "error",
3531
3786
  message: `"${field.label}" must have at most ${field.maxRows} row(s) (has ${rows.length})`,
3532
3787
  ref: field.id,
3533
3788
  source: "builtin"
3534
3789
  });
3535
- for (let i = 0; i < rows.length; i++) issues.push(...validateTableRow(rows[i], field.columns, field.id, i));
3790
+ for (let i = 0; i < rows.length; i++) issues.push(...validateTableRow(rows[i], field.columns, field.id, i, field.label));
3536
3791
  return issues;
3537
3792
  }
3538
3793
  /**
@@ -4385,17 +4640,17 @@ function applyPatch(form, responses, patch) {
4385
4640
  break;
4386
4641
  }
4387
4642
  case "set_table": {
4388
- const rows = (patch.value ?? []).map((patchRow) => {
4643
+ const substantiveRows = (patch.value ?? []).map((patchRow) => {
4389
4644
  const row = {};
4390
4645
  if (patchRow != null) for (const [colId, cellValue] of Object.entries(patchRow)) row[colId] = patchValueToCell(cellValue);
4391
4646
  return row;
4392
- });
4647
+ }).filter((r) => !isRowFullyEmpty(r));
4393
4648
  responses[patch.fieldId] = {
4394
- state: "answered",
4395
- value: {
4649
+ state: substantiveRows.length > 0 ? "answered" : "unanswered",
4650
+ ...substantiveRows.length > 0 && { value: {
4396
4651
  kind: "table",
4397
- rows
4398
- }
4652
+ rows: substantiveRows
4653
+ } }
4399
4654
  };
4400
4655
  break;
4401
4656
  }
@@ -4407,12 +4662,13 @@ function applyPatch(form, responses, patch) {
4407
4662
  if (patchRow != null) for (const [colId, cellValue] of Object.entries(patchRow)) row[colId] = patchValueToCell(cellValue);
4408
4663
  return row;
4409
4664
  });
4665
+ const allRows = [...currentRows, ...newRows].filter((r) => !isRowFullyEmpty(r));
4410
4666
  responses[patch.fieldId] = {
4411
- state: "answered",
4412
- value: {
4667
+ state: allRows.length > 0 ? "answered" : "unanswered",
4668
+ ...allRows.length > 0 && { value: {
4413
4669
  kind: "table",
4414
- rows: [...currentRows, ...newRows]
4415
- }
4670
+ rows: allRows
4671
+ } }
4416
4672
  };
4417
4673
  break;
4418
4674
  }
@@ -5420,5 +5676,5 @@ const SECTION_HEADERS = {
5420
5676
  };
5421
5677
 
5422
5678
  //#endregion
5423
- export { DEFAULT_RESEARCH_MAX_PATCHES_PER_TURN as $, tryParseSentinelResponse as A, isParseError as At, isTagNode as B, isFormComplete as C, MarkformPatchError as Ct, detectSyntaxStyle as D, isConfigError as Dt, serializeReport as E, isAbortError as Et, getBooleanAttr as F, DEFAULT_MAX_PARALLEL_AGENTS as G, AGENT_ROLE as H, getNumberAttr as I, DEFAULT_MAX_STEPS_PER_TURN as J, DEFAULT_MAX_PATCHES_PER_TURN as K, getStringArrayAttr as L, extractFenceValue as M, isRetryableError as Mt, extractOptionItems as N, isValidationError as Nt, preprocessCommentSyntax as O, isLlmError as Ot, extractTableContent as P, wrapApiError as Pt, DEFAULT_RESEARCH_MAX_ISSUES_PER_TURN as Q, getStringAttr as R, computeStructureSummary as S, MarkformParseError as St, serializeRawMarkdown as T, ParseError as Tt, DEFAULT_FORMS_DIR as U, parseOptionText as V, DEFAULT_MAX_ISSUES_PER_TURN as W, DEFAULT_PORT as X, DEFAULT_MAX_TURNS as Y, DEFAULT_PRIORITY as Z, inspect as _, parseModelIdForDisplay as _t, WEB_SEARCH_INSTRUCTIONS as a, deriveExportPath as at, computeFormState as b, MarkformError as bt, filterIssuesByOrder as c, deriveSchemaPath as ct, coerceInputContext as d, transformHarnessConfigToTs as dt, DEFAULT_ROLES as et, coerceToFieldPatch as f, SUGGESTED_LLMS as ft, getFieldsForRoles as g, hasWebSearchSupport as gt, getAllFields as h, getWebSearchConfig as ht, SECTION_HEADERS as i, USER_ROLE as it, CHECKBOX_MARKERS as j, isPatchError as jt, validateSyntaxConsistency as k, isMarkformError as kt, filterIssuesByScope as l, detectFileType as lt, applyPatches as m, formatSuggestedLlms as mt, GENERAL_INSTRUCTIONS as n, MAX_FORMS_IN_MENU as nt, getIssuesIntro as o, deriveFillRecordPath as ot, findFieldById as p, WEB_SEARCH_CONFIG as pt, DEFAULT_MAX_RETRIES as q, ISSUES_HEADER as r, REPORT_EXTENSION as rt, getPatchFormatHint as s, deriveReportPath as st, DEFAULT_SYSTEM_PROMPT as t, DEFAULT_ROLE_INSTRUCTIONS as tt, getFieldIdFromRef as u, parseRolesFlag as ut, validate as v, MarkformAbortError as vt, serializeForm as w, MarkformValidationError as wt, computeProgressSummary as x, MarkformLlmError as xt, computeAllSummaries as y, MarkformConfigError as yt, getValidateAttr as z };
5424
- //# sourceMappingURL=prompts-CwEV0X5z.mjs.map
5679
+ export { DEFAULT_MAX_TURNS as $, extractTableHeaderLabels as A, isAbortError as At, getNumberAttr as B, isFormComplete as C, MarkformConfigError as Ct, detectSyntaxStyle as D, MarkformPatchError as Dt, serializeReport as E, MarkformParseError as Et, CHECKBOX_MARKERS as F, isPatchError as Ft, parseOptionText as G, getStringAttr as H, extractFenceValue as I, isRetryableError as It, DEFAULT_FORMS_DIR as J, AGENT_ROLE as K, extractOptionItems as L, isValidationError as Lt, parseMarkdownTable as M, isLlmError as Mt, parseRawTable as N, isMarkformError as Nt, preprocessCommentSyntax as O, MarkformValidationError as Ot, tryParseSentinelResponse as P, isParseError as Pt, DEFAULT_MAX_STEPS_PER_TURN as Q, extractTableContent as R, wrapApiError as Rt, computeStructureSummary as S, MarkformAbortError as St, serializeRawMarkdown as T, MarkformLlmError as Tt, getValidateAttr as U, getStringArrayAttr as V, isTagNode as W, DEFAULT_MAX_PARALLEL_AGENTS as X, DEFAULT_MAX_ISSUES_PER_TURN as Y, DEFAULT_MAX_PATCHES_PER_TURN as Z, inspect as _, WEB_SEARCH_CONFIG as _t, WEB_SEARCH_INSTRUCTIONS as a, DEFAULT_ROLE_INSTRUCTIONS as at, computeFormState as b, hasWebSearchSupport as bt, filterIssuesByOrder as c, USER_ROLE as ct, coerceInputContext as d, deriveReportPath as dt, DEFAULT_PORT as et, coerceToFieldPatch as f, deriveSchemaPath as ft, getFieldsForRoles as g, SUGGESTED_LLMS as gt, getAllFields as h, transformHarnessConfigToTs as ht, SECTION_HEADERS as i, DEFAULT_ROLES as it, parseCellValue as j, isConfigError as jt, validateSyntaxConsistency as k, ParseError as kt, filterIssuesByScope as l, deriveExportPath as lt, applyPatches as m, parseRolesFlag as mt, GENERAL_INSTRUCTIONS as n, DEFAULT_RESEARCH_MAX_ISSUES_PER_TURN as nt, getIssuesIntro as o, MAX_FORMS_IN_MENU as ot, findFieldById as p, detectFileType as pt, CLI_DEFAULT_MAX_RETRIES as q, ISSUES_HEADER as r, DEFAULT_RESEARCH_MAX_PATCHES_PER_TURN as rt, getPatchFormatHint as s, REPORT_EXTENSION as st, DEFAULT_SYSTEM_PROMPT as t, DEFAULT_PRIORITY as tt, getFieldIdFromRef as u, deriveFillRecordPath as ut, validate as v, formatSuggestedLlms as vt, serializeForm as w, MarkformError as wt, computeProgressSummary as x, parseModelIdForDisplay as xt, computeAllSummaries as y, getWebSearchConfig as yt, getBooleanAttr as z };
5680
+ //# sourceMappingURL=prompts-BR5xYbvY.mjs.map