agent-first-data 0.23.0 → 0.25.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,7 +17,7 @@ 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`, `normalizeUtcOffset`, `isValidRfc3339Date`, `isValidRfc3339Time`, `isValidRfc3339`, `isValidBcp47`, `decodeProtocolEvent`, `cliParseOutput`, `cliParseLogFilters`, `buildCliError`, `buildCliVersion`, and `cliHandleVersionOrContinue`.
20
+ Useful names use TypeScript casing: `render`, `outputOptionsForPolicy`, `redactedValue`, `redactUrlSecrets`, `redactArgv`, `normalizeUtcOffset`, `isValidRfc3339Date`, `isValidRfc3339Time`, `isValidRfc3339`, `isValidBcp47`, `decodeProtocolEvent`, `cliParseOutput`, `cliParseLogFilters`, `buildCliError`, `buildCliVersion`, and `cliHandleVersionOrContinue`.
21
21
 
22
22
  ## Behavior Notes
23
23
 
@@ -26,7 +26,7 @@ Useful names use TypeScript casing: `render`, `outputOptionsForPolicy`, `redacte
26
26
  - 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
27
  - 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
28
  - `buildCliError(message, hint?)` returns a strict-ready CLI error with `error.retryable:false` and `trace:{}`.
29
- - Use `cliHandleVersionOrContinue()` before argument parsing so `--version`/`-V` always answers with a structured protocol-v1 `kind:"result"` version event — JSON by default, or `--output yaml|plain`/`--json` for another format; there is no conventional bare-text form. Pass your own value-taking global flag names so their value is not mistaken for the subcommand boundary.
29
+ - Use `cliHandleVersionOrContinue()` before argument parsing so `--version` always answers with a structured protocol-v1 `kind:"result"` version event. An explicit `--output` wins; pass the command's normal output as `defaultOutput` (JSON when omitted), plus its value-taking global flag names.
30
30
 
31
31
  ## Reference
32
32
 
