@bjoernrochel/sevro 0.1.0-rc.7 → 1.0.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 (230) hide show
  1. package/CONTRIBUTING.md +22 -6
  2. package/README.md +5 -1
  3. package/docs/README.md +19 -15
  4. package/docs/architecture.md +138 -17
  5. package/docs/assets/README.md +5 -4
  6. package/docs/builtin-graders-v1.md +17 -3
  7. package/docs/codex-host.md +155 -49
  8. package/docs/contracts.md +2 -1
  9. package/docs/creating-cases.md +9 -2
  10. package/docs/development-cli.md +187 -19
  11. package/docs/documentation-quality.md +12 -2
  12. package/docs/evaluation-workflow.md +110 -0
  13. package/docs/extension-protocol-v1.md +26 -3
  14. package/docs/getting-started.md +23 -2
  15. package/docs/guide-evaluation.md +33 -1
  16. package/docs/identity-v1.md +25 -2
  17. package/docs/installing.md +11 -11
  18. package/docs/native-controls.md +76 -5
  19. package/docs/native-hosts.md +196 -7
  20. package/docs/reading-results.md +102 -0
  21. package/docs/recipes.md +489 -0
  22. package/docs/releases.md +31 -12
  23. package/docs/report-v1.md +29 -1
  24. package/docs/results-v1.md +141 -4
  25. package/docs/run-settings-v1.md +147 -0
  26. package/docs/runtime-v1.md +307 -18
  27. package/docs/troubleshooting.md +12 -12
  28. package/docs/typescript-quality.md +89 -26
  29. package/examples/recipes/candidate.ts +26 -0
  30. package/examples/recipes/cases/coding-change.json +21 -0
  31. package/examples/recipes/cases/host-tools.json +21 -0
  32. package/examples/recipes/cases/mise.json +21 -0
  33. package/examples/recipes/cases/node.json +21 -0
  34. package/examples/recipes/cases/python-uv.json +21 -0
  35. package/examples/recipes/cases/semantic.json +17 -0
  36. package/examples/recipes/coding-change/check.ts +23 -0
  37. package/examples/recipes/extension-artifacts.ts +65 -0
  38. package/examples/recipes/extension-methods.ts +174 -0
  39. package/examples/recipes/extension.ts +37 -0
  40. package/examples/recipes/repository-skill/.agents/skills/startup-guide/SKILL.md +7 -0
  41. package/examples/recipes/repository-skill/.claude/skills/startup-guide/SKILL.md +7 -0
  42. package/examples/recipes/repository-skill/README.md +3 -0
  43. package/examples/recipes/run-inputs.ts +188 -0
  44. package/examples/recipes/run-options.ts +131 -0
  45. package/examples/recipes/run.ts +63 -0
  46. package/examples/recipes/runtime/empty.json +1 -0
  47. package/examples/recipes/runtime/goals.json +1 -0
  48. package/examples/recipes/runtime/mise.json +6 -0
  49. package/examples/recipes/runtime/path.json +1 -0
  50. package/examples/recipes/runtime/plugins.json +4 -0
  51. package/examples/recipes/runtime/python-uv.json +10 -0
  52. package/examples/recipes/semantic-judge.ts +29 -0
  53. package/examples/templates/coding/adapter.ts +17 -0
  54. package/examples/templates/coding/case.json +15 -0
  55. package/examples/templates/repository-skill/.agents/skills/startup-guide/SKILL.md +6 -0
  56. package/examples/templates/repository-skill/extension-data.ts +64 -0
  57. package/examples/templates/repository-skill/extension.ts +31 -0
  58. package/examples/templates/response/adapter.ts +12 -0
  59. package/examples/templates/response/case.json +13 -0
  60. package/package.json +11 -5
  61. package/schemas/report-v1.schema.json +9 -0
  62. package/schemas/run-evidence-v1.schema.json +2 -1
  63. package/schemas/runtime-v1.schema.json +63 -7
  64. package/src/advisory.ts +2 -2
  65. package/src/candidate-artifacts.ts +206 -0
  66. package/src/candidate-codex-state.ts +185 -0
  67. package/src/case-validation.ts +73 -50
  68. package/src/cli/cancellation.ts +20 -0
  69. package/src/cli/command.ts +87 -0
  70. package/src/cli/completion.ts +15 -0
  71. package/src/cli/demo.ts +60 -0
  72. package/src/cli/evaluation.ts +55 -0
  73. package/src/cli/extension.ts +79 -0
  74. package/src/cli/help.ts +198 -0
  75. package/src/cli/hosts.ts +55 -0
  76. package/src/cli/init-settings.ts +30 -0
  77. package/src/cli/init.ts +111 -0
  78. package/src/{cli-invocation.ts → cli/invocation.ts} +214 -218
  79. package/src/cli/loading.ts +151 -0
  80. package/src/cli/preparation.ts +154 -0
  81. package/src/cli/presentation.ts +93 -0
  82. package/src/cli/progress.ts +6 -0
  83. package/src/cli/run-manifest.ts +128 -0
  84. package/src/cli/run-options.ts +403 -0
  85. package/src/cli/run-overrides.ts +69 -0
  86. package/src/cli/settings.ts +154 -0
  87. package/src/cli/summary.ts +43 -0
  88. package/src/cli.ts +13 -591
  89. package/src/contract-types.ts +94 -0
  90. package/src/engine.ts +13 -5
  91. package/src/evaluation/advisory.ts +150 -0
  92. package/src/{evaluation-check-plan.ts → evaluation/check-plan.ts} +103 -67
  93. package/src/evaluation/collection.ts +88 -0
  94. package/src/evaluation/context.ts +10 -0
  95. package/src/{evaluation-grading-host.ts → evaluation/grading-host.ts} +5 -5
  96. package/src/evaluation/grading.ts +235 -0
  97. package/src/{evaluation-invocation-plan.ts → evaluation/invocation-plan.ts} +147 -58
  98. package/src/{evaluation-plan.ts → evaluation/plan.ts} +208 -141
  99. package/src/evaluation/progress.ts +19 -0
  100. package/src/evaluation/resources.ts +241 -0
  101. package/src/evaluation/run.ts +206 -0
  102. package/src/{evaluation-semantic.ts → evaluation/semantic.ts} +133 -115
  103. package/src/evaluation/trial.ts +800 -0
  104. package/src/evaluation/types.ts +207 -0
  105. package/src/evidence/host-results.ts +85 -0
  106. package/src/evidence/retained-artifacts.ts +18 -0
  107. package/src/evidence/trial-writer.ts +203 -0
  108. package/src/evidence/usage.ts +17 -0
  109. package/src/extension-client.ts +34 -96
  110. package/src/extension-session.ts +24 -48
  111. package/src/{advisory-fixture.ts → fixtures/advisory.ts} +15 -76
  112. package/src/{fixture-bin.ts → fixtures/bin.ts} +1 -1
  113. package/src/{fixture-cleanup.ts → fixtures/cleanup.ts} +13 -7
  114. package/src/fixtures/create.ts +183 -0
  115. package/src/{generated-fixture.ts → fixtures/generated.ts} +10 -53
  116. package/src/{git-hooks.ts → fixtures/git-hooks.ts} +1 -1
  117. package/src/{preparation.ts → fixtures/preparation.ts} +6 -16
  118. package/src/{repository-fixture.ts → fixtures/repository.ts} +30 -64
  119. package/src/{fixture-setup.ts → fixtures/setup.ts} +33 -51
  120. package/src/{fixture-tools.ts → fixtures/tools.ts} +1 -1
  121. package/src/fixtures/workspace-state.ts +212 -0
  122. package/src/generated/cli-result.d.cts +2 -1
  123. package/src/generated/extension.d.cts +2 -1
  124. package/src/generated/report.cjs +1 -1
  125. package/src/generated/report.d.cts +2 -1
  126. package/src/generated/run-evidence.cjs +1 -1
  127. package/src/generated/run-evidence.d.cts +2 -1
  128. package/src/generated/runtime.cjs +1 -1
  129. package/src/generated/runtime.d.cts +2 -1
  130. package/src/git.ts +93 -0
  131. package/src/graders/git-head.ts +29 -84
  132. package/src/graders/shell.ts +57 -68
  133. package/src/host-diagnostic-redaction.ts +52 -0
  134. package/src/host-diagnostics.ts +331 -0
  135. package/src/hosts/claude-continuation.ts +57 -40
  136. package/src/hosts/claude-credential.ts +160 -63
  137. package/src/hosts/claude-events.ts +34 -18
  138. package/src/hosts/claude-keychain.ts +78 -21
  139. package/src/hosts/claude-login-recovery.ts +85 -0
  140. package/src/hosts/claude-login-refresh.ts +178 -0
  141. package/src/hosts/claude-login-store.ts +162 -0
  142. package/src/hosts/claude-login.ts +107 -0
  143. package/src/hosts/claude-native-goal.ts +15 -12
  144. package/src/hosts/claude-process.ts +10 -50
  145. package/src/hosts/claude-refresh-lock.ts +81 -0
  146. package/src/hosts/claude-repository-invocation.ts +9 -34
  147. package/src/hosts/claude-settings.ts +91 -14
  148. package/src/hosts/claude-skill-activations.ts +169 -0
  149. package/src/hosts/claude-state.ts +46 -16
  150. package/src/hosts/claude-tool-calls.ts +13 -10
  151. package/src/hosts/claude.ts +122 -73
  152. package/src/hosts/codex-app-server.ts +78 -52
  153. package/src/hosts/codex-configuration.ts +5 -10
  154. package/src/hosts/codex-exec-controls.ts +516 -0
  155. package/src/hosts/codex-marketplace.ts +12 -10
  156. package/src/hosts/codex-native-calls.ts +15 -122
  157. package/src/hosts/codex-process.ts +10 -54
  158. package/src/hosts/codex-profile.ts +50 -21
  159. package/src/hosts/codex-session-files.ts +1 -9
  160. package/src/hosts/codex-state.ts +141 -19
  161. package/src/hosts/codex.ts +221 -179
  162. package/src/hosts/isolation-common.ts +15 -11
  163. package/src/hosts/isolation-roots.ts +13 -20
  164. package/src/hosts/linux-sandbox.ts +27 -3
  165. package/src/hosts/mac-sandbox.ts +111 -18
  166. package/src/hosts/native-controls.ts +72 -22
  167. package/src/hosts/native-request.ts +55 -0
  168. package/src/hosts/process-lifecycle.ts +221 -45
  169. package/src/hosts/protected-worktrees.ts +1 -1
  170. package/src/hosts/skill-hook-catalog.ts +131 -0
  171. package/src/hosts/skill-hook-handler.ts +374 -0
  172. package/src/hosts/skill-hooks.ts +577 -0
  173. package/src/instrumentation.ts +7 -8
  174. package/src/native-transcript-state.ts +22 -3
  175. package/src/native-transcript-view.ts +52 -13
  176. package/src/native-transcripts.ts +34 -15
  177. package/src/paths.ts +22 -0
  178. package/src/process-lifecycle.ts +150 -0
  179. package/src/provenance.ts +27 -7
  180. package/src/prune.ts +300 -0
  181. package/src/report.ts +63 -36
  182. package/src/resolved-case.ts +1 -1
  183. package/src/results-lock.ts +42 -0
  184. package/src/results.ts +14 -18
  185. package/src/run-owner.ts +4 -4
  186. package/src/{runtime-config.ts → runtime/config.ts} +182 -44
  187. package/src/{runtime-discovery-apple.ts → runtime/discovery-apple.ts} +3 -3
  188. package/src/{runtime-discovery-providers.ts → runtime/discovery-providers.ts} +3 -9
  189. package/src/{runtime-discovery.ts → runtime/discovery.ts} +4 -4
  190. package/src/{runtime-hook-processes.ts → runtime/hook-processes.ts} +1 -1
  191. package/src/{runtime-hooks.ts → runtime/hooks.ts} +33 -22
  192. package/src/{runtime-paths.ts → runtime/paths.ts} +6 -18
  193. package/src/{runtime-query.ts → runtime/query.ts} +5 -5
  194. package/src/{runtime-seeds.ts → runtime/seeds.ts} +3 -3
  195. package/src/runtime/shared-cache.ts +130 -0
  196. package/src/{runtime-state.ts → runtime/state.ts} +28 -11
  197. package/src/schema-types.ts +73 -161
  198. package/src/shell.ts +4 -0
  199. package/src/transcript-retention.ts +146 -0
  200. package/src/value-guards.ts +22 -0
  201. package/docs/assets/sevro-logo.png +0 -0
  202. package/docs/assets/sevro-symbol.svg +0 -1
  203. package/docs/assets/sevro-wordmark.svg +0 -1
  204. package/docs/cache-ownership-validation.md +0 -49
  205. package/docs/claude-continuation-validation.md +0 -47
  206. package/docs/concurrency-validation.md +0 -86
  207. package/docs/configuration-root-validation.md +0 -70
  208. package/docs/engine-slice.md +0 -114
  209. package/docs/evidence/runtime-startup-30/README.md +0 -185
  210. package/docs/evidence/runtime-startup-30/after.json +0 -319
  211. package/docs/evidence/runtime-startup-30/baseline-timeout.jsonl +0 -2
  212. package/docs/evidence/runtime-startup-30/before.json +0 -403
  213. package/docs/evidence/runtime-startup-30/consumer-smoke.json +0 -63
  214. package/docs/evidence/runtime-startup-30/full-policy-diagnostic.jsonl +0 -3
  215. package/docs/evidence/runtime-startup-30/minimal-policy-diagnostic.jsonl +0 -3
  216. package/docs/evidence/runtime-startup-30/plugin-template-assessment.json +0 -20
  217. package/docs/evidence/runtime-startup-30/seedless-timeout.jsonl +0 -2
  218. package/docs/evidence.md +0 -17
  219. package/docs/fixture-cleanup-validation.md +0 -70
  220. package/docs/guide-verification.json +0 -239
  221. package/src/evaluation-context.ts +0 -257
  222. package/src/evaluation-fixture.ts +0 -313
  223. package/src/evaluation-run.ts +0 -198
  224. package/src/evaluation-trial.ts +0 -946
  225. package/src/evaluation-types.ts +0 -149
  226. package/src/hosts/claude-nested-skills.ts +0 -272
  227. package/src/hosts/codex-command-output.ts +0 -510
  228. package/src/hosts/codex-executor-command.ts +0 -291
  229. package/src/hosts/codex-skill-reads.ts +0 -609
  230. /package/src/{trial-scheduler.ts → evaluation/scheduler.ts} +0 -0
