stacktrace-cli 0.2.2__py3-none-any.whl → 0.2.3__py3-none-any.whl
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.
- stacktrace_cli/__init__.py +1 -1
- stacktrace_cli/cli.py +25 -17
- stacktrace_cli/correlate/acquire.py +154 -2
- stacktrace_cli/detector/render.py +9 -12
- stacktrace_cli/monitor/site/index.html +1 -5
- stacktrace_cli/monitor/site/styles.css +0 -5
- stacktrace_cli/remote/cli.py +3 -4
- stacktrace_cli/remote/sync_detect.py +7 -1
- {stacktrace_cli-0.2.2.dist-info → stacktrace_cli-0.2.3.dist-info}/METADATA +5 -4
- {stacktrace_cli-0.2.2.dist-info → stacktrace_cli-0.2.3.dist-info}/RECORD +12 -12
- {stacktrace_cli-0.2.2.dist-info → stacktrace_cli-0.2.3.dist-info}/WHEEL +0 -0
- {stacktrace_cli-0.2.2.dist-info → stacktrace_cli-0.2.3.dist-info}/entry_points.txt +0 -0
stacktrace_cli/__init__.py
CHANGED
stacktrace_cli/cli.py
CHANGED
|
@@ -224,15 +224,17 @@ def sessions(
|
|
|
224
224
|
)
|
|
225
225
|
@click.option(
|
|
226
226
|
"--escalate/--no-escalate",
|
|
227
|
-
default=
|
|
227
|
+
default=False,
|
|
228
228
|
show_default=True,
|
|
229
|
-
help="Send flagged sessions to the agent's own CLI for semantic analysis.
|
|
230
|
-
"by default
|
|
231
|
-
"
|
|
232
|
-
"
|
|
233
|
-
"day
|
|
234
|
-
"either way and matches advisories by
|
|
235
|
-
"the components a session invoked to
|
|
229
|
+
help="Send flagged sessions to the agent's own CLI for semantic analysis. Off "
|
|
230
|
+
"by default: it is the only stage that sends anything session-derived off "
|
|
231
|
+
"this machine, and it spends the developer's own provider quota, so a run "
|
|
232
|
+
"that does neither is the one to reach for first. --escalate turns it on "
|
|
233
|
+
"and --budget caps a noisy day. Leaving it off does not make the run "
|
|
234
|
+
"offline: correlation runs first either way and matches advisories by "
|
|
235
|
+
"sending the package coordinates of the components a session invoked to "
|
|
236
|
+
"osv.dev. Sessions that qualified are still counted, and named in "
|
|
237
|
+
"--format json, so the run says what it did not do.",
|
|
236
238
|
)
|
|
237
239
|
@click.option(
|
|
238
240
|
"--budget",
|
|
@@ -295,18 +297,20 @@ def detect(
|
|
|
295
297
|
families carry their own severity ladders, because a stalled loop and a
|
|
296
298
|
leaked credential cannot share one (ADR-0010).
|
|
297
299
|
|
|
298
|
-
Two stages need no model or credential
|
|
299
|
-
the agent's own CLI:
|
|
300
|
-
--
|
|
300
|
+
Two stages need no model or credential, and they are the two that run by
|
|
301
|
+
default. The third sends flagged sessions to the agent's own CLI:
|
|
302
|
+
--escalate turns it on, capped by --budget. Sessions that qualified for it
|
|
303
|
+
are counted either way, and named in --format json, so a run without it
|
|
304
|
+
says so rather than reading as a clean one.
|
|
301
305
|
|
|
302
306
|
That third stage is the one that sends session content off this machine:
|
|
303
307
|
the agent's own CLI hands the prompts, arguments and results a rule needs
|
|
304
308
|
to the provider it is already authenticated against (ADR-0004 -- provider
|
|
305
309
|
affinity, so a transcript goes back to the vendor that produced it, and
|
|
306
|
-
there is no fallback to any other). --
|
|
307
|
-
that send nothing.
|
|
310
|
+
there is no fallback to any other). Without --escalate the run is the two
|
|
311
|
+
stages that send nothing.
|
|
308
312
|
|
|
309
|
-
One network call happens before any of them
|
|
313
|
+
One network call happens before any of them, with or without --escalate:
|
|
310
314
|
correlation matches advisories by sending the package coordinates of the
|
|
311
315
|
components a session invoked to osv.dev. Coordinates only -- never a
|
|
312
316
|
prompt, an argument or a result.
|
|
@@ -324,9 +328,13 @@ def detect(
|
|
|
324
328
|
escalate=escalate,
|
|
325
329
|
budget=budget,
|
|
326
330
|
sample_budget=sample_budget,
|
|
327
|
-
#
|
|
328
|
-
#
|
|
329
|
-
|
|
331
|
+
# Not gated on `escalate`. A verdict already paid for is an
|
|
332
|
+
# answer this run has, and `escalate` governs whether new ones may
|
|
333
|
+
# be commissioned, not whether old ones may be read -- the rule
|
|
334
|
+
# `run_detector` states at its cache pass. Gating it here made a
|
|
335
|
+
# session read as graded or ungraded depending on a flag that
|
|
336
|
+
# spent nothing either way.
|
|
337
|
+
cache=VerdictCache(default_directory()) if cache else None,
|
|
330
338
|
)
|
|
331
339
|
except ValueError as error:
|
|
332
340
|
raise click.ClickException(str(error)) from error
|
|
@@ -16,13 +16,23 @@ answer naming a component that was never involved.
|
|
|
16
16
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
|
+
import base64
|
|
20
|
+
import hashlib
|
|
19
21
|
import json
|
|
22
|
+
import os
|
|
20
23
|
import subprocess
|
|
24
|
+
import sys
|
|
21
25
|
import tempfile
|
|
22
26
|
from collections.abc import Callable, Sequence
|
|
23
27
|
from collections.abc import Set as AbstractSet
|
|
24
28
|
from dataclasses import dataclass
|
|
25
29
|
from datetime import UTC, datetime
|
|
30
|
+
from importlib.metadata import (
|
|
31
|
+
Distribution,
|
|
32
|
+
PackageNotFoundError,
|
|
33
|
+
PackagePath,
|
|
34
|
+
distribution,
|
|
35
|
+
)
|
|
26
36
|
from pathlib import Path
|
|
27
37
|
from typing import Any
|
|
28
38
|
|
|
@@ -36,6 +46,140 @@ from stacktrace_cli.correlate.composition import (
|
|
|
36
46
|
|
|
37
47
|
_AGENT_KIND_PROPERTY = "openaca:agent_kind"
|
|
38
48
|
|
|
49
|
+
#: The name OpenACA publishes its console script under. `.exe` on Windows
|
|
50
|
+
#: because that is the launcher installers write there, and this package claims
|
|
51
|
+
#: `Operating System :: OS Independent`.
|
|
52
|
+
_SCRIPT = "openaca.exe" if os.name == "nt" else "openaca"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _openaca() -> str:
|
|
56
|
+
"""The OpenACA console script this package pins, addressed by path.
|
|
57
|
+
|
|
58
|
+
The bare string `"openaca"` is a `PATH` lookup, and `PATH` is not where the
|
|
59
|
+
pinned copy lives: `uv tool install stacktrace-cli` links only the
|
|
60
|
+
`stacktrace` entry point out of the tool environment, so the OpenACA that
|
|
61
|
+
`[project.dependencies]` resolved sits in `bin/` reachable but unnamed. A
|
|
62
|
+
bare name therefore selects whichever global, `pipx` or `--user` copy the
|
|
63
|
+
machine carries — a stale one silently does the work and its version need
|
|
64
|
+
not be the one this package depends on — or, on a machine with none,
|
|
65
|
+
nothing at all. This is the rule `docs/specs/cli-composition.md` states for
|
|
66
|
+
the mounted commands, applied to the one path that reaches OpenACA as a
|
|
67
|
+
subprocess.
|
|
68
|
+
|
|
69
|
+
**The path is the one the pinned distribution's own install recorded, not a
|
|
70
|
+
guess from this interpreter's location.** Python defines separate prefix,
|
|
71
|
+
virtual-environment, user and home installation schemes, and only the first
|
|
72
|
+
two put console scripts beside the interpreter: `pip install --user
|
|
73
|
+
stacktrace-cli` puts them under `site.USER_BASE` while `sys.executable`
|
|
74
|
+
stays the base interpreter. Deriving the path from `sys.executable` alone
|
|
75
|
+
therefore names a file that does not exist under a supported install, and
|
|
76
|
+
`detect` dies at process launch before it can build anything.
|
|
77
|
+
`importlib.metadata` answers instead: it resolves the OpenACA on *this*
|
|
78
|
+
interpreter's `sys.path` — the pinned one, by construction — and that
|
|
79
|
+
install's `RECORD` names the script file it wrote, wherever its scheme put
|
|
80
|
+
it.
|
|
81
|
+
|
|
82
|
+
**The only thing run is a file that install recorded writing, still holding
|
|
83
|
+
the contents it recorded.** Nothing is run for being named `openaca` in a
|
|
84
|
+
directory the distribution merely shares: an installation scheme pairs a
|
|
85
|
+
library directory with a scripts directory, but that scripts directory holds
|
|
86
|
+
the launchers of *every* distribution installed into the scheme and records
|
|
87
|
+
nothing about which one wrote any of them, so co-location establishes where
|
|
88
|
+
installers put scripts in general and never that this distribution put this
|
|
89
|
+
one there. Nor does a recorded path settle it on its own, because a record
|
|
90
|
+
describes what an install wrote rather than reserving where it wrote it: the
|
|
91
|
+
scripts directory stays shared afterwards, so a later install of another
|
|
92
|
+
distribution can overwrite that very file while the record still names it.
|
|
93
|
+
A stale, global, independently managed or overwritten launcher of that name
|
|
94
|
+
reintroduces exactly the version skew this addressing exists to remove, and
|
|
95
|
+
it does so invisibly — a wrong-version OpenACA can return a structurally
|
|
96
|
+
valid BOM. Where ownership cannot be established the answer is a
|
|
97
|
+
`RuntimeError` naming why, which `_build` renders as a legible CLI error.
|
|
98
|
+
|
|
99
|
+
Still the published console script, so the ADR-0007 seam is unchanged: this
|
|
100
|
+
module imports no OpenACA internals and `tests/test_seam_boundary.py` holds
|
|
101
|
+
that line.
|
|
102
|
+
"""
|
|
103
|
+
try:
|
|
104
|
+
installed = distribution("openaca")
|
|
105
|
+
except PackageNotFoundError as error:
|
|
106
|
+
raise RuntimeError(
|
|
107
|
+
"the OpenACA this package pins is not installed on "
|
|
108
|
+
f"{sys.executable}'s import path, so no {_SCRIPT!r} on this machine "
|
|
109
|
+
"can be known to be it; reinstalling stacktrace-cli restores it"
|
|
110
|
+
) from error
|
|
111
|
+
recorded = _recorded_script(installed)
|
|
112
|
+
if recorded is not None:
|
|
113
|
+
return str(recorded)
|
|
114
|
+
raise RuntimeError(
|
|
115
|
+
f"the pinned OpenACA installed at {installed.locate_file('')} records no "
|
|
116
|
+
f"{_SCRIPT!r} console script of its own that still holds the contents it "
|
|
117
|
+
"recorded; a copy found by name alone — by sharing a directory with that "
|
|
118
|
+
"install, or by having replaced a file it wrote — need not be the version "
|
|
119
|
+
"this package depends on, so none is run; reinstalling stacktrace-cli "
|
|
120
|
+
"restores it"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _recorded_script(installed: Distribution) -> Path | None:
|
|
125
|
+
"""The console script the pinned OpenACA's install recorded, if it did.
|
|
126
|
+
|
|
127
|
+
A `RECORD` entry says the distribution `[project.dependencies]` resolved
|
|
128
|
+
wrote a file of these contents at this path — which is more than a directory
|
|
129
|
+
a scheme suggested can say, and less than the path alone would suggest,
|
|
130
|
+
because the two halves age differently: the path stays shared, the contents
|
|
131
|
+
do not. Scripts live outside `site-packages` and are recorded relative to
|
|
132
|
+
it, so the entry resolves correctly under every scheme.
|
|
133
|
+
|
|
134
|
+
Absent when the install enumerated no files: `importlib.metadata` answers
|
|
135
|
+
`None` when the metadata that lists them is missing — `RECORD` for a
|
|
136
|
+
`dist-info` install — and an `egg-info` install lists the sources it was
|
|
137
|
+
built from rather than the scripts it wrote. That is a distribution that
|
|
138
|
+
cannot name its own launcher, not licence to run someone else's: the only
|
|
139
|
+
other thing available about such an install is where it sits, and a
|
|
140
|
+
directory is shared by everything installed alongside it.
|
|
141
|
+
|
|
142
|
+
Absent, too, when the file at the recorded path is not the file that was
|
|
143
|
+
recorded there. Every candidate is authenticated against its own recorded
|
|
144
|
+
digest, because the two halves of an entry answer different questions: the
|
|
145
|
+
path says where the install wrote a launcher, and the digest says what it
|
|
146
|
+
wrote. Only the second survives another install overwriting the shared
|
|
147
|
+
scripts directory afterwards.
|
|
148
|
+
"""
|
|
149
|
+
for recorded in installed.files or ():
|
|
150
|
+
if recorded.name == _SCRIPT:
|
|
151
|
+
candidate = Path(str(installed.locate_file(recorded))).resolve()
|
|
152
|
+
if _holds_recorded_contents(recorded, candidate):
|
|
153
|
+
return candidate
|
|
154
|
+
return None
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _holds_recorded_contents(recorded: PackagePath, candidate: Path) -> bool:
|
|
158
|
+
"""Whether the file now at a recorded path hashes to what was recorded for it.
|
|
159
|
+
|
|
160
|
+
Fails closed on every reason the question cannot be answered — no digest,
|
|
161
|
+
a digest naming an algorithm this interpreter does not implement, an
|
|
162
|
+
unreadable file — because "we could not check" and "it matches" differ by
|
|
163
|
+
exactly the guarantee this locator exists to give, and the unchecked case
|
|
164
|
+
fails invisibly: a wrong-version OpenACA returns a structurally valid BOM.
|
|
165
|
+
The digest field is optional in a `RECORD` row, so an install can decline
|
|
166
|
+
to say what it wrote; that install cannot then be shown to own the file
|
|
167
|
+
sitting at the path it names, and a reinstall is what restores the
|
|
168
|
+
evidence.
|
|
169
|
+
|
|
170
|
+
Digests are base64url without padding, so the padding is stripped from
|
|
171
|
+
both sides rather than assumed absent from either.
|
|
172
|
+
"""
|
|
173
|
+
digest = recorded.hash
|
|
174
|
+
if digest is None:
|
|
175
|
+
return False
|
|
176
|
+
try:
|
|
177
|
+
computed = hashlib.new(digest.mode, candidate.read_bytes()).digest()
|
|
178
|
+
except (ValueError, TypeError, OSError):
|
|
179
|
+
return False
|
|
180
|
+
encoded = base64.urlsafe_b64encode(computed).decode("ascii")
|
|
181
|
+
return encoded.rstrip("=") == digest.value.rstrip("=")
|
|
182
|
+
|
|
39
183
|
|
|
40
184
|
def load_bom(path: Path) -> tuple[str, Built]:
|
|
41
185
|
"""Read a supplied Agent BOM, or say why it cannot be used.
|
|
@@ -95,7 +239,7 @@ def build_bom(
|
|
|
95
239
|
with tempfile.TemporaryDirectory() as scratch:
|
|
96
240
|
directory = Path(scratch)
|
|
97
241
|
argv = [
|
|
98
|
-
|
|
242
|
+
_openaca(),
|
|
99
243
|
"bom",
|
|
100
244
|
"endpoint",
|
|
101
245
|
"--kind",
|
|
@@ -291,8 +435,16 @@ def _scan(
|
|
|
291
435
|
array, and a family we do not read is a fact about the scan rather than a
|
|
292
436
|
fault in it.
|
|
293
437
|
"""
|
|
438
|
+
try:
|
|
439
|
+
openaca = _openaca()
|
|
440
|
+
except RuntimeError:
|
|
441
|
+
# The same answer as an unreadable response, for the same reason: with no
|
|
442
|
+
# OpenACA that can be known to be the pinned one, this scan did not run.
|
|
443
|
+
# A `--bom` run reaches here without having built anything, so this is
|
|
444
|
+
# the first place that can be discovered — and `{}` would say we looked.
|
|
445
|
+
return None
|
|
294
446
|
result = subprocess.run(
|
|
295
|
-
[
|
|
447
|
+
[openaca, "scan", "bom", "--input", str(bom_path), "--format", "json"],
|
|
296
448
|
capture_output=True,
|
|
297
449
|
text=True,
|
|
298
450
|
check=False,
|
|
@@ -220,14 +220,11 @@ def render_text(result: DetectorRun, detail: bool = False) -> str:
|
|
|
220
220
|
|
|
221
221
|
lines.extend(_rollup_lines(result))
|
|
222
222
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
for reason, count in sorted(counts.items(), key=lambda kv: (-kv[1], kv[0])):
|
|
229
|
-
lines.append(f" {count:>4} {reason}")
|
|
230
|
-
lines.append("")
|
|
223
|
+
# The per-reason breakdown of what went unsettled is no longer printed by
|
|
224
|
+
# default. The count still travels in the summary line, `--json` still
|
|
225
|
+
# carries every `Unknown` whole, and the reasoning stage still names its
|
|
226
|
+
# own outcomes below, so nothing is dropped from the record -- only from
|
|
227
|
+
# the default terminal view.
|
|
231
228
|
|
|
232
229
|
lines.extend(_reasoning_lines(result))
|
|
233
230
|
|
|
@@ -256,7 +253,7 @@ def render_text(result: DetectorRun, detail: bool = False) -> str:
|
|
|
256
253
|
#: session-level row, whether or not it also has unanswered questions.
|
|
257
254
|
_REASONING_OUTCOMES: dict[str, str] = {
|
|
258
255
|
"budget_exhausted": "deferred: the run's --budget was reached",
|
|
259
|
-
"reasoning_not_requested": "not requested: --
|
|
256
|
+
"reasoning_not_requested": "not requested: re-run with --escalate to analyse them",
|
|
260
257
|
"analyzer_unavailable": "no analyzer available for the agent kind",
|
|
261
258
|
"session_too_large": "too large for the analyzer's context window",
|
|
262
259
|
"insufficient_context": "compaction removed the turns a rule needed",
|
|
@@ -270,9 +267,9 @@ _REASONING_OUTCOMES: dict[str, str] = {
|
|
|
270
267
|
def _reasoning_lines(result: DetectorRun) -> list[str]:
|
|
271
268
|
"""What the third stage actually spent, and where every escalation went.
|
|
272
269
|
|
|
273
|
-
Stated as accounting rather than as one number
|
|
274
|
-
|
|
275
|
-
|
|
270
|
+
Stated as accounting rather than as one number. With the stage opt-in the
|
|
271
|
+
reader has both questions -- *did it run* and, when it did, *what did this
|
|
272
|
+
run cost me* -- and one number answers neither. Three outcomes are not the same
|
|
276
273
|
fact: a model call spends seconds and money, a cache hit settles the same
|
|
277
274
|
question for free, and a deferred escalation spends nothing and leaves the
|
|
278
275
|
concern open.
|
|
@@ -72,15 +72,11 @@
|
|
|
72
72
|
<span class="panel-note">read from this machine's own transcripts</span>
|
|
73
73
|
</div>
|
|
74
74
|
|
|
75
|
-
<div class="legend" id="live-legend">
|
|
76
|
-
<span><b class="lg-conn">MCP</b> = a link to an outside service</span>
|
|
77
|
-
</div>
|
|
78
|
-
|
|
79
75
|
<div class="logs">
|
|
80
76
|
<section class="logcol">
|
|
81
77
|
<header class="logcol-head">
|
|
82
78
|
<span class="logcol-dot"></span>
|
|
83
|
-
<h3>Agent Session
|
|
79
|
+
<h3>Agent Session Trace</h3>
|
|
84
80
|
<span class="logcol-sub">every tool, skill & connector your sessions used</span>
|
|
85
81
|
</header>
|
|
86
82
|
<div class="feed" id="activity"><div class="feed-empty">Watching for agent activity…</div></div>
|
|
@@ -294,11 +294,6 @@ body.watch-mode .hero, body.watch-mode .band, body.watch-mode .status, body.watc
|
|
|
294
294
|
.comp-chip.hot { border-color:var(--coral); color:var(--coral-d); background:color-mix(in srgb,var(--coral) 6%,var(--paper)); }
|
|
295
295
|
.comp-chip.hot b { color:var(--coral-d); }
|
|
296
296
|
|
|
297
|
-
.legend { display:flex; gap:1.4rem; flex-wrap:wrap; margin:1rem 0 1.2rem; padding:0.6rem 0.9rem;
|
|
298
|
-
background:var(--panel); border:1px solid var(--line); border-radius:4px; font-size:0.74rem; color:var(--ink-dim); }
|
|
299
|
-
.legend b { font-weight:700; }
|
|
300
|
-
.lg-conn { color:var(--coral-d); } .lg-ok { color:var(--ok); } .lg-warn { color:var(--coral-d); }
|
|
301
|
-
|
|
302
297
|
/* two continuous logs */
|
|
303
298
|
.logs { display:grid; grid-template-columns:minmax(0,1.5fr) minmax(0,1fr); gap:1.2rem; align-items:start; }
|
|
304
299
|
@media (max-width:860px){ .logs { grid-template-columns:1fr; } }
|
stacktrace_cli/remote/cli.py
CHANGED
|
@@ -354,10 +354,9 @@ def _mask_token(token: str) -> str:
|
|
|
354
354
|
default=False,
|
|
355
355
|
show_default=True,
|
|
356
356
|
help="Send flagged sessions to the agent's own CLI for semantic analysis. "
|
|
357
|
-
"Off by default
|
|
358
|
-
"the
|
|
359
|
-
"
|
|
360
|
-
"place for either to be implicit.",
|
|
357
|
+
"Off by default: stage 3 spends the developer's own provider quota and is "
|
|
358
|
+
"the one stage that sends session content off this machine, and an "
|
|
359
|
+
"unattended run is the wrong place for either to be implicit.",
|
|
361
360
|
)
|
|
362
361
|
@click.option(
|
|
363
362
|
"--budget",
|
|
@@ -154,7 +154,13 @@ def _collect_detect_run(
|
|
|
154
154
|
escalate=escalate,
|
|
155
155
|
budget=budget,
|
|
156
156
|
sample_budget=sample_budget,
|
|
157
|
-
|
|
157
|
+
# Not gated on `escalate`. A verdict already paid for is an answer
|
|
158
|
+
# this run has, and `escalate` governs whether new ones may be
|
|
159
|
+
# commissioned, not whether old ones may be read -- the rule
|
|
160
|
+
# `run_detector` states at its cache pass. Gating it here made a
|
|
161
|
+
# scheduled run call a session ungraded that `stacktrace detect`
|
|
162
|
+
# calls graded, off the same cache and with neither one spending.
|
|
163
|
+
cache=VerdictCache(default_directory()) if cache else None,
|
|
158
164
|
)
|
|
159
165
|
except ValueError as error:
|
|
160
166
|
raise SyncError(str(error)) from error
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: stacktrace-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: CLI for Stacktrace — Detection and Response platform for AI Agents.
|
|
5
5
|
Project-URL: Homepage, https://stacktrace.ai
|
|
6
6
|
Author-email: "Stacktrace AI, Inc" <founders@stacktrace.ai>
|
|
@@ -126,9 +126,10 @@ because it is installed.
|
|
|
126
126
|
## What leaves your machine
|
|
127
127
|
|
|
128
128
|
Two of `detect`'s three stages run entirely locally and need no model or
|
|
129
|
-
credential
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
credential, and they are the two a bare `detect` runs. The third sends flagged
|
|
130
|
+
sessions to the agent's *own* CLI — the provider that produced the transcript,
|
|
131
|
+
never a different one — and runs only when you pass `--escalate`, capped by
|
|
132
|
+
`--budget`.
|
|
132
133
|
|
|
133
134
|
`sessions` omits prompts, tool arguments and results unless you pass
|
|
134
135
|
`--include-content`. `monitor` binds to loopback only, refuses a non-loopback
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
stacktrace_cli/__init__.py,sha256=
|
|
1
|
+
stacktrace_cli/__init__.py,sha256=78vR-YqB8AYVsKnA_cC7awuK3Q18MU2oWvRKBnQd8mc,111
|
|
2
2
|
stacktrace_cli/__main__.py,sha256=F_tqj3PRzeBtY-uvBs923H8oc-s9bebhIh6UnAUwNYc,448
|
|
3
3
|
stacktrace_cli/analysis.py,sha256=PECyhd_398fDVjg3K78HVzB4xHYS7sfLNXpASRXNRsY,15303
|
|
4
|
-
stacktrace_cli/cli.py,sha256=
|
|
4
|
+
stacktrace_cli/cli.py,sha256=88FXhQxvOhmd6zHveNUfbuZ-k3xRHVPfLbO0rKtN8Kc,17617
|
|
5
5
|
stacktrace_cli/correlate/__init__.py,sha256=SexF0pF83OGfBW_569yoyKG94-tb-jGr_ih1q4fHFgE,81
|
|
6
|
-
stacktrace_cli/correlate/acquire.py,sha256=
|
|
6
|
+
stacktrace_cli/correlate/acquire.py,sha256=gqXx_CIZ4hw5GeYfI1f6f5uUFMfA1CO2JdMD8LpEZOc,24249
|
|
7
7
|
stacktrace_cli/correlate/composition.py,sha256=ZFP3qPOjZvrGVexGWaH7Iq0lIyQLEY-1YxOZ3iMZIbk,20503
|
|
8
8
|
stacktrace_cli/correlate/join.py,sha256=iyjjmAQoMz6tcISzovQZAqnWA3kZO-Wfbo0ZrmYfquo,17187
|
|
9
9
|
stacktrace_cli/correlate/observed.py,sha256=MCF3b_oCjebHtTb63KQR7w1sO0-jun78CJ00QAUSsXo,86294
|
|
@@ -19,7 +19,7 @@ stacktrace_cli/detector/finding.py,sha256=Nshe6w26VyumGXnyzrh48WWmJ-zpR08J3Lo3z-
|
|
|
19
19
|
stacktrace_cli/detector/markers.py,sha256=PUmNitbX4H6l29v-x1FiXohrf2UIPvGs0VnbcHF5E-U,7017
|
|
20
20
|
stacktrace_cli/detector/priors.py,sha256=sRF7kLr_q-Tma9RG96xwSaV_CpDLFEVmqUMo_LUtVrg,22180
|
|
21
21
|
stacktrace_cli/detector/reasoning.py,sha256=6E36BtWoWpSEAXtCr7Tv3h3HghytghWEDeKkdAk0dMA,54792
|
|
22
|
-
stacktrace_cli/detector/render.py,sha256=
|
|
22
|
+
stacktrace_cli/detector/render.py,sha256=_P5r399R6skopx5cF2DYyUNufHi-IMoX2Q-UT5WBuUE,16240
|
|
23
23
|
stacktrace_cli/detector/rules.py,sha256=xU2mXP9BTEknwvwVAPJOF7szWAi2w4R57txCuhSIWdM,6046
|
|
24
24
|
stacktrace_cli/detector/run.py,sha256=BMp9FpEBpciZGPzHHabk5nXSR_ecp4z44v9P7fd4yH0,37832
|
|
25
25
|
stacktrace_cli/detector/secrets.py,sha256=x1pMUkTjT213TGvaBruRW3Tzvt_wShEjGBGjxgCdMO4,9092
|
|
@@ -38,14 +38,14 @@ stacktrace_cli/monitor/state.py,sha256=UVTLpAecypsLTBs5IdWlY55dyJTf-2jI8lDAWoH9P
|
|
|
38
38
|
stacktrace_cli/monitor/verdicts.py,sha256=V6IK2C9eVxZ2RXjWkfDdmfvN8f-Ol67U-N5c1kXx8rQ,2275
|
|
39
39
|
stacktrace_cli/monitor/watch.py,sha256=LrbS6RnZg322tbESQ4u2rTVxhkxsNI5UwdhpTEO3GgE,15546
|
|
40
40
|
stacktrace_cli/monitor/site/app.js,sha256=CM28lPaxuy-oourHb85jw35NDhqnFpYxc0bKgQsLrX0,43898
|
|
41
|
-
stacktrace_cli/monitor/site/index.html,sha256=
|
|
42
|
-
stacktrace_cli/monitor/site/styles.css,sha256=
|
|
41
|
+
stacktrace_cli/monitor/site/index.html,sha256=eLjoYpbXy4cg8hl6l5NdRRWgIVN7UaWUN5-KF94zvM8,3856
|
|
42
|
+
stacktrace_cli/monitor/site/styles.css,sha256=3V7lXe3H0qda5rIWo_95SkQaK1Tlbzb92dk-YaTqDrc,35257
|
|
43
43
|
stacktrace_cli/monitor/site/fonts/OFL.txt,sha256=3eGN4fg4dKG6QBHOpLJobIeUAs3eQnmZBiykH5b-TGY,9975
|
|
44
44
|
stacktrace_cli/monitor/site/fonts/dm-mono-400-latin.woff2,sha256=_XUh81MaXM_GVbJcTyLphx3z7BQa15uyf94g0N80e20,8688
|
|
45
45
|
stacktrace_cli/monitor/site/fonts/dm-mono-500-latin.woff2,sha256=DiY9tSeXCG52NnnFT4Te2MwSSYebwn3KK9XdRG9tnzY,8724
|
|
46
46
|
stacktrace_cli/monitor/site/fonts/dm-sans-latin.woff2,sha256=qlMHFrDTUYZq99v6Pu5BIPs28tBxuv-MI0GFFBhlx_8,62556
|
|
47
47
|
stacktrace_cli/remote/__init__.py,sha256=Ba5yZEovOFNDWfgj0ycJkvglUTLN3C47RUQyX-r4opI,82
|
|
48
|
-
stacktrace_cli/remote/cli.py,sha256=
|
|
48
|
+
stacktrace_cli/remote/cli.py,sha256=0yeCj9vJTXSYb41AMJ0Tciic8yu6r5WHyuXRy2mW1Xg,17065
|
|
49
49
|
stacktrace_cli/remote/client.py,sha256=Az1a_CsTvNx9V38iGWKt-fGHN23P1HAgNofrXBQzDFE,13602
|
|
50
50
|
stacktrace_cli/remote/config.py,sha256=xBTLYfY2OX_JieeIYe3ZCrQqzk2-xKZ8MJfJDXDRlxY,4256
|
|
51
51
|
stacktrace_cli/remote/detect_payload.py,sha256=5glNKigGWiozh5VviS_fxat-_njDYUlpGJSDQnGteqI,14902
|
|
@@ -54,14 +54,14 @@ stacktrace_cli/remote/policy.py,sha256=0pDZcPavCTXvul1Zs6oi7-J3K0YoXPNFa3j1aOJG3
|
|
|
54
54
|
stacktrace_cli/remote/redact.py,sha256=cgCMcb2f7Pd7Xt7Ofo6QxFX-fh1Nph-Rb_iiP9UlLjw,29354
|
|
55
55
|
stacktrace_cli/remote/spool.py,sha256=AI3EVrVk-cIbZ8_JgCTZe0yhdBxoUQ1qvwhXOgsADeo,20823
|
|
56
56
|
stacktrace_cli/remote/sync.py,sha256=YmOJiWa8rjrbDLJkQ6cZpC6DF1amv83a8_DhnXUB368,25891
|
|
57
|
-
stacktrace_cli/remote/sync_detect.py,sha256=
|
|
57
|
+
stacktrace_cli/remote/sync_detect.py,sha256=eLkK5dBEJXi8D_1fGOQvHxfB7Nd1itOE9QsYXJB8Kvo,19011
|
|
58
58
|
stacktrace_cli/remote/upload_contract.py,sha256=Jz5icyBHXlImbXTetmQhhXbsma0VCKTLpnlKOe6HDLU,44945
|
|
59
59
|
stacktrace_cli/sessions/__init__.py,sha256=mWb3Z42sN_UqxFQCPpXpsa7Nqe8J9Vd3jspItXqtTmI,76
|
|
60
60
|
stacktrace_cli/sessions/access.py,sha256=mpKMdRufPGTZNJCVPa2MoKWdM8eOYzaYMDsGqob0De0,3401
|
|
61
61
|
stacktrace_cli/sessions/outcome.py,sha256=IQUrOoigPAFHnoA26LlOjSSB8hnSQUIJ8E5tQ0LdUJk,2632
|
|
62
62
|
stacktrace_cli/sessions/protocols.py,sha256=rvQsVd77AekNGhp73masMa61-DbG62QF8Y6hDSwQ9bU,6630
|
|
63
63
|
stacktrace_cli/sessions/render.py,sha256=SCu9Fx-7hWQWOsy3O7zbYzJqCNomaMp_19V7NQTkSm0,14001
|
|
64
|
-
stacktrace_cli-0.2.
|
|
65
|
-
stacktrace_cli-0.2.
|
|
66
|
-
stacktrace_cli-0.2.
|
|
67
|
-
stacktrace_cli-0.2.
|
|
64
|
+
stacktrace_cli-0.2.3.dist-info/METADATA,sha256=U3fPKJ8R63wyoqnLfUIcqjU8QdluSlnqnApmv6ccaAU,5482
|
|
65
|
+
stacktrace_cli-0.2.3.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
66
|
+
stacktrace_cli-0.2.3.dist-info/entry_points.txt,sha256=OYDmb2CtEjd8TV78zxiGB1XVrLrC6vvayAPXa79_tJ0,60
|
|
67
|
+
stacktrace_cli-0.2.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|