threadwire 0.1.5 → 0.1.6

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 CHANGED
@@ -71,15 +71,17 @@ Pass `--resume-session <exact-provider-session-id>` to continue a stored Codex,
71
71
 
72
72
  Provider stdout is decoded as JSONL with a finite 1 MiB UTF-8 byte limit for each pending unterminated record. Exceeding it rejects the run, removes listeners and signal handlers, and terminates the provider without parsing or rendering the oversized content.
73
73
 
74
- For normal `threadwire run` execution, Threadwire's own stdout is a separate caller-facing JSON Lines protocol intended for an outer Hermes launcher. Each line is one JSON object and has no `version` key. It includes normalized `worker_started`, `worker_completed`/`worker_failed`, `tool_started`, `tool_finished`, and suitable `diagnostic` records, followed by exactly one terminal `{"type":"completed","exitCode":0,"assistantText":"..."}` record. When `--workspace-profile` is used, Threadwire first emits one `{"type":"execution_environment",...}` record containing the resolved profile name, in-container repository path, exact Git revision, and immutable worktree identity. Setup, worker, and relay-close errors use terminal exit code 2 while retaining the stderr diagnostic. The terminal `assistantText` is optional and is assembled from parsed assistant text deltas; deltas themselves are never streamed to stdout. Assistant text is credential-redacted, control-normalized, and capped at 16,384 Unicode code points. Tool names, details, and outputs use the relay's credential redaction and control normalization and are capped at 128, 1,024, and 4,096 code points respectively. Duplicate lifecycle phases and tool transitions are suppressed, and at most 64 nonterminal records are emitted per run; the terminal record is always exempt from that limit.
74
+ For normal `threadwire run` execution, Threadwire stdout is the parent-model admission plane. It emits exactly one versioned terminal `delegated_result` JSON object and no progress records. The envelope contains a bounded, credential-redacted, control-normalized final conclusion when one was produced, structured terminal state and exit code, and the exact bounded provider session handle when available. Its closed schema can also represent concise blocker/decision requests, opaque artifact handles, commit/URL references, and a concise validation summary; current provider adapters do not infer these optional fields from prose. Unknown, nested, wrongly typed, cardinality-invalid, or oversized admission candidates fail closed. See [Delegated-result protocol](docs/delegated-result-protocol.md) for the complete schema, limits, and caller obligations.
75
75
 
76
- This Hermes stdout channel does not replace Telegram: the existing human-readable Telegram relay continues independently. Provider stdout remains private input to Threadwire's JSONL parser and is never copied to Threadwire stdout; raw provider records, raw stdout, stderr, reasoning, prompts, tool inputs, and secrets are excluded. Threadwire's own error diagnostics remain on stderr. Help output is the sole non-run, human-readable stdout mode.
76
+ Set the trusted operator setting `THREADWIRE_EVIDENCE_ROOT` for standalone runs to persist the delegated prompt and raw provider stdout/stderr as a scoped file-backed artifact; Telegram ingress uses its dedicated evidence volume automatically. The parent or owning Telegram topic receives only an opaque bearer handle. Retrieve later with `threadwire evidence read` or the authenticated `/evidence` Telegram command and an explicit bounded selector. See [Evidence artifacts](docs/evidence-artifacts.md) for permissions, quotas, retention, recovery, authorization, redaction, privacy, and cleanup behavior.
77
+
78
+ Telegram is the separate user-visible progress plane. Lifecycle notices, diagnostics, tool activity, and assistant streaming continue there independently; `--tool-messages` affects only Telegram. Execution-environment details, provider records and streams, lifecycle progress, diagnostics, tool names/arguments/details/output, stderr, prompts, narration/reasoning, and full transcripts never enter stdout. Threadwire's bounded error diagnostic remains on stderr. Help output is the sole non-run, human-readable stdout mode. This default is an intentional pre-1.0 protocol break from the former mixed Hermes JSONL stream.
77
79
 
