agent-first-data 0.30.0 → 0.31.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
@@ -17,12 +17,15 @@ console.log(render(event.toJSON(), "json"));
17
17
  console.log(render(event.toJSON(), "plain"));
18
18
  ```
19
19
 
20
- Useful names use TypeScript casing: `render`, `outputOptionsForPolicy`, `redactedValue`, `redactUrlSecrets`, `redactArgv`, `normalizeUtcOffset`, `isValidRfc3339Date`, `isValidRfc3339Time`, `isValidRfc3339`, `isValidBcp47`, `decodeProtocolEvent`, `cliParseOutput`, `cliParseLogFilters`, `buildCliError`, and `buildCliVersion`.
20
+ Useful names use TypeScript casing: `render`, `outputOptionsForPolicy`, `redactedValue`, `redactUrlSecrets`, `redactUrlsInText`, `redactArgv`, `normalizeUtcOffset`, `isValidRfc3339Date`, `isValidRfc3339Time`, `isValidRfc3339`, `isValidBcp47`, `decodeProtocolEvent`, `cliParseOutput`, `cliParseLogFilters`, `buildCliError`, and `buildCliVersion`.
21
21
 
22
22
  ## Behavior Notes
23
23
 
24
24
  - Default redaction replaces every `_secret` or configured secret-name subtree with `***`, including objects and arrays.
25
25
  - `_url` fields scrub userinfo passwords and secret-named query parameters; surrounding whitespace is trimmed and internal whitespace redacts the whole field.
26
+ - `OutputOptions.redaction.urlNames` applies URL treatment to exact legacy field names
27
+ and recurses through collections. `redactUrlsInText` is explicit and scans
28
+ only complete scheme URLs, never arbitrary prose secrets.
26
29
  - YAML keeps original keys and values (structure-preserving, like JSON), sorting keys by UTF-16 code unit order and quoting/escaping unsafe keys and string scalars. Plain strips formatting suffixes, formats values, sorts the same way, and renders nested objects/arrays as canonical JSON.
27
30
  - Logging records use `kind:"log"` with a nested `log` payload and a separate `level` field, so error-level logs are not terminal protocol errors.
28
31
  - `buildCliError(message, hint?)` returns a strict-ready CLI error with `error.retryable:false` and `trace:{}`.
@@ -32,6 +32,13 @@
32
32
  "about": {
33
33
  "$ref": "#/$defs/nonEmpty"
34
34
  },
35
+ "shared_arguments": {
36
+ "description": "Arguments every command accepts, declared once. Spliced into each command and into every combination's optional set when the registry is built, so a resolved spec behaves as if each command declared them.",
37
+ "type": "array",
38
+ "items": {
39
+ "$ref": "#/$defs/argument"
40
+ }
41
+ },
35
42
  "lifecycle_output": {
36
43
  "$ref": "#/$defs/output"
37
44
  },
@@ -164,7 +171,8 @@
164
171
  "i64",
165
172
  "finite_f64",
166
173
  "enum",
167
- "json"
174
+ "json",
175
+ "uuid"
168
176
  ]
169
177
  },
170
178
  "value_name": {
@@ -178,6 +186,15 @@
178
186
  "$ref": "#/$defs/nonEmpty"
179
187
  }
180
188
  },
189
+ "range": {
190
+ "description": "Inclusive [minimum, maximum] bounds for an I64 argument, checked when the value is parsed so an out-of-range value is a usage error.",
191
+ "type": "array",
192
+ "items": {
193
+ "type": "integer"
194
+ },
195
+ "minItems": 2,
196
+ "maxItems": 2
197
+ },
181
198
  "default": true,
182
199
  "repeatable": {
183
200
  "const": true
package/dist/cli.d.ts CHANGED
@@ -6,7 +6,8 @@ import { JsonValue, type OutputOptions, Event } from "./format.js";
6
6
  export type OutputFormat = "json" | "yaml" | "plain";
7
7
  /**
8
8
  * Parse the --output flag value into an OutputFormat.
9
- * Throws on unknown values; catch and pass message to buildCliError.
9
+ * Throws a value-safe message on unknown values; catch and pass it to
10
+ * buildCliError.
10
11
  *
11
12
  * @example
12
13
  * cliParseOutput("json") // → "json"
@@ -78,8 +79,8 @@ export type CliEventWriter = (line: string) => void;
78
79
  export type OutputTo = "split" | "stdout" | "stderr";
79
80
  /**
80
81
  * Parse an `--output-to` value into an OutputTo: "split" (default), "stdout", or
81
- * "stderr". Throws on unknown values; catch and pass the message to
82
- * buildCliError.
82
+ * "stderr". Throws a value-safe message on unknown values; catch and pass it
83
+ * to buildCliError.
83
84
  *
84
85
  * @example
85
86
  * parseOutputTo("split") // → "split"
package/dist/cli.js CHANGED
@@ -4,7 +4,8 @@
4
4
  import { Event, jsonError, jsonResult, formatJsonValue, formatYamlValue, formatPlainValue, validateProtocolEvent, } from "./format.js";
5
5
  /**
6
6
  * Parse the --output flag value into an OutputFormat.
7
- * Throws on unknown values; catch and pass message to buildCliError.
7
+ * Throws a value-safe message on unknown values; catch and pass it to
8
+ * buildCliError.
8
9
  *
9
10
  * @example
10
11
  * cliParseOutput("json") // → "json"
@@ -14,7 +15,7 @@ export function cliParseOutput(s) {
14
15
  if (s === "json" || s === "yaml" || s === "plain") {
15
16
  return s;
16
17
  }
17
- throw new Error(`invalid --output format '${s}': expected json, yaml, or plain`);
18
+ throw new Error("invalid --output format: expected json, yaml, or plain");
18
19
  }
19
20
  /**
20
21
  * Normalized log filter result with enabled() matching and readonly filters property.
@@ -96,8 +97,8 @@ export function render(value, format, options = {}) {
96
97
  }
97
98
  /**
98
99
  * Parse an `--output-to` value into an OutputTo: "split" (default), "stdout", or
99
- * "stderr". Throws on unknown values; catch and pass the message to
100
- * buildCliError.
100
+ * "stderr". Throws a value-safe message on unknown values; catch and pass it
101
+ * to buildCliError.
101
102
  *
102
103
  * @example
103
104
  * parseOutputTo("split") // → "split"
@@ -107,7 +108,7 @@ export function parseOutputTo(value) {
107
108
  if (value === "split" || value === "stdout" || value === "stderr") {
108
109
  return value;
109
110
  }
110
- throw new Error(`invalid --output-to '${value}': expected split, stdout, or stderr`);
111
+ throw new Error("invalid --output-to: expected split, stdout, or stderr");
111
112
  }
112
113
  /** Event writer bound to the process stdout stream. */
113
114
  const processStdoutWriter = (line) => {
package/dist/format.d.ts CHANGED
@@ -153,6 +153,11 @@ export type OutputOptions = {
153
153
  * Matching is exact field-name equality at any nesting level.
154
154
  */
155
155
  secretNames?: readonly string[];
156
+ /**
157
+ * Exact legacy field names whose string leaves receive URL-aware
158
+ * redaction in addition to _url/_URL fields.
159
+ */
160
+ urlNames?: readonly string[];
156
161
  };
157
162
  /** Rendering style for plain (logfmt) output only. Omitted means readable.
158
163
  * JSON and YAML are structure-preserving and ignore this setting. */
@@ -185,6 +190,7 @@ export declare function formatPlainValue(value: JsonValue | Event, options?: Out
185
190
  export declare function redactedValue(value: unknown, options?: {
186
191
  policy?: RedactionPolicy;
187
192
  secretNames?: readonly string[];
193
+ urlNames?: readonly string[];
188
194
  }): JsonValue;
189
195
  /**
190
196
  * Redact secret components of a single URL string.
@@ -206,6 +212,16 @@ export declare function redactUrlSecrets(url: string, options?: {
206
212
  secretNames?: readonly string[];
207
213
  policy?: RedactionPolicy;
208
214
  }): string;
215
+ /**
216
+ * Redact complete scheme-prefixed URL spans embedded in prose.
217
+ *
218
+ * This helper is explicit and URL-only: surrounding text is never scanned for
219
+ * secret-looking names or values.
220
+ */
221
+ export declare function redactUrlsInText(text: string, options?: {
222
+ secretNames?: readonly string[];
223
+ policy?: RedactionPolicy;
224
+ }): string;
209
225
  /**
210
226
  * Redact secret values out of a command line.
211
227
  *
package/dist/format.js CHANGED
@@ -517,6 +517,17 @@ export function redactUrlSecrets(url, options) {
517
517
  const redacted = redactUrlInStr(url, secretNameSet(options ?? {}));
518
518
  return redacted ?? url;
519
519
  }
520
+ /**
521
+ * Redact complete scheme-prefixed URL spans embedded in prose.
522
+ *
523
+ * This helper is explicit and URL-only: surrounding text is never scanned for
524
+ * secret-looking names or values.
525
+ */
526
+ export function redactUrlsInText(text, options) {
527
+ if (!redactsUnscopedInput(options?.policy))
528
+ return text;
529
+ return redactUrlsInTextWithContext(text, contextFromOptions(options ?? {}));
530
+ }
520
531
  /**
521
532
  * Redact secret values out of a command line.
522
533
  *
@@ -749,12 +760,16 @@ function isRedacted(value) {
749
760
  }
750
761
  const DEFAULT_CONTEXT = {
751
762
  secretNames: new Set(),
763
+ urlNames: new Set(),
752
764
  };
753
765
  function secretNameSet(redactionOptions) {
754
766
  return new Set(redactionOptions.secretNames ?? []);
755
767
  }
756
768
  function contextFromOptions(redactionOptions) {
757
- return { secretNames: secretNameSet(redactionOptions) };
769
+ return {
770
+ secretNames: secretNameSet(redactionOptions),
771
+ urlNames: new Set(redactionOptions.urlNames ?? []),
772
+ };
758
773
  }
759
774
  function keyHasSecretSuffix(key) {
760
775
  return key.endsWith("_secret") || key.endsWith("_SECRET");
@@ -765,6 +780,9 @@ function keyHasUrlSuffix(key) {
765
780
  function isSecretKey(key, secretNames) {
766
781
  return keyHasSecretSuffix(key) || secretNames.has(key);
767
782
  }
783
+ function isUrlKey(key, context) {
784
+ return keyHasUrlSuffix(key) || context.urlNames.has(key);
785
+ }
768
786
  const MAX_DEPTH = 256;
769
787
  const MAX_DEPTH_MARKER = "<afdata:max-depth>";
770
788
  function redactSecrets(value, context = DEFAULT_CONTEXT, depth = 0) {
@@ -782,13 +800,8 @@ function redactSecrets(value, context = DEFAULT_CONTEXT, depth = 0) {
782
800
  value[k] = REDACTED_MARKER;
783
801
  }
784
802
  }
785
- else if (keyHasUrlSuffix(k)) {
786
- if (typeof v === "string") {
787
- value[k] = redactUrlFieldValue(v, context.secretNames);
788
- }
789
- else {
790
- value[k] = depth + 1 >= MAX_DEPTH ? MAX_DEPTH_MARKER : (redactSecrets(v, context, depth + 1), v);
791
- }
803
+ else if (isUrlKey(k, context)) {
804
+ value[k] = redactUrlValue(v, context, depth + 1);
792
805
  }
793
806
  else {
794
807
  value[k] = depth + 1 >= MAX_DEPTH ? MAX_DEPTH_MARKER : (redactSecrets(v, context, depth + 1), v);
@@ -804,6 +817,32 @@ function redactSecrets(value, context = DEFAULT_CONTEXT, depth = 0) {
804
817
  }
805
818
  }
806
819
  }
820
+ function redactUrlValue(value, context, depth) {
821
+ if (depth >= MAX_DEPTH)
822
+ return MAX_DEPTH_MARKER;
823
+ if (typeof value === "string") {
824
+ return redactUrlFieldValue(value, context.secretNames);
825
+ }
826
+ if (Array.isArray(value)) {
827
+ for (let index = 0; index < value.length; index++) {
828
+ value[index] = redactUrlValue(value[index], context, depth + 1);
829
+ }
830
+ return value;
831
+ }
832
+ if (isObject(value)) {
833
+ for (const key of Object.keys(value)) {
834
+ const item = value[key];
835
+ if (isSecretKey(key, context.secretNames)) {
836
+ if (item !== null)
837
+ value[key] = REDACTED_MARKER;
838
+ }
839
+ else {
840
+ value[key] = redactUrlValue(item, context, depth + 1);
841
+ }
842
+ }
843
+ }
844
+ return value;
845
+ }
807
846
  function applyRedactionOptions(value, redactionOptions) {
808
847
  applyRedactionPolicyWithContext(value, redactionOptions.policy, contextFromOptions(redactionOptions));
809
848
  }
@@ -872,6 +911,120 @@ function redactUrlInStr(s, secretNames) {
872
911
  const newFragment = fragment === null ? "" : `#${redactQuery(fragment, secretNames)}`;