@@ -0,0 +1,227 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://agentfirstkit.org/schemas/agent-first-data/cli-help-v1.schema.json",
4
+ "title": "AFDATA CLI help v1 event",
5
+ "description": "Compact, progressively disclosed CLI help carried by an AFDATA result event.",
6
+ "type": "object",
7
+ "required": [
8
+ "kind",
9
+ "result",
10
+ "trace"
11
+ ],
12
+ "additionalProperties": false,
13
+ "properties": {
14
+ "kind": {
15
+ "const": "result"
16
+ },
17
+ "result": {
18
+ "type": "object",
19
+ "required": [
20
+ "code",
21
+ "help"
22
+ ],
23
+ "additionalProperties": false,
24
+ "properties": {
25
+ "code": {
26
+ "const": "help"
27
+ },
28
+ "help": {
29
+ "$ref": "#/$defs/help"
30
+ }
31
+ }
32
+ },
33
+ "trace": {
34
+ "type": "object"
35
+ }
36
+ },
37
+ "$defs": {
38
+ "argument": {
39
+ "type": "object",
40
+ "required": [
41
+ "name"
42
+ ],
43
+ "additionalProperties": false,
44
+ "properties": {
45
+ "name": {
46
+ "type": "string",
47
+ "minLength": 1
48
+ },
49
+ "short": {
50
+ "type": "string",
51
+ "pattern": "^-[^-]$"
52
+ },
53
+ "help": {
54
+ "type": "string",
55
+ "minLength": 1
56
+ },
57
+ "required": {
58
+ "const": true
59
+ },
60
+ "global": {
61
+ "const": true
62
+ },
63
+ "repeatable": {
64
+ "const": true
65
+ },
66
+ "value": {
67
+ "type": "string",
68
+ "minLength": 1
69
+ },
70
+ "values": {
71
+ "type": "array",
72
+ "minItems": 1,
73
+ "items": {
74
+ "type": "string",
75
+ "minLength": 1
76
+ }
77
+ },
78
+ "default": {
79
+ "type": "string"
80
+ },
81
+ "defaults": {
82
+ "type": "array",
83
+ "minItems": 1,
84
+ "items": {
85
+ "type": "string"
86
+ }
87
+ }
88
+ },
89
+ "allOf": [
90
+ {
91
+ "if": {
92
+ "properties": {
93
+ "name": {
94
+ "pattern": "^-"
95
+ }
96
+ }
97
+ },
98
+ "else": {
99
+ "not": {
100
+ "anyOf": [
101
+ {
102
+ "required": [
103
+ "value"
104
+ ]
105
+ },
106
+ {
107
+ "required": [
108
+ "values"
109
+ ]
110
+ }
111
+ ]
112
+ }
113
+ }
114
+ },
115
+ {
116
+ "not": {
117
+ "required": [
118
+ "value",
119
+ "values"
120
+ ]
121
+ }
122
+ },
123
+ {
124
+ "not": {
125
+ "required": [
126
+ "default",
127
+ "defaults"
128
+ ]
129
+ }
130
+ }
131
+ ]
132
+ },
133
+ "command": {
134
+ "type": "object",
135
+ "required": [
136
+ "name"
137
+ ],
138
+ "additionalProperties": false,
139
+ "properties": {
140
+ "name": {
141
+ "type": "string",
142
+ "minLength": 1
143
+ },
144
+ "about": {
145
+ "type": "string",
146
+ "minLength": 1
147
+ },
148
+ "usage": {
149
+ "type": "string",
150
+ "minLength": 1,
151
+ "pattern": "^[^\\n\\r]+$"
152
+ },
153
+ "arguments": {
154
+ "type": "array",
155
+ "minItems": 1,
156
+ "items": {
157
+ "$ref": "#/$defs/argument"
158
+ }
159
+ },
160
+ "subcommands": {
161
+ "type": "array",
162
+ "minItems": 1,
163
+ "items": {
164
+ "$ref": "#/$defs/command"
165
+ }
166
+ }
167
+ }
168
+ },
169
+ "help": {
170
+ "type": "object",
171
+ "required": [
172
+ "scope",
173
+ "command_path",
174
+ "name"
175
+ ],
176
+ "additionalProperties": false,
177
+ "properties": {
178
+ "scope": {
179
+ "enum": [
180
+ "one_level",
181
+ "recursive"
182
+ ]
183
+ },
184
+ "command_path": {
185
+ "type": "string",
186
+ "minLength": 1
187
+ },
188
+ "inherited_arguments_from": {
189
+ "type": "array",
190
+ "minItems": 1,
191
+ "uniqueItems": true,
192
+ "items": {
193
+ "type": "string",
194
+ "minLength": 1
195
+ }
196
+ },
197
+ "name": {
198
+ "type": "string",
199
+ "minLength": 1
200
+ },
201
+ "about": {
202
+ "type": "string",
203
+ "minLength": 1
204
+ },
205
+ "usage": {
206
+ "type": "string",
207
+ "minLength": 1,
208
+ "pattern": "^[^\\n\\r]+$"
209
+ },
210
+ "arguments": {
211
+ "type": "array",
212
+ "minItems": 1,
213
+ "items": {
214
+ "$ref": "#/$defs/argument"
215
+ }
216
+ },
217
+ "subcommands": {
218
+ "type": "array",
219
+ "minItems": 1,
220
+ "items": {
221
+ "$ref": "#/$defs/command"
222
+ }
223
+ }
224
+ }
225
+ }
226
+ }
227
+ }
package/dist/cli.d.ts CHANGED
@@ -186,8 +186,8 @@ export declare function cliRenderVersion(name: string, displayName: string | und
186
186
  * Throws for malformed version requests, for example `--version --output xml`.
187
187
  *
188
188
  * The one blessed behavior: `--version` always answers with a protocol-v1
189
- * `kind:"result"` version event — JSON by default, or `--output yaml|plain` (or
190
- * `--json`) for another format. There is no conventional bare-text path.
189
+ * `kind:"result"` version event. An explicit `--output` wins; otherwise
190
+ * `defaultOutput` should be the command's normal output default.
191
191
  *
192
192
  * `valueFlags` is the caller's own value-taking global long flags (with or
193
193
  * without leading dashes; the leading dashes are stripped internally). It is the
