@tangle-network/agent-profile-materialize 0.15.2 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/candidate-types.d.ts +32 -0
  2. package/dist/candidate-types.js +1 -0
  3. package/dist/candidate.d.ts +9 -0
  4. package/dist/candidate.js +279 -0
  5. package/dist/commands.d.ts +2 -0
  6. package/dist/commands.js +32 -0
  7. package/dist/control-maps.d.ts +34 -0
  8. package/dist/control-maps.js +185 -0
  9. package/dist/execution-controls.d.ts +5 -0
  10. package/dist/execution-controls.js +186 -0
  11. package/dist/harness.d.ts +81 -0
  12. package/dist/harness.js +167 -0
  13. package/dist/hooks.d.ts +6 -0
  14. package/dist/hooks.js +261 -0
  15. package/dist/index.d.ts +24 -623
  16. package/dist/index.js +15 -3733
  17. package/dist/mcp.d.ts +22 -0
  18. package/dist/mcp.js +244 -0
  19. package/dist/pi-models-config.d.ts +30 -0
  20. package/dist/pi-models-config.js +46 -0
  21. package/dist/plan-application.d.ts +10 -0
  22. package/dist/plan-application.js +152 -0
  23. package/dist/plan-digest.d.ts +18 -0
  24. package/dist/plan-digest.js +90 -0
  25. package/dist/plan-json.d.ts +18 -0
  26. package/dist/plan-json.js +91 -0
  27. package/dist/plan-normalize.d.ts +13 -0
  28. package/dist/plan-normalize.js +156 -0
  29. package/dist/plan-prompt.d.ts +38 -0
  30. package/dist/plan-prompt.js +49 -0
  31. package/dist/plan-support.d.ts +9 -0
  32. package/dist/plan-support.js +22 -0
  33. package/dist/plan-types.d.ts +294 -0
  34. package/dist/plan-types.js +106 -0
  35. package/dist/prime-agent-dir.d.ts +47 -0
  36. package/dist/prime-agent-dir.js +164 -0
  37. package/dist/prime-profile.d.ts +88 -0
  38. package/dist/prime-profile.js +284 -0
  39. package/dist/profile-materializer.d.ts +12 -0
  40. package/dist/profile-materializer.js +59 -0
  41. package/dist/profile-plan.d.ts +14 -0
  42. package/dist/profile-plan.js +86 -0
  43. package/dist/profile-prompt.d.ts +4 -0
  44. package/dist/profile-prompt.js +105 -0
  45. package/dist/profile-support.d.ts +8 -0
  46. package/dist/profile-support.js +6 -0
  47. package/dist/resource-lowering.d.ts +7 -0
  48. package/dist/resource-lowering.js +103 -0
  49. package/dist/resource-resolution.d.ts +27 -0
  50. package/dist/resource-resolution.js +241 -0
  51. package/dist/subagents.d.ts +6 -0
  52. package/dist/subagents.js +133 -0
  53. package/dist/workspace-apply.d.ts +12 -0
  54. package/dist/workspace-apply.js +334 -0
  55. package/dist/workspace-files.d.ts +8 -0
  56. package/dist/workspace-files.js +46 -0
  57. package/package.json +3 -3
package/dist/index.d.ts CHANGED
@@ -1,624 +1,25 @@
1
- /**
2
- * materializeProfile — THE ONE per-harness profile materializer, shared by every
3
- * layer (cli-bridge host spawn, agent-dev-container box adapter, VB). It turns a
4
- * structured {@link AgentProfile} into a {@link WorkspacePlan}: the exact native
5
- * files to write into the run workspace (cwd), plus the env/flags some harnesses
6
- * need because they have NO cwd auto-discovery for certain dimensions.
7
- *
8
- * Routed per the VERIFIED capability matrix (harness-capability-matrix, 2026-06-14)
9
- * across every dimension (context, skills, mcp, hooks, subagents, commands).
10
- *
11
- * FAIL-CLOSED, not silent-drop: when a requested dimension has no path on the
12
- * chosen harness (e.g. kimi MCP is flag-only, hermes hooks are opt-in global), it
13
- * is recorded in `plan.unsupported` with the reason — never silently ignored,
14
- * which is exactly the "looks provisioned, loads nothing" trap.
15
- *
16
- * The ONLY trustworthy proof a dimension works is the in-session effect (skill
17
- * secret word, MCP tool called n>0, hook sentinel file) — see the canary tests.
18
- *
19
- * Types come from `@tangle-network/agent-interface` (the canonical AgentProfile
20
- * contract); this package adds only the harness-specific materialization + the
21
- * `node:fs` IO consumer. It was previously copied byte-for-byte into both
22
- * cli-bridge and agent-dev-container — this is the single source those re-export.
23
- */
1
+ /** Stable public facade for profile materialization and workspace application. */
2
+ export { applyAgentCandidateWorkspacePlan, materializeCandidateProfile, } from "./candidate.js";
3
+ export type { AgentCandidateWorkspacePlan, AgentCandidateWorkspacePlanReceipt, MaterializeCandidateProfileOptions, } from "./candidate-types.js";
4
+ export { OPENCODE_NATIVE_TOOL_IDS, openCodeNativeToolId, } from "./control-maps.js";
5
+ export type { HarnessId } from "./harness.js";
6
+ export { HARNESS_SKILL_DIRS, harnessAutoLoadsContextFile, harnessContextFile, isMaterializerHarness, MATERIALIZER_HARNESSES, skillDirForHarness, } from "./harness.js";
7
+ export type { OpenCodeMcpConfig } from "./mcp.js";
8
+ export { openCodeMcpConfig } from "./mcp.js";
24
9
  export { modelIdsMatch, qualifyModelId } from "./model-id.js";
