@tangle-network/sandbox-cli 0.22.102 → 0.22.104

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
@@ -87,10 +87,190 @@ Progress goes to stderr; `--json` returns the result or the shared error contrac
87
87
  on stdout. Local run journals live under `~/.tangle/runs/<run-id>`, and local graph history
88
88
  lives in `~/.tangle/graph-registry`. Unknown token and cost totals remain `null`.
89
89
 
90
+ To learn from retained runs, admit related tasks under the same independent unit
91
+ and keep each unit in one partition. Repeating ingestion updates that run's
92
+ checkpoint without adding another example. Unavailable runs remain visible with
93
+ evidence gaps; lifecycle completion never becomes a quality label.
94
+
95
+ ```bash
96
+ tangle --json graph dataset ./runs <run-id> --domain software --unit repository-a --split train
97
+ tangle --json graph dataset ./runs <another-run-id> --domain software --unit repository-b --split dev
98
+ tangle --json graph dataset ./runs <heldout-run-id> --domain software --unit repository-c --split test
99
+ tangle --json graph improve ./delivery.graph.yaml ./runs --suite ./software-evaluation.json --campaign ./campaign
100
+ tangle --json graph activate ./campaign ./delivery.graph.yaml
101
+ tangle --json graph observe ./campaign <subsequent-run-id> --unit new-production-task
102
+ ```
103
+
104
+ For local tasks that depend on repository files, first capture one explicit Git root while its other writers are idle. The capture uses Runtime's maintained archive and limits. It retains HEAD, the index, tracked files and unignored untracked files in private local artifacts. Keep the reference outside the repository:
105
+
106
+ ```sh
107
+ tangle --json graph workspace capture ./repository --output ./task-workspace.json
108
+ tangle --json graph run ./factory.graph.yaml --task-workspace ./task-workspace.json --param task=example
109
+ ```
110
+
111
+ Dataset ingestion retains that exact workspace reference, and learning materializes it into every fresh candidate's private directory. Retries reuse the same allocation and preserve agent edits; a standalone dry-run releases only its own fresh validation copy. Missing or corrupt archive bytes refuse fresh replay; capture never executes repository scripts. Environment variables, installed tools and Git-ignored files are not snapshotted. Tracked files and Git history may contain private data; these artifacts remain local, and cloud dispatch refuses these local-only references. Legacy runs without captures retain a `task-workspace-not-snapshotted` gap rather than acquiring an unrelated current workspace.
112
+
113
+ Datasets retain exact trigger payloads and captured MCP host policies. Legacy manifests that omitted trigger context must be reingested before learning. `dispatch`, `improve` and `repair` accept `--mcp-policy` and private `--mcp-secret key=ENVIRONMENT_VARIABLE` bindings; secret values and environment variable names are not campaign identities.
114
+
115
+ Each graph, including the proposer, reserves its complete declared ceiling through Runtime's budget pool and reconciles only its matching retained settlement. Restart verifies every previously hashed settlement and replays its actual spend through the same owner pool, preserving cache and dollar completeness; missing or inconsistent historical receipts hold. An interrupted reservation keeps the exact run ID, input and compiled graph during the owner's resume attempt. An unavailable native attachment or unknown usage cannot authorize replacement work or a new comparison. Eval may close an interrupted proposal as failed even when its native evidence is recovered. Recovered final-test cells with incomplete end-to-end latency hold the operational comparison instead of appearing artificially fast. Supplied benchmark arms use content-addressed source snapshots throughout a campaign.
116
+
117
+ Activation locks the canonical target across campaigns and rechecks its bytes after evaluator calibration and immediately before replacement. Atomic rename does not provide a filesystem compare-and-swap against unrelated editors. Activation also recompiles each measured case with ordinary execution settings and refuses a seat override or changed default that would not carry into an ordinary run. It freezes measured harness/model/seat/connection selections and MCP policy from retained compiled graph records. Observations verify those frozen host selections without consulting today's defaults, while allowing new task inputs through the same authored source. Missing execution records, historical activation records without this binding, and previously unmeasured selections refuse observation. Observations must start after activation, exclude every campaign execution, and identify a new production task unit with inputs distinct from the learning cohort and earlier observations. Repeating the same observation returns its retained verdict; another run cannot count that unit or task again.
118
+
119
+ The evaluation suite is JSON with `version: 1`, `domain`, the inline-prompt
120
+ `node` to improve, `objective`, `minimumEffect` and `reps`. Its `evaluator`
121
+ declares an absolute executable `command`, `args`, `files` (every script, rubric and data dependency)
122
+ and `timeoutMs`. The command reads one JSON request from stdin and emits exactly
123
+ `{"quality": 0.0, "notes": "independent outcome evidence"}` on stdout. Requests
124
+ contain `scenario`, retained `evidence`, and the candidate `artifact`, including
125
+ its native run ID, output, measured usage and duration. The evaluator runs outside
126
+ the candidate's workspace. Include `calibration` entries with a `request` and
127
+ independently known `quality` of zero or one; both classes must pass before
128
+ inference begins. A failed evaluator is an unmeasured cell, never a quality zero.
129
+ Evaluator commands follow the operator's subscription-only spending policy.
130
+
131
+ The suite's `budget` requires total `maxTokens`, `maxIterations`, `deadlineMs`,
132
+ `maxExpansions`, plus `proposalTokens`, `proposalIterations` and
133
+ `proposalDeadlineMs`. The graph also declares finite per-run budgets. Runtime's
134
+ existing reflective proposer generates detached prompt candidates, and its search
135
+ owns train/selection/final-test partitions, paired decisions and the closed
136
+ ledger. A single conserved Runtime pool bounds native candidate and proposal
137
+ calls; interruption retains the pending ceiling conservatively. Reusing a
138
+ finished campaign returns its exact retained result. Subscription-only execution forbids provider billing; an observed billed charge holds further work. Operating costs remain explicitly unknown.
139
+ The suite also requires `operatingConstraints.maxMeanTokens` and
140
+ `operatingConstraints.maxMeanDurationMs`. Only candidates with a fully matched
141
+ final-test cohort, known reported tokens, and measured end-to-end cell latency
142
+ including queueing can enter Eval's quality/token/latency frontier. Activation
143
+ requires those ceilings as well as the independent quality decision. Setting
144
+ `operatingConstraints.requireKnownOperatingCost` to true holds while environment
145
+ and subscription allocation costs are unknown; the report does not claim a
146
+ dollar frontier. Evaluator bytes are checked before and after every score and
147
+ again before the decision is retained.
148
+
149
+ Activation requires Runtime's independent final-test promotion, unchanged
150
+ evaluator dependencies, the exact measured candidate bytes and the original
151
+ baseline. A hold leaves the graph unchanged. Subsequent runs are graded into
152
+ separate observation records. The selected change is one authored inline
153
+ `prompt.systemPrompt`, otherwise `prompt.appendSystemPrompt`, compiled separately
154
+ for each task. An unchanged candidate preserves the original source bytes.
155
+ Full-profile, structure, code and Knowledge candidate generation stay with their
156
+ existing owners and are not activated by this command.
157
+
158
+ The optional suite `optimizer` defaults to `{ "kind": "native" }`. Set `kind` to
159
+ `gepa` and choose `recipe.kind: "engine"`, with `recipe.run.maxEvaluations`, or
160
+ `recipe.kind: "omni"`, with `recipe.explore` runs and `recipe.continueWith`.
161
+ Both use Runtime's official GEPA implementation, the same retained proposal runs,
162
+ independent grader and campaign pool. Supply the request, response, candidate,
163
+ evidence and model-request bounds declared in the [maintained optimizer schema](src/lib/graph-optimizer.ts).
164
+ Campaign work is serialized by the retained-attempt contract; larger engine/Omni worker counts refuse.
165
+ GEPA resume requires an explicit compatible-state policy and `trustLocalState`;
166
+ Omni requires `resume: "never"`. These adapters accept ordered text reflection
167
+ requests through an explicit native JSON-content protocol. They refuse tools,
168
+ images and unsupported model controls before dispatch. The legacy js-issues replay remains available
169
+ without `--suite`; it matches seats across arms and accepts total replay
170
+ `--max-tokens`, `--max-iterations` and `--deadline-ms` ceilings.
171
+
172
+ Native graph nodes can use Knowledge through Runtime's existing authenticated
173
+ coordination MCP. Declare only the tools the node needs in `profile.tools`:
174
+ `agent_runtime_coordination_knowledge_search`, `..._knowledge_read`,
175
+ `..._knowledge_record`, and `..._knowledge_resolve`. Declare a native graph input
176
+ `knowledge: { default: null }` to make the binding optional. Only `null` or an omitted binding disables Knowledge; every other value must pass the existing strict local/Hub binding schema. The local binding
177
+ comes from `tangle --json graph knowledge bind ./knowledge-store`; supply that
178
+ JSON as `--param knowledge=<JSON>`. It pins the curated store's exact hash, reads
179
+ that view, and writes proposed changes only to private run stores. A changed
180
+ curated hash refuses retrieval rather than silently selecting new knowledge.
181
+
182
+ Hosted bindings use `{"kind":"hub","references":[{"sourceId":"...","generation":"kg_..."}]}`.
183
+ The workflow owner materializes those exact references for the admitted native
184
+ node's sandbox and uses Knowledge's existing live credential, attachment and
185
+ connection checks. Each returned lexical retrieval retains a Knowledge receipt,
186
+ canonical visibility, source identities, generation, query and trusted Runtime
187
+ run/node/profile identity before delivering the result. Hosted vector retrieval
188
+ with graph receipts refuses before embedding calls until that spending has an
189
+ enforced budget. Hosted `knowledge_record` retains an isolated, unevaluated
190
+ proposal artifact and leaves published generations unchanged.
191
+
192
+ An independently measured local candidate reference from the maintained Knowledge
193
+ improvement API can be applied with `graph knowledge promote <binding.json>
194
+ <candidate.json>` or restored with `graph knowledge restore`. Knowledge verifies
195
+ the exact baseline, candidate and evaluation identities and performs its durable
196
+ transaction. The command returns the next exact binding. Hub generation
197
+ activation through this file-backed candidate API is explicitly unsupported;
198
+ Hub source publication remains with its existing owner. Retrieval and a proposed
199
+ write do not establish an improvement.
200
+
90
201
  `--cloud` saves the same source through Hub Workflows and returns its run ID