@@ -200,7 +200,7 @@ export declare function cliRenderVersion(name: string, displayName: string | und
200
200
  * leaves `--version` for the subcommand's parser rather than printing the
201
201
  * tool version.
202
202
  */
203
- export declare function cliHandleVersionOrContinue(rawArgs: string[], valueFlags: string[], name: string, displayName: string | undefined, version: string, build: string | undefined): string | undefined;
203
+ export declare function cliHandleVersionOrContinue(rawArgs: string[], valueFlags: string[], name: string, displayName: string | undefined, version: string, build: string | undefined, defaultOutput?: OutputFormat): string | undefined;
204
204
  /**
205
205
  * Build a standard CLI parse error value. This function cannot fail.
206
206
  * Use when flag parsing fails or a flag value is invalid.
package/dist/cli.js CHANGED
@@ -322,8 +322,8 @@ function splitFlag(arg) {
322
322
  * Throws for malformed version requests, for example `--version --output xml`.
323
323
  *
324
324
  * The one blessed behavior: `--version` always answers with a protocol-v1
325
- * `kind:"result"` version event — JSON by default, or `--output yaml|plain` (or
326
- * `--json`) for another format. There is no conventional bare-text path.
325
+ * `kind:"result"` version event. An explicit `--output` wins; otherwise
326
+ * `defaultOutput` should be the command's normal output default.
327
327
  *
328
328
  * `valueFlags` is the caller's own value-taking global long flags (with or
329
329
  * without leading dashes; the leading dashes are stripped internally). It is the
@@ -336,7 +336,7 @@ function splitFlag(arg) {
336
336
  * leaves `--version` for the subcommand's parser rather than printing the
337
337
  * tool version.
338
338
  */
339
- export function cliHandleVersionOrContinue(rawArgs, valueFlags, name, displayName, version, build) {
339
+ export function cliHandleVersionOrContinue(rawArgs, valueFlags, name, displayName, version, build, defaultOutput = "json") {
340
340
  const valueFlagSet = new Set(valueFlags.map((flag) => flag.replace(/^-+/u, "")));
341
341
  let versionRequested = false;
342
342
  let outputFormat;
@@ -351,21 +351,11 @@ export function cliHandleVersionOrContinue(rawArgs, valueFlags, name, displayNam
351
351
  if (!arg.startsWith("-"))
352
352
  break;
353
353
  const { name: flagName, inlineValue } = splitFlag(arg);
354
- if (arg === "--version" || arg === "-V") {
354
+ if (arg === "--version") {
355
355
  versionRequested = true;
356
356
  i += 1;
357
357
  continue;
358
358
  }
359
- if (arg === "--json") {
360
- if (outputFormat !== undefined && outputFormat !== "json") {
361
- outputError = new Error("conflicting output formats: --json conflicts with previous output format");
362
- }
363
- else {
364
- outputFormat = "json";
365
- }
366
- i += 1;
367
- continue;
368
- }
369
359
  // `--output-to` takes a value but does not affect version text output.
370
360
  // Consume its space-separated value so it is not mistaken for the
371
361
  // subcommand boundary (which would hide a later `--version`/`--output`).
@@ -412,7 +402,7 @@ export function cliHandleVersionOrContinue(rawArgs, valueFlags, name, displayNam
412
402
  return undefined;
413
403
  if (outputError !== undefined)
414
404
  throw outputError;
415
- return cliRenderVersion(name, displayName, version, build, outputFormat ?? "json");
405
+ return cliRenderVersion(name, displayName, version, build, outputFormat ?? defaultOutput);
416
406
  }
417
407
  /**
418
408
  * Build a standard CLI parse error value. This function cannot fail.
package/dist/format.d.ts CHANGED
@@ -191,6 +191,31 @@ export declare function redactedValue(value: unknown, options?: {
191
191
  export declare function redactUrlSecrets(url: string, options?: {
192
192
  secretNames?: readonly string[];
193
193
  }): string;
194
+ /**
195
+ * Redact secret values out of a command line.
196
+ *
197
+ * A long flag whose name is secret by AFDATA naming (`--api-key-secret`, or an
198
+ * exact `secretNames` entry) has its value replaced by `***`, in both
199
+ * `--flag=value` and `--flag value` spellings. Everything else is preserved
200
+ * byte-for-byte.
201
+ *
202
+ * Free text is deliberately never scanned: a bare `api_key_secret=sk-live`
203
+ * positional, or a secret-looking token after a non-secret flag, is left alone.
204
+ * AFDATA decides sensitivity from the *field name*, and argv is no exception —
205
+ * rename the flag rather than pattern-matching values. A flag with no value
206
+ * (end of argv, or followed by another flag) is likewise left inspectable.
207
+ *
208
+ * Only long (`--`) flags are recognized, matching the convention's
209
+ * long-flags-only rule.
210
+ *
211
+ * Intended for CLIs that record their own invocation — startup diagnostics,
212
+ * audit trails, crash reports — where writing argv verbatim would put a
213
+ * credential in the log.
214
+ */
215
+ export declare function redactArgv(args: readonly string[], options?: {
216
+ secretNames?: readonly string[];
217
+ policy?: RedactionPolicy;
218
+ }): string[];
194
219
  /**
195
220
  * Normalize a fixed UTC offset string to "UTC" or ±HH:MM.
196
221
  * This helper handles fixed offsets only; IANA timezone names and DST rules
package/dist/format.js CHANGED
@@ -476,6 +476,67 @@ export function redactUrlSecrets(url, options) {
476
476
  const redacted = redactUrlInStr(url, secretNameSet(options ?? {}));
477
477
  return redacted ?? url;
478
478
  }
479
+ /**
480
+ * Redact secret values out of a command line.
481
+ *
482
+ * A long flag whose name is secret by AFDATA naming (`--api-key-secret`, or an
483
+ * exact `secretNames` entry) has its value replaced by `***`, in both
484
+ * `--flag=value` and `--flag value` spellings. Everything else is preserved
485
+ * byte-for-byte.
486
+ *
487
+ * Free text is deliberately never scanned: a bare `api_key_secret=sk-live`
488
+ * positional, or a secret-looking token after a non-secret flag, is left alone.
489
+ * AFDATA decides sensitivity from the *field name*, and argv is no exception —
490
+ * rename the flag rather than pattern-matching values. A flag with no value
491
+ * (end of argv, or followed by another flag) is likewise left inspectable.
492
+ *
493
+ * Only long (`--`) flags are recognized, matching the convention's
494
+ * long-flags-only rule.
495
+ *
496
+ * Intended for CLIs that record their own invocation — startup diagnostics,
497
+ * audit trails, crash reports — where writing argv verbatim would put a
498
+ * credential in the log.
499
+ */
500
+ export function redactArgv(args, options) {
501
+ if (options?.policy === RedactionPolicy.Off)
502
+ return [...args];
503
+ const secretNames = secretNameSet(options ?? {});
504
+ const out = [];
505
+ let redactNext = false;
506
+ for (const arg of args) {
507
+ if (redactNext) {
508
+ redactNext = false;
509
+ if (!arg.startsWith("-")) {
510
+ out.push("***");
511
+ continue;
512
+ }
513
+ }
514
+ if (arg.startsWith("--")) {
515
+ const rest = arg.slice(2);
516
+ const equals = rest.indexOf("=");
517
+ if (equals >= 0) {
518
+ const name = rest.slice(0, equals);
519
+ if (isSecretFlagName(name, secretNames)) {
520
+ out.push(`--${name}=***`);
521
+ continue;
522
+ }
523
+ }
524
+ else if (isSecretFlagName(rest, secretNames)) {
525
+ redactNext = true;
526
+ }
527
+ }
528
+ out.push(arg);
529
+ }
530
+ return out;
531
+ }
532
+ /**
533
+ * Whether a long flag's name is secret, normalizing the kebab-case flag
534
+ * spelling to the snake_case field spelling the convention is defined in.
535
+ */
536
+ function isSecretFlagName(flagName, secretNames) {
537
+ const normalized = flagName.replace(/-/gu, "_");
538
+ return isSecretKey(normalized, secretNames) || isSecretKey(flagName, secretNames);
539
+ }
479
540
  /**
480
541
  * Normalize a fixed UTC offset string to "UTC" or ±HH:MM.
481
542
  * This helper handles fixed offsets only; IANA timezone names and DST rules
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, 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, 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, cliHandleVersionOrContinue, } 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, 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, normalizeUtcOffset, isValidRfc3339Date, isValidRfc3339Time, isValidRfc3339, isValidBcp47, } from "./format.js";
5
5
  export { CliEmitter, LogFilters, cliParseOutput, parseOutputTo, cliParseLogFilters, render, buildCliError, buildCliVersion, cliRenderVersion, cliHandleVersionOrContinue, } from "./cli.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-first-data",
3
- "version": "0.23.0",
3
+ "version": "0.25.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 and safely editing structured JSON, TOML, YAML, dotenv, and INI documents.",
5
5
  "license": "MIT",
6
6
  "repository": {