custos-code 0.0.2__tar.gz → 0.0.4__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.
- {custos_code-0.0.2 → custos_code-0.0.4}/PKG-INFO +13 -1
- {custos_code-0.0.2 → custos_code-0.0.4}/README.md +12 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/pyproject.toml +1 -1
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/__init__.py +1 -1
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/cli.py +24 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/scope.py +10 -2
- {custos_code-0.0.2 → custos_code-0.0.4}/.gitignore +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/LICENSE +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/adapters/__init__.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/adapters/claude_code.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/adapters/codex.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/adapters/copilot.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/adapters/devin.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/adapters/machine.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/adapters/otel.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/adapters/state.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/arch.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/claims.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/compress.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/cost.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/demo_fixtures/__init__.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/demo_fixtures/ok_tests_0.jsonl +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/demo_fixtures/trap_echo_0.jsonl +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/demo_fixtures/trap_failing_0.jsonl +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/demo_fixtures/trap_ghost_0.jsonl +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/demo_fixtures/trap_piped_0.jsonl +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/feedback.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/hooks.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/judge.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/ledger.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/models.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/parsers.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/report.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/rerun.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/review.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/rules.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/twopass.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/verdicts.py +0 -0
- {custos_code-0.0.2 → custos_code-0.0.4}/src/custos_code/watchdog.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: custos-code
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Checks a coding agent's final report against the log of what it actually did.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -64,6 +64,18 @@ did, what it said, the receipt, and the deterministic nudge that goes back. `cus
|
|
|
64
64
|
the claims, the ledger they cite, and what the check cost, with no JavaScript in it.
|
|
65
65
|
`--format markdown` writes what the PR bot posts. Both are options on `check`, not `demo`.
|
|
66
66
|
|
|
67
|
+
## Architecture Scope
|
|
68
|
+
|
|
69
|
+
`custos-code arch` reads Mermaid flowcharts in repo docs and reports when touched files span
|
|
70
|
+
components with no declared edge:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
custos-code arch --repo . --touched "$(git diff --name-only | paste -sd, -)"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The diagram should live in a Markdown file such as `docs/ARCHITECTURE.md`, and component names
|
|
77
|
+
should roughly match folders or files, for example `Billing` -> `src/billing/`.
|
|
78
|
+
|
|
67
79
|
## Prototype
|
|
68
80
|
|
|
69
81
|
`docs/prototype/index.html` is an interactive, non-functional mock of the editor experience: marks on the agent's message, the evidence panel, editor decorations, the auto-mode loop, and the PR receipt. It is a single self-contained file:
|
|
@@ -38,6 +38,18 @@ did, what it said, the receipt, and the deterministic nudge that goes back. `cus
|
|
|
38
38
|
the claims, the ledger they cite, and what the check cost, with no JavaScript in it.
|
|
39
39
|
`--format markdown` writes what the PR bot posts. Both are options on `check`, not `demo`.
|
|
40
40
|
|
|
41
|
+
## Architecture Scope
|
|
42
|
+
|
|
43
|
+
`custos-code arch` reads Mermaid flowcharts in repo docs and reports when touched files span
|
|
44
|
+
components with no declared edge:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
custos-code arch --repo . --touched "$(git diff --name-only | paste -sd, -)"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The diagram should live in a Markdown file such as `docs/ARCHITECTURE.md`, and component names
|
|
51
|
+
should roughly match folders or files, for example `Billing` -> `src/billing/`.
|
|
52
|
+
|
|
41
53
|
## Prototype
|
|
42
54
|
|
|
43
55
|
`docs/prototype/index.html` is an interactive, non-functional mock of the editor experience: marks on the agent's message, the evidence panel, editor decorations, the auto-mode loop, and the PR receipt. It is a single self-contained file:
|
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
import pathlib
|
|
12
12
|
import re
|
|
13
13
|
from dataclasses import dataclass
|
|
14
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
14
15
|
|
|
15
16
|
import typer
|
|
16
17
|
from rich.console import Console
|
|
@@ -42,6 +43,29 @@ app = typer.Typer(
|
|
|
42
43
|
console = Console()
|
|
43
44
|
|
|
44
45
|
|
|
46
|
+
def _print_version(show: bool) -> None:
|
|
47
|
+
if not show:
|
|
48
|
+
return
|
|
49
|
+
# Read from the installed package's own metadata, not a literal here, so this can never say
|
|
50
|
+
# something other than what was actually installed -- a hardcoded string drifts the moment a
|
|
51
|
+
# release changes pyproject.toml without someone remembering this one too.
|
|
52
|
+
try:
|
|
53
|
+
console.print(f"custos-code {version('custos-code')}")
|
|
54
|
+
except PackageNotFoundError:
|
|
55
|
+
console.print("custos-code (unknown version: not installed as a package)")
|
|
56
|
+
raise typer.Exit()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@app.callback()
|
|
60
|
+
def _main(
|
|
61
|
+
version_: bool = typer.Option(
|
|
62
|
+
False, "--version", "-V", callback=_print_version, is_eager=True,
|
|
63
|
+
help="Print the installed version and exit.",
|
|
64
|
+
),
|
|
65
|
+
) -> None:
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
|
|
45
69
|
@app.command()
|
|
46
70
|
def check(
|
|
47
71
|
session: str | None = typer.Argument(
|
|
@@ -310,7 +310,7 @@ _FILE_WRITERS = frozenset({"tee", "touch", "cp", "mv", "dd", "install", "ln", "t
|
|
|
310
310
|
_PREFIX_TOKENS = frozenset({"cd", "time", "timeout", "command", "exec", "nohup", "nice", "env"})
|
|
311
311
|
_ASSIGN = re.compile(r"(?:^|[;&|]|\n)\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=([^\s;&|<>]+)")
|
|
312
312
|
_VARREF = re.compile(r"\$\{?([A-Za-z_][A-Za-z0-9_]*)\}?")
|
|
313
|
-
_CD = re.compile(r"(?:^|[;&|]|\n)\s*cd\s+(?:--\s+)?([^\s;&|<>]+)")
|
|
313
|
+
_CD = re.compile(r"""(?:^|[;&|]|\n)\s*cd\s+(?:--\s+)?(?:"([^"]*)"|'([^']*)'|([^\s;&|<>]+))""")
|
|
314
314
|
_SHELLS = frozenset({"bash", "sh", "zsh", "dash", "ksh", "eval", "xargs", "source", ".",
|
|
315
315
|
"ssh", "env", "nohup", "timeout", "watch", "script"})
|
|
316
316
|
|
|
@@ -442,10 +442,18 @@ def _effective_cwd(cmd: str, cwd: str) -> str:
|
|
|
442
442
|
Resolving against the session root invents a path that does not exist -- most of the
|
|
443
443
|
`unrecoverable-write` volume -- and in the other direction MISSES the real target when the
|
|
444
444
|
`cd` leaves the grant. An unexpandable `$VAR` aborts the walk rather than guessing.
|
|
445
|
+
|
|
446
|
+
`_CD` has three alternative groups -- double-quoted, single-quoted, bare -- because a bare
|
|
447
|
+
`[^\\s...]+` capture stops at the first space, and a path with a space in it is not a rare
|
|
448
|
+
edge case: `cd "/Users/x/Documents/HackMIT 2026/receipts" && ...` is what every compound
|
|
449
|
+
command in *this project's own checkout* looks like. Truncating the quoted target at that
|
|
450
|
+
space silently rebased every subsequent path in the command onto a directory one level up
|
|
451
|
+
that happens not to exist, which made `write-outside-cwd` fire on commands that never left
|
|
452
|
+
the grant at all.
|
|
445
453
|
"""
|
|
446
454
|
d = cwd
|
|
447
455
|
for m in _CD.finditer(_strip_heredocs(cmd)):
|
|
448
|
-
tgt = m.
|
|
456
|
+
tgt = next(g for g in m.groups() if g is not None)
|
|
449
457
|
if "$" in tgt or "`" in tgt:
|
|
450
458
|
return d
|
|
451
459
|
d = _abs(tgt, d)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|