78
80
  The Telegram bot token is used only by Threadwire's notifier and both `TELEGRAM_BOT_TOKEN` and `THREADWIRE_TELEGRAM_BOT_TOKEN` are removed from every provider child environment. The three libexec adapters repeat that scrub as defense in depth. Other environment variables, including the providers' own authentication and normal process configuration, are preserved. Outbound Telegram fetch and response-body parsing share a 30-second deadline by default; set `THREADWIRE_TELEGRAM_REQUEST_TIMEOUT_MS` to a positive safe integer no greater than `2147483647` to override it.
79
81
 
80
82
  A single trusted renderer is the only code allowed to enqueue Telegram notices. By default, parsed assistant text is forwarded in order with every nonblank rendered line labeled `[P<n>] Assistant: `; no CLI flag is required. This preserves Markdown, code-block indentation, blank lines, and whitespace attached to nonblank content while preventing assistant text from imitating trusted activity on a later line. Streamed fenced JavaScript blocks (` ```js ` / ` ```javascript `) are instead emitted as independently valid, escaped Telegram HTML code messages: the `[P<n>] Assistant:` label stays above the code block, and long blocks are Unicode-safe chunked without exposing raw fences. A short blank-only stream is suppressed at normal close. Because retention is bounded, a blank-only prefix longer than the buffer limit is emitted in oldest-first chunks while at most one limit's worth remains deferred; a later visible assistant character therefore still reconstructs the input exactly, but an indefinitely blank stream cannot be suppressed indefinitely. With `--tool-messages`, tool activity uses a single edit-in-place status line (silent `🛠 …` on start, edited to begin `✅` on finish); without it, both the send and completion edit are suppressed. Worker start/completion/failure and warning/error diagnostics continue to use fixed labeled templates in either mode. Non-assistant provider fields—including summaries, tool names, metadata IDs, inputs, commands, stderr content, raw JSON, reasoning/thinking, tokens, and retry internals—are not forwarded. When tool messages are enabled, the sole provider-data exception is normalized Codex command-completion output: it is appended only to its original tool status edit as an escaped, bounded, expandable Telegram HTML blockquote after shared credential redaction.
81
83
 
82
- Assistant deltas from all provider stream IDs share one ordered sentence-boundary buffer, preserving provider-event order. The buffer has a finite 16,384-character default: a continuously active punctuation-free stream emits and clears Unicode-safe fixed-size chunks instead of growing indefinitely. Structured events flush any earlier assistant tail, including retained leading whitespace, before their own fixed notice. Completed boundaries enter delivery without a deliberate batching delay; messages combine only when already naturally queued behind delivery. Notices remain ordered, size-limited, paced, and retried conservatively when Telegram reports throttling or a transient failure.
84
+ Assistant deltas from all provider stream IDs share one ordered sentence-boundary buffer, preserving provider-event order. The buffer has a finite 16,384-character default: a continuously active punctuation-free stream emits and clears Unicode-safe fixed-size chunks instead of growing indefinitely. Structured events flush any earlier assistant tail, including retained leading whitespace, before their own fixed notice. Completed boundaries enter delivery without a deliberate batching delay; messages combine only when already naturally queued behind delivery. When Telegram briefly falls behind, Threadwire emits a fixed safe notice that the notifier saturated and then coalesces only eligible assistant progress until headroom returns; lifecycle, diagnostics, and tool activity remain ordered and non-droppable. Notices remain ordered, size-limited, paced, and retried conservatively when Telegram reports throttling or a transient failure.
83
85
 
84
86
  The delivery queue has finite defaults of 100 pending notices and 256 KiB of pending UTF-8 text. Message length and capacity settings require positive safe integers; pacing settings require nonnegative safe integers. A notice larger than the byte limit or a limit-plus-one enqueue latches a terminal capacity error, discards queued (not already in-flight) notices, and rejects every later enqueue. Unicode chunks never split a surrogate pair, and every labeled continuation retains its complete process label. If the label cannot fit with content under a configured message length, delivery latches a terminal chunking error before sending. These rules make delivery loss visible and prevent slow or rate-limited transports from consuming unbounded memory.
85
87
 