@@ -0,0 +1,235 @@
1
+ import {
2
+ assessGitHeadCheck,
3
+ gitHeadState,
4
+ type PreparedGitHeadCheck,
5
+ } from "../graders/git-head";
6
+ import { gradeOutput, type PreparedOutputCheck } from "../graders/output";
7
+ import {
8
+ assessShellCheck,
9
+ runShellCheck,
10
+ type PreparedShellCheck,
11
+ } from "../graders/shell";
12
+ import { evaluationProtectedRoots } from "../hosts/isolation-roots";
13
+ import { sha256 } from "../identity";
14
+ import type { TrialObservation } from "../evidence/trial-writer";
15
+ import {
16
+ ExtensionSourceChangedError,
17
+ type EvaluationRequest,
18
+ type EvaluationResult,
19
+ } from "../extension-session";
20
+ import type { CheckOutcome } from "../results";
21
+
22
+ export interface GradingFailure {
23
+ readonly message: string;
24
+ readonly cancelable: boolean;
25
+ }
26
+
27
+ export interface GradingResult {
28
+ checks: CheckOutcome[];
29
+ observations: TrialObservation[];
30
+ failure: GradingFailure | null;
31
+ }
32
+
33
+ function failedGrading(
34
+ checks: CheckOutcome[],
35
+ observations: TrialObservation[],
36
+ message: string,
37
+ ): GradingResult {
38
+ const failure = { message, cancelable: true };
39
+ return { checks, observations, failure };
40
+ }
41
+
42
+ export function gradeCandidateOutput(input: {
43
+ readonly result: { finalMessage: string | null; complete: boolean } | null;
44
+ readonly checks: readonly PreparedOutputCheck[];
45
+ readonly evidenceRefs: string[];
46
+ }): GradingResult {
47
+ try {
48
+ if (!input.result) throw new Error("host result is unavailable");
49
+ const checks = gradeOutput(
50
+ input.result.finalMessage,
51
+ input.result.complete,
52
+ [...input.checks],
53
+ ).map((check) => ({ ...check, evidenceRefs: [...input.evidenceRefs] }));
54
+ return { checks, observations: [], failure: null };
55
+ } catch {
56
+ return {
57
+ checks: [],
58
+ observations: [],
59
+ failure: {
60
+ message: "output grading did not complete",
61
+ cancelable: false,
62
+ },
63
+ };
64
+ }
65
+ }
66
+
67
+ interface ShellGradingInput {
68
+ readonly checks: readonly PreparedShellCheck[];
69
+ readonly protectedRoots:
70
+ Parameters<typeof evaluationProtectedRoots>[0] | null;
71
+ readonly execution: Omit<
72
+ Parameters<typeof runShellCheck>[1],
73
+ "protectedRoots"
74
+ >;
75
+ }
76
+
77
+ async function gradeShellCheck(
78
+ check: PreparedShellCheck,
79
+ execution: Parameters<typeof runShellCheck>[1],
80
+ ): Promise<{ check: CheckOutcome; observation: TrialObservation }> {
81
+ const result = await runShellCheck(check, execution);
82
+ const graded = assessShellCheck(check, result);
83
+ const id = `sevro.observation.shell.${check.id}`;
84
+ return {
85
+ observation: {
86
+ id,
87
+ source: "sevro.shell",
88
+ completeness: "complete",
89
+ data: {
90
+ exitCode: result.exitCode,
91
+ expectedExitCode: check.expectedExitCode,
92
+ ...(result.stdout === null
93
+ ? {}
94
+ : {
95
+ stdoutSha256: sha256(result.stdout),
96
+ stdoutByteLength: Buffer.byteLength(result.stdout, "utf8"),
97
+ }),
98
+ },
99
+ },
100
+ check: {
101
+ id: check.id,
102
+ grader: "sevro.shell",
103
+ status: graded.passed ? "passed" : "failed",
104
+ detail: graded.detail,
105
+ evidenceRefs: [id],
106
+ },
107
+ };
108
+ }
109
+
110
+ export async function gradeShellChecks(
111
+ input: ShellGradingInput,
112
+ ): Promise<GradingResult> {
113
+ const checks: CheckOutcome[] = [];
114
+ const observations: TrialObservation[] = [];
115
+ try {
116
+ if (!input.protectedRoots)
117
+ throw new Error("shell checks require explicit protected source roots");
118
+ const protectedRoots = await evaluationProtectedRoots(input.protectedRoots);
119
+ for (const check of input.checks) {
120
+ const graded = await gradeShellCheck(check, {
121
+ ...input.execution,
122
+ protectedRoots,
123
+ protectedRootsCanonical: true,
124
+ });
125
+ checks.push(graded.check);
126
+ observations.push(graded.observation);
127
+ }
128
+ return { checks, observations, failure: null };
129
+ } catch {
130
+ return failedGrading(
131
+ checks,
132
+ observations,
133
+ "shell grading did not complete",
134
+ );
135
+ }
136
+ }
137
+
138
+ export async function gradeGitHeadChecks(input: {
139
+ readonly checks: readonly PreparedGitHeadCheck[];
140
+ readonly base: string | null;
141
+ readonly workspace: string;
142
+ readonly signal?: AbortSignal;
143
+ }): Promise<GradingResult> {
144
+ const observations: TrialObservation[] = [];
145
+ try {
146
+ const base = input.base;
147
+ if (base === null) throw new Error("Git HEAD base revision is unavailable");
148
+ const state = await gitHeadState(input.workspace, base, input.signal);
149
+ const id = "sevro.observation.git-head";
150
+ observations.push({
151
+ id,
152
+ source: "sevro.git-head",
153
+ completeness: "complete",
154
+ data: {
155
+ baseRevision: base,
156
+ currentRevision: state.currentRevision,
157
+ baseAncestor: state.baseAncestor,
158
+ },
159
+ });
160
+ const checks = input.checks.map((check): CheckOutcome => {
161
+ const graded = assessGitHeadCheck(check, base, state);
162
+ return {
163
+ id: check.id,
164
+ grader: "sevro.git-head",
165
+ status: graded.passed ? "passed" : "failed",
166
+ detail: graded.detail,
167
+ evidenceRefs: [id],
168
+ };
169
+ });
170
+ return { checks, observations, failure: null };
171
+ } catch {
172
+ return failedGrading([], observations, "Git HEAD grading did not complete");
173
+ }
174
+ }
175
+
176
+ function extensionCheckResult(
177
+ check: EvaluationResult["checks"][number],
178
+ declared: ReadonlyMap<string, string>,
179
+ ): CheckOutcome {
180
+ const grader = declared.get(check.id);
181
+ if (grader === undefined)
182
+ throw new Error("extension returned an undeclared check");
183
+ return {
184
+ id: check.id,
185
+ grader,
186
+ status: check.status,
187
+ ...(check.detail ? { detail: check.detail } : {}),
188
+ evidenceRefs: check.evidenceRefs,
189
+ };
190
+ }
191
+
192
+ export interface ExtensionGradingResult {
193
+ checks: CheckOutcome[];
194
+ metrics: EvaluationResult["metrics"];
195
+ domainOutcomes: NonNullable<EvaluationResult["domainOutcomes"]>;
196
+ recommendation: "passed" | "failed" | "not_assessed" | null;
197
+ failure: GradingFailure | null;
198
+ }
199
+
200
+ export async function gradeExtensionChecks(input: {
201
+ readonly evaluate: (request: EvaluationRequest) => Promise<EvaluationResult>;
202
+ readonly request: EvaluationRequest;
203
+ readonly declarations: readonly { id: string; grader: string }[];
204
+ }): Promise<ExtensionGradingResult> {
205
+ try {
206
+ const result = await input.evaluate(input.request);
207
+ const declared = new Map(
208
+ input.declarations.map((check) => [check.id, check.grader]),
209
+ );
210
+ return {
211
+ checks: result.checks.map((check) =>
212
+ extensionCheckResult(check, declared),
213
+ ),
214
+ metrics: result.metrics,
215
+ domainOutcomes: result.domainOutcomes ?? [],
216
+ recommendation: result.taskVerdictRecommendation ?? null,
217
+ failure: null,
218
+ };
219
+ } catch (error) {
220
+ const failure = {
221
+ message:
222
+ error instanceof ExtensionSourceChangedError
223
+ ? "extension source inputs changed during evaluation; assessment was refused. Finish changing evaluator inputs, then start a fresh evaluation with inputs held stable."
224
+ : "extension grading did not complete",
225
+ cancelable: true,
226
+ };
227
+ return {
228
+ checks: [],
229
+ metrics: [],
230
+ domainOutcomes: [],
231
+ recommendation: null,
232
+ failure,
233
+ };
234
+ }
235
+ }
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  EvaluationConfigurationError,
3
3
  type EvaluationOptions,