873
912
  return `${scheme}://${newAuthority}${newBeforeFragment}${newFragment}`;
874
913
  }
914
+ function redactUrlsInTextWithContext(text, context) {
915
+ const output = [];
916
+ let copiedThrough = 0;
917
+ let searchFrom = 0;
918
+ while (true) {
919
+ const span = nextSchemeUrlSpan(text, searchFrom);
920
+ if (span === null)
921
+ break;
922
+ const [start, end] = span;
923
+ output.push(text.slice(copiedThrough, start));
924
+ const url = text.slice(start, end);
925
+ output.push(redactUrlInStr(url, context.secretNames) ?? url);
926
+ copiedThrough = end;
927
+ searchFrom = end;
928
+ }
929
+ if (output.length === 0)
930
+ return text;
931
+ output.push(text.slice(copiedThrough));
932
+ return output.join("");
933
+ }
934
+ function nextSchemeUrlSpan(text, startAt) {
935
+ let start = startAt;
936
+ while (start < text.length) {
937
+ // Only consider the head of a maximal scheme-byte run: a scheme cannot begin
938
+ // mid-run, so a position whose predecessor is a scheme byte was already
939
+ // covered by the run that contains it.
940
+ const atRunHead = start === 0 || !isSchemeCodeUnit(text.charCodeAt(start - 1));
941
+ if (atRunHead) {
942
+ let schemeEnd = start;
943
+ while (schemeEnd < text.length && isSchemeCodeUnit(text.charCodeAt(schemeEnd))) {
944
+ schemeEnd += 1;
945
+ }
946
+ // A scheme must start with a letter, but the run need not: prose like
947
+ // "2https://h/?token_secret=x" glues a digit onto the URL. Retry from the
948
+ // first letter *inside* the run instead of abandoning the span — giving up
949
+ // there fails open and leaks the whole query.
950
+ let schemeStart = -1;
951
+ for (let i = start; i < schemeEnd; i++) {
952
+ if (isAsciiAlpha(text.charCodeAt(i))) {
953
+ schemeStart = i;
954
+ break;
955
+ }
956
+ }
957
+ if (schemeStart >= 0 && text.startsWith("://", schemeEnd)) {
958
+ let end = schemeEnd + 3;
959
+ while (end < text.length
960
+ && !isSpanTerminatorWhitespace(text.charCodeAt(end))
961
+ && !isTextUrlDelimiter(text[end])) {
962
+ end += 1;
963
+ }
964
+ while (end > schemeEnd + 3
965
+ && isTrailingTextUrlPunctuation(text[end - 1])) {
966
+ end -= 1;
967
+ }
968
+ if (end > schemeEnd + 3)
969
+ return [schemeStart, end];
970
+ }
971
+ }
972
+ start += 1;
973
+ }
974
+ return null;
975
+ }
976
+ function isSchemeCodeUnit(code) {
977
+ return isAsciiAlphanumeric(code) || code === 0x2b || code === 0x2d || code === 0x2e;
978
+ }
979
+ /**
980
+ * True for a code unit that ends a URL span in prose: the Unicode `White_Space`
981
+ * property, written out here instead of delegated to `/\s/u`.
982
+ *
983
+ * The four AFDATA implementations must cut the span at the same byte, and each
984
+ * language's native predicate covers a different set — `\s` counts U+FEFF but
985
+ * not U+0085, Python's `str.isspace()` counts U+001C–U+001F, Rust and Go count
986
+ * neither. Divergence is a defect in both directions: ending a span early leaves
987
+ * the rest of the query readable, and ending it late pulls the following prose
988
+ * into the URL, where redacting the parameter it lands in deletes it. So the set
989
+ * is enumerated, and it is generous — a redaction helper exists to keep a log
990
+ * line readable, so anything a human reads as a space must end the URL.
991
+ *
992
+ * Two exclusions are deliberate, not oversights:
993
+ * - **U+FEFF** (zero-width no-break space) is not `White_Space`. `\s` counts it,
994
+ * which is what used to cut a URL carrying it short and leave the secret after
995
+ * it in the clear. It must not creep back in.
996
+ * - **U+001C–U+001F** (the file/group/record/unit separators) are not
997
+ * `White_Space` either; only Python's `str.isspace()` counted them.
998
+ *
999
+ * This is a different question from `isSingleUrl`, which asks whether a whole
1000
+ * string is one URL and stays ASCII-only. A span this scanner produces contains
1001
+ * no whitespace at all, so it satisfies that stricter gate either way.
1002
+ */
1003
+ function isSpanTerminatorWhitespace(code) {
1004
+ return (
1005
+ // TAB, LF, VT, FF, CR, SPACE
1006
+ (code >= 0x09 && code <= 0x0d)
1007
+ || code === 0x20
1008
+ // NEL, NBSP, OGHAM SPACE MARK
1009
+ || code === 0x85
1010
+ || code === 0xa0
1011
+ || code === 0x1680
1012
+ // EN QUAD .. HAIR SPACE
1013
+ || (code >= 0x2000 && code <= 0x200a)
1014
+ // LINE SEPARATOR, PARAGRAPH SEPARATOR, NARROW NO-BREAK SPACE,
1015
+ // MEDIUM MATHEMATICAL SPACE, IDEOGRAPHIC SPACE
1016
+ || code === 0x2028
1017
+ || code === 0x2029
1018
+ || code === 0x202f
1019
+ || code === 0x205f
1020
+ || code === 0x3000);
1021
+ }
1022
+ function isTextUrlDelimiter(character) {
1023
+ return "\"'<>`,。;!?)》】」』".includes(character);
1024
+ }
1025
+ function isTrailingTextUrlPunctuation(character) {
1026
+ return ".,;!)]},。;!)》】".includes(character);
1027
+ }
875
1028
  function redactUrlFieldValue(s, secretNames) {
876
1029
  const redacted = redactUrlInStr(s, secretNames);
877
1030
  if (redacted !== null)
@@ -1018,8 +1171,9 @@ function decimalIntText(value) {
1018
1171
  }
1019
1172
  return null;
1020
1173
  }