25
- export { matchPrimeKernelDeadMarker, PRIME_AGENT_DIR_ENV_VAR, PRIME_AGENT_DIR_ENV_VARS, PRIME_FORK_INSTALL, PRIME_FORK_PIN, PRIME_HARNESS_STATE_ENV_DENYLIST, PRIME_KERNEL_DEAD_MARKERS, PRIME_KERNEL_ENV_PASSTHROUGH, PRIME_MCP_UNSUPPORTED_REASON, PRIME_THINKING_LEVELS, PrimeHarnessStateError, PrimeProfileError, type PrimeProfileErrorKind, type PrimeThinkingLevel, parsePrimeModelsJson, primeAgentDirEnv, primeApiKeyEnvNames, primeThinkingLevel, stripPrimeJsonComments, } from "./prime-fork.js";
26
- import type { AgentCandidateConfigValue, AgentCandidateProfile, AgentCandidateProfileActivation, AgentCandidateProfileApplication, AgentCandidateProfilePlanEvidence, AgentCandidateProfilePlanMaterial, AgentProfile, AgentProfileConfigValue, AgentProfileMcpServer, AgentProfileSecretProvider, AgentProfileSecretRef, Sha256Digest } from "@tangle-network/agent-interface";
27
- export declare const UNAVAILABLE_AGENT_PROFILE_SECRET_PROVIDER: AgentProfileSecretProvider;
28
- /**
29
- * The harnesses this materializer can lower an AgentProfile into. `satisfies` binds every id to
30
- * the canonical harness enum, so a rename upstream is a compile error here rather than an
31
- * `isMaterializerHarness` that silently returns false for a harness that still exists.
32
- */
33
- export declare const MATERIALIZER_HARNESSES: readonly ["claude-code", "nanoclaw", "codex", "opencode", "kimi-code", "pi", "prime", "gemini", "hermes", "openclaw"];
34
- export type HarnessId = (typeof MATERIALIZER_HARNESSES)[number];
35
- export declare function isMaterializerHarness(harness: string): harness is HarnessId;
36
- export interface PlanFile {
37
- relPath: string;
38
- content: string;
39
- /** chmod mode (e.g. 0o755 for hook scripts); default 0o644. */
40
- mode?: number;
41
- /**
42
- * Provenance of this entry. `"generated"` = the materializer synthesized the
43
- * content itself (native harness config, merged settings, lowered prompt/MCP/
44
- * hooks/subagents). `"user"` = the exact bytes of a profile-declared resource
45
- * ref (`resources.files`/`tools`/`agents`/`skills`/`commands`), passed through
46
- * verbatim at the path the profile author chose.
47
- *
48
- * A consumer that needs to reinterpret a SPECIFIC generated file (e.g. parse
49
- * `opencode.json` as the synthetic native config) MUST gate on
50
- * `source === "generated"` at that relPath — matching by relPath alone cannot
51
- * tell a harness-authored config apart from a user resource mount that
52
- * happens to share the same conventional path, and treating arbitrary user
53
- * content as trusted generated config is a fail-open bug, not a fallback.
54
- *
55
- * Optional: callers that hand-construct a {@link WorkspacePlan} directly for
56
- * {@link applyWorkspacePlan} (tests, ad hoc writes) are not materializer
57
- * output and have no provenance to report. `materializeProfile` always sets
58
- * this on every file it emits.
59
- */
60
- source?: "user" | "generated";
61
- /**
62
- * Who owns the PATH — which decides whether an existing file there may be
63
- * replaced.
64
- *
65
- * `"materializer"` = a path this package invented. No harness convention
66
- * names it and no user authors it, so a file already there can only be this
67
- * materializer's own output from an earlier application into the same
68
- * workspace, and replacing it is how turn two of a resumed session gets the
69
- * current profile instead of the previous one.
70
- *
71
- * `"shared"` (the default, and every other file) = a path the user or the
72
- * harness also owns — `CLAUDE.md`, `AGENTS.md`, `opencode.json`,
73
- * `.gemini/system.md` are all documented, user-authorable names. An existing
74
- * file there may be the caller's own work, so it is never replaced.
75
- *
76
- * Optional because hand-constructed plans have no path provenance to report;
77
- * absent reads as `"shared"`, the safe answer.
78
- */
79
- ownership?: "materializer" | "shared";
80
- /**
81
- * Secret leaves in a generated JSON document. `content` contains `null` at
82
- * each path until the private executor resolves the named reference. The
83
- * public plan, its digest, and its receipt retain only these references.
84
- */
85
- secretSlots?: PlanFileSecretSlot[];
86
- }
87
- export interface PlanFileSecretSlot {
88
- path: Array<string | number>;
89
- ref: AgentProfileSecretRef;
90
- }
91
- export interface WorkspacePlanSecretSegment {
92
- kind: "secret";
93
- ref: AgentProfileSecretRef;
94
- /** Encoding applied after private resolution. */
95
- encoding: "raw" | "json-string";
96
- }
97
- /** A launch argument whose private leaves are resolved immediately before spawn. */
98
- export interface WorkspacePlanArgumentTemplate {
99
- kind: "workspace-plan-argument-template";
100
- segments: Array<string | WorkspacePlanSecretSegment>;
101
- }
102
- export type WorkspacePlanArgument = string | WorkspacePlanArgumentTemplate;
103
- /** Public bytes stay strings; secret references stay opaque until application. */
104
- export type WorkspacePlanConfigValue = string | AgentProfileSecretRef;
105
- export interface Unsupported {
106
- dimension: "files" | "skills" | "mcp" | "hooks" | "subagents" | "commands" | "instructions" | "systemPrompt" | "appendSystemPrompt" | "connections" | "confidential" | "permissions" | "tools" | "modes" | "extensions";
107
- reason: string;
108
- }
109
- /**
110
- * The subset of {@link BINDABLE_LAUNCH_CONTROLS} the plan HANDS OVER rather than
111
- * executes: controls a caller reaches only by composing the harness's own
112
- * configuration, so no file, flag or env var the plan writes can touch them.
113
- *
114
- * - `opencode.agent-prompt` — opencode's `agent.<name>.prompt` config field,
115
- * the one control that replaces its built-in provider prompt. It binds to a
116
- * SINGLE agent, and the agent is chosen at launch. A caller that builds
117
- * opencode's config itself and picks the agent there reads neither
118
- * `plan.files` nor `plan.flags`, so for that one the plan names the control
119
- * and hands over the text in {@link WorkspacePlan.systemPromptBinding}.
120
- *
121
- * Every other bindable control names a capability the plan still lowers itself
122
- * once the caller has declared the plan's launch inputs really reach the spawn.
123
- */
124
- export declare const EXECUTOR_SYSTEM_PROMPT_BINDINGS: readonly ["opencode.agent-prompt"];
125
- export type ExecutorSystemPromptBinding = (typeof EXECUTOR_SYSTEM_PROMPT_BINDINGS)[number];
126
- export declare function isExecutorSystemPromptBinding(value: string): value is ExecutorSystemPromptBinding;
127
- /**
128
- * A system-prompt intent handed to the launcher that declared it owns the
129
- * control, instead of being lowered into the workspace.
130
- *
131
- * Distinct from {@link WorkspacePlan.systemPrompt} — a launch ARGUMENT the
132
- * executor hands to a harness flag — and from the file/flag/env lowerings the
133
- * plan performs on its own. This names the exact control that must receive the
134
- * text and which of the two intents it is, so the launcher cannot apply it to
135
- * the wrong channel. Never written into an additive channel and never dropped:
136
- * a caller that has not declared it owns `control` gets the plan's own lowering
137
- * (or a refusal where the harness has no control at all) instead of this field.
138
- */
139
- export interface WorkspacePlanSystemPromptBinding {
140
- /** Which of the two prompt intents this is — never inferred from presence. */
141
- intent: "replace";
142
- /** The exact launcher control that must receive `systemPrompt`. */
143
- control: ExecutorSystemPromptBinding;
144
- /** Exact text the control receives. */
145
- systemPrompt: string;
146
- }
147
- /**
148
- * The dimensions `materializeProfile`'s `skip` option honors.
149
- *
150
- * Every other dimension is materialized unconditionally: generated plan files are pushed through
151
- * a single site that carries no dimension tag, so there is nothing to gate them on. Naming the
152
- * honored set keeps `skip: ["hooks"]` a loud rejection instead of a silent no-op.
153
- */
154
- export declare const SKIPPABLE_DIMENSIONS: readonly ["mcp", "extensions"];
155
- export type SkippableDimension = (typeof SKIPPABLE_DIMENSIONS)[number];
156
- export declare function isSkippableDimension(value: string): value is SkippableDimension;
157
- /**
158
- * Launcher controls an executor can declare it OWNS via `materializeProfile`'s
159
- * `binds` option.
160
- *
161
- * Some harness controls live outside any workspace: opencode's exact
162
- * system-prompt replacement (`agent.<name>.prompt`) binds to the ONE agent
163
- * whoever starts the process selects, which a plan-forwarding executor cannot
164
- * guarantee — so the plan refuses the intent (harnessSystemPromptIntents in
165
- * @tangle-network/agent-interface answers `replace: false` for opencode).
166
- *
167
- * The two declarations describe the two executor shapes that CAN reach it, and
168
- * each gets the lowering it can actually apply:
169
- *
170
- * - `systemPrompt` — the executor applies the plan's launch flags to the
171
- * spawn it owns, so the plan writes the generated `mode: primary` agent and
172
- * selects it with `--agent`.
173
- * - `opencode.agent-prompt` — the executor composes opencode's own config and
174
- * picks the agent there, reading neither plan files nor plan flags, so the
175
- * plan hands the text over in {@link WorkspacePlan.systemPromptBinding}
176
- * instead of writing a workspace agent that would never be selected.
177
- *
178
- * They are mutually exclusive claims about the same caller: declaring both is a
179
- * caller bug, not a broader capability.
180
- */
181
- export declare const BINDABLE_LAUNCH_CONTROLS: readonly ["systemPrompt", "opencode.agent-prompt"];
182
- export type BindableLaunchControl = (typeof BINDABLE_LAUNCH_CONTROLS)[number];
183
- /** The plan a caller writes into the run cwd, then applies to the spawn. */
184
- export interface WorkspacePlan {
185
- harness: HarnessId;
186
- /** Files to write relative to the run workspace (cwd). */
187
- files: PlanFile[];
188
- /** Env vars to set on the spawned process (for harnesses needing them). */
189
- env: Record<string, WorkspacePlanConfigValue>;
190
- /** Extra CLI flags to pass (e.g. kimi --mcp-config-file <path>). */
191
- flags: WorkspacePlanArgument[];
192
- /**
193
- * Exact text that REPLACES the harness's own system prompt, for harnesses
194
- * whose replacement control takes it as a launch argument the executor
195
- * supplies (claude-code `--system-prompt`, pi `--system-prompt`).
196
- *
197
- * Absent does NOT mean "no replacement was requested": a harness whose
198
- * control reads a file (codex, gemini) carries the replacement in
199
- * {@link WorkspacePlan.files} plus a flag or env var instead. Present means
200
- * the executor MUST bind it to that harness's replacement control — never to
201
- * an additive one, which would leave the built-in prompt in force.
202
- */
203
- systemPrompt?: string;
204
- /**
205
- * Exact text ADDED to the harness's own system prompt, which stays intact.
206
- *
207
- * Separate from {@link WorkspacePlan.systemPrompt} because the two are
208
- * different intents against the same channel, and every harness that has one
209
- * control may lack the other. An executor binds this ONLY to an additive
210
- * control (claude-code `--append-system-prompt`, pi
211
- * `--append-system-prompt`); there is no harness for which folding it into
212
- * the replacement is correct, because that would delete the built-in prompt
213
- * the caller asked to keep.
214
- */
215
- appendSystemPrompt?: string;
216
- /**
217
- * A prompt intent no workspace file, flag, or env var can execute, addressed
218
- * to the launcher control that can — see
219
- * {@link WorkspacePlanSystemPromptBinding}.
220
- *
221
- * Present ONLY when the caller declared it owns the named control, so a plan
222
- * built by a caller that forwards it to someone else's launcher never carries
223
- * one; that caller gets the intent in {@link WorkspacePlan.unsupported}
224
- * instead. Whoever reads it must bind it or throw — {@link
225
- * takeSystemPromptBinding} does both.
226
- */
227
- systemPromptBinding?: WorkspacePlanSystemPromptBinding;
228
- /** Dimensions requested but with NO cwd path on this harness — fail-closed record. */
229
- unsupported: Unsupported[];
230
- /**
231
- * Prerequisites the workspace files CANNOT establish on their own.
232
- *
233
- * A plan is a set of files, an env map, and flags. Some harness capabilities need more than
234
- * that to actually function: pi's MCP support is not built in, it arrives from an extension
235
- * that must be installed into the harness's own package directory and permitted to load. No
236
- * file written into a run workspace can make either true.
237
- *
238
- * Writing the config anyway and hoping is the failure this field exists to prevent: the
239
- * harness starts, silently has no MCP, and the agent runs without the tools it was configured
240
- * with while nothing reports a problem. So the plan states the requirement and the executor —
241
- * which knows where its harness is installed and how it spawns — verifies or refuses it.
242
- *
243
- * Optional because this is an additive field on a published type: a plan built before it
244
- * existed, or by a caller that does not construct one, is still a valid plan with no
245
- * prerequisites. Every plan this package builds sets it.
246
- */
247
- requires?: PlanRequirement[];
248
- }
249
- /**
250
- * One prerequisite a {@link WorkspacePlan} depends on but cannot create.
251
- *
252
- * Declarative on purpose: this package builds plans and never probes a filesystem, spawns a
253
- * process, or reaches the network. The executor holds that context and does the checking.
254
- */
255
- export interface PlanRequirement {
256
- /** The only kind so far: a harness extension/plugin that must be loaded for a dimension to work. */
257
- kind: "harness-extension";
258
- /** Dimension that produced the requirement, so a refusal can name what will not work. */
259
- dimension: Unsupported["dimension"];
260
- /** Package spec in the harness's own vocabulary, e.g. `npm:pi-mcp-adapter`. */
261
- id: string;
262
- /** Why the plan needs it — goes verbatim into the executor's refusal message. */
263
- reason: string;
264
- /** The exact command that satisfies it, so a failure is actionable without a doc lookup. */
265
- remedy: string;
266
- }
267
- /**
268
- * Proof of the profile workspace inputs applied before a harness is spawned.
269
- * `workspacePlanDigest` covers only the {@link WorkspacePlan}; it is not an
270
- * execution-plan digest and does not attest unrelated files in `workspaceDir`.
271
- */
272
- export interface WorkspacePlanReceipt {
273
- workspacePlanDigest: string;
274
- /** Public launch identity only; secret values never enter this receipt. */
275
- env: Record<string, WorkspacePlanConfigValue>;
276
- /** Public launch identity only; templates retain opaque secret references. */
277
- flags: WorkspacePlanArgument[];
278
- systemPrompt?: string;
279
- appendSystemPrompt?: string;
280
- /** The launcher-bound intent, so a receipt says which control owed the work. */
281
- systemPromptBinding?: WorkspacePlanSystemPromptBinding;
282
- unsupported: Unsupported[];
283
- written: string[];
284
- }
285
- /** Private values handed directly to the provider spawn, never to receipts. */
286
- export interface WorkspacePlanSpawnInputs {
287
- env: Record<string, string>;
288
- flags: string[];
289
- systemPrompt?: string;
290
- appendSystemPrompt?: string;
291
- /** Read it with {@link takeSystemPromptBinding}, which refuses a foreign control. */
292
- systemPromptBinding?: WorkspacePlanSystemPromptBinding;
293
- }
294
- /** Result of applying a public plan at the private executor boundary. */
295
- export interface WorkspacePlanApplication {
296
- receipt: WorkspacePlanReceipt;
297
- spawn: WorkspacePlanSpawnInputs;
298
- /** Resolved generated files intentionally consumed in memory by the runtime. */
299
- runtimeOnlyFiles: Record<string, string>;
300
- }
301
- /** The plan was applied, but one or more private staging files remain. */
302
- export declare class WorkspacePlanCleanupError extends AggregateError {
303
- readonly receipt: WorkspacePlanReceipt;
304
- readonly temporaryPaths: readonly string[];
305
- constructor(errors: readonly unknown[], receipt: WorkspacePlanReceipt, temporaryPaths: readonly string[]);
306
- }
307
- export interface ApplyWorkspacePlanOptions {
308
- /** Plan files consumed in memory by the runtime and never persisted to cwd. */
309
- runtimeOnlyFiles?: readonly string[];
310
- /** Existing workspace paths are either exact idempotent inputs or forbidden. */
311
- existingFiles?: "allow-identical" | "reject";
312
- /**
313
- * `workspacePlanDigest` of a plan a prior call already applied into this
314
- * workspace. When it equals this plan's digest, application writes no files:
315
- * the workspace holds the running agent's live state, and a file the agent
316
- * edited or removed since the prior application stays exactly as the agent
317
- * left it. Env, flags, prompt intents, and the receipt are still produced.
318
- * A different digest applies normally, so a plan that changed mid-session
319
- * still meets the existing-file refusal.
320
- */
321
- appliedPlanDigest?: string;
322
- }
323
- /** Fail when a profile asks for controls the chosen harness cannot execute. */
324
- export declare function assertWorkspacePlanSupported(plan: Pick<WorkspacePlan, "unsupported">): void;
325
- /**
326
- * Enforce plan supportability under the profile's `resources.failOnError`
327
- * policy. Strict by default: `failOnError` absent or `true` throws on any
328
- * unsupported dimension. An explicitly best-effort profile
329
- * (`failOnError: false`) materializes the supported subset instead; the
330
- * returned `"dimension: reason"` entries are what the caller must surface
331
- * as a warning so the skipped dimensions stay visible to operators.
332
- */
333
- export declare function enforceWorkspacePlanSupport(plan: Pick<WorkspacePlan, "unsupported">, failOnError: boolean | undefined): string[];
334
- /**
335
- * Candidate-safe workspace plan. Spawn values remain typed until the runtime
336
- * resolves them; the materializer never joins argv into a shell command.
337
- */
338
- export interface AgentCandidateWorkspacePlan {
339
- sourceProfileDigest: Sha256Digest;
340
- harness: HarnessId;
341
- files: PlanFile[];
342
- env: Record<string, AgentCandidateConfigValue>;
343
- flags: AgentCandidateConfigValue[];
344
- systemPrompt?: AgentCandidateConfigValue;
345
- appendSystemPrompt?: AgentCandidateConfigValue;
346
- unsupported: Unsupported[];
347
- }
348
- export interface AgentCandidateWorkspacePlanReceipt {
349
- profileActivation: AgentCandidateProfileActivation;
350
- application: AgentCandidateProfileApplication;
351
- env: Record<string, AgentCandidateConfigValue>;
352
- flags: AgentCandidateConfigValue[];
353
- systemPrompt?: AgentCandidateConfigValue;
354
- appendSystemPrompt?: AgentCandidateConfigValue;
355
- unsupported: Unsupported[];
356
- }
357
- /**
358
- * The replacement text this launcher must bind to `control`, or `undefined`
359
- * when the plan carries no launcher-bound intent.
360
- *
361
- * Throws for a binding addressed to a DIFFERENT control: the reader cannot
362
- * execute it, and answering `undefined` would start the agent with the
363
- * harness's own prompt still in force while nothing reported a problem — the
364
- * silent downgrade the binding exists to prevent. This is the seam where an
365
- * executor that cannot bind an intent says so, by name, instead of running a
366
- * profile whose prompt never took effect.
367
- */
368
- export declare function takeSystemPromptBinding(spawn: Pick<WorkspacePlanSpawnInputs, "systemPromptBinding">, control: ExecutorSystemPromptBinding): string | undefined;
369
- export interface MaterializeCandidateProfileOptions {
370
- /** Exact text fetched from pinned resource refs, keyed by declared SHA-256. */
371
- resolvedResources?: ReadonlyMap<Sha256Digest, string>;
372
- /**
373
- * Launcher controls this caller owns and will bind itself. The declaration
374
- * is forwarded to the classic materializer so candidate execution uses the
375
- * same lowering as ordinary profile execution.
376
- */
377
- binds?: readonly BindableLaunchControl[];
378
- }
379
- /**
380
- * Whether the harness LOADS its {@link CONTEXT_FILE} from cwd on its own.
381
- *
382
- * True for every harness whose CLI discovers the file by name (CLAUDE.md,
383
- * AGENTS.md, …). opencode is the exception: it reads only what its
384
- * `opencode.json` `instructions[]` names, so a caller writing context for
385
- * opencode must register the path as well as write it — see the `instructions`
386
- * lowering below, and the interactive TUI's persona fold.
387
- */
388
- export declare function harnessAutoLoadsContextFile(harness: HarnessId): boolean;
389
- /**
390
- * The project context file this harness reads from cwd — its stable, documented
391
- * ALWAYS-LOADED surface. Exported so a caller lowering additive context (e.g. a
392
- * bare TUI's persona, which has no per-message system channel) targets the same
393
- * file the materializer writes instructions to, instead of keeping its own copy
394
- * of this per-harness map.
395
- */
396
- export declare function harnessContextFile(harness: HarnessId): string;
397
- /**
398
- * cwd-relative native skill dir per harness, or null if the harness has no
399
- * cwd skill primitive (skills live in a user/global dir the workspace plan
400
- * cannot reach). Public so consumers composing a profile can (a) render the
401
- * exact path the platform will mount a skill at into their prompts instead
402
- * of hardcoding `~/.claude/skills/...`, and (b) branch on skill support
403
- * ahead of materialization instead of catching the materialize-time throw.
404
- */
405
- export declare const HARNESS_SKILL_DIRS: Readonly<Record<HarnessId, string | null>>;
406
- /**
407
- * Resolve the cwd-relative directory `resources.skills` refs materialize
408
- * into on `harness`. `null` means the harness cannot receive cwd skills, the
409
- * same condition that surfaces as an `unsupported`
410
- * "skills" entry (and an {@link assertWorkspacePlanSupported} throw) at
411
- * materialize time, exposed here as branchable data.
412
- */
413
- export declare function skillDirForHarness(harness: HarnessId): string | null;
414
- export interface ResolveAgentProfileResourcesOptions {
415
- /** Repository used when a GitHub resource omits its own `repository`. */
416
- repository?: string;
417
- fetch?: typeof globalThis.fetch;
418
- timeoutMs?: number;
419
- }
420
- /**
421
- * Resolve every GitHub resource to exact inline bytes before materialization.
422
- * The profile's default harness does not affect resource resolution.
423
- */
424
- export declare function resolveAgentProfileResources(inputProfile: AgentProfile, options?: ResolveAgentProfileResourcesOptions): Promise<AgentProfile>;
425
- /** Normalize any skill markdown (VB frontmatter `skill:`/`description:`, or raw) into a
426
- * harness SKILL.md with `name:`/`description:` frontmatter the harnesses require. */
427
- export declare function normalizeSkillMd(name: string, raw: string): string;
428
- /**
429
- * Build the WorkspacePlan for `profile` on `harness`. Pure — no IO. The caller
430
- * writes plan.files into the run cwd and applies plan.env/plan.flags to the spawn.
431
- * The explicit target harness takes precedence over the profile's default.
432
- */
433
- export declare function materializeProfile(inputProfile: AgentProfile, harness: HarnessId, opts?: {
434
- skip?: SkippableDimension[];
435
- /**
436
- * Launcher controls THIS caller owns and will bind itself — see
437
- * {@link BINDABLE_LAUNCH_CONTROLS}. Each names a control no workspace file,
438
- * flag or env var reaches on its own, so declaring one turns a plan-time
439
- * refusal into the lowering (or the hand-over) that control can execute.
440
- *
441
- * A promise, not a hint: declare a control only from the code that starts
442
- * the harness and writes that control. A caller that hands the plan to
443
- * someone else's launcher declares nothing and keeps the refusal, which is
444
- * what it can actually deliver.
445
- */
446
- binds?: readonly BindableLaunchControl[];
447
- }): WorkspacePlan;
448
- /**
449
- * Materialize a sealed candidate profile without weakening its process values.
450
- * Codex and Claude hooks use generated no-shell wrappers to preserve executable,
451
- * argv, and environment values separately. Other hook formats fail closed.
452
- */
453
- export declare function materializeCandidateProfile(profile: AgentCandidateProfile, harness: HarnessId, opts?: MaterializeCandidateProfileOptions): AgentCandidateWorkspacePlan;
454
- /**
455
- * Hash the exact files, modes, flags, environment, and unsupported dimensions
456
- * represented by a plan. Array order is preserved only where it changes spawn
457
- * behavior; unordered maps and file records are canonicalized first.
458
- */
459
- export declare function hashWorkspacePlan(plan: WorkspacePlan): string;
460
- /** Build the exact digest-free identity document required by agent-interface. */
461
- export declare function agentCandidateProfilePlanMaterial(plan: AgentCandidateWorkspacePlan): AgentCandidateProfilePlanMaterial;
462
- /**
463
- * Return the RFC 8785 UTF-8 bytes and SHA-256 identity of a candidate profile
464
- * plan. The returned bytes are the exact bytes embedded in receipt evidence.
465
- */
466
- export declare function canonicalizeAgentCandidateProfilePlan(plan: AgentCandidateWorkspacePlan): {
467
- material: AgentCandidateProfilePlanMaterial;
468
- bytes: Uint8Array;
469
- digest: Sha256Digest;
470
- };
471
- /** Capture portable evidence of the exact canonical profile-plan bytes. */
472
- export declare function captureAgentCandidateProfilePlan(plan: AgentCandidateWorkspacePlan): AgentCandidateProfilePlanEvidence;
473
- /**
474
- * Apply a candidate plan and return its spawn values together with captured
475
- * canonical evidence. No caller needs to re-serialize or reinterpret the plan.
476
- */
477
- export declare function applyAgentCandidateWorkspacePlan(plan: AgentCandidateWorkspacePlan, workspaceDir: string, targetWorkspace: AgentCandidateProfileApplication["targetWorkspace"]): AgentCandidateWorkspacePlanReceipt;
478
- /**
479
- * Apply a public-only WorkspacePlan. A plan with any secret reference fails
480
- * before the first write; private executors use
481
- * {@link applyWorkspacePlanWithSecretProvider} instead.
482
- */
483
- export declare function applyWorkspacePlan(plan: WorkspacePlan, workspaceDir: string, options?: ApplyWorkspacePlanOptions): WorkspacePlanReceipt;
484
- /**
485
- * Resolve opaque profile references through an executor-owned provider, then
486
- * apply the resulting private native files and launch inputs. Resolution
487
- * completes before any workspace write, and resolved values never enter the
488
- * public plan, digest, receipt, logs, or error messages.
489
- */
490
- export declare function applyWorkspacePlanWithSecretProvider(plan: WorkspacePlan, workspaceDir: string, secretProvider: AgentProfileSecretProvider, options?: ApplyWorkspacePlanOptions): Promise<WorkspacePlanApplication>;
491
- /** Tool IDs reported by the OpenCode binary shipped in the Sandbox image. */
492
- export declare const OPENCODE_NATIVE_TOOL_IDS: readonly ["apply_patch", "bash", "codesearch", "edit", "glob", "grep", "question", "read", "skill", "task", "todowrite", "webfetch", "websearch", "write"];
493
- /** Resolve portable and legacy profile names to current OpenCode tool IDs. */
494
- export declare function openCodeNativeToolId(name: string): string | undefined;
495
- /** OpenCode-native MCP configuration used by workspace and startup paths. */
496
- export type OpenCodeMcpConfig = Record<string, {
497
- type: "remote";
498
- url: string;
499
- enabled: boolean;
500
- headers?: Record<string, AgentProfileConfigValue>;
501
- } | {
502
- type: "local";
503
- command: Array<string | AgentProfileConfigValue>;
504
- enabled: boolean;
505
- environment?: Record<string, AgentProfileConfigValue>;
506
- }>;
507
- /** Lower canonical MCP definitions to OpenCode's native startup configuration. */
508
- export declare function openCodeMcpConfig(mcp: Record<string, AgentProfileMcpServer>): OpenCodeMcpConfig;
509
- export interface PrimeProfileSkill {
510
- name: string;
511
- content: string;
512
- }
513
- export interface PrimeProfileSubagent {
514
- name: string;
515
- description?: string;
516
- prompt?: string;
517
- metadata?: Record<string, unknown>;
518
- }
519
- /** Validated, materialization-ready view of the profile controls prime applies. */
520
- export interface PrimeProfileControls {
521
- systemPrompt?: string;
522
- appendSystemPrompt?: string;
523
- /** Composed caller instructions, lowered to the agent dir's AGENTS.md. */
524
- instructions?: string;
525
- skills: PrimeProfileSkill[];
526
- subagents: PrimeProfileSubagent[];
527
- }
528
- /** True when the controls materialize anything at all. */
529
- export declare function hasPrimeProfileMaterial(controls: PrimeProfileControls): boolean;
530
- /**
531
- * True when the controls must WRITE INTO the agent dir itself.
532
- *
533
- * Prompt files and skill dirs are named by a flag, so they can live anywhere
534
- * the agent can read (`--system-prompt` / `--append-system-prompt` resolve a
535
- * path when it exists, fork resource-loader.ts:41-56; `--skill` takes an
536
- * arbitrary dir, :437-442). The context file and the continual-harness store
537
- * are located BY the agent dir and have no flag, so they cannot move.
538
- *
539
- * An executor pointed at an agent dir it does not own (an operator's shared
540
- * dir) uses this to refuse exactly the controls it would have to write there,
541
- * while still binding the ones it can materialize elsewhere.
542
- */
543
- export declare function primeProfileNeedsAgentDir(controls: PrimeProfileControls): boolean;
544
- /**
545
- * Validate and extract the profile controls the prime agent-dir lowering
546
- * materializes. Throws {@link PrimeProfileError} on any control (or control
547
- * facet) the fork has no verified read path for — partial acceptance would
548
- * silently drop the rest.
549
- */
550
- export declare function readPrimeProfileControls(profile: AgentProfile | undefined): PrimeProfileControls;
551
- /**
552
- * Refuse a run whose selected model disagrees with the profile's own.
553
- *
554
- * One authority per run: a profile names the model it was written and scored
555
- * against, so running it on a different one silently scores a different agent.
556
- * Both sides go through {@link modelIdsMatch}, so the qualification level a
557
- * caller happened to use is not a conflict.
558
- *
559
- * `provider` is the executor's PROVIDER SELECTION, and is compared only when
560
- * the executor's provider is part of model identity. An executor whose
561
- * provider key is merely a namespace inside the agent dir passes it as
562
- * undefined and gets the model-name comparison alone.
563
- */
564
- export declare function assertPrimeModelAgreement(profile: AgentProfile | undefined, selected: {
565
- provider?: string;
566
- model: string;
567
- }): void;
568
- /** Deterministic harness-state entry id for a profile subagent name. */
569
- export declare function primeSubagentEntryId(name: string): string;
570
- /**
571
- * Write one agent-dir file atomically (temp + rename).
572
- *
573
- * Every file this lowering writes lands in a directory a LIVE agent may be
574
- * reading: prime reloads models.json at model-resolution time and re-reads the
575
- * harness store on every system-prompt build, so a partial write is observable.
576
- * `mode` is applied to the temp file before the rename, so the final file is
577
- * never briefly world-readable.
578
- */
579
- export declare function writePrimeAgentFile(path: string, data: string, mode?: number): void;
580
- export interface PrimeMaterializeOptions {
581
- /**
582
- * Where the FLAG-NAMED files go — the prompt files and the skills root.
583
- * Defaults to `agentDir`. An executor that does not own the agent dir points
584
- * this at a per-run directory of its own, so binding a profile's prompts and
585
- * skills writes nothing into a dir it must not modify. The context file and
586
- * the harness store have no flag and always land in `agentDir`; refuse those
587
- * with {@link primeProfileNeedsAgentDir} instead.
588
- */
589
- flagFileRoot?: string;
590
- /**
591
- * Reports state the executor should see but that does not fail the run
592
- * (currently: adopting entries a pre-shared executor left behind).
593
- */
594
- warn?: (msg: string, meta?: Record<string, unknown>) => void;
595
- }
596
- /**
597
- * Materialize the validated controls and return the extra spawn args that bind
598
- * them. Runs before every spawn (same place models.json is materialized), so a
599
- * continual agent dir is re-pinned to the current profile on each fresh prime
600
- * process.
601
- */
602
- export declare function materializePrimeProfileControls(agentDir: string, controls: PrimeProfileControls, options?: PrimeMaterializeOptions): string[];
603
- /**
604
- * Remove the files a PREVIOUS materialization of this lowering wrote, so a
605
- * profile that shrank cannot leave a stale instruction file or skill behind for
606
- * the next run against the same dirs.
607
- *
608
- * Only the paths this lowering NAMES are removed. There is deliberately no
609
- * manifest: a manifest would live where the agent can write it, and reading a
610
- * delete list out of agent-writable state turns pruning into an arbitrary-path
611
- * delete.
612
- */
613
- export declare function prunePrimeProfileMaterial(agentDir: string, options?: Pick<PrimeMaterializeOptions, "flagFileRoot">): void;
614
- /**
615
- * Upsert profile subagent specs into the fork's global continual-harness
616
- * store and remove profile-sourced entries the current profile no longer
617
- * declares. Agent-written entries (`source: "agent"`) — and every top-level
618
- * key this lowering does not manage — are preserved untouched.
619
- *
620
- * A store that exists but no longer parses raises
621
- * {@link PrimeHarnessStateError}: the file is the agent's own self-modification
622
- * state, and overwriting it destroys what the run was supposed to observe.
623
- */
624
- export declare function seedPrimeProfileSubagents(agentDir: string, subagents: PrimeProfileSubagent[], warn?: (msg: string, meta?: Record<string, unknown>) => void): void;
10
+ export { buildPiModelsConfig, buildPiModelsConfigFile, PI_MODELS_CONFIG_PATH, type PiModelsConfigFile, type PiModelsConfigInput, } from "./pi-models-config.js";
11
+ export { applyWorkspacePlan, applyWorkspacePlanWithSecretProvider, } from "./plan-application.js";
12
+ export { agentCandidateProfilePlanMaterial, canonicalizeAgentCandidateProfilePlan, captureAgentCandidateProfilePlan, hashWorkspacePlan, } from "./plan-digest.js";
13
+ export { takeSystemPromptBinding } from "./plan-prompt.js";
14
+ export { assertWorkspacePlanSupported, enforceWorkspacePlanSupport, } from "./plan-support.js";
15
+ export type { ApplyWorkspacePlanOptions, BindableLaunchControl, ExecutorSystemPromptBinding, PlanFile, PlanFileSecretSlot, PlanRequirement, SkippableDimension, Unsupported, WorkspacePlan, WorkspacePlanApplication, WorkspacePlanArgument, WorkspacePlanArgumentTemplate, WorkspacePlanConfigValue, WorkspacePlanReceipt, WorkspacePlanSecretSegment, WorkspacePlanSpawnInputs, WorkspacePlanSystemPromptBinding, } from "./plan-types.js";
16
+ export { BINDABLE_LAUNCH_CONTROLS, EXECUTOR_SYSTEM_PROMPT_BINDINGS, isExecutorSystemPromptBinding, isSkippableDimension, SKIPPABLE_DIMENSIONS, WorkspacePlanCleanupError, } from "./plan-types.js";
17
+ export type { PrimeMaterializeOptions } from "./prime-agent-dir.js";
18
+ export { materializePrimeProfileControls, 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_FORK_INSTALL, PRIME_FORK_PIN, 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 { materializeProfile, UNAVAILABLE_AGENT_PROFILE_SECRET_PROVIDER, } from "./profile-materializer.js";
24
+ export type { ResolveAgentProfileResourcesOptions } from "./resource-resolution.js";
25
+ export { normalizeSkillMd, resolveAgentProfileResources, } from "./resource-resolution.js";