91
- immediately. The Workflow API owns execution, retained evidence and recovery;
92
- closing the CLI leaves the cloud run running. `inspect` reads that same run and
93
- prints the shared workflow viewer URL outside JSON mode.
202
+ immediately. Later runs reuse that named deployment without changing its triggers.
203
+ Changed source or bindings require `graph apply` first. The Workflow API owns
204
+ execution, retained evidence and recovery; closing the CLI leaves the cloud run
205
+ running. `inspect` reads that same run and prints the shared workflow viewer URL
206
+ outside JSON mode.
207
+
208
+ Publish without starting a run, then run the exact deployed revision:
209
+
210
+ ```bash
211
+ tangle graph apply haiku-review --deploy ./deploy.yaml --dry-run --json
212
+ tangle graph apply haiku-review --deploy ./deploy.yaml --json
213
+ tangle graph run haiku-review --workflow <workflow-id> --json
214
+ tangle workflows get <workflow-id>
215
+ ```
216
+
217
+ Deployment settings use the existing Hub Workflow graph deployment contract,
218
+ separate from the portable graph. `--param` and `--seat` override the file's
219
+ defaults. The platform validates trigger availability, connections and schedules.
220
+ For example:
221
+
222
+ ```yaml
223
+ name: weekly-audit
224
+ enabled: true
225
+ on:
226
+ - schedule:
227
+ cron: "0 8 * * 1"
228
+ timezone: America/Los_Angeles
229
+ - webhook: {}
230
+ ```
231
+
232
+ A provider event can instead declare
233
+ `provider_event: { connection: github, event: issues, actions: [opened], repo: example/project }`.
234
+ The graph must consume that event's `trigger` data; declaring a subscription does
235
+ not map an event to a static graph parameter. Provider action tools do not imply
236
+ that a deployment can receive its events.
237
+
238
+ An API key's expiry also bounds any schedule it authors. Set `schedule.until`
239
+ within that grant, or use an owner credential whose authority covers the intended
240
+ schedule. Dry-run reports `schedule_outlives_grant` before publication when it does
241
+ not; a browser login's short-lived CLI key does not grant indefinite recurrence.
242
+
243
+ `apply` matches one workflow by name, or `--workflow <id>` selects it explicitly.
244
+ An unchanged resolved graph and deployment create no revision for manual, webhook
245
+ or scheduled jobs. Provider-event apply refreshes the owner's ingress bindings,
246
+ including after a reconnect. First publication reserves
247
+ one paused, manual graph atomically, then applies the requested revision and its
248
+ triggers. A failed first update leaves that reservation paused and retryable. Concurrent
249
+ different updates conflict instead of overwriting one another. Use distinct names
250
+ for different deployed jobs. Deployment settings contain references and policy,
251
+ never credential values.
252
+
253
+ After configuring a webhook, explicitly mint its bearer with
254
+ `tangle graph webhook <workflow-id> --rotate`. The JSON response reveals the new
255
+ bearer once and retires the previous one; keep it in the receiver's secret store.
256
+ It is not written into graph source or deployment settings.
257
+
258
+ For local recurring work, an OS scheduler or webhook receiver owns the trigger
259
+ and calls the same durable local executor:
260
+
261
+ ```bash
262
+ tangle graph dispatch weekly-audit --event ./event.json --delivery schedule:2026-11-16T08:00:00-08:00 --json
263
+ ```
264
+
265
+ The event file is a JSON object visible as `trigger` in the graph. Use the same
266
+ delivery id for retries and the nominal scheduled occurrence, not the retry time.
267
+ The private `~/.tangle/deliveries` record binds that delivery to one Runtime run,
268
+ source, workspace, event and parameters. Retries resume that run. A completed
269
+ result replays without starting another native execution. Changed event or graph
270
+ bytes refuse the reused id; concurrent delivery attempts refuse while the owner
271
+ holds the delivery lock. A failed terminal run requires inspection and an explicit
272
+ new delivery. Local dispatch does not install a daemon or expose a public webhook;
273
+ the scheduler/receiver must remain running and manage provider authentication.
94
274
 