4
+ type HostAdapter,
4
5
  type ResolvedCase,
5
- } from "./evaluation-types";
6
- import { fixtureParts, type InlineArtifact } from "./preparation";
7
- import { isStringArray } from "./value-guards";
8
- import type { PreparationResult } from "./extension-session";
6
+ } from "./types";
7
+ import { fixtureParts, type InlineArtifact } from "../fixtures/preparation";
8
+ import { isStringArray } from "../value-guards";
9
+ import type { PreparationResult } from "../extension-session";
9
10
 
10
11
  interface InvocationArtifacts {
11
12
  extensionPreparation: PreparationResult | null;
@@ -13,12 +14,39 @@ interface InvocationArtifacts {
13
14
  }
14
15
 
15
16
  type ClaudePluginDirectories = NonNullable<
16
- NonNullable<InvocationArtifacts["extensionPreparation"]>["claudePluginDirs"]
17
+ PreparationResult["claudePluginDirs"]
17
18
  >;
18
- type CodexMarketplace = NonNullable<
19
- NonNullable<InvocationArtifacts["extensionPreparation"]>["codexMarketplace"]
19
+ type CodexMarketplace = NonNullable<PreparationResult["codexMarketplace"]>;
20
+
21
+ interface PackageDeclarations {
22
+ readonly codexMarketplace: PreparationResult["codexMarketplace"];
23
+ readonly claudePluginDirs: PreparationResult["claudePluginDirs"];
24
+ }
25
+
26
+ interface PackagePlan extends InvocationArtifacts, PackageDeclarations {}
27
+
28
+ interface SkillDeclarations {
29
+ readonly codexSkillInvocation: PreparationResult["codexSkillInvocation"];
30
+ readonly codexRepositorySkillInvocation: PreparationResult["codexRepositorySkillInvocation"];
31
+ readonly claudeSkillInvocation: PreparationResult["claudeSkillInvocation"];
32
+ readonly claudeRepositorySkillInvocation: PreparationResult["claudeRepositorySkillInvocation"];
33
+ }
34
+
35
+ type CandidatePackageRequest = Pick<
36
+ Parameters<HostAdapter["run"]>[0],
37
+ "codexMarketplace" | "claudePluginDirs" | "explicitSkillInvocation"
20
38
  >;
21
39
 
40
+ export interface PreparedInvocation extends PackageDeclarations {
41
+ readonly selected: SelectedSkillInvocation;
42
+ readonly invocationToken: string | null;
43
+ readonly configuration: Partial<SkillDeclarations>;
44
+ readonly hostRequest: CandidatePackageRequest;
45
+ }
46
+
47
+ export const INVOCATION_PLACEHOLDER = "{{sevro.skill_invocation}}";
48
+ export const LEGACY_CODEX_PLACEHOLDER = "{{sevro.codex.skill_invocation}}";
49
+
22
50
  function uniquePluginRoots(value: unknown): value is string[] {
23
51
  return (
24
52
  isStringArray(value) &&
@@ -144,10 +172,10 @@ function validateCodexMarketplacePackage(
144
172
  );
145
173
  }
146
174
 
147
- function preparePackageArtifacts<T extends InvocationArtifacts>(
175
+ function preparePackageArtifacts(
148
176
  options: EvaluationOptions,
149
- state: T,
150
- ) {
177
+ state: InvocationArtifacts,
178
+ ): PackagePlan {
151
179
  const codexMarketplace = state.extensionPreparation?.codexMarketplace;
152
180
  const claudePluginDirs = state.extensionPreparation?.claudePluginDirs;
153
181
  validateClaudePluginPackage(options, claudePluginDirs, state.inlineArtifacts);
@@ -159,15 +187,9 @@ function preparePackageArtifacts<T extends InvocationArtifacts>(
159
187
  return { ...state, codexMarketplace, claudePluginDirs };
160
188
  }
161
189
 
162
- type PackagePlan = ReturnType<
163
- typeof preparePackageArtifacts<InvocationArtifacts>
164
- >;
165
- const INVOCATION_PLACEHOLDER = "{{sevro.skill_invocation}}";
166
- const LEGACY_CODEX_PLACEHOLDER = "{{sevro.codex.skill_invocation}}";
167
-
168
190
  function skillInvocationDeclarations(
169
- preparation: PackagePlan["extensionPreparation"],
170
- ) {
191
+ preparation: PreparationResult | null,
192
+ ): SkillDeclarations {
171
193
  return {
172
194
  codexSkillInvocation: preparation?.codexSkillInvocation,
173
195
  codexRepositorySkillInvocation: preparation?.codexRepositorySkillInvocation,
@@ -177,7 +199,6 @@ function skillInvocationDeclarations(
177
199
  };
178
200
  }
179
201
 
180
- type SkillDeclarations = ReturnType<typeof skillInvocationDeclarations>;
181
202
  type PluginSkillInvocation = NonNullable<
182
203
  SkillDeclarations["codexSkillInvocation"]
183
204
  >;
@@ -211,26 +232,96 @@ function selectedSkillInvocation(
211
232
  return { kind: "none" };
212
233
  }
213
234
 
214
- function invocationTokenFor(declarations: SkillDeclarations): string | null {
215
- if (declarations.codexRepositorySkillInvocation)
216
- return `$${declarations.codexRepositorySkillInvocation.skillName}`;
217
- if (declarations.claudeRepositorySkillInvocation)
218
- return `/${declarations.claudeRepositorySkillInvocation.skillName}`;
219
- if (declarations.codexSkillInvocation)
220
- return `$${declarations.codexSkillInvocation.pluginName}:${declarations.codexSkillInvocation.skillName}`;
221
- if (declarations.claudeSkillInvocation)
222
- return `/${declarations.claudeSkillInvocation.pluginName}:${declarations.claudeSkillInvocation.skillName}`;
223
- return null;
235
+ function skillInvocationConfiguration(
236
+ selected: SelectedSkillInvocation,
237
+ ): Partial<SkillDeclarations> {
238
+ switch (selected.kind) {
239
+ case "codex-plugin":
240
+ return { codexSkillInvocation: selected.value };
241
+ case "codex-repository":
242
+ return { codexRepositorySkillInvocation: selected.value };
243
+ case "claude-plugin":
244
+ return { claudeSkillInvocation: selected.value };
245
+ case "claude-repository":
246
+ return { claudeRepositorySkillInvocation: selected.value };
247
+ case "none":
248
+ return {};
249
+ }
224
250
  }
225
251
 
226
- function invocationMetadata(declarations: SkillDeclarations) {
227
- const repositoryInvocation =
228
- declarations.codexRepositorySkillInvocation ??
229
- declarations.claudeRepositorySkillInvocation;
230
- const invocation = repositoryInvocation
231
- ? { ...repositoryInvocation, scope: "repository" as const }
232
- : (declarations.codexSkillInvocation ?? declarations.claudeSkillInvocation);
233
- return { repositoryInvocation, invocation };
252
+ function candidateInvocationRequest(
253
+ selected: SelectedSkillInvocation,
254
+ ): CandidatePackageRequest {
255
+ switch (selected.kind) {
256
+ case "codex-plugin":
257
+ return {
258
+ explicitSkillInvocation: {
259
+ ...selected.value,
260
+ token: `$${selected.value.pluginName}:${selected.value.skillName}`,
261
+ },
262
+ };
263
+ case "claude-plugin":
264
+ return {
265
+ explicitSkillInvocation: {
266
+ ...selected.value,
267
+ token: `/${selected.value.pluginName}:${selected.value.skillName}`,
268
+ },
269
+ };
270
+ case "codex-repository":
271
+ return {
272
+ explicitSkillInvocation: {
273
+ ...selected.value,
274
+ scope: "repository",
275
+ token: `$${selected.value.skillName}`,
276
+ },
277
+ };
278
+ case "claude-repository":
279
+ return {
280
+ explicitSkillInvocation: {
281
+ ...selected.value,
282
+ scope: "repository",
283
+ token: `/${selected.value.skillName}`,
284
+ },
285
+ };
286
+ case "none":
287
+ return {};
288
+ }
289
+ }
290
+
291
+ function candidateMarketplaceRequest(
292
+ context: PackagePlan,
293
+ ): CandidatePackageRequest {
294
+ const marketplace = context.codexMarketplace;
295
+ if (!marketplace) return {};
296
+ return {
297
+ codexMarketplace: {
298
+ ...marketplace,
299
+ artifactPaths: context.inlineArtifacts
300
+ .filter((artifact) =>
301
+ artifact.relativePath.startsWith(`${marketplace.artifactRoot}/`),
302
+ )
303
+ .map((artifact) => artifact.relativePath),
304
+ },
305
+ };
306
+ }
307
+
308
+ function candidatePluginDirectoriesRequest(
309
+ context: PackagePlan,
310
+ ): CandidatePackageRequest {
311
+ const directories = context.claudePluginDirs;
312
+ if (!directories) return {};
313
+ return {
314
+ claudePluginDirs: {
315
+ ...directories,
316
+ artifactPaths: context.inlineArtifacts
317
+ .filter((artifact) =>
318
+ directories.artifactRoots.some((root) =>
319
+ artifact.relativePath.startsWith(`${root}/`),
320
+ ),
321
+ )
322
+ .map((artifact) => artifact.relativePath),
323
+ },
324
+ };
234
325
  }
235
326
 
236
327
  function promptPlaceholderCount(
@@ -509,38 +600,36 @@ function validateSelectedSkillInvocation(
509
600
  }
510
601
  }
511
602
 
512
- function prepareSkillInvocation<T extends PackagePlan>(
603
+ function prepareSkillInvocation(
513
604
  options: EvaluationOptions,
514
- state: T,
515
- ) {
605
+ state: PackagePlan,
606
+ ): PreparedInvocation {
516
607
  const declarations = skillInvocationDeclarations(state.extensionPreparation);
517
- const metadata = invocationMetadata(declarations);
518
- const invocationToken = invocationTokenFor(declarations);
519
608
  const placeholderCount =
520
609
  promptPlaceholderCount(options.case, INVOCATION_PLACEHOLDER) +
521
610
  promptPlaceholderCount(options.case, LEGACY_CODEX_PLACEHOLDER);
522
611
  validateOnlyOneInvocation(declarations);
523
- validateSelectedSkillInvocation(
524
- options,
525
- state,
526
- selectedSkillInvocation(declarations),
527
- placeholderCount,
528
- );
612
+ const selected = selectedSkillInvocation(declarations);
613
+ validateSelectedSkillInvocation(options, state, selected, placeholderCount);
614
+ const hostRequest = {
615
+ ...candidateMarketplaceRequest(state),
616
+ ...candidatePluginDirectoriesRequest(state),
617
+ ...candidateInvocationRequest(selected),
618
+ };
529
619
  return {
530
- ...state,
531
- ...declarations,
532
- ...metadata,
533
- invocationToken,
534
- invocationPlaceholder: INVOCATION_PLACEHOLDER,
535
- legacyCodexPlaceholder: LEGACY_CODEX_PLACEHOLDER,
536
- placeholderCount,
620
+ codexMarketplace: state.codexMarketplace,
621
+ claudePluginDirs: state.claudePluginDirs,
622
+ selected,
623
+ invocationToken: hostRequest.explicitSkillInvocation?.token ?? null,
624
+ configuration: skillInvocationConfiguration(selected),
625
+ hostRequest,
537
626
  };
538
627
  }
539
628
 
540
- export function prepareInvocationPlan<T extends InvocationArtifacts>(
629
+ export function prepareInvocationPlan(
541
630
  options: EvaluationOptions,
542
- state: T,
543
- ) {
631
+ state: InvocationArtifacts,
632
+ ): PreparedInvocation {
544
633
  return prepareSkillInvocation(
545
634
  options,
546
635
  preparePackageArtifacts(options, state),