@@ -0,0 +1,45 @@
1
+ # Card 10520 scoped implementation plan
2
+
3
+ ## Existing information flow
4
+
5
+ 1. `src/cli.js` reads the prompt, resolves the provider command, and gives both to
6
+ `runWorker`.
7
+ 2. `src/run-worker.js` spawns the provider, incrementally frames stdout JSONL,
8
+ calls `onRecord` with each raw provider record, normalizes it through the
9
+ provider parser, and serially calls `onEvent`. Stderr is currently reduced to
10
+ one diagnostic; its bytes are discarded.
11
+ 3. `src/cli.js` sends normalized events to `WorkerControl`, which renders bounded
12
+ progress to the explicit Telegram target. `ActivityLog` separately records
13
+ only workspace provenance, PID, and resumable session identifiers.
14
+ 4. The same normalized stream reaches `DelegatedResultAdmission`, but only
15
+ assistant text is accumulated. On termination, admission writes exactly one
16
+ bounded `delegated_result` JSON object to stdout. That stdout object is the
17
+ parent-facing result; tool/provider records are not emitted there.
18
+
19
+ The current boundary therefore avoids most raw-event admission, but detailed
20
+ prompt/provider/tool/stderr evidence is discarded or reduced and cannot be
21
+ retrieved through an opaque, scoped contract.
22
+
23
+ ## Ownership and implementation
24
+
25
+ `EvidenceStore` is the sole persistence and retrieval owner. `runWorker`
26
+ remains the streaming/process-lifecycle owner and exposes raw stdout and stderr
27
+ chunks to one evidence sink with its existing serial backpressure. `cli.js` and
28
+ authenticated Telegram `dispatchWorker()` each own one run-scoped artifact and
29
+ finalize it with the worker lifecycle. CLI admission and the owning Telegram
30
+ topic receive only the bearer handle. `ActivityLog` does not duplicate evidence.
31
+
32
+ Work proceeds RED-GREEN-REFACTOR:
33
+
34
+ 1. Add failing store and real CLI-pipeline tests proving the current retrieval
35
+ gap and specifying opaque IDs, permissions, atomic lifecycle, quotas,
36
+ recovery, cleanup, scope isolation, bounded reads, UTF-8/binary behavior, and
37
+ streaming redaction.
38
+ 2. Implement the pinned file-backed store and authenticated CLI/Telegram bearer
39
+ retrieval boundaries, then connect both real provider/worker paths without
40
+ changing existing terminal/error semantics.
41
+ 3. Add deterministic concurrency, expiry, corruption, filesystem-attack, and
42
+ tool-heavy end-to-end coverage; document operation and run every repository
43
+ check before a full diff/security audit and commit.
44
+
45
+ Card 10521 metrics and admission-policy expansion are explicitly out of scope.
@@ -97,8 +97,9 @@ node bin/threadwire.js run \
97
97
  --prompt 'Inspect the container worktree.'
