@tangle-network/agent-profile-materialize 1.1.6 → 1.1.8

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.
Files changed (95) hide show
  1. package/dist/index.d.ts +1226 -29
  2. package/dist/index.js +4987 -23
  3. package/package.json +7 -5
  4. package/dist/candidate-types.d.ts +0 -36
  5. package/dist/candidate-types.js +0 -1
  6. package/dist/candidate.d.ts +0 -9
  7. package/dist/candidate.js +0 -283
  8. package/dist/commands.d.ts +0 -2
  9. package/dist/commands.js +0 -32
  10. package/dist/control-maps.d.ts +0 -58
  11. package/dist/control-maps.js +0 -277
  12. package/dist/execution-controls.d.ts +0 -5
  13. package/dist/execution-controls.js +0 -199
  14. package/dist/harness-prompt.d.ts +0 -22
  15. package/dist/harness-prompt.js +0 -64
  16. package/dist/harness.d.ts +0 -131
  17. package/dist/harness.js +0 -416
  18. package/dist/hooks.d.ts +0 -6
  19. package/dist/hooks.js +0 -250
  20. package/dist/managed-workspace-bind.d.ts +0 -4
  21. package/dist/managed-workspace-bind.js +0 -112
  22. package/dist/managed-workspace-stage.d.ts +0 -25
  23. package/dist/managed-workspace-stage.js +0 -199
  24. package/dist/managed-workspace-types.d.ts +0 -38
  25. package/dist/managed-workspace-types.js +0 -1
  26. package/dist/managed-workspace.d.ts +0 -37
  27. package/dist/managed-workspace.js +0 -290
  28. package/dist/mcp-config-ownership.d.ts +0 -13
  29. package/dist/mcp-config-ownership.js +0 -79
  30. package/dist/mcp-opencode.d.ts +0 -25
  31. package/dist/mcp-opencode.js +0 -52
  32. package/dist/mcp-timeouts.d.ts +0 -7
  33. package/dist/mcp-timeouts.js +0 -48
  34. package/dist/mcp.d.ts +0 -4
  35. package/dist/mcp.js +0 -246
  36. package/dist/model-id.d.ts +0 -55
  37. package/dist/model-id.js +0 -67
  38. package/dist/pi-models-config.d.ts +0 -32
  39. package/dist/pi-models-config.js +0 -65
  40. package/dist/plan-application.d.ts +0 -10
  41. package/dist/plan-application.js +0 -190
  42. package/dist/plan-digest.d.ts +0 -18
  43. package/dist/plan-digest.js +0 -116
  44. package/dist/plan-json.d.ts +0 -13
  45. package/dist/plan-json.js +0 -91
  46. package/dist/plan-normalize.d.ts +0 -12
  47. package/dist/plan-normalize.js +0 -168
  48. package/dist/plan-prompt.d.ts +0 -38
  49. package/dist/plan-prompt.js +0 -49
  50. package/dist/plan-support.d.ts +0 -9
  51. package/dist/plan-support.js +0 -22
  52. package/dist/plan-types.d.ts +0 -341
  53. package/dist/plan-types.js +0 -105
  54. package/dist/prime-agent-dir.d.ts +0 -64
  55. package/dist/prime-agent-dir.js +0 -173
  56. package/dist/prime-fork.d.ts +0 -155
  57. package/dist/prime-fork.js +0 -262
  58. package/dist/prime-profile.d.ts +0 -88
  59. package/dist/prime-profile.js +0 -297
  60. package/dist/profile-bundle-cache.d.ts +0 -37
  61. package/dist/profile-bundle-cache.js +0 -320
  62. package/dist/profile-bundle-key.d.ts +0 -69
  63. package/dist/profile-bundle-key.js +0 -62
  64. package/dist/profile-bundle-lru.d.ts +0 -56
  65. package/dist/profile-bundle-lru.js +0 -220
  66. package/dist/profile-materializer.d.ts +0 -24
  67. package/dist/profile-materializer.js +0 -114
  68. package/dist/profile-plan.d.ts +0 -16
  69. package/dist/profile-plan.js +0 -90
  70. package/dist/profile-prompt.d.ts +0 -4
  71. package/dist/profile-prompt.js +0 -107
  72. package/dist/profile-support.d.ts +0 -8
  73. package/dist/profile-support.js +0 -6
  74. package/dist/resource-lowering.d.ts +0 -6
  75. package/dist/resource-lowering.js +0 -103
  76. package/dist/resource-resolution.d.ts +0 -27
  77. package/dist/resource-resolution.js +0 -265
  78. package/dist/secret-concurrent-revision.d.ts +0 -30
  79. package/dist/secret-concurrent-revision.js +0 -291
  80. package/dist/secret-session-view.d.ts +0 -36
  81. package/dist/secret-session-view.js +0 -179
  82. package/dist/subagents.d.ts +0 -6
  83. package/dist/subagents.js +0 -137
  84. package/dist/tool-bin-path.d.ts +0 -23
  85. package/dist/tool-bin-path.js +0 -61
  86. package/dist/workspace-apply-files.d.ts +0 -57
  87. package/dist/workspace-apply-files.js +0 -193
  88. package/dist/workspace-apply-publish.d.ts +0 -22
  89. package/dist/workspace-apply-publish.js +0 -178
  90. package/dist/workspace-apply.d.ts +0 -11
  91. package/dist/workspace-apply.js +0 -124
  92. package/dist/workspace-files.d.ts +0 -8
  93. package/dist/workspace-files.js +0 -46
  94. package/dist/workspace-launch.d.ts +0 -3
  95. package/dist/workspace-launch.js +0 -13