1174
+ const MIN_I64 = -9223372036854775808n;
1021
1175
  const MAX_I64 = 9223372036854775807n;
1022
- function nonNegativeI64(value) {
1176
+ function signedI64(value) {
1023
1177
  let text = null;
1024
1178
  if (typeof value === "bigint") {
1025
1179
  text = value.toString();
@@ -1036,14 +1190,16 @@ function nonNegativeI64(value) {
1036
1190
  return null;
1037
1191
  try {
1038
1192
  const integer = BigInt(text);
1039
- return integer >= 0n && integer <= MAX_I64 ? integer : null;
1193
+ return integer >= MIN_I64 && integer <= MAX_I64 ? integer : null;
1040
1194
  }
1041
1195
  catch {
1042
1196
  return null;
1043
1197
  }
1044
1198
  }
1045
1199
  function formatCents(value, symbol) {
1046
- return `${symbol}${value / 100n}.${String(value % 100n).padStart(2, "0")}`;
1200
+ const sign = value < 0n ? "-" : "";
1201
+ const magnitude = value < 0n ? -value : value;
1202
+ return `${sign}${symbol}${magnitude / 100n}.${String(magnitude % 100n).padStart(2, "0")}`;
1047
1203
  }
1048
1204
  function epochNsToMs(value) {
1049
1205
  const text = decimalIntText(value);
@@ -1114,14 +1270,14 @@ function tryProcessField(key, value) {
1114
1270
  // Group 2: compound currency suffixes
1115
1271
  stripped = stripSuffixCI(key, "_usd_cents");
1116
1272
  if (stripped !== null) {
1117
- const integer = nonNegativeI64(value);
1273
+ const integer = signedI64(value);
1118
1274
  if (integer !== null)
1119
1275
  return [stripped, formatCents(integer, "$")];
1120
1276
  return null;
1121
1277
  }
1122
1278
  stripped = stripSuffixCI(key, "_eur_cents");
1123
1279
  if (stripped !== null) {
1124
- const integer = nonNegativeI64(value);
1280
+ const integer = signedI64(value);
1125
1281
  if (integer !== null)
1126
1282
  return [stripped, formatCents(integer, "\u20ac")];
1127
1283
  return null;
@@ -1129,18 +1285,22 @@ function tryProcessField(key, value) {
1129
1285
  const gc = tryStripGenericCents(key);
1130
1286
  if (gc !== null) {
1131
1287
  const [gcStripped, code] = gc;
1132
- const integer = nonNegativeI64(value);
1288
+ const integer = signedI64(value);
1133
1289
  if (integer !== null) {
1134
- return [gcStripped, `${integer / 100n}.${String(integer % 100n).padStart(2, "0")} ${code.toUpperCase()}`];
1290
+ const sign = integer < 0n ? "-" : "";
1291
+ const magnitude = integer < 0n ? -integer : integer;
1292
+ return [gcStripped, `${sign}${magnitude / 100n}.${String(magnitude % 100n).padStart(2, "0")} ${code.toUpperCase()}`];
1135
1293
  }
1136
1294
  return null;
1137
1295
  }
1138
1296
  const gm = tryStripGenericMicro(key);
1139
1297
  if (gm !== null) {
1140
1298
  const [gmStripped, code] = gm;
1141
- const integer = nonNegativeI64(value);
1299
+ const integer = signedI64(value);
1142
1300
  if (integer !== null) {
1143
- return [gmStripped, `${integer / 1000000n}.${String(integer % 1000000n).padStart(6, "0")} ${code.toUpperCase()}`];
1301
+ const sign = integer < 0n ? "-" : "";
1302
+ const magnitude = integer < 0n ? -integer : integer;
1303
+ return [gmStripped, `${sign}${magnitude / 1000000n}.${String(magnitude % 1000000n).padStart(6, "0")} ${code.toUpperCase()}`];
1144
1304
  }
1145
1305
  return null;
1146
1306
  }
@@ -1199,9 +1359,12 @@ function tryProcessField(key, value) {
1199
1359
  // Group 5: short suffixes (last to avoid false positives)
1200
1360
  stripped = stripSuffixCI(key, "_jpy");
1201
1361
  if (stripped !== null) {
1202
- const integer = nonNegativeI64(value);
1203
- if (integer !== null)
1204
- return [stripped, `\u00a5${formatWithCommas(integer)}`];
1362
+ const integer = signedI64(value);
1363
+ if (integer !== null) {
1364
+ const sign = integer < 0n ? "-" : "";
1365
+ const magnitude = integer < 0n ? -integer : integer;
1366
+ return [stripped, `${sign}\u00a5${formatWithCommas(magnitude)}`];
1367
+ }
1205
1368
  return null;
1206
1369
  }
1207
1370
  stripped = stripSuffixCI(key, "_ns");
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * Agent-First Data (AFDATA) — suffix-driven output formatting and protocol templates.
3
3
  */
4
- export { jsonResult, jsonError, jsonProgress, jsonLog, Event, EventBuildError, JsonResultBuilder, JsonErrorBuilder, JsonProgressBuilder, JsonLogBuilder, type LogLevel, validateProtocolEvent, validateProtocolStream, decodeProtocolEvent, type DecodedEvent, type DecodedResult, type DecodedError, type DecodedProgress, type DecodedLog, EventDecodeError, type JsonValue, RedactionPolicy, PlainStyle, type OutputOptions, outputOptionsForPolicy, redactedValue, redactArgv, redactUrlSecrets, normalizeUtcOffset, isValidRfc3339Date, isValidRfc3339Time, isValidRfc3339, isValidBcp47, } from "./format.js";
4
+ export { jsonResult, jsonError, jsonProgress, jsonLog, Event, EventBuildError, JsonResultBuilder, JsonErrorBuilder, JsonProgressBuilder, JsonLogBuilder, type LogLevel, validateProtocolEvent, validateProtocolStream, decodeProtocolEvent, type DecodedEvent, type DecodedResult, type DecodedError, type DecodedProgress, type DecodedLog, EventDecodeError, type JsonValue, RedactionPolicy, PlainStyle, type OutputOptions, outputOptionsForPolicy, redactedValue, redactArgv, redactUrlSecrets, redactUrlsInText, normalizeUtcOffset, isValidRfc3339Date, isValidRfc3339Time, isValidRfc3339, isValidBcp47, } from "./format.js";
5
5
  export { type OutputFormat, type OutputTo, type CliEventWriter, CliEmitter, LogFilters, cliParseOutput, parseOutputTo, cliParseLogFilters, render, buildCliError, buildCliVersion, cliRenderVersion, } from "./cli.js";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * Agent-First Data (AFDATA) — suffix-driven output formatting and protocol templates.
3
3
  */
4
- export { jsonResult, jsonError, jsonProgress, jsonLog, Event, EventBuildError, JsonResultBuilder, JsonErrorBuilder, JsonProgressBuilder, JsonLogBuilder, validateProtocolEvent, validateProtocolStream, decodeProtocolEvent, EventDecodeError, RedactionPolicy, PlainStyle, outputOptionsForPolicy, redactedValue, redactArgv, redactUrlSecrets, normalizeUtcOffset, isValidRfc3339Date, isValidRfc3339Time, isValidRfc3339, isValidBcp47, } from "./format.js";
4
+ export { jsonResult, jsonError, jsonProgress, jsonLog, Event, EventBuildError, JsonResultBuilder, JsonErrorBuilder, JsonProgressBuilder, JsonLogBuilder, validateProtocolEvent, validateProtocolStream, decodeProtocolEvent, EventDecodeError, RedactionPolicy, PlainStyle, outputOptionsForPolicy, redactedValue, redactArgv, redactUrlSecrets, redactUrlsInText, normalizeUtcOffset, isValidRfc3339Date, isValidRfc3339Time, isValidRfc3339, isValidBcp47, } from "./format.js";
5
5
  export { CliEmitter, LogFilters, cliParseOutput, parseOutputTo, cliParseLogFilters, render, buildCliError, buildCliVersion, cliRenderVersion, } from "./cli.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-first-data",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "A naming convention that lets AI agents understand your data without being told what it means, plus a CLI and library for reading Markdown structure and safely editing structured JSON, TOML, YAML, dotenv, and INI documents.",
5
5
  "license": "MIT",
6
6
  "repository": {