98
98
  ```
99
99
 
100
- Provider activity/state persists at `/var/lib/threadwire/activity` and
101
- `/home/threadwire/.codex`. The Codex adapter reads only
100
+ Provider activity persists at `/var/lib/threadwire/activity`, detailed
101
+ delegated evidence persists privately at `/var/lib/threadwire/evidence`, and
102
+ Codex state persists at `/home/threadwire/.codex`. The Codex adapter reads only
102
103
  `OPENAI_API_KEY_FILE`, exports the provider credential immediately before
103
104
  `exec`, removes its pointer, and removes every ingress value and pointer from
104
105
  the provider environment. Threadwire repeats ingress filtering before spawn.
@@ -0,0 +1,161 @@
1
+ # Delegated-result admission protocol
2
+
3
+ Threadwire has two deliberately separate output planes:
4
+
5
+ - Telegram is the user-visible progress plane. It may receive assistant streaming,
6
+ lifecycle notices, diagnostics, and opt-in tool status.
7
+ - Standard output for a normal `threadwire run` is the parent-model admission
8
+ plane. It contains exactly one newline-terminated terminal JSON envelope.
9
+
10
+ Standard error remains a caller diagnostic channel and is never admission
11
+ content. Provider stdout is private parser input.
12
+
13
+ ## Context-budget metrics
14
+
15
+ Each delegated run emits one concise `threadwire-context-metrics` JSON record
16
+ on standard error. It contains content-free integer counters only. Detailed
17
+ fixed-class counters are appended to the run's existing file-backed evidence
18
+ artifact when evidence is configured; they are never added to the admission
19
+ envelope.
20
+
21
+ Byte counters are UTF-8 byte counts. Event and handle counters are counts.
22
+ `estimatedTokens` is `ceil(admittedBytes / 4)` and is explicitly an estimate,
23
+ not provider tokenization. Every counter saturates at 2,147,483,647. Metric
24
+ classes and envelope-field names are closed, fixed sets, so worker-controlled
25
+ values cannot create labels or cardinality. Counters retain no child text,
26
+ commands, arguments, output, secrets, handles, reference values, or other raw
27
+ values.
28
+
29
+ The raw-child counters separately measure provider stdout/stderr stream chunks
30
+ and bytes at the child stream boundary, and successfully JSON-parsed provider
31
+ records at the parser boundary. A parsed record is not an OS chunk: one chunk
32
+ may contain multiple records and one record may span chunks. Rejected counters
33
+ distinguish provider stream, stderr, and lifecycle, diagnostic, and tool
34
+ progress excluded from admission.
35
+
36
+ Progress has fixed `attempted`, `suppressed`, `coalesced`, and `delivered`
37
+ classes. Attempted sizes are JSON-encoded normalized-event bytes. Suppressed
38
+ counts progress disabled by policy, while coalesced counts rendered assistant
39
+ notices merged under notifier saturation. Delivered alone means a rendered
40
+ message or edit was successfully sent; its size is the exact UTF-8 size of the
41
+ JSON-encoded transport value. Consequently batching, rendering, and escaping
42
+ may make delivered sizes differ from attempted sizes.
43
+
44
+ Artifact counters measure finalized logical payload bytes and admitted
45
+ opaque-handle count. When detailed metrics are the last event in that same
46
+ artifact, `artifacts.bytes` is a fixed-point projection that includes the
47
+ newline-terminated metrics JSON itself. Finalization must equal the projection
48
+ or the run fails closed. This avoids a second metrics artifact while giving the
49
+ stored record exact self-inclusive semantics.
50
+
51
+ `admitted.bytes` and `parentContextDeltaBytes` measure the exact UTF-8 bytes of
52
+ the newline-terminated terminal envelope written to stdout. Admitted field
53
+ sizes are the UTF-8 sizes of each field's JSON-encoded value, including string
54
+ quotes, escapes, and multibyte encoding.
55
+
56
+ The regression invariant is exact: given quiet and tool-heavy runs with the
57
+ same terminal conclusion, validation, references, and artifact handles, every
58
+ admitted semantic field is identical and:
59
+
60
+ ```text
61
+ heavy.parentContextDeltaBytes
62
+ <= quiet.parentContextDeltaBytes + 256
63
+ ```
64
+
65
+ The 256-byte allowance is fixed metadata headroom and is independent of raw
66
+ event volume. The current version adds no per-run metric metadata to parent
67
+ context, so equivalent envelopes normally have equal deltas. Tests deliberately
68
+ inject a provider-transcript-shaped conclusion large enough to exceed the
69
+ allowance; this makes accidental stream admission fail deterministically.
70
+
71
+ ## Version 1 envelope
72
+
73
+ The closed envelope has these required fields:
74
+
75
+ ```json
76
+ {
77
+ "version": 1,
78
+ "type": "delegated_result",
79
+ "state": "completed",
80
+ "exitCode": 0
81
+ }
82
+ ```
83
+
84
+ `state` is exactly one of `completed`, `failed`, `blocked`, or
85
+ `needs_decision`. `exitCode` is a nonnegative safe integer. The CLI currently
86
+ produces `completed` for exit code zero and `failed` otherwise.
87
+
88
+ The only optional fields are:
89
+
90
+ | Field | Shape | Limit |
91
+ | --- | --- | --- |
92
+ | `conclusion` | string | 16,384 Unicode code points |
93
+ | `blocker` | string | 1,024 Unicode code points |
94
+ | `decisionRequest` | string | 1,024 Unicode code points |
95
+ | `continuationHandle` | opaque ASCII provider token | 512 characters |
96
+ | `artifactHandles` | array of opaque ASCII IDs or safe POSIX-style paths | 16 entries; 512 characters each |
97
+ | `references` | array of `{kind,value}` | 16 entries; 2,048 code points per value |
98
+ | `validationSummary` | string | 2,048 Unicode code points |
99
+
100
+ A reference `kind` is exactly `commit` or `url`. Commit values are 7–64
101
+ hexadecimal characters. URL values are non-whitespace HTTP or HTTPS URLs
102
+ without embedded credentials.
103
+ Artifact handles are opaque identifiers only; artifact content is forbidden.
104
+ The complete UTF-8 JSON envelope is limited to 98,304 bytes.
105
+
106
+ Threadwire preserves accepted continuation handles, artifact handles, and
107
+ references exactly. Streamed conclusion collection is credential-redacted,
108
+ control-normalized, and deterministically truncated with a final ellipsis when
109
+ necessary. Code-point accounting never splits a UTF-16 surrogate pair.
110
+
111
+ A continuation handle consists of one or more colon-separated opaque segments.
112
+ Each segment must start with an ASCII letter or digit and may then contain only
113
+ ASCII letters, digits, `_`, `-`, and `.`. This covers provider UUIDs, token IDs
114
+ such as `ses_123`, and namespaced IDs such as `provider:session-123` without
115
+ admitting prose. Empty segments and known URL/transport scheme prefixes are
116
+ forbidden. An artifact handle uses a single segment's alphabet and may
117
+ additionally use `/` separators with one optional leading `/`; empty, `.` and
118
+ `..` path components are forbidden. Both handle types reject whitespace,
119
+ backslashes, controls (including C0, C1, and ESC), URL forms, userinfo, query
120
+ strings, and fragments.
121
+
122
+ ## Fail-closed rules
123
+
124
+ Admission is an explicit allowlist, not a projection of arbitrary provider
125
+ data. A candidate is rejected if it:
126
+
127
+ - has an unknown field or terminal state;
128
+ - uses a wrong or nested type, including an object mislabeled as an allowed
129
+ string or opaque handle;
130
+ - adds fields inside a reference;
131
+ - has an empty, oversized, or over-cardinality optional collection;
132
+ - contains an invalid commit or URL reference; or
133
+ - exceeds a per-field or aggregate limit.
134
+
135
+ Unknown normalized worker event kinds fail the run. Known lifecycle,
136
+ diagnostic, and tool events remain progress-only and cannot affect the
137
+ envelope. Threadwire does not silently remove a forbidden field and admit the
138
+ remainder.
139
+
140
+ ## Excluded material
141
+
142
+ The admission envelope never contains execution-environment progress,
143
+ lifecycle progress, diagnostics, provider records or streams, tool names,
144
+ arguments, details, commands or raw output, stderr, prompts,
145
+ narration/reasoning, full transcripts, or artifact content. Optional structured
146
+ fields are populated only from explicit trusted facts; provider prose is not
147
+ parsed to invent them.
148
+
149
+ ## Caller obligations and compatibility
150
+
151
+ The caller must parse exactly one envelope, require `version: 1` and
152
+ `type: "delegated_result"`, enforce this closed schema, and reject missing,
153
+ duplicate, trailing, unknown-version, unknown-field, or oversized records
154
+ before parent transcript or context persistence. Standard error and Telegram
155
+ delivery must never be merged into parent context.
156
+
157
+ This protocol is the default and is an intentional pre-1.0 breaking change.
158
+ Callers of the former unversioned mixed progress stream must upgrade before
159
+ using this release. Future file-backed evidence may use opaque
160
+ `artifactHandles`; retrieval and artifact storage are outside version 1 and are
161
+ not implied by a handle.
@@ -0,0 +1,106 @@
1
+ # Delegated-worker evidence artifacts
2
+
3
+ Threadwire retains detailed delegated-worker evidence without adding it to the
4
+ parent admission stream. Telegram uses the dedicated
5
+ `/var/lib/threadwire/evidence` volume. A standalone run enables the same store
6
+ with the trusted operator setting `THREADWIRE_EVIDENCE_ROOT`; callers cannot
7
+ select a root through CLI arguments.
8
+
9
+ The store records the prompt and framed provider stdout/stderr events, including
10
+ tool calls, commands, raw results, and intermediate narration the provider
11
+ emits. Threadwire stdout still contains one bounded `delegated_result`; evidence
12
+ adds only an unguessable bearer handle. Storage failure fails the run explicitly
13
+ and never falls back to inlining evidence.
14
+
15
+ ## Security and lifecycle
16
+
17
+ The Linux-only store walks an absolute path from a pinned `/` descriptor,
18
+ opening every existing component with `O_DIRECTORY|O_NOFOLLOW`. It accepts
19
+ root-owned non-writable ancestors, root-owned sticky directories such as
20
+ `/tmp`, and same-user directories that are not group/world-writable. Only a missing final component is
21
+ created, relative to its pinned trusted parent, as an owned `0700` directory.
22
+ The store then performs child operations through `/proc/self/fd`; destructive
23
+ work rechecks device/inode. Payload and metadata
24
+ files are `0600`, regular, single-link files. Reconciliation removes only
25
+ recognized implementation-owned artifact and atomic-temporary names. Any
26
+ unknown entry is preserved and makes store opening fail closed.
27
+
28
+ Only one live deployment can open a shared-volume root. The parent opens the
29
+ lock file through the pinned root descriptor and authenticates `/usr/bin/flock`
30
+ through its own descriptor. A synchronous child executes that inherited
31
+ executable descriptor and applies `flock -n` to an inherited duplicate of the
32
+ lock-file open description. The child emits no output and exits; the parent
33
+ retains the locked open description until close or process death.
34
+
35
+ Each event has a bounded kind and length frame, preserving ordering, binary
36
+ data, and split-record provenance without accumulating a transcript in memory.
37
+ Pending evidence counts against quotas, is unreadable, and is not expiry-cleaned
38
+ while active. Fsync and atomic rename publish payload before ready metadata.
39
+ Startup removes partial/corrupt states and rehydrates only exact-schema,
40
+ unexpired ready artifacts.
41
+
42
+ Defaults are 1 MiB/event; 64 MiB and 100,000 events/artifact; 128 MiB and
43
+ 200,000 events/run; 1 GiB, 1,000,000 events, and 10,000 artifacts/store;
44
+ seven-day retention; and a 64 KiB/1,000-line serialized-response ceiling.
45
+ Durable reservations include metadata publication overlap and directory-entry
46
+ allowance, so zero-event artifacts consume capacity.
47
+
48
+ ## Authorization and retrieval
49
+
50
+ The `evidence_…` handle is a 256-bit bearer capability returned only through the
51
+ owning parent envelope or Telegram topic. Metadata stores its SHA-256 binding,
52
+ not the capability. Artifact redaction policy is AES-GCM sealed under the
53
+ capability with versioned AAD binding every immutable lifecycle/accounting
54
+ field. Ready metadata also contains an HMAC-SHA-256 commitment over the complete
55
+ ordered framed payload, keyed from the bearer without storing the key.
56
+ Ephemeral in-process owner objects are tracked only by weak identity membership;
57
+ completed webhook jobs do not accumulate in an enumerable authorization registry.
58
+
59
+ Telegram retrieval also requires an authenticated webhook update whose
60
+ allowlisted sender and server-derived chat/topic/sender identity match the
61
+ artifact metadata and encrypted-policy AAD. A requester
62
+ cannot submit destination, run, or agent identity. Wrong scope, bad capability,
63
+ missing, corrupt, removed, and expired artifacts all report generic
64
+ unavailability.
65
+
66
+ Parent retrieval syntax:
67
+
68
+ ```console
69
+ threadwire evidence read --handle evidence_<bearer> --bytes 2048:512
70
+ threadwire evidence read --handle evidence_<bearer> --lines 40:5
71
+ threadwire evidence read --handle evidence_<bearer> --query "exact command identity" --context-bytes 80
72
+ ```
73
+
74
+ Authenticated Telegram syntax is
75
+ `/evidence evidence_<bearer> bytes 2048:512` or a bounded `lines` selector in
76
+ the owning chat/topic.
77
+
78
+ Byte offsets are zero-based bytes in the redacted logical stream. Line starts
79
+ are one-based and include terminating newlines. Text boundaries are valid UTF-8;
80
+ binary output is base64. Queries are bounded UTF-8 literal searches—never
81
+ regular expressions. One universal encoded output-byte maximum applies even to
82
+ one huge line. Verification should request the smallest useful excerpt.
83
+
84
+ Retrieval opens the payload once with `O_NOFOLLOW`, verifies the descriptor, and
85
+ in one bounded-memory streaming pass authenticates the exact raw frames while
86
+ parsing, redacting, and retaining only the bounded selection. It drains through
87
+ EOF and releases that selection only after timing-safe commitment verification;
88
+ there is no authenticated-then-reread interval. It does not read whole artifacts
89
+ or build transcript-wide offset arrays. Known runtime secret values, securely read secret-file contents,
90
+ and their pointer values become `[REDACTED]`; responses state whether they were
91
+ redacted or truncated. This finite policy is defense in depth, not
92
+ arbitrary-secret detection.
93
+
94
+ ## Operations
95
+
96
+ Run `cleanup()` from maintenance and use scoped removal for revocation. Cleanup
97
+ is idempotent, skips active descriptor-pinned readers, fsyncs the root after
98
+ unlink, and releases capacity only after that transaction succeeds. Trusted
99
+ structured references already approved through the admission boundary remain
100
+ independent of artifact cleanup. No provider currently supplies authenticated
101
+ structured commit or URL metadata, so production does not infer either from
102
+ stdout or ambient repository state.
103
+
104
+ Treat the volume as sensitive provider-transcript data. Exclude it from general
105
+ logs and broad backups. Any required backup must be encrypted and preserve the
106
+ same authorization and retention. Suppressed raw content is never logged.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threadwire",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Stream Codex, Claude, and OpenCode worker progress to an explicit Telegram destination",
5
5
  "keywords": [
6
6
  "ai-agent",
@@ -19,7 +19,10 @@ const EXPECTED_FILES = [
19
19
  "TELEGRAM-INGRESS.md",
20
20
  "bin/telegram-webhook.js",
21
21
  "bin/threadwire.js",
22
+ "docs/card-10520-plan.md",
22
23
  "docs/container-runtime.md",
24
+ "docs/delegated-result-protocol.md",
25
+ "docs/evidence-artifacts.md",
23
26
  "package.json",
24
27
  "scripts/atomic-install.js",
25
28
  "scripts/install-local-launcher.js",
@@ -31,7 +34,9 @@ const EXPECTED_FILES = [
31
34
  "scripts/verify-package.js",
32
35
  "src/activity-log.js",
33
36
  "src/cli.js",
34
- "src/hermes-protocol.js",
37
+ "src/context-budget-metrics.js",
38
+ "src/delegated-result-admission.js",
39
+ "src/evidence-store.js",
35
40
  "src/notice-queue.js",
36
41
  "src/notifiers/fetch-transport.js",
37
42
  "src/notifiers/telegram.js",
@@ -51,6 +56,7 @@ const EXPECTED_FILES = [
51
56
  "src/telegram-ingress/update-guard.js",
52
57
  "src/telegram-webhook.js",
53
58
  "src/types.js",
59
+ "src/worker-control.js",
54
60
  "src/workspace-profile.js",
55
61
  "threadwire.workspace-profiles.json"
56
62
  ]