95
275
  `--resume` restores saved inputs and rejects changed source, parameters, seat
96
276
  settings or placement. A completed winner returns its retained result without
@@ -360,3 +540,18 @@ the credential's verified attribution and pins it server-side. Reads
360
540
  (`sandbox list`, `sandbox get`) surface it as the read-only `compliance:
361
541
  { hipaa: true }` echo field — absent means the platform made no claim, and
362
542
  `hipaa: false` never appears.
543
+
544
+ A graph deployment can bind an owner Sandbox template or snapshot without changing the graph source:
545
+
546
+ ```yaml
547
+ name: crm-audit
548
+ mcpPolicy:
549
+ allowedMcpHosts: [crm.example.com]
550
+ sandbox:
551
+ templateId: my-owner-template
552
+ secrets: [CRM_TOKEN]
553
+ ```
554
+
555
+ `secrets` names entries already stored in the owner's Sandbox vault. A profile's MCP `secret-ref.key` uses that same name; the private sidecar materializer resolves its value. Apply and cloud run never read or upload local environment values. Missing or unselected refs fail before native dispatch. Select `publicTemplateId` with optional `publicTemplateVersionId`, or both `fromSandboxId` and `fromSnapshot`, instead of `templateId`. Sandbox checks source ownership and capabilities through its normal creation API. A recovered Runtime checkpoint takes precedence over the deployment's initial source.
556
+
557
+ An isolated check opts into the same Sandbox binding with `environment: deployment`; its shell uses the restored `/home/agent`. Built-in `universal` and `agent-container` checks keep their existing placement. Check secrets still use the graph repository credential contract. Custom scripts needing other credentials run through the admitted native Sandbox or MCP tool path; isolated checks receive no owner vault grants.
package/SKILL.md CHANGED
@@ -73,8 +73,37 @@ tangle graph run reviewed-change
73
73
  tangle --json graph run reviewed-change --cloud
