aer1-scan 1.0.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.
- aer1_scan-1.0.0/LICENSE +21 -0
- aer1_scan-1.0.0/PKG-INFO +59 -0
- aer1_scan-1.0.0/README.md +45 -0
- aer1_scan-1.0.0/aer1_scan.egg-info/PKG-INFO +59 -0
- aer1_scan-1.0.0/aer1_scan.egg-info/SOURCES.txt +9 -0
- aer1_scan-1.0.0/aer1_scan.egg-info/dependency_links.txt +1 -0
- aer1_scan-1.0.0/aer1_scan.egg-info/entry_points.txt +2 -0
- aer1_scan-1.0.0/aer1_scan.egg-info/top_level.txt +1 -0
- aer1_scan-1.0.0/aer1_scan.py +106 -0
- aer1_scan-1.0.0/pyproject.toml +25 -0
- aer1_scan-1.0.0/setup.cfg +4 -0
aer1_scan-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Brennan Zambo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
aer1_scan-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aer1-scan
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Check every Zambo receipt link in a file, a web page, or stdin, right from your terminal. A Zambo receipt proves the saved result of an AI job was not changed after the fact.
|
|
5
|
+
Author: Brennan Zambo
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://zambo.dev/verify/
|
|
8
|
+
Project-URL: Repository, https://github.com/zambodotdev/aer1-scan
|
|
9
|
+
Keywords: aer-1,zambo,receipts,verification,ai-agents,mcp
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# aer1-scan
|
|
16
|
+
|
|
17
|
+
Check every Zambo receipt in the work you were handed, from your terminal.
|
|
18
|
+
|
|
19
|
+
Someone gives you AI work full of receipt links: a pull request, a report, a chat log. Instead of clicking each one, run one command. aer1-scan finds every Zambo receipt in a file, a web page, or piped text, checks each one live, and prints one line per receipt. It sends only the receipt ids, nothing else from the document.
|
|
20
|
+
|
|
21
|
+
A Zambo receipt proves the saved result of an AI job was not changed after the fact. It does not prove the answer was right. It proves the record you are checking is the record that was saved at the time.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
Node:
|
|
26
|
+
```
|
|
27
|
+
npx aer1-scan FILE
|
|
28
|
+
```
|
|
29
|
+
or `npm install -g aer1-scan`
|
|
30
|
+
|
|
31
|
+
Python:
|
|
32
|
+
```
|
|
33
|
+
pipx run aer1-scan FILE
|
|
34
|
+
```
|
|
35
|
+
or `pip install aer1-scan`
|
|
36
|
+
|
|
37
|
+
Same tool, same output, both published from this repo.
|
|
38
|
+
|
|
39
|
+
## Use
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
aer1-scan report.md
|
|
43
|
+
aer1-scan https://gist.github.com/zambodotdev/777872582b8dd2feefa43bf1d4fa1acf
|
|
44
|
+
cat chat-log.txt | aer1-scan
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Output, one line per receipt:
|
|
48
|
+
```
|
|
49
|
+
verified 5420f6f0-a635-4010-a7d4-311f7cd6b0ab https://zambo.dev/verify/?id=5420f6f0-a635-4010-a7d4-311f7cd6b0ab
|
|
50
|
+
not found 00000000-0000-4000-8000-000000000000 https://zambo.dev/verify/?id=00000000-0000-4000-8000-000000000000
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Exit code is 0 when every receipt verifies, 1 when any does not, so it drops straight into CI and pre-commit hooks.
|
|
54
|
+
|
|
55
|
+
Prefer clicking? The same check runs in your browser at https://zambodotdev.github.io/receipt-scan/
|
|
56
|
+
|
|
57
|
+
Want receipts on your own AI work: add Zambo in one URL, no key, at https://zambo.dev/add/?ref=aer1-scan
|
|
58
|
+
|
|
59
|
+
Founder: Brennan Zambo (https://zambo.dev/founder/). Support: https://zambo.dev/add/?ref=aer1-scan
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# aer1-scan
|
|
2
|
+
|
|
3
|
+
Check every Zambo receipt in the work you were handed, from your terminal.
|
|
4
|
+
|
|
5
|
+
Someone gives you AI work full of receipt links: a pull request, a report, a chat log. Instead of clicking each one, run one command. aer1-scan finds every Zambo receipt in a file, a web page, or piped text, checks each one live, and prints one line per receipt. It sends only the receipt ids, nothing else from the document.
|
|
6
|
+
|
|
7
|
+
A Zambo receipt proves the saved result of an AI job was not changed after the fact. It does not prove the answer was right. It proves the record you are checking is the record that was saved at the time.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Node:
|
|
12
|
+
```
|
|
13
|
+
npx aer1-scan FILE
|
|
14
|
+
```
|
|
15
|
+
or `npm install -g aer1-scan`
|
|
16
|
+
|
|
17
|
+
Python:
|
|
18
|
+
```
|
|
19
|
+
pipx run aer1-scan FILE
|
|
20
|
+
```
|
|
21
|
+
or `pip install aer1-scan`
|
|
22
|
+
|
|
23
|
+
Same tool, same output, both published from this repo.
|
|
24
|
+
|
|
25
|
+
## Use
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
aer1-scan report.md
|
|
29
|
+
aer1-scan https://gist.github.com/zambodotdev/777872582b8dd2feefa43bf1d4fa1acf
|
|
30
|
+
cat chat-log.txt | aer1-scan
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Output, one line per receipt:
|
|
34
|
+
```
|
|
35
|
+
verified 5420f6f0-a635-4010-a7d4-311f7cd6b0ab https://zambo.dev/verify/?id=5420f6f0-a635-4010-a7d4-311f7cd6b0ab
|
|
36
|
+
not found 00000000-0000-4000-8000-000000000000 https://zambo.dev/verify/?id=00000000-0000-4000-8000-000000000000
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Exit code is 0 when every receipt verifies, 1 when any does not, so it drops straight into CI and pre-commit hooks.
|
|
40
|
+
|
|
41
|
+
Prefer clicking? The same check runs in your browser at https://zambodotdev.github.io/receipt-scan/
|
|
42
|
+
|
|
43
|
+
Want receipts on your own AI work: add Zambo in one URL, no key, at https://zambo.dev/add/?ref=aer1-scan
|
|
44
|
+
|
|
45
|
+
Founder: Brennan Zambo (https://zambo.dev/founder/). Support: https://zambo.dev/add/?ref=aer1-scan
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aer1-scan
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Check every Zambo receipt link in a file, a web page, or stdin, right from your terminal. A Zambo receipt proves the saved result of an AI job was not changed after the fact.
|
|
5
|
+
Author: Brennan Zambo
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://zambo.dev/verify/
|
|
8
|
+
Project-URL: Repository, https://github.com/zambodotdev/aer1-scan
|
|
9
|
+
Keywords: aer-1,zambo,receipts,verification,ai-agents,mcp
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# aer1-scan
|
|
16
|
+
|
|
17
|
+
Check every Zambo receipt in the work you were handed, from your terminal.
|
|
18
|
+
|
|
19
|
+
Someone gives you AI work full of receipt links: a pull request, a report, a chat log. Instead of clicking each one, run one command. aer1-scan finds every Zambo receipt in a file, a web page, or piped text, checks each one live, and prints one line per receipt. It sends only the receipt ids, nothing else from the document.
|
|
20
|
+
|
|
21
|
+
A Zambo receipt proves the saved result of an AI job was not changed after the fact. It does not prove the answer was right. It proves the record you are checking is the record that was saved at the time.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
Node:
|
|
26
|
+
```
|
|
27
|
+
npx aer1-scan FILE
|
|
28
|
+
```
|
|
29
|
+
or `npm install -g aer1-scan`
|
|
30
|
+
|
|
31
|
+
Python:
|
|
32
|
+
```
|
|
33
|
+
pipx run aer1-scan FILE
|
|
34
|
+
```
|
|
35
|
+
or `pip install aer1-scan`
|
|
36
|
+
|
|
37
|
+
Same tool, same output, both published from this repo.
|
|
38
|
+
|
|
39
|
+
## Use
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
aer1-scan report.md
|
|
43
|
+
aer1-scan https://gist.github.com/zambodotdev/777872582b8dd2feefa43bf1d4fa1acf
|
|
44
|
+
cat chat-log.txt | aer1-scan
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Output, one line per receipt:
|
|
48
|
+
```
|
|
49
|
+
verified 5420f6f0-a635-4010-a7d4-311f7cd6b0ab https://zambo.dev/verify/?id=5420f6f0-a635-4010-a7d4-311f7cd6b0ab
|
|
50
|
+
not found 00000000-0000-4000-8000-000000000000 https://zambo.dev/verify/?id=00000000-0000-4000-8000-000000000000
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Exit code is 0 when every receipt verifies, 1 when any does not, so it drops straight into CI and pre-commit hooks.
|
|
54
|
+
|
|
55
|
+
Prefer clicking? The same check runs in your browser at https://zambodotdev.github.io/receipt-scan/
|
|
56
|
+
|
|
57
|
+
Want receipts on your own AI work: add Zambo in one URL, no key, at https://zambo.dev/add/?ref=aer1-scan
|
|
58
|
+
|
|
59
|
+
Founder: Brennan Zambo (https://zambo.dev/founder/). Support: https://zambo.dev/add/?ref=aer1-scan
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
aer1_scan
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""aer1-scan: check every zambo receipt in a file, a web page, or stdin.
|
|
3
|
+
|
|
4
|
+
A zambo receipt proves the saved result of an AI job was not changed
|
|
5
|
+
after the fact. This tool sends only the receipt ids, nothing else.
|
|
6
|
+
Pure standard library, no dependencies.
|
|
7
|
+
"""
|
|
8
|
+
import json
|
|
9
|
+
import re
|
|
10
|
+
import sys
|
|
11
|
+
import urllib.error
|
|
12
|
+
import urllib.request
|
|
13
|
+
|
|
14
|
+
UUID = r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
|
|
15
|
+
LINK_RE = re.compile(r"zambo\.dev/[^\s\"'<>\])]*?(" + UUID + r")", re.IGNORECASE)
|
|
16
|
+
BARE_RE = re.compile(r"^\s*(" + UUID + r")\s*$", re.MULTILINE)
|
|
17
|
+
MAX = 50
|
|
18
|
+
TIMEOUT = 20
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def raw_url(u):
|
|
22
|
+
try:
|
|
23
|
+
from urllib.parse import urlparse
|
|
24
|
+
p = urlparse(u)
|
|
25
|
+
if p.hostname == "gist.github.com":
|
|
26
|
+
return u.rstrip("/") + "/raw"
|
|
27
|
+
if p.hostname == "github.com" and "/blob/" in p.path:
|
|
28
|
+
return u.replace("github.com", "raw.githubusercontent.com").replace("/blob/", "/")
|
|
29
|
+
except Exception:
|
|
30
|
+
pass
|
|
31
|
+
return u
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def extract(text):
|
|
35
|
+
seen = set()
|
|
36
|
+
ids = []
|
|
37
|
+
|
|
38
|
+
def add(rid):
|
|
39
|
+
rid = rid.lower()
|
|
40
|
+
if rid not in seen:
|
|
41
|
+
seen.add(rid)
|
|
42
|
+
ids.append(rid)
|
|
43
|
+
|
|
44
|
+
# A pasted receipt JSON export: its own top-level id is a receipt id.
|
|
45
|
+
if "receipt_schema_version" in text:
|
|
46
|
+
jm = re.search(r'"id"\s*:\s*"(' + UUID + r')"', text, re.IGNORECASE)
|
|
47
|
+
if jm:
|
|
48
|
+
add(jm.group(1))
|
|
49
|
+
for m in LINK_RE.finditer(text):
|
|
50
|
+
if m.group(0).lower().startswith("zambo.dev/workflow/"):
|
|
51
|
+
continue # workflow ids are not receipt ids
|
|
52
|
+
add(m.group(1))
|
|
53
|
+
for m in BARE_RE.finditer(text):
|
|
54
|
+
add(m.group(1))
|
|
55
|
+
return ids[:MAX]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def read_input(arg):
|
|
59
|
+
if not arg or arg == "-":
|
|
60
|
+
return sys.stdin.read()
|
|
61
|
+
if arg.lower().startswith(("http://", "https://")):
|
|
62
|
+
req = urllib.request.Request(raw_url(arg), headers={"User-Agent": "aer1-scan"})
|
|
63
|
+
with urllib.request.urlopen(req, timeout=TIMEOUT) as res:
|
|
64
|
+
return res.read().decode("utf-8", "replace")
|
|
65
|
+
with open(arg, "r", encoding="utf-8", errors="replace") as f:
|
|
66
|
+
return f.read()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def verify(rid):
|
|
70
|
+
req = urllib.request.Request(
|
|
71
|
+
"https://zambo.dev/api/v2/receipt/" + rid + "/verify",
|
|
72
|
+
headers={"User-Agent": "aer1-scan"})
|
|
73
|
+
try:
|
|
74
|
+
with urllib.request.urlopen(req, timeout=TIMEOUT) as res:
|
|
75
|
+
data = json.loads(res.read().decode("utf-8", "replace"))
|
|
76
|
+
except urllib.error.HTTPError as e:
|
|
77
|
+
return "not found" if e.code == 404 else "could not verify"
|
|
78
|
+
except Exception:
|
|
79
|
+
return "could not verify"
|
|
80
|
+
status = data.get("verification_status")
|
|
81
|
+
return "verified" if status == "verified" else str(status or "could not verify")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def main():
|
|
85
|
+
arg = sys.argv[1] if len(sys.argv) > 1 else None
|
|
86
|
+
try:
|
|
87
|
+
text = read_input(arg)
|
|
88
|
+
except Exception as e:
|
|
89
|
+
print("aer1-scan: " + str(e), file=sys.stderr)
|
|
90
|
+
return 1
|
|
91
|
+
ids = extract(text)
|
|
92
|
+
if not ids:
|
|
93
|
+
print("no zambo receipt links found. receipts look like zambo.dev/run/ followed by an id.",
|
|
94
|
+
file=sys.stderr)
|
|
95
|
+
return 1
|
|
96
|
+
failed = False
|
|
97
|
+
for rid in ids:
|
|
98
|
+
state = verify(rid)
|
|
99
|
+
if state != "verified":
|
|
100
|
+
failed = True
|
|
101
|
+
print(state + " " + rid + " https://zambo.dev/verify/?id=" + rid)
|
|
102
|
+
return 1 if failed else 0
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
if __name__ == "__main__":
|
|
106
|
+
sys.exit(main())
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "aer1-scan"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Check every Zambo receipt link in a file, a web page, or stdin, right from your terminal. A Zambo receipt proves the saved result of an AI job was not changed after the fact."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Brennan Zambo" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["aer-1", "zambo", "receipts", "verification", "ai-agents", "mcp"]
|
|
16
|
+
|
|
17
|
+
[project.urls]
|
|
18
|
+
Homepage = "https://zambo.dev/verify/"
|
|
19
|
+
Repository = "https://github.com/zambodotdev/aer1-scan"
|
|
20
|
+
|
|
21
|
+
[project.scripts]
|
|
22
|
+
aer1-scan = "aer1_scan:main"
|
|
23
|
+
|
|
24
|
+
[tool.setuptools]
|
|
25
|
+
py-modules = ["aer1_scan"]
|