package/dist/index.d.ts CHANGED
@@ -1,29 +1,1226 @@
1
- export { applyAgentCandidateWorkspacePlan, materializeCandidateProfile, } from "./candidate.js";
2
- export type { AgentCandidateWorkspacePlan, AgentCandidateWorkspacePlanReceipt, ApplyAgentCandidateWorkspacePlanOptions, MaterializeCandidateProfileOptions, } from "./candidate-types.js";
3
- export { OPENCODE_NATIVE_TOOL_IDS, openCodeNativeToolId, } from "./control-maps.js";
4
- export type { HarnessId } from "./harness.js";
5
- export { HARNESS_SKILL_DIRS, harnessAutoLoadsAgentContextFile, isMaterializerHarness, MATERIALIZER_CONTEXT_PATHS, MATERIALIZER_HARNESSES, markMaterializerContextFile, skillDirForHarness, } from "./harness.js";
6
- export * from "./harness-prompt.js";
7
- export { type ConcurrentProfileRevision, ensurePublicConcurrentProfileRoots, type ManagedWorkspaceFileDigest, type ManagedWorkspaceManifest, preparePublicConcurrentProfileRevision, } from "./managed-workspace.js";
8
- export { isMaterializerMcpConfig } from "./mcp-config-ownership.js";
9
- export { type OpenCodeMcpConfig, openCodeMcpConfig } from "./mcp-opencode.js";
10
- export * from "./model-id.js";
11
- export { buildPiModelsConfig, buildPiModelsConfigFile, PI_MODELS_CONFIG_PATH, type PiModelsConfigFile, type PiModelsConfigInput, type PiRuntimePaths, resolvePiRuntimePaths, } from "./pi-models-config.js";
12
- export { applyWorkspacePlan, applyWorkspacePlanWithSecretProvider, } from "./plan-application.js";
13
- export { agentCandidateProfilePlanMaterial, canonicalizeAgentCandidateProfilePlan, captureAgentCandidateProfilePlan, hashWorkspacePlan, } from "./plan-digest.js";
14
- export { takeSystemPromptBinding } from "./plan-prompt.js";
15
- export { assertWorkspacePlanSupported, enforceWorkspacePlanSupport, } from "./plan-support.js";
16
- export type { ApplyWorkspacePlanOptions, BindableLaunchControl, ExecutorSystemPromptBinding, PlanFile, PlanFileRoot, PlanFileSecretSlot, PlanRequirement, SkippableDimension, Unsupported, WorkspacePlan, WorkspacePlanApplication, WorkspacePlanArgument, WorkspacePlanArgumentTemplate, WorkspacePlanConfigValue, WorkspacePlanReceipt, WorkspacePlanSecretSegment, WorkspacePlanSpawnInputs, WorkspacePlanSystemPromptBinding, WorkspacePlanWrittenFile, } from "./plan-types.js";
17
- export { BINDABLE_LAUNCH_CONTROLS, EXECUTOR_SYSTEM_PROMPT_BINDINGS, isSkippableDimension, SKIPPABLE_DIMENSIONS, WorkspacePlanCleanupError, } from "./plan-types.js";
18
- export { materializePrimeProfileControls, type PrimeMaterializeOptions, primeHarnessStatePath, prunePrimeProfileMaterial, seedPrimeProfileSubagents, writePrimeAgentFile, } from "./prime-agent-dir.js";
19
- export type { PrimeProfileErrorKind, PrimeThinkingLevel, } from "./prime-fork.js";
20
- export { matchPrimeKernelDeadMarker, PRIME_AGENT_DIR_ENV_VAR, PRIME_AGENT_DIR_ENV_VARS, PRIME_HARNESS_STATE_ENV_DENYLIST, PRIME_KERNEL_DEAD_MARKERS, PRIME_KERNEL_ENV_PASSTHROUGH, PRIME_MCP_UNSUPPORTED_REASON, PRIME_THINKING_LEVELS, PrimeHarnessStateError, PrimeProfileError, parsePrimeModelsJson, primeAgentDirEnv, primeApiKeyEnvNames, primeThinkingLevel, stripPrimeJsonComments, } from "./prime-fork.js";
21
- export type { PrimeProfileControls, PrimeProfileSkill, PrimeProfileSubagent, } from "./prime-profile.js";
22
- export { assertPrimeModelAgreement, hasPrimeProfileMaterial, primeProfileNeedsAgentDir, primeSubagentEntryId, readPrimeProfileControls, } from "./prime-profile.js";
23
- export * from "./profile-bundle-cache.js";
24
- export { executionControlConflict, materializeProfile, UNAVAILABLE_AGENT_PROFILE_SECRET_PROVIDER, } from "./profile-materializer.js";
25
- export type { ResolveAgentProfileResourcesOptions } from "./resource-resolution.js";
26
- export { normalizeSkillMd, resolveAgentProfileResources, } from "./resource-resolution.js";
27
- export { prepareSecretConcurrentProfileRevision } from "./secret-concurrent-revision.js";
28
- export * from "./secret-session-view.js";
29
- export * from "./tool-bin-path.js";
1
+ import { AgentCandidateConfigValue, AgentCandidateProfile, AgentCandidateProfileActivation, AgentCandidateProfileApplication, AgentCandidateProfilePlanEvidence, AgentCandidateProfilePlanMaterial, AgentProfile, AgentProfileConfigValue, AgentProfileFileMount, AgentProfileMcpServer, AgentProfileSecretProvider, AgentProfileSecretRef, AgentRuntimeAttachments, Sha256Digest } from "@tangle-network/agent-interface";
2
+
3
+ //#region src/harness.d.ts
4
+ declare const MATERIALIZER_HARNESSES: readonly ["claude-code", "nanoclaw", "codex", "opencode", "kimi-code", "pi", "prime", "gemini", "hermes", "openclaw"];
5
+ type HarnessId = (typeof MATERIALIZER_HARNESSES)[number];
6
+ declare function isMaterializerHarness(harness: string): harness is HarnessId;
7
+ /** Whether the shared materializer may place its context file in the harness agent directory. */
8
+ declare function harnessAutoLoadsAgentContextFile(harness: HarnessId): boolean;
9
+ /**
10
+ * The context files this package owns by MARKER rather than by name:
11
+ * `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `HERMES.md`.
12
+ *
13
+ * Each is a documented name a repository can already carry, so the name proves
14
+ * nothing. A generated one carries the line {@link markMaterializerContextFile}
15
+ * writes, and only that line lets the next materialization replace it.
16
+ *
17
+ * opencode's context file is absent because it is a RESERVED name this package
18
+ * invented, already owned by the name alone.
19
+ */
20
+ declare const MATERIALIZER_CONTEXT_PATHS: ReadonlySet<string>;
21
+ /**
22
+ * Mark one generated context file so the NEXT materialization can prove this
23
+ * package wrote the bytes it is about to replace.
24
+ *
25
+ * The marker is an HTML comment on line 1. CommonMark closes an HTML block at
26
+ * the line holding `-->`, so every instruction below it parses exactly as it
27
+ * did without the line, and the line itself states no instruction. It is one
28
+ * more line this package composes into a file it already composes: it goes on
29
+ * a context file, which carries `prompt.instructions`, and NEVER on a
30
+ * system-prompt REPLACEMENT, whose bytes are the caller's exact text
31
+ * (`.gemini/system.md`; `.codex/system-prompt.md` is a reserved name this
32
+ * package invented and needs no marker to be owned).
33
+ *
34
+ * It carries the digest of the generated body below it, which the subagent
35
+ * marker does not need. `CLAUDE.md` is claude-code's own memory file and the
36
+ * agent appends to it mid-session, so a bare marker would still sit on line 1
37
+ * of a file the agent has since rewritten. The digest tells which leading bytes
38
+ * are still this package's own: the next materialization replaces exactly
39
+ * those and keeps what the agent appended below them
40
+ * ({@link generatedContextAppendix}). The marker's wording is part of every
41
+ * marker already written into live workspaces, so it stays as it is.
42
+ *
43
+ * A reserved context path — opencode's invented instruction file — is returned
44
+ * unchanged: its NAME already proves the provenance, and nothing else may mount
45
+ * there.
46
+ */
47
+ declare function markMaterializerContextFile(relPath: string, content: string): string;
48
+ /**
49
+ * cwd-relative native skill dir per harness, or null if the harness has no
50
+ * cwd skill primitive (skills live in a user/global dir the workspace plan
51
+ * cannot reach). Public so consumers composing a profile can (a) render the
52
+ * exact path the platform will mount a skill at into their prompts instead
53
+ * of hardcoding `~/.claude/skills/...`, and (b) branch on skill support
54
+ * ahead of materialization instead of catching the materialize-time throw.
55
+ */
56
+ declare const HARNESS_SKILL_DIRS: Readonly<Record<HarnessId, string | null>>;
57
+ /**
58
+ * Resolve the cwd-relative directory `resources.skills` refs materialize
59
+ * into on `harness`. `null` means the harness cannot receive cwd skills, the
60
+ * same condition that surfaces as an `unsupported`
61
+ * "skills" entry (and an {@link assertWorkspacePlanSupported} throw) at
62
+ * materialize time, exposed here as branchable data.
63
+ */
64
+ declare function skillDirForHarness(harness: HarnessId): string | null;
65
+ //#endregion
66
+ //#region src/plan-types.d.ts
67
+ /** The executor-owned root that receives a materialized file. */
68
+ type PlanFileRoot = "workspace" | "agent";
69
+ interface PlanFile {
70
+ relPath: string;
71
+ content: string;
72
+ /** Defaults to the run workspace. `agent` is the harness's private agent directory. */
73
+ root?: PlanFileRoot;
74
+ /** chmod mode (e.g. 0o755 for hook scripts); default 0o644. */
75
+ mode?: number;
76
+ /**
77
+ * Provenance of this entry. `"generated"` = the materializer synthesized the
78
+ * content itself (native harness config, merged settings, lowered prompt/MCP/
79
+ * hooks/subagents). `"user"` = the exact bytes of a profile-declared resource
80
+ * ref (`resources.files`/`tools`/`agents`/`skills`/`commands`), passed through
81
+ * verbatim at the path the profile author chose.
82
+ *
83
+ * A consumer that needs to reinterpret a SPECIFIC generated file (e.g. parse
84
+ * `opencode.json` as the synthetic native config) MUST gate on
85
+ * `source === "generated"` at that relPath — matching by relPath alone cannot
86
+ * tell a harness-authored config apart from a user resource mount that
87
+ * happens to share the same conventional path, and treating arbitrary user
88
+ * content as trusted generated config is a fail-open bug, not a fallback.
89
+ *
90
+ * Optional: callers that hand-construct a {@link WorkspacePlan} directly for
91
+ * {@link applyWorkspacePlan} (tests, ad hoc writes) are not materializer
92
+ * output and have no provenance to report. `materializeProfile` always sets
93
+ * this on every file it emits.
94
+ */
95
+ source?: "user" | "generated";
96
+ /**
97
+ * Who owns the PATH — which decides whether an existing file there may be
98
+ * replaced.
99
+ *
100
+ * `"materializer"` = a path whose generated content is wholly this
101
+ * package's output: a name this package invented, the generated context file
102
+ * (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, `HERMES.md`), or `opencode.json`,
103
+ * which carries only the registrations generated from the profile. A file
104
+ * already there is this materializer's own output from an earlier application
105
+ * into the same workspace, and replacing it is how turn two of a resumed
106
+ * session — or the first turn of a branched one — gets the current profile
107
+ * instead of the previous one. Application replaces it only when the existing
108
+ * bytes prove that provenance — by the name for an invented path, by a marker
109
+ * line committing to the body digest for a context file, by the content for
110
+ * `opencode.json`.
111
+ *
112
+ * `"shared"` (the default, and every other file) = a path the user or the
113
+ * harness also owns. `.gemini/system.md` is a documented, user-authorable
114
+ * name whose content this package cannot tell from its own, and so is a
115
+ * context file mounted as an explicit profile resource rather than generated.
116
+ * An existing file there may be the caller's own work, so it is never
117
+ * replaced.
118
+ *
119
+ * Optional because hand-constructed plans have no path provenance to report;
120
+ * absent reads as `"shared"`, the safe answer.
121
+ */
122
+ ownership?: "materializer" | "shared";
123
+ /**
124
+ * Secret leaves in a generated JSON document. `content` contains `null` at
125
+ * each path until the private executor resolves the named reference. The
126
+ * public plan, its digest, and its receipt retain only these references.
127
+ */
128
+ secretSlots?: PlanFileSecretSlot[];
129
+ }
130
+ interface PlanFileSecretSlot {
131
+ path: Array<string | number>;
132
+ ref: AgentProfileSecretRef;
133
+ }
134
+ interface WorkspacePlanSecretSegment {
135
+ kind: "secret";
136
+ ref: AgentProfileSecretRef;
137
+ /** Encoding applied after private resolution. */
138
+ encoding: "raw" | "json-string";
139
+ }
140
+ /** A launch argument whose private leaves are resolved immediately before spawn. */
141
+ interface WorkspacePlanArgumentTemplate {
142
+ kind: "workspace-plan-argument-template";
143
+ segments: Array<string | WorkspacePlanSecretSegment>;
144
+ }
145
+ type WorkspacePlanArgument = string | WorkspacePlanArgumentTemplate;
146
+ /** Public bytes stay strings; secret references stay opaque until application. */
147
+ type WorkspacePlanConfigValue = string | AgentProfileSecretRef;
148
+ interface Unsupported {
149
+ dimension: "files" | "skills" | "mcp" | "hooks" | "subagents" | "commands" | "instructions" | "systemPrompt" | "appendSystemPrompt" | "connections" | "confidential" | "permissions" | "tools" | "modes" | "extensions";
150
+ reason: string;
151
+ }
152
+ /**
153
+ * The subset of {@link BINDABLE_LAUNCH_CONTROLS} the plan HANDS OVER rather than
154
+ * executes: controls a caller reaches only by composing the harness's own
155
+ * configuration, so no file, flag or env var the plan writes can touch them.
156
+ *
157
+ * - `opencode.agent-prompt` — opencode's `agent.<name>.prompt` config field,
158
+ * the one control that replaces its built-in provider prompt. It binds to a
159
+ * SINGLE agent, and the agent is chosen at launch. A caller that builds
160
+ * opencode's config itself and picks the agent there reads neither
161
+ * `plan.files` nor `plan.flags`, so for that one the plan names the control
162
+ * and hands over the text in {@link WorkspacePlan.systemPromptBinding}.
163
+ *
164
+ * Every other bindable control names a capability the plan still lowers itself
165
+ * once the caller has declared the plan's launch inputs really reach the spawn.
166
+ */
167
+ declare const EXECUTOR_SYSTEM_PROMPT_BINDINGS: readonly ["opencode.agent-prompt"];
168
+ type ExecutorSystemPromptBinding = (typeof EXECUTOR_SYSTEM_PROMPT_BINDINGS)[number];
169
+ /**
170
+ * A system-prompt intent handed to the launcher that declared it owns the
171
+ * control, instead of being lowered into the workspace.
172
+ *
173
+ * Distinct from {@link WorkspacePlan.systemPrompt} — a launch ARGUMENT the
174
+ * executor hands to a harness flag — and from the file/flag/env lowerings the
175
+ * plan performs on its own. This names the exact control that must receive the
176
+ * text and which of the two intents it is, so the launcher cannot apply it to
177
+ * the wrong channel. Never written into an additive channel and never dropped:
178
+ * a caller that has not declared it owns `control` gets the plan's own lowering
179
+ * (or a refusal where the harness has no control at all) instead of this field.
180
+ */
181
+ interface WorkspacePlanSystemPromptBinding {
182
+ /** Which of the two prompt intents this is — never inferred from presence. */
183
+ intent: "replace";
184
+ /** The exact launcher control that must receive `systemPrompt`. */
185
+ control: ExecutorSystemPromptBinding;
186
+ /** Exact text the control receives. */
187
+ systemPrompt: string;
188
+ }
189
+ /** One file applied by a plan, with the executor root kept explicit. */
190
+ interface WorkspacePlanWrittenFile {
191
+ root: PlanFileRoot;
192
+ relPath: string;
193
+ }
194
+ /**
195
+ * The dimensions `materializeProfile`'s `skip` option honors.
196
+ *
197
+ * Every other dimension is materialized unconditionally: generated plan files are pushed through
198
+ * a single site that carries no dimension tag, so there is nothing to gate them on. Naming the
199
+ * honored set keeps `skip: ["hooks"]` a loud rejection instead of a silent no-op.
200
+ */
201
+ declare const SKIPPABLE_DIMENSIONS: readonly ["mcp", "extensions"];
202
+ type SkippableDimension = (typeof SKIPPABLE_DIMENSIONS)[number];
203
+ declare function isSkippableDimension(value: string): value is SkippableDimension;
204
+ /**
205
+ * Launcher controls an executor can declare it OWNS via `materializeProfile`'s
206
+ * `binds` option.
207
+ *
208
+ * Some harness controls live outside any workspace: opencode's exact
209
+ * system-prompt replacement (`agent.<name>.prompt`) binds to the ONE agent
210
+ * whoever starts the process selects, which a plan-forwarding executor cannot
211
+ * guarantee — so the plan refuses the intent (harnessSystemPromptIntents in
212
+ * @tangle-network/agent-interface answers `replace: false` for opencode).
213
+ *
214
+ * The replacement declarations describe the executor shapes that can reach it;
215
+ * each gets the lowering it can apply. Codex launchers separately declare
216
+ * `codex.developer-instructions` to consume ordinary instructions as additive
217
+ * context; undeclared callers retain workspace files:
218
+ *
219
+ * - `systemPrompt` — the executor applies the plan's launch flags to the
220
+ * spawn it owns, so the plan writes the generated `mode: primary` agent and
221
+ * selects it with `--agent`.
222
+ * - `opencode.agent-prompt` — the executor composes opencode's own config and
223
+ * picks the agent there, reading neither plan files nor plan flags, so the
224
+ * plan hands the text over in {@link WorkspacePlan.systemPromptBinding}
225
+ * instead of writing a workspace agent that would never be selected.
226
+ *
227
+ * The replacement declarations are mutually exclusive: declaring both is a
228
+ * caller bug, not a broader capability.
229
+ */
230
+ declare const BINDABLE_LAUNCH_CONTROLS: readonly ["systemPrompt", "codex.developer-instructions", "opencode.agent-prompt"];
231
+ type BindableLaunchControl = (typeof BINDABLE_LAUNCH_CONTROLS)[number];
232
+ /** The plan a caller writes into the run cwd, then applies to the spawn. */
233
+ interface WorkspacePlan {
234
+ harness: HarnessId;
235
+ /** Files to write relative to the run workspace (cwd). */
236
+ files: PlanFile[];
237
+ /** Env vars to set on the spawned process (for harnesses needing them). */
238
+ env: Record<string, WorkspacePlanConfigValue>;
239
+ /** Extra CLI flags to pass (e.g. claude --mcp-config <path>). */
240
+ flags: WorkspacePlanArgument[];
241
+ /**
242
+ * Exact text that REPLACES the harness's own system prompt, for harnesses
243
+ * whose replacement control takes it as a launch argument the executor
244
+ * supplies (claude-code `--system-prompt`, pi `--system-prompt`).
245
+ *
246
+ * Absent does NOT mean "no replacement was requested": a harness whose
247
+ * control reads a file (codex, gemini) carries the replacement in
248
+ * {@link WorkspacePlan.files} plus a flag or env var instead. Present means
249
+ * the executor MUST bind it to that harness's replacement control — never to
250
+ * an additive one, which would leave the built-in prompt in force.
251
+ */
252
+ systemPrompt?: string;
253
+ /**
254
+ * Text added to the harness context; its own system prompt stays intact.
255
+ *
256
+ * Claude Code and Pi bind their additive system-prompt control. Codex binds
257
+ * ordinary profile instructions to developer_instructions, composed once
258
+ * with host context; this is not a privileged system-prompt append. Authored
259
+ * Codex appendSystemPrompt remains unsupported. Never fold this into an exact
260
+ * system-prompt replacement, which carries the caller's unchanged bytes.
261
+ */
262
+ appendSystemPrompt?: string;
263
+ /**
264
+ * A prompt intent no workspace file, flag, or env var can execute, addressed
265
+ * to the launcher control that can — see
266
+ * {@link WorkspacePlanSystemPromptBinding}.
267
+ *
268
+ * Present ONLY when the caller declared it owns the named control, so a plan
269
+ * built by a caller that forwards it to someone else's launcher never carries
270
+ * one; that caller gets the intent in {@link WorkspacePlan.unsupported}
271
+ * instead. Whoever reads it must bind it or throw — {@link
272
+ * takeSystemPromptBinding} does both.
273
+ */
274
+ systemPromptBinding?: WorkspacePlanSystemPromptBinding;
275
+ /** Dimensions requested but with NO cwd path on this harness — fail-closed record. */
276
+ unsupported: Unsupported[];
277
+ /**
278
+ * Prerequisites the workspace files CANNOT establish on their own.
279
+ *
280
+ * A plan is a set of files, an env map, and flags. Some harness capabilities need more than
281
+ * that to actually function: pi's MCP support is not built in, it arrives from an extension
282
+ * that must be installed into the harness's own package directory and permitted to load. No
283
+ * file written into a run workspace can make either true.
284
+ *
285
+ * Writing the config anyway and hoping is the failure this field exists to prevent: the
286
+ * harness starts, silently has no MCP, and the agent runs without the tools it was configured
287
+ * with while nothing reports a problem. So the plan states the requirement and the executor —
288
+ * which knows where its harness is installed and how it spawns — verifies or refuses it.
289
+ *
290
+ * Optional because this is an additive field on a published type: a plan built before it
291
+ * existed, or by a caller that does not construct one, is still a valid plan with no
292
+ * prerequisites. Every plan this package builds sets it.
293
+ */
294
+ requires?: PlanRequirement[];
295
+ }
296
+ /**
297
+ * One prerequisite a {@link WorkspacePlan} depends on but cannot create.
298
+ *
299
+ * Declarative on purpose: this package builds plans and never probes a filesystem, spawns a
300
+ * process, or reaches the network. The executor holds that context and does the checking.
301
+ */
302
+ interface PlanRequirement {
303
+ /** The only kind so far: a harness extension/plugin that must be loaded for a dimension to work. */
304
+ kind: "harness-extension";
305
+ /** Dimension that produced the requirement, so a refusal can name what will not work. */
306
+ dimension: Unsupported["dimension"];
307
+ /** Package spec in the harness's own vocabulary, e.g. `npm:pi-mcp-adapter`. */
308
+ id: string;
309
+ /** Why the plan needs it — goes verbatim into the executor's refusal message. */
310
+ reason: string;
311
+ /** The exact command that satisfies it, so a failure is actionable without a doc lookup. */
312
+ remedy: string;
313
+ }
314
+ /**
315
+ * Proof of the profile workspace inputs applied before a harness is spawned.
316
+ * `workspacePlanDigest` covers only the {@link WorkspacePlan}; it is not an
317
+ * execution-plan digest and does not attest unrelated files in `workspaceDir`.
318
+ */
319
+ interface WorkspacePlanReceipt {
320
+ workspacePlanDigest: string;
321
+ /** Public launch identity only; secret values never enter this receipt. */
322
+ env: Record<string, WorkspacePlanConfigValue>;
323
+ /** Public launch identity only; templates retain opaque secret references. */
324
+ flags: WorkspacePlanArgument[];
325
+ systemPrompt?: string;
326
+ appendSystemPrompt?: string;
327
+ /** The launcher-bound intent, so a receipt says which control owed the work. */
328
+ systemPromptBinding?: WorkspacePlanSystemPromptBinding;
329
+ unsupported: Unsupported[];
330
+ /**
331
+ * Workspace-root paths, for consumers that mount the workspace only.
332
+ * Agent-root files are available in `writtenFiles` and are never encoded as
333
+ * an `agent:` path because that spelling is legal in the workspace root.
334
+ */
335
+ written: string[];
336
+ /** Every applied file, including its executor-owned root. */
337
+ writtenFiles: WorkspacePlanWrittenFile[];
338
+ }
339
+ /** Private values handed directly to the provider spawn, never to receipts. */
340
+ interface WorkspacePlanSpawnInputs {
341
+ env: Record<string, string>;
342
+ flags: string[];
343
+ systemPrompt?: string;
344
+ appendSystemPrompt?: string;
345
+ /** Read it with {@link takeSystemPromptBinding}, which refuses a foreign control. */
346
+ systemPromptBinding?: WorkspacePlanSystemPromptBinding;
347
+ /**
348
+ * Absolute dirs of the profile's declared executable `reference/` tools in
349
+ * the immutable revision the launch runs from. The provider puts them on
350
+ * the launch PATH in place of the app's own tool dirs (bindLaunchToolBinDirs),
351
+ * so a profile names its CLI bare.
352
+ */
353
+ toolBinDirs?: string[];
354
+ }
355
+ /** Result of applying a public plan at the private executor boundary. */
356
+ interface WorkspacePlanApplication {
357
+ receipt: WorkspacePlanReceipt;
358
+ spawn: WorkspacePlanSpawnInputs;
359
+ /** Resolved generated files intentionally consumed in memory by the runtime. */
360
+ runtimeOnlyFiles: Record<string, string>;
361
+ }
362
+ /** The plan was applied, but one or more private staging files remain. */
363
+ declare class WorkspacePlanCleanupError extends AggregateError {
364
+ readonly receipt: WorkspacePlanReceipt;
365
+ readonly temporaryPaths: readonly string[];
366
+ constructor(errors: readonly unknown[], receipt: WorkspacePlanReceipt, temporaryPaths: readonly string[]);
367
+ }
368
+ interface ApplyWorkspacePlanOptions {
369
+ /** Plan files consumed in memory by the runtime and never persisted to cwd. */
370
+ runtimeOnlyFiles?: readonly string[];
371
+ /** Absolute private agent directory required by files whose root is `agent`. */
372
+ agentDir?: string;
373
+ /** Own newly written workspace files as the process that will read them. */
374
+ ownership?: {
375
+ uid: number;
376
+ gid: number;
377
+ };
378
+ /** Existing workspace paths are either exact idempotent inputs or forbidden. */
379
+ existingFiles?: "allow-identical" | "reject";
380
+ /**
381
+ * `workspacePlanDigest` of a plan a prior call already applied into this
382
+ * workspace. When it equals this plan's digest, application changes no file
383
+ * content. It can repair ownership on unchanged materializer-owned files.
384
+ * A file the agent edited or removed stays exactly as the agent left it.
385
+ * Env, flags, prompt intents, and the receipt are still produced. A different
386
+ * digest applies normally, so a changed plan still meets the existing-file
387
+ * refusal.
388
+ */
389
+ appliedPlanDigest?: string;
390
+ /**
391
+ * Write every JSON file secret slot as an `{env:NAME}` reference (OpenCode
392
+ * config substitution) and never its value, so file bytes and every digest
393
+ * over them stay identical when only a secret's value changes. The value
394
+ * lands here under NAME for the executor alone: never put it in the launch
395
+ * environment, argv or any file the native process reads, because that
396
+ * process hands everything it holds to every tool it runs. A value that
397
+ * could not be substituted safely is refused.
398
+ */
399
+ secretFileSlotReferences?: Record<string, string>;
400
+ }
401
+ //#endregion
402
+ //#region src/candidate-types.d.ts
403
+ interface AgentCandidateWorkspacePlan {
404
+ sourceProfileDigest: Sha256Digest;
405
+ harness: HarnessId;
406
+ files: PlanFile[];
407
+ env: Record<string, AgentCandidateConfigValue>;
408
+ flags: AgentCandidateConfigValue[];
409
+ systemPrompt?: AgentCandidateConfigValue;
410
+ appendSystemPrompt?: AgentCandidateConfigValue;
411
+ unsupported: Unsupported[];
412
+ }
413
+ interface AgentCandidateWorkspacePlanReceipt {
414
+ profileActivation: AgentCandidateProfileActivation;
415
+ application: AgentCandidateProfileApplication;
416
+ env: Record<string, AgentCandidateConfigValue>;
417
+ flags: AgentCandidateConfigValue[];
418
+ systemPrompt?: AgentCandidateConfigValue;
419
+ appendSystemPrompt?: AgentCandidateConfigValue;
420
+ unsupported: Unsupported[];
421
+ }
422
+ interface ApplyAgentCandidateWorkspacePlanOptions {
423
+ /** Absolute private agent directory required by agent-root plan files. */
424
+ agentDir?: string;
425
+ }
426
+ interface MaterializeCandidateProfileOptions {
427
+ /** Exact text fetched from pinned resource refs, keyed by declared SHA-256. */
428
+ resolvedResources?: ReadonlyMap<Sha256Digest, string>;
429
+ /**
430
+ * Launcher controls this caller owns and will bind itself. The declaration
431
+ * is forwarded to the classic materializer so candidate execution uses the
432
+ * same lowering as ordinary profile execution.
433
+ */
434
+ binds?: readonly BindableLaunchControl[];
435
+ }
436
+ //#endregion
437
+ //#region src/candidate.d.ts
438
+ declare function materializeCandidateProfile(profile: AgentCandidateProfile, harness: HarnessId, opts?: MaterializeCandidateProfileOptions): AgentCandidateWorkspacePlan;
439
+ /**
440
+ * Apply a candidate plan and return its spawn values together with captured
441
+ * canonical evidence. No caller needs to re-serialize or reinterpret the plan.
442
+ */
443
+ declare function applyAgentCandidateWorkspacePlan(plan: AgentCandidateWorkspacePlan, workspaceDir: string, targetWorkspace: AgentCandidateProfileApplication["targetWorkspace"], options?: ApplyAgentCandidateWorkspacePlanOptions): AgentCandidateWorkspacePlanReceipt;
444
+ //#endregion
445
+ //#region src/control-maps.d.ts
446
+ /** Tool IDs reported by the OpenCode binary shipped in the Sandbox image. */
447
+ declare const OPENCODE_NATIVE_TOOL_IDS: readonly ["apply_patch", "bash", "codesearch", "edit", "glob", "grep", "question", "read", "skill", "task", "todowrite", "webfetch", "websearch", "write"];
448
+ /** Resolve portable and legacy profile names to current OpenCode tool IDs. */
449
+ declare function openCodeNativeToolId(name: string): string | undefined;
450
+ //#endregion
451
+ //#region src/harness-prompt.d.ts
452
+ /** Keep controlled Codex launches on declared tools, not account apps or plugins. */
453
+ declare const CODEX_DISABLED_FEATURE_ARGS: readonly string[];
454
+ /**
455
+ * Whether a run keeps the harness's own system prompt, so that a host's
456
+ * environment context joins the profile's addition instead of replacing the
457
+ * harness prompt.
458
+ *
459
+ * A profile that declares prompt intent (`prompt.instructions` or
460
+ * `prompt.appendSystemPrompt`) without `prompt.systemPrompt` asked for the
461
+ * harness prompt to stay in force: that is what `appendSystemPrompt` means.
462
+ * A host that replaced it with its own template would delete exactly what the
463
+ * profile kept. Every Discovery research director ran under the
464
+ * sandbox's app-builder template this way: claude-code through
465
+ * `--system-prompt`, opencode through a generated primary agent.
466
+ */
467
+ declare function keepsHarnessSystemPrompt(profile: AgentProfile | undefined, harness: HarnessId | string | undefined): boolean;
468
+ /** Join prompt additions in order, skipping empty ones. */
469
+ declare function joinSystemPromptAdditions(...additions: Array<string | undefined>): string | undefined;
470
+ /** Native inline context has a bounded argument; long context belongs in resources.files. */
471
+ declare function codexDeveloperInstructionArgs(value: string | undefined, flags?: readonly string[]): string[];
472
+ //#endregion
473
+ //#region src/managed-workspace-types.d.ts
474
+ interface ManagedWorkspaceFileDigest {
475
+ root: PlanFileRoot;
476
+ relPath: string;
477
+ source: PlanFile["source"];
478
+ ownership: PlanFile["ownership"];
479
+ size: number;
480
+ mode: number;
481
+ /** The host view exposes only visible entries for this pinned turn. */
482
+ visible: boolean;
483
+ /** A side copy of this original path, when a user file won the collision. */
484
+ relocatedFrom?: string;
485
+ /** Digest of the actual staged bytes, including resolved secret leaves. Private. */
486
+ sha256: string;
487
+ }
488
+ /** Private executor inventory; never expose hashes of resolved credentials. */
489
+ interface ManagedWorkspaceManifest {
490
+ workspacePlanDigest: string;
491
+ /** Hashes the resolved stage inventory and launch inputs, not only public refs. */
492
+ materializedDigest: string;
493
+ files: ManagedWorkspaceFileDigest[];
494
+ /** User-owned path stays in place; profile bytes are staged beside it. */
495
+ conflicts: Array<{
496
+ relPath: string;
497
+ copyRelPath: string;
498
+ reason: "existing" | "symlink";
499
+ }>;
500
+ /** Resolved for the runtime but intentionally absent from the visible tree. */
501
+ runtimeOnlyFiles: Array<{
502
+ name: string;
503
+ size: number;
504
+ sha256: string;
505
+ }>;
506
+ /** Private digest of resolved spawn controls, including secret-bearing env. */
507
+ spawnDigest: string;
508
+ /** Exact native spawn controls after absolute revision paths are bound. */
509
+ launchDigest?: string;
510
+ }
511
+ //#endregion
512
+ //#region src/managed-workspace.d.ts
513
+ interface ConcurrentProfileRevision {
514
+ directory: string;
515
+ manifest: ManagedWorkspaceManifest;
516
+ application: WorkspacePlanApplication;
517
+ }
518
+ declare function ensurePublicConcurrentProfileRoots(base: string): {
519
+ managedRoot: string;
520
+ launchRoot: string;
521
+ };
522
+ declare function preparePublicConcurrentProfileRevision(input: {
523
+ plan: WorkspacePlan;
524
+ managedRoot: string;
525
+ launchRoot: string;
526
+ sharedWorkspaceDir: string;
527
+ ownerId: string;
528
+ secretProvider: AgentProfileSecretProvider;
529
+ options?: Pick<ApplyWorkspacePlanOptions, "ownership" | "runtimeOnlyFiles">;
530
+ }): Promise<ConcurrentProfileRevision>;
531
+ //#endregion
532
+ //#region src/mcp-config-ownership.d.ts
533
+ /**
534
+ * Harness MCP config files this package generates wholesale from
535
+ * `profile.mcp`: exactly one `mcpServers` object whose entries carry only
536
+ * the fields the generators write. Recognizable by that shape alone (no
537
+ * schema id to key on), so an existing file holding ONLY those registrations
538
+ * is this package's earlier output and a new plan replaces it — a per-turn
539
+ * profile changes these bytes routinely (physim's MCP env carries turn
540
+ * state). Anything else at the path (a user's own keys, extra fields) still
541
+ * refuses: the name alone proves nothing, same rule as `opencode.json`.
542
+ */
543
+ /** Whether the existing file at `relPath` is this package's own earlier MCP
544
+ * config output (shape rule above). `undefined` content = no regular file. */
545
+ declare function isMaterializerMcpConfig(relPath: string, content: () => string | undefined): boolean;
546
+ //#endregion
547
+ //#region src/mcp-opencode.d.ts
548
+ /** OpenCode-native MCP configuration used by workspace and startup paths. */
549
+ type OpenCodeMcpConfig = Record<string, {
550
+ type: "remote";
551
+ url: string;
552
+ enabled: boolean;
553
+ headers?: Record<string, AgentProfileConfigValue>; /** Milliseconds; OpenCode bounds this server's connect, tool listing and tool calls by it. */
554
+ timeout?: number; /** `false` turns off OpenCode's OAuth discovery for this server. */
555
+ oauth?: false;
556
+ } | {
557
+ type: "local";
558
+ command: Array<string | AgentProfileConfigValue>;
559
+ enabled: boolean;
560
+ environment?: Record<string, AgentProfileConfigValue>;
561
+ timeout?: number;
562
+ }>;
563
+ /**
564
+ * Lower canonical MCP definitions to OpenCode's native startup configuration.
565
+ * `toolTimeouts` holds the validated `metadata.toolTimeoutMs` of each server
566
+ * that declared one; without it OpenCode applies the MCP SDK's 60 s default to
567
+ * every tool call.
568
+ */
569
+ declare function openCodeMcpConfig(mcp: Record<string, AgentProfileMcpServer>, toolTimeouts?: ReadonlyMap<string, number>): OpenCodeMcpConfig;
570
+ //#endregion
571
+ //#region src/model-id.d.ts
572
+ /**
573
+ * The one canonicalization of a model id, shared by everything that writes a
574
+ * model id into an {@link AgentProfile} and everything that later compares one
575
+ * against it.
576
+ *
577
+ * A model id is qualified by prepending provider segments, and the same model
578
+ * is legitimately spelled at more than one qualification level as it travels:
579
+ * the caller sends `{ provider: "openai-compat", model: "deepseek/deepseek-v4-flash" }`,
580
+ * the profile records the qualified `openai-compat/deepseek/deepseek-v4-flash`,
581
+ * and the CLI is spawned with that qualified form. Two spellings, one model.
582
+ *
583
+ * Every writer and every reader must run both sides through here, so a
584
+ * comparison cannot mistake two spellings of one model for a conflict. Two
585
+ * independent copies of this rule are exactly how that bug arises.
586
+ */
587
+ /**
588
+ * Qualify `modelId` with `provider` — the canonical form of a model id.
589
+ *
590
+ * The already-qualified check is prefix-SPECIFIC rather than "already contains
591
+ * a slash": a router slug legitimately carries an upstream segment of its own
592
+ * (`deepseek/deepseek-v4-flash`, `zai/glm-4.7`), so a generic slash test would
593
+ * leave those unqualified, while an unconditional prefix would double-qualify
594
+ * an id that has already been through here.
595
+ *
596
+ * Idempotent by construction:
597
+ * `qualifyModelId(p, qualifyModelId(p, m)) === qualifyModelId(p, m)`.
598
+ */
599
+ declare function qualifyModelId<T extends string | undefined>(provider: string | undefined, modelId: T): T;
600
+ /**
601
+ * Remove one exact `provider/` qualification from `modelId`.
602
+ *
603
+ * This is the inverse operation for a model id that was qualified by this
604
+ * provider. It removes only the known outer prefix and preserves upstream
605
+ * segments such as `zai/glm-4.7`.
606
+ *
607
+ * The helper removes one outer qualification per call. It leaves missing
608
+ * providers and model ids unchanged.
609
+ */
610
+ declare function unqualifyModelId(provider: string | undefined, modelId: string): string;
611
+ declare function unqualifyModelId(provider: string | undefined, modelId: undefined): undefined;
612
+ declare function unqualifyModelId(provider: string | undefined, modelId: string | undefined): string | undefined;
613
+ /**
614
+ * Do two model ids name the same model?
615
+ *
616
+ * Both operands are qualified by `provider` before comparison, so the
617
+ * qualification level a caller happened to use is not a difference. Two
618
+ * different model names are still different — this narrows a comparison to the
619
+ * model's identity, it does not make the comparison permissive.
620
+ *
621
+ * `provider` is optional because a profile may carry a `model.default` that was
622
+ * qualified by a writer which did not also record `model.provider`. With no
623
+ * provider to qualify by, a bare id and its single-segment-qualified spelling
624
+ * are still the same model, which is the only tolerance the undeclared case gets.
625
+ */
626
+ declare function modelIdsMatch(a: string | undefined, b: string | undefined, provider?: string): boolean;
627
+ //#endregion
628
+ //#region src/pi-models-config.d.ts
629
+ interface PiModelsConfigInput {
630
+ /** Provider key in models.json and the matching `--provider` value. */
631
+ providerName: string;
632
+ /** Model id in models.json and the matching `--model` value. */
633
+ modelId: string;
634
+ /** Provider endpoint. OpenAI-compatible endpoints include `/v1`. */
635
+ baseUrl: string;
636
+ /** Literal in-box credential or an environment reference. */
637
+ apiKey: string;
638
+ /** Pi wire protocol. */
639
+ api?: "anthropic-messages" | "google-generative-ai" | "openai-completions" | "openai-responses";
640
+ contextWindow?: number;
641
+ maxTokens?: number;
642
+ reasoning?: boolean;
643
+ /** OpenAI-compatible completions may reject the optional store field. */
644
+ supportsStore?: boolean;
645
+ }
646
+ interface PiModelsConfigFile {
647
+ path: string;
648
+ content: string;
649
+ mode: number;
650
+ }
651
+ declare const PI_MODELS_CONFIG_PATH = ".pi/agent/models.json";
652
+ interface PiRuntimePaths {
653
+ agentDir: string;
654
+ sessionDir: string;
655
+ }
656
+ /** Resolve Pi's private roots from the one runtime HOME supplied to Pi. */
657
+ declare function resolvePiRuntimePaths(runtimeHome: string): PiRuntimePaths;
658
+ declare function buildPiModelsConfig(input: PiModelsConfigInput): Record<string, unknown>;
659
+ /** Build the owner-only Pi file used by headless and interactive processes. */
660
+ declare function buildPiModelsConfigFile(input: PiModelsConfigInput): PiModelsConfigFile;
661
+ //#endregion
662
+ //#region src/plan-application.d.ts
663
+ declare function applyWorkspacePlan(plan: WorkspacePlan, workspaceDir: string, options?: ApplyWorkspacePlanOptions): WorkspacePlanReceipt;
664
+ /**
665
+ * Resolve opaque profile references through an executor-owned provider, then
666
+ * apply the resulting private native files and launch inputs. Resolution
667
+ * completes before any workspace write, and resolved values never enter the
668
+ * public plan, digest, receipt, logs, or error messages.
669
+ */
670
+ declare function applyWorkspacePlanWithSecretProvider(plan: WorkspacePlan, workspaceDir: string, secretProvider: AgentProfileSecretProvider, options?: ApplyWorkspacePlanOptions): Promise<WorkspacePlanApplication>;
671
+ //#endregion
672
+ //#region src/plan-digest.d.ts
673
+ declare function hashWorkspacePlan(plan: WorkspacePlan): string;
674
+ /** Build the exact digest-free identity document required by agent-interface. */
675
+ declare function agentCandidateProfilePlanMaterial(plan: AgentCandidateWorkspacePlan): AgentCandidateProfilePlanMaterial;
676
+ /**
677
+ * Return the RFC 8785 UTF-8 bytes and SHA-256 identity of a candidate profile
678
+ * plan. The returned bytes are the exact bytes embedded in receipt evidence.
679
+ */
680
+ declare function canonicalizeAgentCandidateProfilePlan(plan: AgentCandidateWorkspacePlan): {
681
+ material: AgentCandidateProfilePlanMaterial;
682
+ bytes: Uint8Array;
683
+ digest: Sha256Digest;
684
+ };
685
+ /** Capture portable evidence of the exact canonical profile-plan bytes. */
686
+ declare function captureAgentCandidateProfilePlan(plan: AgentCandidateWorkspacePlan): AgentCandidateProfilePlanEvidence;
687
+ //#endregion
688
+ //#region src/plan-prompt.d.ts
689
+ /**
690
+ * The replacement text this launcher must bind to `control`, or `undefined`
691
+ * when the plan carries no launcher-bound intent.
692
+ *
693
+ * Throws for a binding addressed to a DIFFERENT control: the reader cannot
694
+ * execute it, and answering `undefined` would start the agent with the
695
+ * harness's own prompt still in force while nothing reported a problem — the
696
+ * silent downgrade the binding exists to prevent. This is the seam where an
697
+ * executor that cannot bind an intent says so, by name, instead of running a
698
+ * profile whose prompt never took effect.
699
+ */
700
+ declare function takeSystemPromptBinding(spawn: Pick<WorkspacePlanSpawnInputs, "systemPromptBinding">, control: ExecutorSystemPromptBinding): string | undefined;
701
+ //#endregion
702
+ //#region src/plan-support.d.ts
703
+ /** Fail when a profile asks for controls the chosen harness cannot execute. */
704
+ declare function assertWorkspacePlanSupported(plan: Pick<WorkspacePlan, "unsupported">): void;
705
+ /**
706
+ * Enforce supportability under the profile's failOnError policy.
707
+ * Strict mode throws; best-effort mode returns visible warnings.
708
+ */
709
+ declare function enforceWorkspacePlanSupport(plan: Pick<WorkspacePlan, "unsupported">, failOnError: boolean | undefined): string[];
710
+ //#endregion
711
+ //#region src/prime-profile.d.ts
712
+ interface PrimeProfileSkill {
713
+ name: string;
714
+ content: string;
715
+ }
716
+ interface PrimeProfileSubagent {
717
+ name: string;
718
+ description?: string;
719
+ prompt?: string;
720
+ metadata?: Record<string, unknown>;
721
+ }
722
+ /** Validated, materialization-ready view of the profile controls prime applies. */
723
+ interface PrimeProfileControls {
724
+ systemPrompt?: string;
725
+ appendSystemPrompt?: string;
726
+ /** Composed caller instructions, lowered to the agent dir's AGENTS.md. */
727
+ instructions?: string;
728
+ skills: PrimeProfileSkill[];
729
+ subagents: PrimeProfileSubagent[];
730
+ }
731
+ /** True when the controls materialize anything at all. */
732
+ declare function hasPrimeProfileMaterial(controls: PrimeProfileControls): boolean;
733
+ /**
734
+ * True when the controls must WRITE INTO the agent dir itself.
735
+ *
736
+ * Prompt files and skill dirs are named by a flag, so they can live anywhere
737
+ * the agent can read (`--system-prompt` / `--append-system-prompt` resolve a
738
+ * path when it exists, fork resource-loader.ts:41-56; `--skill` takes an
739
+ * arbitrary dir, :437-442). The context file and the continual-harness store
740
+ * are located BY the agent dir and have no flag, so they cannot move.
741
+ *
742
+ * An executor pointed at an agent dir it does not own (an operator's shared
743
+ * dir) uses this to refuse exactly the controls it would have to write there,
744
+ * while still binding the ones it can materialize elsewhere.
745
+ */
746
+ declare function primeProfileNeedsAgentDir(controls: PrimeProfileControls): boolean;
747
+ /**
748
+ * Validate and extract the profile controls the prime agent-dir lowering
749
+ * materializes. Throws {@link PrimeProfileError} on any control (or control
750
+ * facet) the fork has no verified read path for — partial acceptance would
751
+ * silently drop the rest.
752
+ */
753
+ declare function readPrimeProfileControls(profile: AgentProfile | undefined): PrimeProfileControls;
754
+ /**
755
+ * Refuse a run whose selected model disagrees with the profile's own.
756
+ *
757
+ * One authority per run: a profile names the model it was written and scored
758
+ * against, so running it on a different one silently scores a different agent.
759
+ * Both sides go through {@link modelIdsMatch}, so the qualification level a
760
+ * caller happened to use is not a conflict.
761
+ *
762
+ * `provider` is the executor's PROVIDER SELECTION, and is compared only when
763
+ * the executor's provider is part of model identity. An executor whose
764
+ * provider key is merely a namespace inside the agent dir passes it as
765
+ * undefined and gets the model-name comparison alone.
766
+ */
767
+ declare function assertPrimeModelAgreement(profile: AgentProfile | undefined, selected: {
768
+ provider?: string;
769
+ model: string;
770
+ }): void;
771
+ /** Deterministic harness-state entry id for a profile subagent name. */
772
+ declare function primeSubagentEntryId(name: string): string;
773
+ //#endregion
774
+ //#region src/prime-agent-dir.d.ts
775
+ declare function writePrimeAgentFile(path: string, data: string, mode?: number): void;
776
+ /**
777
+ * File access on a prime agent dir. The default reads and writes the local
778
+ * filesystem as the calling process. An executor whose agent dir belongs to
779
+ * another user (a root sidecar that demotes prime-agent) passes reads it took
780
+ * as that user and replays the writes as that user, so it never touches the
781
+ * agent's files with its own rights.
782
+ */
783
+ interface PrimeAgentDirIo {
784
+ /** The file's text, or undefined when it does not exist. */
785
+ read(path: string): string | undefined;
786
+ /** Replace the whole file: atomic and owner-only. */
787
+ write(path: string, data: string): void;
788
+ }
789
+ /** The fork's continual-harness store, the only agent-dir file a materialization reads. */
790
+ declare function primeHarnessStatePath(agentDir: string): string;
791
+ interface PrimeMaterializeOptions {
792
+ /**
793
+ * Where the FLAG-NAMED files go — the prompt files and the skills root.
794
+ * Defaults to `agentDir`. An executor that does not own the agent dir points
795
+ * this at a per-run directory of its own, so binding a profile's prompts and
796
+ * skills writes nothing into a dir it must not modify. The context file and
797
+ * the harness store have no flag and always land in `agentDir`; refuse those
798
+ * with {@link primeProfileNeedsAgentDir} instead.
799
+ */
800
+ flagFileRoot?: string;
801
+ /**
802
+ * Reports state the executor should see but that does not fail the run
803
+ * (currently: adopting entries a pre-shared executor left behind).
804
+ */
805
+ warn?: (msg: string, meta?: Record<string, unknown>) => void;
806
+ /** Agent-dir file access; the local filesystem when omitted. */
807
+ io?: PrimeAgentDirIo;
808
+ }
809
+ /**
810
+ * Materialize the validated controls and return the extra spawn args that bind
811
+ * them. Runs before every spawn (same place models.json is materialized), so a
812
+ * continual agent dir is re-pinned to the current profile on each fresh prime
813
+ * process.
814
+ */
815
+ declare function materializePrimeProfileControls(agentDir: string, controls: PrimeProfileControls, options?: PrimeMaterializeOptions): string[];
816
+ /**
817
+ * Remove the files a PREVIOUS materialization of this lowering wrote, so a
818
+ * profile that shrank cannot leave a stale instruction file or skill behind for
819
+ * the next run against the same dirs.
820
+ *
821
+ * Only the paths this lowering NAMES are removed. There is deliberately no
822
+ * manifest: a manifest would live where the agent can write it, and reading a
823
+ * delete list out of agent-writable state turns pruning into an arbitrary-path
824
+ * delete.
825
+ */
826
+ declare function prunePrimeProfileMaterial(agentDir: string, options?: Pick<PrimeMaterializeOptions, "flagFileRoot">): void;
827
+ /**
828
+ * Upsert profile subagent specs into the fork's global continual-harness
829
+ * store and remove profile-sourced entries the current profile no longer
830
+ * declares. Agent-written entries (`source: "agent"`) — and every top-level
831
+ * key this lowering does not manage — are preserved untouched.
832
+ *
833
+ * A store that exists but no longer parses raises
834
+ * {@link PrimeHarnessStateError}: the file is the agent's own self-modification
835
+ * state, and overwriting it destroys what the run was supposed to observe.
836
+ */
837
+ declare function seedPrimeProfileSubagents(agentDir: string, subagents: PrimeProfileSubagent[], warn?: (msg: string, meta?: Record<string, unknown>) => void, io?: PrimeAgentDirIo): void;
838
+ //#endregion
839
+ //#region src/prime-fork.d.ts
840
+ /**
841
+ * Fork FACTS for prime-agent (PrimeIntellect-ai/prime-agent) — the constants,
842
+ * dialects and refusal reasons every executor that drives the fork needs, with
843
+ * no `node:fs` and no executor assumptions. The agent-dir MATERIALIZATION that
844
+ * consumes them lives in `./index.ts`; both consumers (cli-bridge's host-spawn
845
+ * backend on `--mode rpc`, sdk-provider-prime's in-sandbox adapter on
846
+ * `--mode acp`) read these instead of each keeping a private copy, because a
847
+ * fork bump must move one file, not two repositories.
848
+ *
849
+ * Every value here was read from PrimeIntellect-ai/prime-agent 0.7.0
850
+ * (be9e2fa0); a fork bump re-reads them against the new clone.
851
+ */
852
+ /**
853
+ * Env vars the agent resolves its config dir from, most-specific first.
854
+ *
855
+ * The fork derives the name from its own package identity —
856
+ * `ENV_AGENT_DIR = \`${envPrefix}_CODING_AGENT_DIR\`` where `envPrefix` comes
857
+ * from `package.json` `piConfig.name` (config.ts:485-498) — so the fork reads
858
+ * `PRIME_AGENT_CODING_AGENT_DIR` and upstream pi reads `PI_CODING_AGENT_DIR`.
859
+ * An executor that sets only the fork's name has its isolation SILENTLY
860
+ * disabled when the binary on PATH turns out to be upstream pi: `getAgentDir()`
861
+ * falls back to `homedir()/<CONFIG_DIR_NAME>` (config.ts:520-527), one shared
862
+ * dir — and therefore one shared self-modifying `harness_state.json` — for
863
+ * every session on the box. Setting BOTH names costs nothing and keeps the
864
+ * isolation fail-closed under either binary.
865
+ */
866
+ declare const PRIME_AGENT_DIR_ENV_VARS: readonly ["PRIME_AGENT_CODING_AGENT_DIR", "PI_CODING_AGENT_DIR"];
867
+ /** Canonical agent-dir env var for the fork itself (config.ts:498). */
868
+ declare const PRIME_AGENT_DIR_ENV_VAR: "PRIME_AGENT_CODING_AGENT_DIR";
869
+ /** Pin `agentDir` under every name the agent could resolve its config dir from. */
870
+ declare function primeAgentDirEnv(agentDir: string): Record<string, string>;
871
+ /**
872
+ * Operator knobs an executor forwards into the agent when they are set.
873
+ *
874
+ * `PRIME_AGENT_KERNEL_VENV` is load-bearing for any executor that also pins
875
+ * HOME: the kernel venv defaults under `homedir()/.prime/agent/kernel-venv`
876
+ * (kernel/bootstrap.ts:331-342), so a fresh HOME re-bootstraps it through uv on
877
+ * every run unless the operator's venv path is forwarded
878
+ * (bootstrap.ts:340 override, :358 branch).
879
+ */
880
+ declare const PRIME_KERNEL_ENV_PASSTHROUGH: readonly ["PRIME_AGENT_INSTALL_UV", "PRIME_AGENT_KERNEL_PYTHON", "PRIME_AGENT_KERNEL_VENV"];
881
+ /**
882
+ * Env vars an executor must NEVER forward from its own environment.
883
+ *
884
+ * These re-point the self-modifying continual-harness store OUTSIDE the agent
885
+ * dir (agent-session.ts:8805 hands the kernel its store location), which
886
+ * defeats per-session isolation without changing anything an executor inspects.
887
+ * Isolation is the fail-closed default; sharing state is an explicit opt-in
888
+ * that names a directory, never an inherited env var.
889
+ */
890
+ declare const PRIME_HARNESS_STATE_ENV_DENYLIST: readonly ["RLM_GLOBAL_HARNESS_STATE_DIR", "RLM_HARNESS_STATE_DIR"];
891
+ /**
892
+ * A prime-agent IPython kernel that dies is never re-provisioned headlessly —
893
+ * every later `ipython` call fails with one of these markers until the process
894
+ * is replaced. An executor that cannot recognize them either reports a generic
895
+ * turn failure or burns its whole timeout against a permanently dead tool.
896
+ *
897
+ * Verified in `core/kernel/index.ts`: :723 ("forked kernel exited
898
+ * unexpectedly"), :750 ("Kernel exited before resolving ports"), :779 ("Kernel
899
+ * exited during startup"), :820/:837/:1172/:1295 ("Kernel has been shut down").
900
+ */
901
+ declare const PRIME_KERNEL_DEAD_MARKERS: readonly string[];
902
+ /** The first kernel-death marker present in `text`, or undefined. */
903
+ declare function matchPrimeKernelDeadMarker(text: string): string | undefined;
904
+ /**
905
+ * `--thinking` rungs the fork's argument parser accepts
906
+ * (cli/args.ts:62 `VALID_THINKING_LEVELS`, rejected at :175). Read from the
907
+ * fork itself rather than borrowed from upstream pi's measured table: the two
908
+ * agreeing today is a coincidence this module must not depend on.
909
+ */
910
+ declare const PRIME_THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
911
+ type PrimeThinkingLevel = (typeof PRIME_THINKING_LEVELS)[number];
912
+ /**
913
+ * Map the portable reasoning ladder onto the fork's `--thinking` value.
914
+ *
915
+ * Throws on an effort with no rung instead of returning undefined: omitting the
916
+ * flag runs the agent at its default thinking level while the caller believes
917
+ * the requested effort is in force, which is a silently dropped control.
918
+ */
919
+ declare function primeThinkingLevel(effort: string | null | undefined): PrimeThinkingLevel | undefined;
920
+ /**
921
+ * Why `profile.mcp` (and any hub connection that resolves to MCP) is refused.
922
+ *
923
+ * The fork's `mcpServers` settings surface IS read at startup
924
+ * (settings-manager.ts:98-120,219) but a user-declared server never becomes
925
+ * model-visible: the host McpManager registers OAuth providers and serves
926
+ * mcp.config/refresh host-requests only (core/mcp/mcp-manager.ts:62-124),
927
+ * skips stdio servers entirely (mcp-manager.ts:73), and nothing generates a
928
+ * skill or prompt section for one. Model-visible MCP is exactly the built-in
929
+ * catalog skills, which are hand-written Python `McpIntegration` subclasses
930
+ * (prime-agent-runtime/src/rlm/mcp_base.py:112-125; only linear and notion
931
+ * ship). Materializing a per-run entry would run the agent WITHOUT the
932
+ * requested tools while the config on disk says otherwise.
933
+ */
934
+ declare const PRIME_MCP_UNSUPPORTED_REASON: string;
935
+ /** Which half of a profile refusal this is: a fork limit, or a bad declaration. */
936
+ type PrimeProfileErrorKind = "unsupported" | "invalid";
937
+ /**
938
+ * Refusal raised by the shared prime lowering, carrying the control and the
939
+ * reason separately so each executor can render them in its own error contract
940
+ * (an HTTP backend's typed `BackendError`, an SDK adapter's plain `Error`)
941
+ * without the reason text — which is where the fork evidence lives — being
942
+ * rewritten per repository.
943
+ */
944
+ declare class PrimeProfileError extends Error {
945
+ readonly kind: PrimeProfileErrorKind;
946
+ readonly control: string;
947
+ readonly reason: string;
948
+ constructor(kind: PrimeProfileErrorKind, control: string, reason: string);
949
+ }
950
+ /**
951
+ * The fork's continual-harness store exists but no longer parses.
952
+ *
953
+ * The store is the agent's own self-modification state — refinements, learned
954
+ * prompts, subagents it created mid-session — so an executor that reseeds it
955
+ * from empty destroys evidence and silently mutates the thing under study. The
956
+ * turn is failed instead; the file is the operator's to repair or remove.
957
+ */
958
+ declare class PrimeHarnessStateError extends Error {
959
+ readonly statePath: string;
960
+ constructor(statePath: string, detail: string);
961
+ }
962
+ /**
963
+ * Strip `//` line comments and trailing commas, leaving string literals
964
+ * untouched — byte-for-byte the fork's own `stripJsonComments`
965
+ * (core/model-registry.ts), so a models.json the agent accepts is never refused
966
+ * by an executor and vice versa.
967
+ */
968
+ declare function stripPrimeJsonComments(input: string): string;
969
+ /**
970
+ * Parse a models.json with the fork's own laxness and assert the one structural
971
+ * invariant it requires (a `providers` object). Throws naming `sourcePath`.
972
+ *
973
+ * This is the SHAPE and DIALECT only. Producing the file is deliberately not
974
+ * shared: an executor holding real operator credentials copies an
975
+ * operator-authored file and forwards only the env var names its `apiKey`
976
+ * entries reference, while an in-sandbox executor synthesizes a one-provider
977
+ * entry with a literal key that is a proxy dummy. Same schema, opposite threat
978
+ * models.
979
+ */
980
+ declare function parsePrimeModelsJson(text: string, sourcePath: string): Record<string, unknown>;
981
+ /**
982
+ * Environment variables a models.json names as `apiKey` sources.
983
+ *
984
+ * prime resolves an `apiKey` value env-var first and LITERAL second
985
+ * (core/resolve-config-value.ts), so an executor that forwards exactly the
986
+ * named variables lets an operator keep secrets out of the file — and an
987
+ * executor that forwards NONE of them silently turns the variable name itself
988
+ * into the credential string.
989
+ */
990
+ declare function primeApiKeyEnvNames(modelsConfig: Record<string, unknown>): string[];
991
+ //#endregion
992
+ //#region src/profile-bundle-key.d.ts
993
+ declare const PROFILE_BUNDLE_SCHEMA = "agent-profile-bundle/v1";
994
+ declare const PROFILE_BUNDLE_MAX_FILES = 512;
995
+ declare const PROFILE_BUNDLE_MAX_BYTES: number;
996
+ declare const PROFILE_BUNDLE_MAX_FILE_BYTES: number;
997
+ declare const PROFILE_BUNDLE_DEFAULT_MAX_BYTES: number;
998
+ interface ProfileBundleFileEntry {
999
+ /** Logical workspace-relative mount path, exactly as declared on the profile. */
1000
+ mountPath: string;
1001
+ /** SHA-256 of the content bytes as lowercase hex, WITHOUT the `sha256:` prefix. */
1002
+ sha256: string;
1003
+ /** Full file mode (0o644 default, 0o755 for executable mounts). */
1004
+ mode: number;
1005
+ }
1006
+ interface ProfileBundleManifest {
1007
+ schema: string;
1008
+ /** Raw bundle key (e.g. `sha256:<hex>`); also recoverable from the filename. */
1009
+ bundle: string;
1010
+ createdAt: string;
1011
+ sizeBytes: number;
1012
+ files: Array<ProfileBundleFileEntry & {
1013
+ target: string;
1014
+ }>;
1015
+ }
1016
+ interface ProfileBundleClaim {
1017
+ bundle: string;
1018
+ files: Array<{
1019
+ mountPath: string;
1020
+ sha256: string;
1021
+ }>;
1022
+ }
1023
+ type ProfileBundleClaimResult = {
1024
+ status: "hit";
1025
+ linked: string[];
1026
+ } | {
1027
+ status: "miss";
1028
+ missing: string[];
1029
+ };
1030
+ interface ProfileBundleCache {
1031
+ root: string;
1032
+ maxBytes: number;
1033
+ admit(manifest: ProfileBundleManifest, readObject: (sha256: string) => Promise<Uint8Array> | Uint8Array): Promise<void>;
1034
+ evict(): Promise<void>;
1035
+ sweep(): Promise<void>;
1036
+ }
1037
+ /**
1038
+ * Derive the canonical bundle file entry for one inline mount. The sha256 is
1039
+ * computed over the exact inline content bytes and the mode mirrors the SDK's
1040
+ * `profileFileMode`/`isExecutableProfileFile`: `mount.executable` wins when
1041
+ * present, otherwise a path under a `bin/` or `sbin/` directory is executable.
1042
+ * A mount whose resource is not inline is a caller bug and throws, matching
1043
+ * the fail-closed discipline of {@link resolveInlineRef}.
1044
+ */
1045
+ declare function profileBundleFileEntry(mount: AgentProfileFileMount): ProfileBundleFileEntry;
1046
+ /**
1047
+ * The canonical file table: one entry per mount, sorted by (mountPath, sha256)
1048
+ * so any array order of the same mounts produces the same table.
1049
+ */
1050
+ declare function profileBundleFileTable(mounts: readonly AgentProfileFileMount[]): ProfileBundleFileEntry[];
1051
+ /**
1052
+ * The content-addressed bundle key. The digest covers EXACTLY the schema
1053
+ * version and, per file, the logical mount path, the sha256 of the content
1054
+ * bytes, and the full file mode — the same image-content-hash discipline as
1055
+ * scripts/ci/image-content-hash.mjs: hash exactly the inputs that determine
1056
+ * the cached bytes (and their placement semantics), nothing more. Any profile
1057
+ * change — content, path, or mode — produces a new key; anything else
1058
+ * (mount order, transport-only target paths, timestamps) does not.
1059
+ */
1060
+ declare function profileFileBundleKey(mounts: readonly AgentProfileFileMount[]): string;
1061
+ //#endregion
1062
+ //#region src/profile-bundle-lru.d.ts
1063
+ /**
1064
+ * Bundle keys come from `canonicalCandidateDigest` as `sha256:<hex>`; the `:`
1065
+ * is encoded so the key is a safe single path segment on any host filesystem.
1066
+ * The raw key is always recoverable from the manifest's `bundle` field.
1067
+ */
1068
+ declare function profileBundleManifestPath(root: string, bundle: string): string;
1069
+ /** Sweep only while holding the per-root lock; active admissions own incoming/. */
1070
+ declare function sweepProfileBundleCache(root: string): Promise<void>;
1071
+ /**
1072
+ * Evict least-recently-used objects until total object bytes are within
1073
+ * `maxBytes`. Unreferenced objects go first (they reclaim space with no
1074
+ * bundle impact); if the cap still does not hold, referenced objects are
1075
+ * evicted oldest-first, which makes their bundles partial — claims then miss
1076
+ * and re-deliver, so eviction can never serve wrong bytes. Bundle manifests
1077
+ * referencing no existing objects are removed. Mid-admit `incoming/` dirs are
1078
+ * never touched.
1079
+ */
1080
+ declare function evictProfileBundles(root: string, maxBytes: number): Promise<void>;
1081
+ //#endregion
1082
+ //#region src/profile-bundle-cache.d.ts
1083
+ /**
1084
+ * Admit a just-delivered bundle to the host cache, all-or-nothing. Every
1085
+ * object's bytes are verified against its content hash BEFORE anything is
1086
+ * renamed into place; a mismatch throws with nothing published. Objects
1087
+ * already present are re-verified against the incoming bytes, then the temp
1088
+ * copy is dropped — the existing object was verified when it was admitted.
1089
+ * The manifest is written LAST as the commit point, followed by lru update
1090
+ * and eviction down to the default cap.
1091
+ */
1092
+ declare function admitProfileBundle(root: string, manifest: ProfileBundleManifest, readObject: (sha256: string) => Promise<Uint8Array> | Uint8Array): Promise<void>;
1093
+ /**
1094
+ * Claim a bundle from a (possibly read-only mounted) cache. Verify-on-read:
1095
+ * every object's bytes are re-hashed and compared to BOTH the manifest entry
1096
+ * and the claim's expected sha256 before `linkFile` is called — a read-only
1097
+ * mount must never serve unverified bytes. `linkFile` returning false sends
1098
+ * the file to `missing` (the caller delivers it normally). Status is "hit"
1099
+ * only when nothing is missing; a partial bundle is NEVER a hit. The only
1100
+ * write is a best-effort lru touch, wrapped so EROFS on a read-only mount is
1101
+ * harmless.
1102
+ */
1103
+ declare function claimProfileBundle(root: string, claim: ProfileBundleClaim, linkFile: (objectPath: string, entry: {
1104
+ mountPath: string;
1105
+ target: string;
1106
+ sha256: string;
1107
+ mode: number;
1108
+ }) => Promise<boolean>): Promise<ProfileBundleClaimResult>;
1109
+ /**
1110
+ * Open a host-side cache handle over `root`, creating the layout and sweeping
1111
+ * stale `incoming/` residue synchronously when the root is idle. A busy root
1112
+ * leaves cleanup to its serialized admissions and sweeps.
1113
+ */
1114
+ declare function openProfileBundleCache(root: string, options?: {
1115
+ maxBytes?: number;
1116
+ }): ProfileBundleCache;
1117
+ //#endregion
1118
+ //#region src/profile-materializer.d.ts
1119
+ declare const UNAVAILABLE_AGENT_PROFILE_SECRET_PROVIDER: AgentProfileSecretProvider;
1120
+ /**
1121
+ * Why a profile's tool and permission controls cannot reach one native policy
1122
+ * on this harness, or undefined when they can.
1123
+ *
1124
+ * Admission boundaries (profile save, Sandbox create) call this so a
1125
+ * contradictory control set is refused when it is submitted, not when a
1126
+ * user's turn materializes it. Controls a harness cannot enforce are not
1127
+ * contradictions: `resources.failOnError` decides those per turn.
1128
+ */
1129
+ declare function executionControlConflict(profile: Pick<AgentProfile, "tools" | "permissions" | "mcp">, harness: HarnessId): string | undefined;
1130
+ /**
1131
+ * Build a pure workspace plan for one canonical harness.
1132
+ * The caller applies files, environment, and flags at its process boundary.
1133
+ */
1134
+ declare function materializeProfile(inputProfile: AgentProfile, harness: HarnessId, opts?: {
1135
+ skip?: SkippableDimension[];
1136
+ binds?: readonly BindableLaunchControl[];
1137
+ instructionsRoot?: PlanFileRoot;
1138
+ runtimeAttachments?: AgentRuntimeAttachments;
1139
+ }): WorkspacePlan;
1140
+ //#endregion
1141
+ //#region src/resource-resolution.d.ts
1142
+ interface ResolveAgentProfileResourcesOptions {
1143
+ /** Repository used when a GitHub resource omits its own `repository`. */
1144
+ repository?: string;
1145
+ fetch?: typeof globalThis.fetch;
1146
+ timeoutMs?: number;
1147
+ }
1148
+ /**
1149
+ * Resolve every GitHub resource to exact inline bytes before materialization.
1150
+ * The profile's default harness does not affect resource resolution.
1151
+ */
1152
+ declare function resolveAgentProfileResources(inputProfile: AgentProfile, options?: ResolveAgentProfileResourcesOptions): Promise<AgentProfile>;
1153
+ /** Normalize any skill markdown (VB frontmatter `skill:`/`description:`, or raw) into a
1154
+ * harness SKILL.md with `name:`/`description:` frontmatter the harnesses require. */
1155
+ declare function normalizeSkillMd(name: string, raw: string): string;
1156
+ //#endregion
1157
+ //#region src/secret-concurrent-revision.d.ts
1158
+ /**
1159
+ * Publish a resolved revision for exactly one native subprocess UID. The
1160
+ * executor-owned naming key hides low-entropy credential guesses from paths;
1161
+ * the resolved digest and manifest never leave this server-side result.
1162
+ */
1163
+ declare function prepareSecretConcurrentProfileRevision(input: {
1164
+ plan: WorkspacePlan; /** Trusted executor transport only; never read from the mutable native HOME. */
1165
+ providerConfig?: Record<string, unknown>;
1166
+ managedRoot: string;
1167
+ launchRoot: string;
1168
+ sharedWorkspaceDir: string;
1169
+ ownerId: string;
1170
+ subprocessUid: number;
1171
+ namingKey: Uint8Array;
1172
+ secretProvider: AgentProfileSecretProvider;
1173
+ options?: Pick<ApplyWorkspacePlanOptions, "runtimeOnlyFiles">;
1174
+ }): Promise<ConcurrentProfileRevision & {
1175
+ /**
1176
+ * The value behind each `{env:NAME}` reference in the revision's config,
1177
+ * for the executor alone: the launch never receives them. An executor
1178
+ * that serves a referencing MCP server through its own loopback proxy
1179
+ * resolves the server's headers here.
1180
+ */
1181
+ secretReferences: Readonly<Record<string, string>>;
1182
+ }>;
1183
+ //#endregion
1184
+ //#region src/secret-session-view.d.ts
1185
+ /** Stable native cwd binds workspace, session and UID across turn revisions. */
1186
+ declare function secretSessionViewWorkspace(input: {
1187
+ launchRoot: string;
1188
+ sharedWorkspaceDir: string;
1189
+ sessionId: string;
1190
+ subprocessUid: number;
1191
+ }): string;
1192
+ /** Bind published read-only resources at literal paths; generated config stays outside cwd.
1193
+ * Callers serialize turns and bind before spawning, never while a native process reads it. */
1194
+ declare function bindSecretSessionView(input: {
1195
+ launchRoot: string;
1196
+ viewWorkspaceDir: string;
1197
+ revisionWorkspaceDir: string;
1198
+ subprocessUid: number;
1199
+ }): void;
1200
+ //#endregion
1201
+ //#region src/tool-bin-path.d.ts
1202
+ /** The colon-separated, absolute CLI bin dirs a sandbox app mounts for its tools. */
1203
+ declare const SANDBOX_TOOL_BIN_DIRS_ENV = "SANDBOX_TOOL_BIN_DIRS";
1204
+ /**
1205
+ * The tool bin dirs a `SANDBOX_TOOL_BIN_DIRS` value names, or `[]` when it is
1206
+ * unset or blank.
1207
+ *
1208
+ * Fail loud, never silently degrade: a malformed value (a relative segment,
1209
+ * or an empty segment from a stray/leading/trailing colon) throws rather than
1210
+ * silently dropping a tool dir from PATH or admitting a relative path that
1211
+ * resolves against whatever the process cwd happens to be.
1212
+ */
1213
+ declare function parseSandboxToolBinDirs(value: string | undefined): string[];
1214
+ /**
1215
+ * A launch environment whose tool bin dirs are `toolBinDirs`, at the TAIL of
1216
+ * PATH after every Nix, npm, image and system entry, so a tool never shadows
1217
+ * a platform-owned binary of the same name.
1218
+ *
1219
+ * They replace `appToolBinDirs` (by default the dirs the environment's own
1220
+ * `SANDBOX_TOOL_BIN_DIRS` names) wherever those sit in PATH, so an app's older
1221
+ * copy of the same tool cannot win by PATH order. Relative PATH entries are
1222
+ * dropped too: they resolve against whatever cwd the turn moves to.
1223
+ */
1224
+ declare function bindLaunchToolBinDirs(env: Readonly<Record<string, string | undefined>>, toolBinDirs: readonly string[], appToolBinDirs?: readonly string[]): Record<string, string | undefined>;
1225
+ //#endregion
1226
+ export { type AgentCandidateWorkspacePlan, type AgentCandidateWorkspacePlanReceipt, type ApplyAgentCandidateWorkspacePlanOptions, type ApplyWorkspacePlanOptions, BINDABLE_LAUNCH_CONTROLS, type BindableLaunchControl, CODEX_DISABLED_FEATURE_ARGS, type ConcurrentProfileRevision, EXECUTOR_SYSTEM_PROMPT_BINDINGS, type ExecutorSystemPromptBinding, HARNESS_SKILL_DIRS, type HarnessId, MATERIALIZER_CONTEXT_PATHS, MATERIALIZER_HARNESSES, type ManagedWorkspaceFileDigest, type ManagedWorkspaceManifest, type MaterializeCandidateProfileOptions, OPENCODE_NATIVE_TOOL_IDS, type OpenCodeMcpConfig, PI_MODELS_CONFIG_PATH, PRIME_AGENT_DIR_ENV_VAR, PRIME_AGENT_DIR_ENV_VARS, PRIME_HARNESS_STATE_ENV_DENYLIST, PRIME_KERNEL_DEAD_MARKERS, PRIME_KERNEL_ENV_PASSTHROUGH, PRIME_MCP_UNSUPPORTED_REASON, PRIME_THINKING_LEVELS, PROFILE_BUNDLE_DEFAULT_MAX_BYTES, PROFILE_BUNDLE_MAX_BYTES, PROFILE_BUNDLE_MAX_FILES, PROFILE_BUNDLE_MAX_FILE_BYTES, PROFILE_BUNDLE_SCHEMA, type PiModelsConfigFile, type PiModelsConfigInput, type PiRuntimePaths, type PlanFile, type PlanFileRoot, type PlanFileSecretSlot, type PlanRequirement, PrimeHarnessStateError, type PrimeMaterializeOptions, type PrimeProfileControls, PrimeProfileError, type PrimeProfileErrorKind, type PrimeProfileSkill, type PrimeProfileSubagent, type PrimeThinkingLevel, ProfileBundleCache, ProfileBundleClaim, ProfileBundleClaimResult, ProfileBundleFileEntry, ProfileBundleManifest, type ResolveAgentProfileResourcesOptions, SANDBOX_TOOL_BIN_DIRS_ENV, SKIPPABLE_DIMENSIONS, type SkippableDimension, UNAVAILABLE_AGENT_PROFILE_SECRET_PROVIDER, type Unsupported, type WorkspacePlan, type WorkspacePlanApplication, type WorkspacePlanArgument, type WorkspacePlanArgumentTemplate, WorkspacePlanCleanupError, type WorkspacePlanConfigValue, type WorkspacePlanReceipt, type WorkspacePlanSecretSegment, type WorkspacePlanSpawnInputs, type WorkspacePlanSystemPromptBinding, type WorkspacePlanWrittenFile, admitProfileBundle, agentCandidateProfilePlanMaterial, applyAgentCandidateWorkspacePlan, applyWorkspacePlan, applyWorkspacePlanWithSecretProvider, assertPrimeModelAgreement, assertWorkspacePlanSupported, bindLaunchToolBinDirs, bindSecretSessionView, buildPiModelsConfig, buildPiModelsConfigFile, canonicalizeAgentCandidateProfilePlan, captureAgentCandidateProfilePlan, claimProfileBundle, codexDeveloperInstructionArgs, enforceWorkspacePlanSupport, ensurePublicConcurrentProfileRoots, evictProfileBundles, executionControlConflict, harnessAutoLoadsAgentContextFile, hasPrimeProfileMaterial, hashWorkspacePlan, isMaterializerHarness, isMaterializerMcpConfig, isSkippableDimension, joinSystemPromptAdditions, keepsHarnessSystemPrompt, markMaterializerContextFile, matchPrimeKernelDeadMarker, materializeCandidateProfile, materializePrimeProfileControls, materializeProfile, modelIdsMatch, normalizeSkillMd, openCodeMcpConfig, openCodeNativeToolId, openProfileBundleCache, parsePrimeModelsJson, parseSandboxToolBinDirs, preparePublicConcurrentProfileRevision, prepareSecretConcurrentProfileRevision, primeAgentDirEnv, primeApiKeyEnvNames, primeHarnessStatePath, primeProfileNeedsAgentDir, primeSubagentEntryId, primeThinkingLevel, profileBundleFileEntry, profileBundleFileTable, profileBundleManifestPath, profileFileBundleKey, prunePrimeProfileMaterial, qualifyModelId, readPrimeProfileControls, resolveAgentProfileResources, resolvePiRuntimePaths, secretSessionViewWorkspace, seedPrimeProfileSubagents, skillDirForHarness, stripPrimeJsonComments, sweepProfileBundleCache, takeSystemPromptBinding, unqualifyModelId, writePrimeAgentFile };