74
74
  tangle --json graph inspect <run-id>
75
75
  tangle graph run reviewed-change --resume <run-id>
76
+ # Custom MCP host admission and private local env binding:
77
+ tangle graph run reviewed-change --mcp-policy host-policy.json --mcp-secret tool-account=TOOL_ACCOUNT_TOKEN
76
78
  ```
77
79
 
80
+ Custom MCP admission comes from the host policy file. Local `--mcp-secret key=ENV_NAME`
81
+ binds a declared AgentProfile secret reference without recording the environment name
82
+ or value in graph identities. Cloud runs refuse this local flag and use their own
83
+ owner-vault bindings. Echoed values are redacted before local process retention and
84
+ native transcript copies. A transformed native capture reports incomplete original
85
+ bytes and the source hash; the vendor source file stays unchanged.
86
+
87
+ For recurring or provider-driven work, apply the captured deployment first and
88
+ inspect its returned workflow ID/revision. Run that workflow explicitly; inspect
89
+ the returned run ID and retained artifacts before reporting success. The
90
+ [Graph factories guide](README.md#graph-factories) owns deployment bindings,
91
+ cron/webhook/provider triggers, local event dispatch, and evaluation suite setup.
92
+
93
+ ```bash
94
+ tangle --json graph apply reviewed-change --deploy ./deploy.yaml
95
+ tangle --json graph run reviewed-change --workflow <workflow-id>
96
+ tangle --json graph inspect <run-id> --artifacts
97
+ tangle --json graph inspect <run-id> --artifact <node/path> --out ./retained.log
98
+ ```
99
+
100
+ Use `graph dataset` to retain admitted attempts, including interrupted or
101
+ unavailable ones. Select independent task units and train/dev/test partitions
102
+ before `graph improve --suite`; inspect the exact promotion or hold result before
103
+ `graph activate`, then use `graph observe` on subsequent work. Process completion
104
+ alone is not a quality label. For Knowledge tools and exact bindings, read the
105
+ same guide before configuring node tool permissions.
106
+
78
107
  Cloud dispatch returns immediately and the Workflow API owns the same run after
79
108
  CLI disconnect. Resume preserves recorded source and execution settings. A
80
109
  completed winner replays retained output; running cloud work attaches by read,
@@ -0,0 +1 @@
1
+ import{createHash as e}from"node:crypto";import{constants as t}from"node:fs";import{isAbsolute as n,join as r,relative as i}from"node:path";import{z as a}from"zod";import{open as o,opendir as s,realpath as c}from"node:fs/promises";import*as l from"@tangle-network/agent-runtime/kernel";import{CODEX_HOME_RULE as u,STORES as d,claudeCodeRefForFile as f,codexRefForFile as p,readSessionInput as m,storeGlob as h,withinPath as g}from"@tangle-network/harness-sessions";const _=a.object({harness:a.enum([`codex`,`claude-code`]),root:a.string().refine(n),basis:a.literal(`host-jail`),nativeSessionId:a.string().min(1),runId:a.string().min(1),requestDigest:a.string().regex(/^sha256:[a-f0-9]{64}$/)}),v=a.object({externalId:a.string(),internalId:a.string(),backend:a.enum([`codex`,`claude-code`]),cwd:a.string(),metadata:a.object({effective_native_store:_,agent_profile_binding:a.object({effectiveProfileDigest:a.string()})})});function y(){let e=new Map;return{observe(t){e.set(`${t.runId}:${t.requestDigest}`,t)},close(){e.clear()},redact(t,n){for(let n of t.runs){let r=e.get(`${n.runId}:${n.requestDigest}`);if(!r||r.sessionId!==t.sessionId||r.profileDigest!==t.profileDigest||r.cwd!==t.cwd)throw Error(`Exact native execution has no trusted redaction authority`)}if(!t.runs.length)throw Error(`Native redaction requires an exact execution binding`);let r=n;for(let n of e.values())n.sessionId===t.sessionId&&n.profileDigest===t.profileDigest&&n.cwd===t.cwd&&(r=n.redact(r));return r}}}function b(e,t){if(e===`codex`)return p(t);let n=t.split(`/`),r=n.indexOf(`subagents`,3);return f(t,r>0?n[r-1]??null:null)}async function x(e,t,n){let a=[],o=d[`claude-code.projects-jsonl`],f=r(t,...o.root.split(`/`).slice(1)),p=e===`codex`?u.sessionDirs.map(e=>r(t,e)):[f],m=e===`codex`?[h(u.rollout)]:o.files.map(e=>h(e)),_=0;for(;p.length;){n.throwIfAborted();let o=p.shift();if(o===void 0)break;let u;try{u=await c(o)}catch(e){if(e.code===`ENOENT`)continue;throw e}if(!g(u,t))throw Error(`Native inventory escaped its attested store`);let d=await s(u);for await(let o of d){if(n.throwIfAborted(),++_>l.HARNESS_TRANSCRIPT_READ_LIMITS.maxFiles)throw Error(`Native inventory exceeds the capture bound`);let s=r(d.path,o.name);o.isDirectory()?p.push(s):o.isFile()&&m.some(t=>t.test(e===`codex`?o.name:i(f,s)))&&a.push({path:i(t,s),nativeSessionId:b(e,i(t,s)).nativeSessionId})}}return a}function S(n){return async i=>{if(![`codex`,`claude-code`].includes(i.harness))return{status:`unavailable`,reason:`unknown-harness`,skipped:[{path:i.harness,reason:`Native transcript capture is not configured for this harness`}]};let s=await fetch(`${n.bridgeUrl}/v1/sessions?session_id=${encodeURIComponent(i.sessionId)}&backend=${i.harness}`,{headers:{authorization:`Bearer ${n.bridgeBearer}`},signal:i.signal});if(!s.ok)throw Error(`Bridge session lookup failed (HTTP ${s.status})`);let u=a.object({data:a.tuple([v])}).parse(await s.json()).data[0],d=u.metadata.effective_native_store,f=await c(d.root);if(u.backend!==i.harness||d.harness!==i.harness||u.externalId!==i.sessionId||u.internalId!==d.nativeSessionId||u.cwd!==n.cwd||i.cwd!==n.cwd||u.metadata.agent_profile_binding.effectiveProfileDigest!==i.profileDigest||f!==d.root||!g(f,r(n.cwd,`.agent-home`))||!i.runs.some(e=>e.runId===d.runId&&e.requestDigest===d.requestDigest))throw Error(`Bridge native binding does not match this execution`);let p=[],h=[...new Set(n.privateMcpSecrets?.()??[])].flatMap(e=>[e,JSON.stringify(e).slice(1,-1)]).filter(Boolean).sort((e,t)=>t.length-e.length),_=await l.captureBoundHarnessTranscript({harness:i.harness,binding:{kind:`bridge`,sessionId:i.sessionId,nativeSessionId:d.nativeSessionId,profileDigest:i.profileDigest,runs:i.runs,...i.node===void 0?{}:{node:i.node}},nativeSessionId:d.nativeSessionId,files:await x(i.harness,f,i.signal),signal:i.signal,parse:(e,t)=>m(i.harness,{text:e},{...b(i.harness,t.path),label:t.path},{corruption:`strict`}),read:async(a,s)=>{let u=await c(r(f,a.path));if(!g(u,f))throw Error(`Native session escaped its attested store`);let d=await o(u,t.O_RDONLY|t.O_NOFOLLOW);try{let t=await d.stat();if(!t.isFile()||t.size>l.HARNESS_TRANSCRIPT_READ_LIMITS.maxFileBytes)throw Error(`Native session is not a bounded regular file`);s?.throwIfAborted();let r=await d.readFile();if(s?.throwIfAborted(),!n.redact)throw Error(`The native host did not supply private redaction authority`);let o=n.redact(i,r),c=new TextDecoder(`utf-8`,{fatal:!0}).decode(o);for(let e of h)c=c.split(e).join(`[redacted:MCP]`);let u=Buffer.from(c,`utf8`);return u.equals(r)||p.push({path:a.path,reason:`Original bytes withheld for private MCP credential redaction; source sha256:${e(`sha256`).update(r).digest(`hex`)}; retained copy is redacted`}),u}finally{await d.close()}}});return _.status!==`captured`||!p.length?_:{..._,artifact:{..._.artifact,skipped:[..._.artifact.skipped,...p]},skippedCount:_.skippedCount+p.length,coverageComplete:!1,missing:[`private-mcp-secret-original-bytes`]}}}const C=async(e,t)=>{if(![`codex`,`claude-code`].includes(e.harness)||e.binding?.kind!==`bridge`)throw Error(`Native transcript reader is not configured for this capture`);return(await l.readBoundHarnessSessions({nativeSessionId:e.binding.nativeSessionId,files:e.files.map(t=>({path:t.path,nativeSessionId:b(e.harness,t.path).nativeSessionId,byteLength:t.bytes})),read:async t=>{let n=e.files.find(e=>e.path===t.path);if(!n)throw Error(`Retained native file is absent`);return Buffer.from(n.content,`utf8`)},parse:(t,n)=>m(e.harness,{text:t},{...b(e.harness,n.path),label:n.path},{corruption:`strict`}),signal:t})).sessions};export{S as graphNativeCapture,y as graphNativeRedaction,C as readGraphSessions};