actradeck 0.5.2 → 0.7.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 +50 -12
- package/dist/THIRD-PARTY-NOTICES.txt +41 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +17 -1
- package/dist/commands/conformance.d.ts +8 -0
- package/dist/commands/conformance.js +57 -0
- package/dist/commands/demo.d.ts +2 -0
- package/dist/commands/demo.js +28 -0
- package/dist/lib/conformance-core.js +65 -0
- package/dist/lib/conformance-types.d.ts +19 -0
- package/dist/lib/conformance-types.js +1 -0
- package/dist/lib/deps.js +8 -1
- package/dist/lib/types.d.ts +3 -0
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# actradeck
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
> Put risky Claude Code and Codex actions back in front of a human.
|
|
4
|
+
|
|
5
|
+
ActraDeck is a local approval and audit cockpit for coding agents. This package gives you
|
|
6
|
+
a zero-side-effect product preview, diagnoses the machine, and verifies the full product
|
|
7
|
+
before handing off to its quickstart.
|
|
6
8
|
|
|
7
9
|
This package is a **thin, dependency-free bootstrapper**. It does not contain the product —
|
|
8
10
|
the full four-tier stack ships as a **signed GitHub Release** and a **signed GHCR image**.
|
|
@@ -14,19 +16,28 @@ The CLI helps you _get to_ a running cockpit and verify what you download.
|
|
|
14
16
|
- **Fail-closed verification.** `install` checks the release's sha256 checksum _and_ its
|
|
15
17
|
SLSA build provenance before extracting a single file.
|
|
16
18
|
|
|
19
|
+
## See the safety story first
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npx actradeck@latest demo
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`demo` prints a five-second **synthetic preview** of detect → hold → deny → redact →
|
|
26
|
+
record. It executes no command, writes no file, starts no subprocess, and makes no network
|
|
27
|
+
request. The output then points to the cockpit's 30-second demo, which exercises the real
|
|
28
|
+
ingestion, redaction, projection, and audit pipeline.
|
|
29
|
+
|
|
17
30
|
## Usage
|
|
18
31
|
|
|
19
32
|
```sh
|
|
33
|
+
npx actradeck@latest demo # safe synthetic preview; no side effects or network
|
|
20
34
|
npx actradeck@latest doctor # diagnose: platform / Node / pnpm / git / Docker (offline-safe)
|
|
21
35
|
npx actradeck@latest install # verify + fetch the latest signed release, then quickstart
|
|
22
36
|
npx actradeck@latest up # print the Docker cockpit command (prints only; runs nothing)
|
|
23
37
|
npx actradeck@latest version # your CLI version + whether a newer stable release exists
|
|
38
|
+
npx actradeck@latest conformance < events.jsonl # check an adapter's stream vs the contract
|
|
24
39
|
```
|
|
25
40
|
|
|
26
|
-
> **Not published yet.** The first npm publish is planned for **v0.5** (see the project's ADR
|
|
27
|
-
> 0013). Until then the commands above describe the intended flow; the canonical, already-signed
|
|
28
|
-
> way to get ActraDeck is the GitHub Release / GHCR image or `scripts/install.sh` from the repo.
|
|
29
|
-
|
|
30
41
|
### `install`
|
|
31
42
|
|
|
32
43
|
Resolves the latest stable GitHub Release (or `--version vX.Y.Z`), downloads the source
|
|
@@ -35,7 +46,7 @@ provenance (`gh attestation verify`), then extracts and hands off to the repo's
|
|
|
35
46
|
`scripts/quickstart`.
|
|
36
47
|
|
|
37
48
|
```sh
|
|
38
|
-
npx actradeck@latest install --version v0.
|
|
49
|
+
npx actradeck@latest install --version v0.7.0 # a specific tag
|
|
39
50
|
npx actradeck@latest install --dry-run # resolve + verify only; change nothing
|
|
40
51
|
npx actradeck@latest install --skip-provenance # explicit opt-out (checksum still enforced)
|
|
41
52
|
```
|
|
@@ -45,12 +56,39 @@ and provenance is verified unless you pass `--skip-provenance` (which requires y
|
|
|
45
56
|
the reduced guarantee). `--skip-provenance` exists only for machines that cannot install the
|
|
46
57
|
GitHub CLI.
|
|
47
58
|
|
|
59
|
+
### `conformance`
|
|
60
|
+
|
|
61
|
+
Validate that a third-party ingestion adapter's event stream satisfies the ActraDeck ingestion
|
|
62
|
+
contract — **without cloning the monorepo**. Capture your adapter's emitted NormalizedEvents as
|
|
63
|
+
**JSONL** (one JSON object per line, in emission order) and pipe them in:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
npx actradeck@latest conformance < events.jsonl # read JSONL from stdin
|
|
67
|
+
npx actradeck@latest conformance events.jsonl # or from a file
|
|
68
|
+
npx actradeck@latest conformance events.jsonl --json # machine-readable JSON report
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
It checks the stream-level and cross-field invariants a single-event schema parse cannot see:
|
|
72
|
+
every event parses as a NormalizedEvent; `payload.kind === event_type`; per-session `timestamp` is
|
|
73
|
+
non-decreasing; and per-session `seq`, when present, is a dense 0-based counter (so the backend can
|
|
74
|
+
detect silent mid-stream drops — a session that emits no `seq` is a **warning**, not an error). A
|
|
75
|
+
repeated `event_id` or `seq` is a **warning**, not an error — an at-least-once retry is legitimate
|
|
76
|
+
and the backend dedupes it (§3.3 / §4.4). Redaction is **not** checked: the backend ingress
|
|
77
|
+
redaction floor is the sole redaction point, so an adapter cannot and need not prove it.
|
|
78
|
+
|
|
79
|
+
**Exit codes:** `0` = conformant (warnings allowed) · `1` = one or more errors · `2` = usage /
|
|
80
|
+
input error. The checker core is ActraDeck's canonical `checkConformance`, bundled into this CLI at
|
|
81
|
+
build time — the published package still has **zero runtime dependencies**. It is the same check as
|
|
82
|
+
the in-repo `scripts/check-conformance.mjs` (see `docs/ingestion-contract.md` §8); for piped output
|
|
83
|
+
it is byte-identical (an interactive TTY differs only in ANSI color). The input is read fully into
|
|
84
|
+
memory, which suits adapter sample streams rather than an unbounded live feed.
|
|
85
|
+
|
|
48
86
|
## Environment
|
|
49
87
|
|
|
50
|
-
| Variable | Default
|
|
51
|
-
| ----------------------- |
|
|
52
|
-
| `ACTRADECK_REPO` | `actradeck/actradeck
|
|
53
|
-
| `ACTRADECK_INSTALL_DIR` | `~/actradeck`
|
|
88
|
+
| Variable | Default | Meaning |
|
|
89
|
+
| ----------------------- | --------------------- | -------------------------------------------------- |
|
|
90
|
+
| `ACTRADECK_REPO` | `actradeck/actradeck` | `owner/name` (or git URL) to resolve releases from |
|
|
91
|
+
| `ACTRADECK_INSTALL_DIR` | `~/actradeck` | where `install` extracts the verified source |
|
|
54
92
|
|
|
55
93
|
## License
|
|
56
94
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
ActraDeck CLI — third-party notices for code bundled into dist/lib/conformance-core.js.
|
|
2
|
+
The `conformance` command inlines the checker's dependency closure at build time; the
|
|
3
|
+
licenses of those bundled packages follow.
|
|
4
|
+
|
|
5
|
+
==============================================================================
|
|
6
|
+
uuid@11.1.1 (MIT)
|
|
7
|
+
==============================================================================
|
|
8
|
+
The MIT License (MIT)
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2010-2020 Robert Kieffer and other contributors
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
17
|
+
|
|
18
|
+
==============================================================================
|
|
19
|
+
zod@4.4.3 (MIT)
|
|
20
|
+
==============================================================================
|
|
21
|
+
MIT License
|
|
22
|
+
|
|
23
|
+
Copyright (c) 2025 Colin McDonnell
|
|
24
|
+
|
|
25
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
26
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
27
|
+
in the Software without restriction, including without limitation the rights
|
|
28
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
29
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
30
|
+
furnished to do so, subject to the following conditions:
|
|
31
|
+
|
|
32
|
+
The above copyright notice and this permission notice shall be included in all
|
|
33
|
+
copies or substantial portions of the Software.
|
|
34
|
+
|
|
35
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
36
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
37
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
38
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
39
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
40
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
41
|
+
SOFTWARE.
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Deps } from "./lib/types.js";
|
|
2
2
|
import { type InstallOpts } from "./commands/install.js";
|
|
3
|
+
import { type ConformanceOpts } from "./commands/conformance.js";
|
|
3
4
|
export declare function parseInstallOpts(args: string[]): InstallOpts;
|
|
5
|
+
export declare function parseConformanceOpts(args: string[]): ConformanceOpts;
|
|
4
6
|
export declare function run(deps: Deps, argv: string[]): Promise<number>;
|
package/dist/cli.js
CHANGED
|
@@ -2,12 +2,15 @@ import { cmdDoctor } from "./commands/doctor.js";
|
|
|
2
2
|
import { cmdUp } from "./commands/up.js";
|
|
3
3
|
import { cmdVersion } from "./commands/version.js";
|
|
4
4
|
import { cmdInstall } from "./commands/install.js";
|
|
5
|
-
|
|
5
|
+
import { cmdConformance } from "./commands/conformance.js";
|
|
6
|
+
import { cmdDemo } from "./commands/demo.js";
|
|
7
|
+
const USAGE = `actradeck — put risky coding-agent actions back in front of a human
|
|
6
8
|
|
|
7
9
|
Usage:
|
|
8
10
|
actradeck <command> [options]
|
|
9
11
|
|
|
10
12
|
Commands:
|
|
13
|
+
demo Show a 5-second safety preview. No install, files, subprocesses, or network.
|
|
11
14
|
doctor Diagnose this machine (platform / Node / pnpm / git / Docker). Offline-safe.
|
|
12
15
|
install Fetch + VERIFY a signed release (checksum + provenance), then hand off to quickstart.
|
|
13
16
|
--version vX.Y.Z install a specific release tag (default: latest stable)
|
|
@@ -15,6 +18,10 @@ Commands:
|
|
|
15
18
|
--skip-provenance checksum-only (explicit opt-out; not recommended)
|
|
16
19
|
up Print the Docker cockpit bring-up command (prints only — does not run it).
|
|
17
20
|
version Print this CLI's version and whether a newer stable release is available.
|
|
21
|
+
conformance Validate an adapter's JSONL event stream against the ingestion contract.
|
|
22
|
+
[file] read JSONL from a file (default: stdin)
|
|
23
|
+
--json emit a machine-readable JSON report instead of the summary
|
|
24
|
+
Exit: 0 = conformant · 1 = one or more errors · 2 = usage/setup error.
|
|
18
25
|
|
|
19
26
|
Global:
|
|
20
27
|
-h, --help show this help
|
|
@@ -53,6 +60,11 @@ export function parseInstallOpts(args) {
|
|
|
53
60
|
}
|
|
54
61
|
return { version, dryRun, skipProvenance };
|
|
55
62
|
}
|
|
63
|
+
export function parseConformanceOpts(args) {
|
|
64
|
+
const json = args.includes("--json");
|
|
65
|
+
const file = args.find((a) => !a.startsWith("--"));
|
|
66
|
+
return file !== undefined ? { file, json } : { json };
|
|
67
|
+
}
|
|
56
68
|
export async function run(deps, argv) {
|
|
57
69
|
const cmd = argv[0];
|
|
58
70
|
const rest = argv.slice(1);
|
|
@@ -70,12 +82,16 @@ export async function run(deps, argv) {
|
|
|
70
82
|
return 0;
|
|
71
83
|
case "doctor":
|
|
72
84
|
return await cmdDoctor(deps);
|
|
85
|
+
case "demo":
|
|
86
|
+
return await cmdDemo(deps);
|
|
73
87
|
case "up":
|
|
74
88
|
return await cmdUp(deps);
|
|
75
89
|
case "version":
|
|
76
90
|
return await cmdVersion(deps);
|
|
77
91
|
case "install":
|
|
78
92
|
return await cmdInstall(deps, parseInstallOpts(rest));
|
|
93
|
+
case "conformance":
|
|
94
|
+
return await cmdConformance(deps, parseConformanceOpts(rest));
|
|
79
95
|
default:
|
|
80
96
|
deps.io.err(`Unknown command: ${cmd}`);
|
|
81
97
|
deps.io.out(USAGE);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Deps } from "../lib/types.js";
|
|
2
|
+
import type { ConformanceReport } from "../lib/conformance-types.js";
|
|
3
|
+
export interface ConformanceOpts {
|
|
4
|
+
file?: string;
|
|
5
|
+
json: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function cmdConformance(deps: Deps, opts: ConformanceOpts): Promise<number>;
|
|
8
|
+
export declare function renderHuman(report: ConformanceReport, malformed: Map<number, string>): string[];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export async function cmdConformance(deps, opts) {
|
|
2
|
+
let raw;
|
|
3
|
+
try {
|
|
4
|
+
raw = await deps.readInput(opts.file);
|
|
5
|
+
}
|
|
6
|
+
catch (err) {
|
|
7
|
+
const code = err.code ?? (err instanceof Error ? err.message : String(err));
|
|
8
|
+
deps.io.err(`conformance: could not read input (${code})`);
|
|
9
|
+
return 2;
|
|
10
|
+
}
|
|
11
|
+
const events = [];
|
|
12
|
+
const malformed = new Map();
|
|
13
|
+
for (const line of raw.split("\n")) {
|
|
14
|
+
const trimmed = line.trim();
|
|
15
|
+
if (trimmed.length === 0)
|
|
16
|
+
continue;
|
|
17
|
+
const index = events.length;
|
|
18
|
+
try {
|
|
19
|
+
events.push(JSON.parse(trimmed));
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
malformed.set(index, err instanceof Error ? err.message : String(err));
|
|
23
|
+
events.push({});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const report = await deps.checkConformance(events);
|
|
27
|
+
if (opts.json) {
|
|
28
|
+
deps.io.out(JSON.stringify(report, null, 2));
|
|
29
|
+
return report.ok ? 0 : 1;
|
|
30
|
+
}
|
|
31
|
+
for (const line of renderHuman(report, malformed))
|
|
32
|
+
deps.io.out(line);
|
|
33
|
+
return report.ok ? 0 : 1;
|
|
34
|
+
}
|
|
35
|
+
export function renderHuman(report, malformed) {
|
|
36
|
+
const lines = [];
|
|
37
|
+
lines.push(`conformance: ${report.total} events · ${report.schemaValid} schema-valid · ${report.sessions} session(s)`);
|
|
38
|
+
for (const f of report.findings)
|
|
39
|
+
lines.push(findingLine(f, malformed));
|
|
40
|
+
if (report.ok) {
|
|
41
|
+
const suffix = report.warnings > 0 ? ` (${report.warnings} warning(s))` : "";
|
|
42
|
+
lines.push(`PASS — the stream conforms to the ingestion contract${suffix}`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
lines.push(`FAIL — ${report.errors} error(s), ${report.warnings} warning(s)`);
|
|
46
|
+
}
|
|
47
|
+
return lines;
|
|
48
|
+
}
|
|
49
|
+
function findingLine(f, malformed) {
|
|
50
|
+
const where = f.index >= 0 ? `event ${f.index}` : "stream";
|
|
51
|
+
const sess = f.sessionId ? ` [session ${f.sessionId}]` : "";
|
|
52
|
+
const message = f.rule === "schema" && malformed.has(f.index)
|
|
53
|
+
? `not valid JSON: ${malformed.get(f.index)}`
|
|
54
|
+
: f.message;
|
|
55
|
+
const tag = f.severity === "error" ? "ERROR" : "WARN";
|
|
56
|
+
return ` ${tag} ${where}${sess} (${f.rule}): ${message}`;
|
|
57
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export async function cmdDemo(deps) {
|
|
2
|
+
deps.io.out(`ActraDeck safety preview
|
|
3
|
+
|
|
4
|
+
SAFE SIMULATION — no command is executed, no file is changed, and no network call is made.
|
|
5
|
+
|
|
6
|
+
Claude Code requests:
|
|
7
|
+
rm -rf ./important-directory
|
|
8
|
+
|
|
9
|
+
[HIGH RISK] recursive filesystem delete detected
|
|
10
|
+
[HELD] waiting for a human decision
|
|
11
|
+
[DENIED] no approval received; safe-side timeout
|
|
12
|
+
|
|
13
|
+
Agent output contains:
|
|
14
|
+
GITHUB_TOKEN=[REDACTED:github-token]
|
|
15
|
+
|
|
16
|
+
[RECORDED] decision + redacted event added to the replayable audit trail
|
|
17
|
+
|
|
18
|
+
That is ActraDeck's first job: put risky coding-agent actions back in front of you.
|
|
19
|
+
|
|
20
|
+
Try the real ingestion -> approval -> redaction -> audit pipeline:
|
|
21
|
+
docker run --rm -p 127.0.0.1:55400:55400 -v actradeck_pgdata:/data \\
|
|
22
|
+
ghcr.io/actradeck/actradeck:latest
|
|
23
|
+
then open http://localhost:55400 and click "Run the 30-second safety demo".
|
|
24
|
+
|
|
25
|
+
Detection is best-effort, not a sandbox. Read the documented limits:
|
|
26
|
+
https://github.com/actradeck/actradeck/blob/main/SECURITY.md`);
|
|
27
|
+
return 0;
|
|
28
|
+
}
|