agent-first-data 0.23.0__tar.gz → 0.25.0__tar.gz
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.
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/PKG-INFO +3 -3
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/README.md +2 -2
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/agent_first_data/__init__.py +2 -0
- agent_first_data-0.25.0/agent_first_data/assets/cli-help-v1.schema.json +227 -0
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/agent_first_data/cli.py +6 -13
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/agent_first_data/format.py +57 -0
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/agent_first_data.egg-info/PKG-INFO +3 -3
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/agent_first_data.egg-info/SOURCES.txt +1 -0
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/pyproject.toml +1 -1
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/tests/test_cli.py +25 -10
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/tests/test_format.py +18 -0
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/agent_first_data/assets/protocol-v1.schema.json +0 -0
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/agent_first_data/assets/registry.json +0 -0
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/agent_first_data.egg-info/dependency_links.txt +0 -0
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/agent_first_data.egg-info/top_level.txt +0 -0
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/setup.cfg +0 -0
- {agent_first_data-0.23.0 → agent_first_data-0.25.0}/tests/test_no_stderr_policy.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-first-data
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.0
|
|
4
4
|
Summary: 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-Expression: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/agentfirstkit/agent-first-data
|
|
@@ -28,7 +28,7 @@ print(render(value, OutputFormat.JSON))
|
|
|
28
28
|
print(render(value, OutputFormat.PLAIN))
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
Useful names use Python casing: `render` (the single value x format x options -> str entry point; takes an `OutputFormat` and an optional keyword-only `options=`), `redacted_value`, `redact_url_secrets`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `is_valid_rfc3339`, `is_valid_bcp47`, `cli_parse_output`, `build_cli_error`, `build_cli_version`, `cli_handle_version_or_continue`, `decode_protocol_event`.
|
|
31
|
+
Useful names use Python casing: `render` (the single value x format x options -> str entry point; takes an `OutputFormat` and an optional keyword-only `options=`), `redacted_value`, `redact_url_secrets`, `redact_argv`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `is_valid_rfc3339`, `is_valid_bcp47`, `cli_parse_output`, `build_cli_error`, `build_cli_version`, `cli_handle_version_or_continue`, `decode_protocol_event`.
|
|
32
32
|
|
|
33
33
|
## Behavior Notes
|
|
34
34
|
|
|
@@ -37,7 +37,7 @@ Useful names use Python casing: `render` (the single value x format x options ->
|
|
|
37
37
|
- 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.
|
|
38
38
|
- Logging records use `kind:"log"` with a nested `log` payload and a separate `level` field, so error-level logs are not terminal protocol errors.
|
|
39
39
|
- `build_cli_error(message, hint?)` returns a strict-ready CLI error with `error.retryable:false` and `trace:{}`.
|
|
40
|
-
- Use `cli_handle_version_or_continue()` before argument parsing so `--version
|
|
40
|
+
- Use `cli_handle_version_or_continue()` 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 `default_format` (JSON when omitted), plus its value-taking global flag names.
|
|
41
41
|
|
|
42
42
|
## Reference
|
|
43
43
|
|
|
@@ -19,7 +19,7 @@ print(render(value, OutputFormat.JSON))
|
|
|
19
19
|
print(render(value, OutputFormat.PLAIN))
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Useful names use Python casing: `render` (the single value x format x options -> str entry point; takes an `OutputFormat` and an optional keyword-only `options=`), `redacted_value`, `redact_url_secrets`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `is_valid_rfc3339`, `is_valid_bcp47`, `cli_parse_output`, `build_cli_error`, `build_cli_version`, `cli_handle_version_or_continue`, `decode_protocol_event`.
|
|
22
|
+
Useful names use Python casing: `render` (the single value x format x options -> str entry point; takes an `OutputFormat` and an optional keyword-only `options=`), `redacted_value`, `redact_url_secrets`, `redact_argv`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `is_valid_rfc3339`, `is_valid_bcp47`, `cli_parse_output`, `build_cli_error`, `build_cli_version`, `cli_handle_version_or_continue`, `decode_protocol_event`.
|
|
23
23
|
|
|
24
24
|
## Behavior Notes
|
|
25
25
|
|
|
@@ -28,7 +28,7 @@ Useful names use Python casing: `render` (the single value x format x options ->
|
|
|
28
28
|
- 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.
|
|
29
29
|
- Logging records use `kind:"log"` with a nested `log` payload and a separate `level` field, so error-level logs are not terminal protocol errors.
|
|
30
30
|
- `build_cli_error(message, hint?)` returns a strict-ready CLI error with `error.retryable:false` and `trace:{}`.
|
|
31
|
-
- Use `cli_handle_version_or_continue()` before argument parsing so `--version
|
|
31
|
+
- Use `cli_handle_version_or_continue()` 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 `default_format` (JSON when omitted), plus its value-taking global flag names.
|
|
32
32
|
|
|
33
33
|
## Reference
|
|
34
34
|
|
|
@@ -24,6 +24,7 @@ from agent_first_data.format import (
|
|
|
24
24
|
PlainStyle,
|
|
25
25
|
OutputOptions,
|
|
26
26
|
redacted_value,
|
|
27
|
+
redact_argv,
|
|
27
28
|
redact_url_secrets,
|
|
28
29
|
normalize_utc_offset,
|
|
29
30
|
is_valid_bcp47,
|
|
@@ -70,6 +71,7 @@ __all__ = [
|
|
|
70
71
|
"PlainStyle",
|
|
71
72
|
"OutputOptions",
|
|
72
73
|
"redacted_value",
|
|
74
|
+
"redact_argv",
|
|
73
75
|
"redact_url_secrets",
|
|
74
76
|
"normalize_utc_offset",
|
|
75
77
|
"is_valid_bcp47",
|
|
@@ -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
|
+
}
|
|
@@ -451,6 +451,8 @@ def cli_handle_version_or_continue(
|
|
|
451
451
|
display_name: str | None,
|
|
452
452
|
version: str,
|
|
453
453
|
build: str | None,
|
|
454
|
+
*,
|
|
455
|
+
default_format: OutputFormat = OutputFormat.JSON,
|
|
454
456
|
) -> str | None:
|
|
455
457
|
"""Render version output if --version/-V is present; otherwise return None.
|
|
456
458
|
|
|
@@ -461,8 +463,8 @@ def cli_handle_version_or_continue(
|
|
|
461
463
|
|
|
462
464
|
The one blessed behavior: ``--version``/``-V`` always answers with a
|
|
463
465
|
protocol-v1 ``kind:"result"`` version event (see :func:`build_cli_version`) —
|
|
464
|
-
|
|
465
|
-
|
|
466
|
+
An explicit ``--output <json|yaml|plain>`` wins; otherwise
|
|
467
|
+
``default_format`` should be the command's normal output default.
|
|
466
468
|
|
|
467
469
|
Only a top-level version request is recognized: scanning stops at the first
|
|
468
470
|
positional argument (the subcommand), so ``tool sub --version <value>``
|
|
@@ -490,19 +492,10 @@ def cli_handle_version_or_continue(
|
|
|
490
492
|
break
|
|
491
493
|
|
|
492
494
|
flag_name, inline_value = _split_flag(arg)
|
|
493
|
-
if arg
|
|
495
|
+
if arg == "--version":
|
|
494
496
|
version_requested = True
|
|
495
497
|
i += 1
|
|
496
498
|
continue
|
|
497
|
-
if arg == "--json":
|
|
498
|
-
if output_format is not None and output_format is not OutputFormat.JSON:
|
|
499
|
-
output_error = ValueError(
|
|
500
|
-
"conflicting output formats: --json conflicts with previous output format"
|
|
501
|
-
)
|
|
502
|
-
else:
|
|
503
|
-
output_format = OutputFormat.JSON
|
|
504
|
-
i += 1
|
|
505
|
-
continue
|
|
506
499
|
# `--output-to` takes a value but does not affect version output. Consume
|
|
507
500
|
# its space-separated value so it is not mistaken for the subcommand
|
|
508
501
|
# boundary (which would hide a later `--version`/`--output`).
|
|
@@ -560,7 +553,7 @@ def cli_handle_version_or_continue(
|
|
|
560
553
|
display_name,
|
|
561
554
|
version,
|
|
562
555
|
build,
|
|
563
|
-
output_format if output_format is not None else
|
|
556
|
+
output_format if output_format is not None else default_format,
|
|
564
557
|
)
|
|
565
558
|
|
|
566
559
|
|
|
@@ -613,6 +613,63 @@ def redact_url_secrets(url: str, *, secret_names: Sequence[str] = ()) -> str:
|
|
|
613
613
|
return redacted if redacted is not None else url
|
|
614
614
|
|
|
615
615
|
|
|
616
|
+
def redact_argv(
|
|
617
|
+
args: Sequence[str],
|
|
618
|
+
*,
|
|
619
|
+
secret_names: Sequence[str] = (),
|
|
620
|
+
policy: RedactionPolicy | None = None,
|
|
621
|
+
) -> list[str]:
|
|
622
|
+
"""Redact secret values out of a command line.
|
|
623
|
+
|
|
624
|
+
A long flag whose name is secret by AFDATA naming (``--api-key-secret``, or
|
|
625
|
+
an exact ``secret_names`` entry) has its value replaced by ``***``, in both
|
|
626
|
+
``--flag=value`` and ``--flag value`` spellings. Everything else is
|
|
627
|
+
preserved byte-for-byte.
|
|
628
|
+
|
|
629
|
+
Free text is deliberately never scanned: a bare ``api_key_secret=sk-live``
|
|
630
|
+
positional, or a secret-looking token after a non-secret flag, is left
|
|
631
|
+
alone. AFDATA decides sensitivity from the *field name*, and argv is no
|
|
632
|
+
exception — rename the flag rather than pattern-matching values. A flag with
|
|
633
|
+
no value (end of argv, or followed by another flag) is likewise left
|
|
634
|
+
inspectable.
|
|
635
|
+
|
|
636
|
+
Only long (``--``) flags are recognized, matching the convention's
|
|
637
|
+
long-flags-only rule.
|
|
638
|
+
|
|
639
|
+
Intended for CLIs that record their own invocation — startup diagnostics,
|
|
640
|
+
audit trails, crash reports — where writing argv verbatim would put a
|
|
641
|
+
credential in the log.
|
|
642
|
+
"""
|
|
643
|
+
if policy is RedactionPolicy.Off:
|
|
644
|
+
return list(args)
|
|
645
|
+
context = _RedactionContext.from_names(secret_names)
|
|
646
|
+
out: list[str] = []
|
|
647
|
+
redact_next = False
|
|
648
|
+
for arg in args:
|
|
649
|
+
if redact_next:
|
|
650
|
+
redact_next = False
|
|
651
|
+
if not arg.startswith("-"):
|
|
652
|
+
out.append("***")
|
|
653
|
+
continue
|
|
654
|
+
if arg.startswith("--"):
|
|
655
|
+
rest = arg[2:]
|
|
656
|
+
name, sep, _value = rest.partition("=")
|
|
657
|
+
if sep:
|
|
658
|
+
if _is_secret_flag_name(name, context):
|
|
659
|
+
out.append(f"--{name}=***")
|
|
660
|
+
continue
|
|
661
|
+
elif _is_secret_flag_name(rest, context):
|
|
662
|
+
redact_next = True
|
|
663
|
+
out.append(arg)
|
|
664
|
+
return out
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
def _is_secret_flag_name(flag_name: str, context: _RedactionContext) -> bool:
|
|
668
|
+
"""Whether a long flag's name is secret, normalizing kebab-case to snake_case."""
|
|
669
|
+
normalized = flag_name.replace("-", "_")
|
|
670
|
+
return context.is_secret_key(normalized) or context.is_secret_key(flag_name)
|
|
671
|
+
|
|
672
|
+
|
|
616
673
|
def _apply_redaction(value: Any, secret_names: Sequence[str], policy: RedactionPolicy | None) -> None:
|
|
617
674
|
context = _RedactionContext.from_names(secret_names)
|
|
618
675
|
_apply_redaction_policy_with_context(value, policy, context)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-first-data
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.0
|
|
4
4
|
Summary: 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-Expression: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/agentfirstkit/agent-first-data
|
|
@@ -28,7 +28,7 @@ print(render(value, OutputFormat.JSON))
|
|
|
28
28
|
print(render(value, OutputFormat.PLAIN))
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
Useful names use Python casing: `render` (the single value x format x options -> str entry point; takes an `OutputFormat` and an optional keyword-only `options=`), `redacted_value`, `redact_url_secrets`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `is_valid_rfc3339`, `is_valid_bcp47`, `cli_parse_output`, `build_cli_error`, `build_cli_version`, `cli_handle_version_or_continue`, `decode_protocol_event`.
|
|
31
|
+
Useful names use Python casing: `render` (the single value x format x options -> str entry point; takes an `OutputFormat` and an optional keyword-only `options=`), `redacted_value`, `redact_url_secrets`, `redact_argv`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `is_valid_rfc3339`, `is_valid_bcp47`, `cli_parse_output`, `build_cli_error`, `build_cli_version`, `cli_handle_version_or_continue`, `decode_protocol_event`.
|
|
32
32
|
|
|
33
33
|
## Behavior Notes
|
|
34
34
|
|
|
@@ -37,7 +37,7 @@ Useful names use Python casing: `render` (the single value x format x options ->
|
|
|
37
37
|
- 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.
|
|
38
38
|
- Logging records use `kind:"log"` with a nested `log` payload and a separate `level` field, so error-level logs are not terminal protocol errors.
|
|
39
39
|
- `build_cli_error(message, hint?)` returns a strict-ready CLI error with `error.retryable:false` and `trace:{}`.
|
|
40
|
-
- Use `cli_handle_version_or_continue()` before argument parsing so `--version
|
|
40
|
+
- Use `cli_handle_version_or_continue()` 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 `default_format` (JSON when omitted), plus its value-taking global flag names.
|
|
41
41
|
|
|
42
42
|
## Reference
|
|
43
43
|
|
|
@@ -7,6 +7,7 @@ agent_first_data.egg-info/PKG-INFO
|
|
|
7
7
|
agent_first_data.egg-info/SOURCES.txt
|
|
8
8
|
agent_first_data.egg-info/dependency_links.txt
|
|
9
9
|
agent_first_data.egg-info/top_level.txt
|
|
10
|
+
agent_first_data/assets/cli-help-v1.schema.json
|
|
10
11
|
agent_first_data/assets/protocol-v1.schema.json
|
|
11
12
|
agent_first_data/assets/registry.json
|
|
12
13
|
tests/test_cli.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "agent-first-data"
|
|
3
|
-
version = "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
|
readme = "README.md"
|
|
@@ -520,9 +520,9 @@ def test_cli_render_version_renders_json():
|
|
|
520
520
|
assert '"version":"1.2.3"' in out
|
|
521
521
|
|
|
522
522
|
|
|
523
|
-
def
|
|
524
|
-
#
|
|
525
|
-
#
|
|
523
|
+
def test_cli_handle_version_bare_inherits_json_default():
|
|
524
|
+
# `--version` answers with a protocol-v1 event and follows the command's
|
|
525
|
+
# declared output default.
|
|
526
526
|
out = cli_handle_version_or_continue(
|
|
527
527
|
["--version"],
|
|
528
528
|
VERSION_VALUE_FLAGS,
|
|
@@ -542,6 +542,21 @@ def test_cli_handle_version_bare_defaults_to_json():
|
|
|
542
542
|
assert parsed["trace"] == {}
|
|
543
543
|
|
|
544
544
|
|
|
545
|
+
def test_cli_handle_version_bare_inherits_plain_default():
|
|
546
|
+
out = cli_handle_version_or_continue(
|
|
547
|
+
["--version"],
|
|
548
|
+
VERSION_VALUE_FLAGS,
|
|
549
|
+
"agent-cli",
|
|
550
|
+
None,
|
|
551
|
+
"1.2.3",
|
|
552
|
+
None,
|
|
553
|
+
default_format=OutputFormat.PLAIN,
|
|
554
|
+
)
|
|
555
|
+
assert out is not None
|
|
556
|
+
assert "result.code=version" in out
|
|
557
|
+
assert "result.version=1.2.3" in out
|
|
558
|
+
|
|
559
|
+
|
|
545
560
|
def test_cli_handle_version_honors_explicit_plain_output():
|
|
546
561
|
out = cli_handle_version_or_continue(
|
|
547
562
|
["--version", "--output", "plain"],
|
|
@@ -656,9 +671,11 @@ def test_cli_handle_version_supports_inline_output_format():
|
|
|
656
671
|
assert 'version: "1.2.3"' in out
|
|
657
672
|
|
|
658
673
|
|
|
659
|
-
def
|
|
674
|
+
def test_cli_handle_version_ignores_json_flag():
|
|
675
|
+
# --json belongs to the application: it must not select a format, and it
|
|
676
|
+
# must not conflict with one. --output yaml still wins.
|
|
660
677
|
out = cli_handle_version_or_continue(
|
|
661
|
-
["--version", "--json"],
|
|
678
|
+
["--version", "--json", "--output", "yaml"],
|
|
662
679
|
VERSION_VALUE_FLAGS,
|
|
663
680
|
"agent-cli",
|
|
664
681
|
None,
|
|
@@ -666,15 +683,13 @@ def test_cli_handle_version_json_alias():
|
|
|
666
683
|
None,
|
|
667
684
|
)
|
|
668
685
|
assert out is not None
|
|
669
|
-
|
|
670
|
-
assert parsed["kind"] == "result"
|
|
671
|
-
assert parsed["result"]["version"] == "1.2.3"
|
|
686
|
+
assert out.startswith("---\n")
|
|
672
687
|
|
|
673
688
|
|
|
674
|
-
def
|
|
689
|
+
def test_cli_handle_version_conflicting_output_formats():
|
|
675
690
|
with pytest.raises(ValueError, match="conflicting output formats"):
|
|
676
691
|
cli_handle_version_or_continue(
|
|
677
|
-
["--version", "--json", "--output", "yaml"],
|
|
692
|
+
["--version", "--output", "json", "--output", "yaml"],
|
|
678
693
|
VERSION_VALUE_FLAGS,
|
|
679
694
|
"agent-cli",
|
|
680
695
|
None,
|
|
@@ -25,6 +25,7 @@ from agent_first_data import (
|
|
|
25
25
|
OutputOptions,
|
|
26
26
|
OutputFormat,
|
|
27
27
|
redacted_value,
|
|
28
|
+
redact_argv,
|
|
28
29
|
redact_url_secrets,
|
|
29
30
|
render,
|
|
30
31
|
normalize_utc_offset,
|
|
@@ -64,6 +65,23 @@ def test_redact_url_fixtures():
|
|
|
64
65
|
assert got == case["expected"], f"[redact_url/{name}] got {got!r}"
|
|
65
66
|
|
|
66
67
|
|
|
68
|
+
def test_redact_argv_fixtures():
|
|
69
|
+
for case in _load("redact_argv.json"):
|
|
70
|
+
name = case["name"]
|
|
71
|
+
options = _redaction_options(case)
|
|
72
|
+
got = redact_argv(
|
|
73
|
+
case["input"],
|
|
74
|
+
secret_names=options.secret_names,
|
|
75
|
+
policy=options.policy,
|
|
76
|
+
)
|
|
77
|
+
assert got == case["expected"], f"[redact_argv/{name}] got {got!r}"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_redact_argv_default_matches_explicit_defaults():
|
|
81
|
+
args = ["tool", "--api-key-secret=sk-live"]
|
|
82
|
+
assert redact_argv(args) == redact_argv(args, secret_names=(), policy=None)
|
|
83
|
+
|
|
84
|
+
|
|
67
85
|
def test_redaction_options_fixtures():
|
|
68
86
|
for case in _load("redaction_options.json"):
|
|
69
87
|
name = case["name"]
|
{agent_first_data-0.23.0 → agent_first_data-0.25.0}/agent_first_data/assets/protocol-v1.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
{agent_first_data-0.23.0 → agent_first_data-0.25.0}/agent_first_data.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|