@bjoernrochel/sevro 0.1.0-rc.2 → 0.1.0-rc.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +170 -0
- package/LICENSE +63 -136
- package/README.md +83 -66
- package/docs/README.md +44 -0
- package/docs/acknowledgements.md +14 -0
- package/docs/architecture.md +146 -0
- package/docs/assets/README.md +27 -0
- package/docs/assets/sevro-logo.png +0 -0
- package/docs/assets/sevro-symbol.svg +1 -0
- package/docs/assets/sevro-wordmark.svg +1 -0
- package/docs/builtin-graders-v1.md +41 -13
- package/docs/codex-host.md +184 -52
- package/docs/contracts.md +19 -0
- package/docs/creating-cases.md +139 -0
- package/docs/development-cli.md +190 -30
- package/docs/documentation-quality.md +61 -0
- package/docs/evaluation-workflow.md +110 -0
- package/docs/evidence/code-mode-controls-71.md +64 -0
- package/docs/evidence/code-mode-programs-85.md +64 -0
- package/docs/evidence/codex-state-73/README.md +204 -0
- package/docs/evidence/codex-state-73/darrow-migration.patch +182 -0
- package/docs/evidence/codex-state-73/results.json +661 -0
- package/docs/evidence/local-http-74.md +104 -0
- package/docs/evidence/runtime-startup-30/README.md +185 -0
- package/docs/evidence/runtime-startup-30/after.json +319 -0
- package/docs/evidence/runtime-startup-30/baseline-timeout.jsonl +2 -0
- package/docs/evidence/runtime-startup-30/before.json +403 -0
- package/docs/evidence/runtime-startup-30/consumer-smoke.json +63 -0
- package/docs/evidence/runtime-startup-30/full-policy-diagnostic.jsonl +3 -0
- package/docs/evidence/runtime-startup-30/minimal-policy-diagnostic.jsonl +3 -0
- package/docs/evidence/runtime-startup-30/plugin-template-assessment.json +20 -0
- package/docs/evidence/runtime-startup-30/seedless-timeout.jsonl +2 -0
- package/docs/evidence/skill-reads-70/results.json +823 -0
- package/docs/evidence.md +21 -0
- package/docs/extension-protocol-v1.md +50 -16
- package/docs/fixture-cleanup-validation.md +3 -0
- package/docs/getting-started.md +102 -0
- package/docs/guide-evaluation.md +89 -0
- package/docs/guide-verification.json +239 -0
- package/docs/identity-v1.md +35 -1
- package/docs/installing.md +88 -0
- package/docs/licenses/BUSL-1.1-0.1.0-rc.2.txt +159 -0
- package/docs/licensing.md +42 -0
- package/docs/native-controls.md +76 -5
- package/docs/native-hosts.md +228 -0
- package/docs/reading-results.md +141 -0
- package/docs/recipes.md +489 -0
- package/docs/releases.md +81 -40
- package/docs/report-v1.md +29 -1
- package/docs/results-v1.md +180 -0
- package/docs/run-settings-v1.md +147 -0
- package/docs/running-evaluations.md +31 -0
- package/docs/runtime-v1.md +614 -0
- package/docs/specs/repository-guide.md +58 -0
- package/docs/troubleshooting.md +30 -0
- package/docs/typescript-quality.md +234 -0
- package/docs/usability-study.md +114 -0
- package/examples/basic/host.ts +2 -2
- package/examples/recipes/candidate.ts +26 -0
- package/examples/recipes/cases/coding-change.json +21 -0
- package/examples/recipes/cases/host-tools.json +21 -0
- package/examples/recipes/cases/mise.json +21 -0
- package/examples/recipes/cases/node.json +21 -0
- package/examples/recipes/cases/python-uv.json +21 -0
- package/examples/recipes/cases/semantic.json +17 -0
- package/examples/recipes/coding-change/check.ts +23 -0
- package/examples/recipes/extension-artifacts.ts +65 -0
- package/examples/recipes/extension-methods.ts +174 -0
- package/examples/recipes/extension.ts +37 -0
- package/examples/recipes/repository-skill/.agents/skills/startup-guide/SKILL.md +7 -0
- package/examples/recipes/repository-skill/.claude/skills/startup-guide/SKILL.md +7 -0
- package/examples/recipes/repository-skill/README.md +3 -0
- package/examples/recipes/run-inputs.ts +188 -0
- package/examples/recipes/run-options.ts +131 -0
- package/examples/recipes/run.ts +63 -0
- package/examples/recipes/runtime/empty.json +1 -0
- package/examples/recipes/runtime/goals.json +1 -0
- package/examples/recipes/runtime/mise.json +6 -0
- package/examples/recipes/runtime/path.json +1 -0
- package/examples/recipes/runtime/plugins.json +4 -0
- package/examples/recipes/runtime/python-uv.json +10 -0
- package/examples/recipes/semantic-judge.ts +29 -0
- package/examples/templates/coding/adapter.ts +17 -0
- package/examples/templates/coding/case.json +15 -0
- package/examples/templates/repository-skill/.agents/skills/startup-guide/SKILL.md +6 -0
- package/examples/templates/repository-skill/extension-data.ts +64 -0
- package/examples/templates/repository-skill/extension.ts +31 -0
- package/examples/templates/response/adapter.ts +12 -0
- package/examples/templates/response/case.json +13 -0
- package/package.json +39 -6
- package/schemas/report-v1.schema.json +9 -0
- package/schemas/run-evidence-v1.schema.json +2 -1
- package/schemas/runtime-v1.schema.json +193 -0
- package/src/advisory.ts +10 -5
- package/src/candidate-artifacts.ts +208 -0
- package/src/candidate-codex-state.ts +185 -0
- package/src/case-validation.ts +105 -0
- package/src/cli/cancellation.ts +20 -0
- package/src/cli/command.ts +81 -0
- package/src/cli/completion.ts +15 -0
- package/src/cli/demo.ts +59 -0
- package/src/cli/evaluation.ts +55 -0
- package/src/cli/extension.ts +79 -0
- package/src/cli/help.ts +222 -0
- package/src/cli/hosts.ts +59 -0
- package/src/cli/init-settings.ts +30 -0
- package/src/cli/init.ts +111 -0
- package/src/cli/invocation.ts +627 -0
- package/src/cli/loading.ts +151 -0
- package/src/cli/preparation.ts +163 -0
- package/src/cli/presentation.ts +91 -0
- package/src/cli/progress.ts +6 -0
- package/src/cli/run-manifest.ts +133 -0
- package/src/cli/run-options.ts +101 -0
- package/src/cli/run-overrides.ts +83 -0
- package/src/cli/settings.ts +160 -0
- package/src/cli/summary.ts +43 -0
- package/src/cli.ts +13 -843
- package/src/contract-types.ts +94 -0
- package/src/engine.ts +19 -2373
- package/src/evaluation/advisory.ts +150 -0
- package/src/evaluation/check-plan.ts +510 -0
- package/src/evaluation/collection.ts +88 -0
- package/src/evaluation/context.ts +10 -0
- package/src/evaluation/grading-host.ts +39 -0
- package/src/evaluation/grading.ts +258 -0
- package/src/evaluation/invocation-plan.ts +548 -0
- package/src/evaluation/plan.ts +736 -0
- package/src/evaluation/progress.ts +19 -0
- package/src/evaluation/resources.ts +241 -0
- package/src/evaluation/run.ts +206 -0
- package/src/{trial-scheduler.ts → evaluation/scheduler.ts} +3 -1
- package/src/evaluation/semantic.ts +312 -0
- package/src/evaluation/trial.ts +866 -0
- package/src/evaluation/types.ts +207 -0
- package/src/evidence/host-results.ts +92 -0
- package/src/evidence/retained-artifacts.ts +18 -0
- package/src/evidence/trial-writer.ts +203 -0
- package/src/evidence/usage.ts +17 -0
- package/src/extension-client.ts +228 -148
- package/src/extension-session.ts +326 -195
- package/src/fixtures/advisory.ts +338 -0
- package/src/fixtures/bin.ts +57 -0
- package/src/{fixture-cleanup.ts → fixtures/cleanup.ts} +13 -7
- package/src/fixtures/create.ts +187 -0
- package/src/fixtures/generated.ts +300 -0
- package/src/fixtures/git-hooks.ts +24 -0
- package/src/fixtures/preparation.ts +270 -0
- package/src/{repository-fixture.ts → fixtures/repository.ts} +207 -85
- package/src/fixtures/setup.ts +224 -0
- package/src/fixtures/tools.ts +88 -0
- package/src/fixtures/workspace-state.ts +212 -0
- package/src/generated/cli-result.cjs +2 -0
- package/src/generated/cli-result.d.cts +3 -0
- package/src/generated/extension.cjs +2 -0
- package/src/generated/extension.d.cts +3 -0
- package/src/generated/report.cjs +2 -0
- package/src/generated/report.d.cts +3 -0
- package/src/generated/run-evidence.cjs +2 -0
- package/src/generated/run-evidence.d.cts +3 -0
- package/src/generated/runtime.cjs +2 -0
- package/src/generated/runtime.d.cts +3 -0
- package/src/graders/artifact.ts +56 -23
- package/src/graders/git-head.ts +79 -75
- package/src/graders/output.ts +222 -140
- package/src/graders/semantic.ts +102 -43
- package/src/graders/shell.ts +379 -207
- package/src/host-diagnostic-redaction.ts +52 -0
- package/src/host-diagnostics.ts +319 -0
- package/src/hosts/claude-continuation.ts +63 -18
- package/src/hosts/claude-credential.ts +43 -62
- package/src/hosts/claude-events.ts +86 -51
- package/src/hosts/claude-keychain.ts +59 -0
- package/src/hosts/claude-native-goal.ts +57 -33
- package/src/hosts/claude-process.ts +111 -0
- package/src/hosts/claude-repository-invocation.ts +208 -117
- package/src/hosts/claude-settings.ts +240 -21
- package/src/hosts/claude-skill-activations.ts +166 -0
- package/src/hosts/claude-state.ts +403 -0
- package/src/hosts/claude-tool-calls.ts +171 -106
- package/src/hosts/claude.ts +561 -451
- package/src/hosts/codex-app-server.ts +326 -178
- package/src/hosts/codex-configuration.ts +44 -18
- package/src/hosts/codex-events.ts +97 -60
- package/src/hosts/codex-exec-controls.ts +516 -0
- package/src/hosts/codex-invocation.ts +70 -0
- package/src/hosts/codex-marketplace.ts +283 -0
- package/src/hosts/codex-native-calls.ts +546 -500
- package/src/hosts/codex-process.ts +202 -0
- package/src/hosts/codex-profile.ts +257 -28
- package/src/hosts/codex-session-files.ts +106 -0
- package/src/hosts/codex-state.ts +492 -0
- package/src/hosts/codex.ts +783 -832
- package/src/hosts/isolation-common.ts +94 -0
- package/src/hosts/isolation-roots.ts +54 -27
- package/src/hosts/isolation.ts +10 -0
- package/src/hosts/linux-sandbox.ts +159 -0
- package/src/hosts/mac-sandbox.ts +187 -61
- package/src/hosts/native-controls.ts +152 -62
- package/src/hosts/process-lifecycle.ts +37 -0
- package/src/hosts/protected-worktrees.ts +51 -19
- package/src/hosts/skill-hook-catalog.ts +131 -0
- package/src/hosts/skill-hook-handler.ts +374 -0
- package/src/hosts/skill-hooks.ts +580 -0
- package/src/hosts/workspace-fingerprint.ts +55 -35
- package/src/identity.ts +102 -48
- package/src/instrumentation.ts +109 -48
- package/src/native-transcript-state.ts +131 -0
- package/src/native-transcript-view.ts +90 -0
- package/src/native-transcripts.ts +286 -0
- package/src/process-lifecycle.ts +150 -0
- package/src/provenance.ts +161 -81
- package/src/prune.ts +215 -0
- package/src/report.ts +172 -140
- package/src/resolved-case.ts +33 -0
- package/src/results-lock.ts +29 -0
- package/src/results.ts +133 -86
- package/src/run-owner.ts +154 -63
- package/src/runtime/config.ts +456 -0
- package/src/runtime/discovery-apple.ts +90 -0
- package/src/runtime/discovery-providers.ts +63 -0
- package/src/runtime/discovery.ts +70 -0
- package/src/runtime/hook-processes.ts +97 -0
- package/src/runtime/hooks.ts +476 -0
- package/src/runtime/paths.ts +313 -0
- package/src/runtime/query.ts +85 -0
- package/src/runtime/seeds.ts +134 -0
- package/src/runtime/shared-cache.ts +143 -0
- package/src/runtime/state.ts +143 -0
- package/src/schema-types.ts +198 -0
- package/src/schema.ts +15 -19
- package/src/transcript-retention.ts +146 -0
- package/src/value-guards.ts +20 -0
- package/src/advisory-fixture.ts +0 -282
- package/src/fixture-bin.ts +0 -87
- package/src/fixture-setup.ts +0 -163
- package/src/generated-fixture.ts +0 -220
- package/src/git-hooks.ts +0 -63
- package/src/hosts/claude-nested-skills.ts +0 -218
- package/src/hosts/codex-command-output.ts +0 -399
- package/src/hosts/codex-executor-command.ts +0 -195
- package/src/hosts/codex-skill-reads.ts +0 -391
- package/src/preparation.ts +0 -211
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EvaluationConfigurationError,
|
|
3
|
+
type EvaluationOptions,
|
|
4
|
+
type ResolvedCase,
|
|
5
|
+
} from "./types";
|
|
6
|
+
import { fixtureParts, type InlineArtifact } from "../fixtures/preparation";
|
|
7
|
+
import { isStringArray } from "../value-guards";
|
|
8
|
+
import type { PreparationResult } from "../extension-session";
|
|
9
|
+
|
|
10
|
+
interface InvocationArtifacts {
|
|
11
|
+
extensionPreparation: PreparationResult | null;
|
|
12
|
+
inlineArtifacts: InlineArtifact[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type ClaudePluginDirectories = NonNullable<
|
|
16
|
+
NonNullable<InvocationArtifacts["extensionPreparation"]>["claudePluginDirs"]
|
|
17
|
+
>;
|
|
18
|
+
type CodexMarketplace = NonNullable<
|
|
19
|
+
NonNullable<InvocationArtifacts["extensionPreparation"]>["codexMarketplace"]
|
|
20
|
+
>;
|
|
21
|
+
|
|
22
|
+
function uniquePluginRoots(value: unknown): value is string[] {
|
|
23
|
+
return (
|
|
24
|
+
isStringArray(value) &&
|
|
25
|
+
value.length > 0 &&
|
|
26
|
+
new Set(value).size === value.length
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function validateClaudePluginRoots(roots: string[]): void {
|
|
31
|
+
try {
|
|
32
|
+
if (!uniquePluginRoots(roots)) throw new Error("invalid plugin roots");
|
|
33
|
+
for (const root of roots) fixtureParts(root);
|
|
34
|
+
if (
|
|
35
|
+
roots.some((root) =>
|
|
36
|
+
roots.some((other) => root !== other && root.startsWith(`${other}/`)),
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
throw new Error("overlapping plugin roots");
|
|
40
|
+
} catch (cause) {
|
|
41
|
+
throw new EvaluationConfigurationError(
|
|
42
|
+
"invalid Claude plugin directory declaration",
|
|
43
|
+
{ cause },
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function requireNegotiatedCapability(
|
|
49
|
+
options: EvaluationOptions,
|
|
50
|
+
capability: string,
|
|
51
|
+
message: string,
|
|
52
|
+
): void {
|
|
53
|
+
if (
|
|
54
|
+
!options.extension?.session.identity.capabilities.includes(capability) ||
|
|
55
|
+
!options.host.hostCapabilities?.includes(capability)
|
|
56
|
+
)
|
|
57
|
+
throw new EvaluationConfigurationError(message);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function validatePackageManifest(
|
|
61
|
+
files: InlineArtifact[],
|
|
62
|
+
manifest: string,
|
|
63
|
+
message: string,
|
|
64
|
+
): void {
|
|
65
|
+
if (
|
|
66
|
+
!files.length ||
|
|
67
|
+
!files.every((artifact) => artifact.gitExclude) ||
|
|
68
|
+
!files.some((artifact) => artifact.relativePath === manifest)
|
|
69
|
+
)
|
|
70
|
+
throw new EvaluationConfigurationError(message);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function validateClaudePluginPackage(
|
|
74
|
+
options: EvaluationOptions,
|
|
75
|
+
directories: ClaudePluginDirectories | undefined,
|
|
76
|
+
artifacts: InlineArtifact[],
|
|
77
|
+
): void {
|
|
78
|
+
if (!directories) return;
|
|
79
|
+
const roots = directories.artifactRoots;
|
|
80
|
+
validateClaudePluginRoots(roots);
|
|
81
|
+
requireNegotiatedCapability(
|
|
82
|
+
options,
|
|
83
|
+
"sevro.claude.plugin-dirs",
|
|
84
|
+
"Claude plugin directory capability was not negotiated",
|
|
85
|
+
);
|
|
86
|
+
for (const root of roots) {
|
|
87
|
+
const files = artifacts.filter((artifact) =>
|
|
88
|
+
artifact.relativePath.startsWith(`${root}/`),
|
|
89
|
+
);
|
|
90
|
+
validatePackageManifest(
|
|
91
|
+
files,
|
|
92
|
+
`${root}/.claude-plugin/plugin.json`,
|
|
93
|
+
"Claude plugin directory requires Git-excluded package artifacts and a manifest",
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function marketplaceNamesValid(name: string, plugins: string[]): boolean {
|
|
99
|
+
return (
|
|
100
|
+
/^[a-z][a-z0-9-]*$/.test(name) &&
|
|
101
|
+
plugins.length > 0 &&
|
|
102
|
+
!plugins.some((plugin) => !/^[a-z][a-z0-9-]*$/.test(plugin)) &&
|
|
103
|
+
new Set(plugins).size === plugins.length
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function validateMarketplaceDeclaration(marketplace: CodexMarketplace): void {
|
|
108
|
+
try {
|
|
109
|
+
fixtureParts(marketplace.artifactRoot);
|
|
110
|
+
if (
|
|
111
|
+
!marketplaceNamesValid(
|
|
112
|
+
marketplace.marketplaceName,
|
|
113
|
+
marketplace.pluginNames,
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
throw new Error("invalid marketplace or plugin name");
|
|
117
|
+
} catch (cause) {
|
|
118
|
+
throw new EvaluationConfigurationError(
|
|
119
|
+
"invalid Codex marketplace declaration",
|
|
120
|
+
{ cause },
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function validateCodexMarketplacePackage(
|
|
126
|
+
options: EvaluationOptions,
|
|
127
|
+
marketplace: CodexMarketplace | undefined,
|
|
128
|
+
artifacts: InlineArtifact[],
|
|
129
|
+
): void {
|
|
130
|
+
if (!marketplace) return;
|
|
131
|
+
validateMarketplaceDeclaration(marketplace);
|
|
132
|
+
requireNegotiatedCapability(
|
|
133
|
+
options,
|
|
134
|
+
"sevro.codex.plugin-marketplace",
|
|
135
|
+
"Codex marketplace capability was not negotiated",
|
|
136
|
+
);
|
|
137
|
+
const files = artifacts.filter((artifact) =>
|
|
138
|
+
artifact.relativePath.startsWith(`${marketplace.artifactRoot}/`),
|
|
139
|
+
);
|
|
140
|
+
validatePackageManifest(
|
|
141
|
+
files,
|
|
142
|
+
`${marketplace.artifactRoot}/.claude-plugin/marketplace.json`,
|
|
143
|
+
"Codex marketplace requires Git-excluded package artifacts and a manifest",
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function preparePackageArtifacts<T extends InvocationArtifacts>(
|
|
148
|
+
options: EvaluationOptions,
|
|
149
|
+
state: T,
|
|
150
|
+
) {
|
|
151
|
+
const codexMarketplace = state.extensionPreparation?.codexMarketplace;
|
|
152
|
+
const claudePluginDirs = state.extensionPreparation?.claudePluginDirs;
|
|
153
|
+
validateClaudePluginPackage(options, claudePluginDirs, state.inlineArtifacts);
|
|
154
|
+
validateCodexMarketplacePackage(
|
|
155
|
+
options,
|
|
156
|
+
codexMarketplace,
|
|
157
|
+
state.inlineArtifacts,
|
|
158
|
+
);
|
|
159
|
+
return { ...state, codexMarketplace, claudePluginDirs };
|
|
160
|
+
}
|
|
161
|
+
|
|
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
|
+
function skillInvocationDeclarations(
|
|
169
|
+
preparation: PackagePlan["extensionPreparation"],
|
|
170
|
+
) {
|
|
171
|
+
return {
|
|
172
|
+
codexSkillInvocation: preparation?.codexSkillInvocation,
|
|
173
|
+
codexRepositorySkillInvocation: preparation?.codexRepositorySkillInvocation,
|
|
174
|
+
claudeSkillInvocation: preparation?.claudeSkillInvocation,
|
|
175
|
+
claudeRepositorySkillInvocation:
|
|
176
|
+
preparation?.claudeRepositorySkillInvocation,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
type SkillDeclarations = ReturnType<typeof skillInvocationDeclarations>;
|
|
181
|
+
type PluginSkillInvocation = NonNullable<
|
|
182
|
+
SkillDeclarations["codexSkillInvocation"]
|
|
183
|
+
>;
|
|
184
|
+
type RepositorySkillInvocation = NonNullable<
|
|
185
|
+
SkillDeclarations["codexRepositorySkillInvocation"]
|
|
186
|
+
>;
|
|
187
|
+
type SelectedSkillInvocation =
|
|
188
|
+
| { kind: "codex-plugin"; value: PluginSkillInvocation }
|
|
189
|
+
| { kind: "codex-repository"; value: RepositorySkillInvocation }
|
|
190
|
+
| { kind: "claude-plugin"; value: PluginSkillInvocation }
|
|
191
|
+
| { kind: "claude-repository"; value: RepositorySkillInvocation }
|
|
192
|
+
| { kind: "none" };
|
|
193
|
+
|
|
194
|
+
function selectedSkillInvocation(
|
|
195
|
+
declarations: SkillDeclarations,
|
|
196
|
+
): SelectedSkillInvocation {
|
|
197
|
+
if (declarations.codexSkillInvocation)
|
|
198
|
+
return { kind: "codex-plugin", value: declarations.codexSkillInvocation };
|
|
199
|
+
if (declarations.codexRepositorySkillInvocation)
|
|
200
|
+
return {
|
|
201
|
+
kind: "codex-repository",
|
|
202
|
+
value: declarations.codexRepositorySkillInvocation,
|
|
203
|
+
};
|
|
204
|
+
if (declarations.claudeRepositorySkillInvocation)
|
|
205
|
+
return {
|
|
206
|
+
kind: "claude-repository",
|
|
207
|
+
value: declarations.claudeRepositorySkillInvocation,
|
|
208
|
+
};
|
|
209
|
+
if (declarations.claudeSkillInvocation)
|
|
210
|
+
return { kind: "claude-plugin", value: declarations.claudeSkillInvocation };
|
|
211
|
+
return { kind: "none" };
|
|
212
|
+
}
|
|
213
|
+
|
|
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;
|
|
224
|
+
}
|
|
225
|
+
|
|
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 };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function promptPlaceholderCount(
|
|
237
|
+
caseData: ResolvedCase,
|
|
238
|
+
placeholder: string,
|
|
239
|
+
): number {
|
|
240
|
+
return (
|
|
241
|
+
caseData.prompt.split(placeholder).length -
|
|
242
|
+
1 +
|
|
243
|
+
(caseData.followUpPrompt?.split(placeholder).length ?? 1) -
|
|
244
|
+
1
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function validateOnlyOneInvocation(declarations: SkillDeclarations): void {
|
|
249
|
+
if (
|
|
250
|
+
[
|
|
251
|
+
declarations.codexSkillInvocation,
|
|
252
|
+
declarations.codexRepositorySkillInvocation,
|
|
253
|
+
declarations.claudeSkillInvocation,
|
|
254
|
+
declarations.claudeRepositorySkillInvocation,
|
|
255
|
+
].filter(Boolean).length > 1
|
|
256
|
+
)
|
|
257
|
+
throw new EvaluationConfigurationError(
|
|
258
|
+
"only one explicit skill invocation may be declared",
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function validateCodexInvocationMembership(
|
|
263
|
+
marketplace: CodexMarketplace | undefined,
|
|
264
|
+
pluginName: string,
|
|
265
|
+
): asserts marketplace is CodexMarketplace {
|
|
266
|
+
if (
|
|
267
|
+
!marketplace ||
|
|
268
|
+
!marketplace.pluginNames.includes(pluginName) ||
|
|
269
|
+
!/^[a-z][a-z0-9-]*$/.test(pluginName)
|
|
270
|
+
)
|
|
271
|
+
throw new EvaluationConfigurationError(
|
|
272
|
+
"invalid Codex skill invocation declaration",
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function validateCodexInvocationBody(
|
|
277
|
+
marketplace: CodexMarketplace,
|
|
278
|
+
skillName: string,
|
|
279
|
+
artifacts: InlineArtifact[],
|
|
280
|
+
placeholders: number,
|
|
281
|
+
): void {
|
|
282
|
+
if (
|
|
283
|
+
!/^[A-Za-z0-9._-]+$/.test(skillName) ||
|
|
284
|
+
placeholders !== 1 ||
|
|
285
|
+
!artifacts.some(
|
|
286
|
+
(artifact) =>
|
|
287
|
+
artifact.relativePath ===
|
|
288
|
+
`${marketplace.artifactRoot}/plugin/skills/${skillName}/SKILL.md`,
|
|
289
|
+
)
|
|
290
|
+
)
|
|
291
|
+
throw new EvaluationConfigurationError(
|
|
292
|
+
"invalid Codex skill invocation declaration",
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function validateCodexPluginInvocation(
|
|
297
|
+
options: EvaluationOptions,
|
|
298
|
+
context: PackagePlan,
|
|
299
|
+
invocation: PluginSkillInvocation,
|
|
300
|
+
placeholders: number,
|
|
301
|
+
): void {
|
|
302
|
+
const marketplace = context.codexMarketplace;
|
|
303
|
+
validateCodexInvocationMembership(marketplace, invocation.pluginName);
|
|
304
|
+
validateCodexInvocationBody(
|
|
305
|
+
marketplace,
|
|
306
|
+
invocation.skillName,
|
|
307
|
+
context.inlineArtifacts,
|
|
308
|
+
placeholders,
|
|
309
|
+
);
|
|
310
|
+
requireNegotiatedCapability(
|
|
311
|
+
options,
|
|
312
|
+
"sevro.codex.explicit-invocation",
|
|
313
|
+
"Codex explicit invocation capability was not negotiated",
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function validRepositoryInvocationIdentity(
|
|
318
|
+
skillName: string,
|
|
319
|
+
placeholders: number,
|
|
320
|
+
): boolean {
|
|
321
|
+
return (
|
|
322
|
+
/^[A-Za-z0-9._-]+$/.test(skillName) &&
|
|
323
|
+
skillName !== "." &&
|
|
324
|
+
skillName !== ".." &&
|
|
325
|
+
placeholders === 1
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function validateRepositoryInvocationBody(
|
|
330
|
+
artifacts: InlineArtifact[],
|
|
331
|
+
path: string,
|
|
332
|
+
message: string,
|
|
333
|
+
): void {
|
|
334
|
+
if (
|
|
335
|
+
!artifacts.some(
|
|
336
|
+
(artifact) => artifact.gitExclude && artifact.relativePath === path,
|
|
337
|
+
)
|
|
338
|
+
)
|
|
339
|
+
throw new EvaluationConfigurationError(message);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function validateCodexRepositoryInvocation(
|
|
343
|
+
options: EvaluationOptions,
|
|
344
|
+
context: PackagePlan,
|
|
345
|
+
invocation: RepositorySkillInvocation,
|
|
346
|
+
placeholders: number,
|
|
347
|
+
): void {
|
|
348
|
+
const message = "invalid Codex repository skill invocation declaration";
|
|
349
|
+
if (!validRepositoryInvocationIdentity(invocation.skillName, placeholders))
|
|
350
|
+
throw new EvaluationConfigurationError(message);
|
|
351
|
+
validateRepositoryInvocationBody(
|
|
352
|
+
context.inlineArtifacts,
|
|
353
|
+
`.agents/skills/${invocation.skillName}/SKILL.md`,
|
|
354
|
+
message,
|
|
355
|
+
);
|
|
356
|
+
requireNegotiatedCapability(
|
|
357
|
+
options,
|
|
358
|
+
"sevro.codex.repository-invocation",
|
|
359
|
+
"Codex repository invocation capability was not negotiated",
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function validateClaudeRepositoryPrompt(prompt: string): void {
|
|
364
|
+
if (
|
|
365
|
+
!prompt.startsWith(INVOCATION_PLACEHOLDER) ||
|
|
366
|
+
prompt.includes(LEGACY_CODEX_PLACEHOLDER)
|
|
367
|
+
)
|
|
368
|
+
throw new EvaluationConfigurationError(
|
|
369
|
+
"invalid Claude repository skill invocation declaration",
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function validateClaudeRepositoryInvocation(
|
|
374
|
+
options: EvaluationOptions,
|
|
375
|
+
context: PackagePlan,
|
|
376
|
+
invocation: RepositorySkillInvocation,
|
|
377
|
+
placeholders: number,
|
|
378
|
+
): void {
|
|
379
|
+
const message = "invalid Claude repository skill invocation declaration";
|
|
380
|
+
if (!validRepositoryInvocationIdentity(invocation.skillName, placeholders))
|
|
381
|
+
throw new EvaluationConfigurationError(message);
|
|
382
|
+
validateClaudeRepositoryPrompt(options.case.prompt);
|
|
383
|
+
validateRepositoryInvocationBody(
|
|
384
|
+
context.inlineArtifacts,
|
|
385
|
+
`.claude/skills/${invocation.skillName}/SKILL.md`,
|
|
386
|
+
message,
|
|
387
|
+
);
|
|
388
|
+
requireNegotiatedCapability(
|
|
389
|
+
options,
|
|
390
|
+
"sevro.claude.repository-invocation",
|
|
391
|
+
"Claude repository invocation capability was not negotiated",
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function validateClaudeInvocationIdentity(
|
|
396
|
+
directories: ClaudePluginDirectories | undefined,
|
|
397
|
+
invocation: PluginSkillInvocation,
|
|
398
|
+
placeholders: number,
|
|
399
|
+
): asserts directories is ClaudePluginDirectories {
|
|
400
|
+
if (
|
|
401
|
+
!directories ||
|
|
402
|
+
!/^[a-z][a-z0-9-]*$/.test(invocation.pluginName) ||
|
|
403
|
+
!/^[A-Za-z0-9._-]+$/.test(invocation.skillName) ||
|
|
404
|
+
placeholders !== 1
|
|
405
|
+
)
|
|
406
|
+
throw new EvaluationConfigurationError(
|
|
407
|
+
"invalid Claude skill invocation declaration",
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function validateClaudePluginPrompt(caseData: ResolvedCase): void {
|
|
412
|
+
if (
|
|
413
|
+
caseData.prompt.includes(LEGACY_CODEX_PLACEHOLDER) ||
|
|
414
|
+
caseData.followUpPrompt?.includes(LEGACY_CODEX_PLACEHOLDER)
|
|
415
|
+
)
|
|
416
|
+
throw new EvaluationConfigurationError(
|
|
417
|
+
"invalid Claude skill invocation declaration",
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function validateClaudeInvocationBody(
|
|
422
|
+
directories: ClaudePluginDirectories,
|
|
423
|
+
skillName: string,
|
|
424
|
+
artifacts: InlineArtifact[],
|
|
425
|
+
): void {
|
|
426
|
+
if (
|
|
427
|
+
!directories.artifactRoots.some((root) =>
|
|
428
|
+
artifacts.some(
|
|
429
|
+
(artifact) =>
|
|
430
|
+
artifact.relativePath === `${root}/skills/${skillName}/SKILL.md`,
|
|
431
|
+
),
|
|
432
|
+
)
|
|
433
|
+
)
|
|
434
|
+
throw new EvaluationConfigurationError(
|
|
435
|
+
"invalid Claude skill invocation declaration",
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function validateClaudePluginInvocation(
|
|
440
|
+
options: EvaluationOptions,
|
|
441
|
+
context: PackagePlan,
|
|
442
|
+
invocation: PluginSkillInvocation,
|
|
443
|
+
placeholders: number,
|
|
444
|
+
): void {
|
|
445
|
+
const directories = context.claudePluginDirs;
|
|
446
|
+
validateClaudeInvocationIdentity(directories, invocation, placeholders);
|
|
447
|
+
validateClaudePluginPrompt(options.case);
|
|
448
|
+
validateClaudeInvocationBody(
|
|
449
|
+
directories,
|
|
450
|
+
invocation.skillName,
|
|
451
|
+
context.inlineArtifacts,
|
|
452
|
+
);
|
|
453
|
+
requireNegotiatedCapability(
|
|
454
|
+
options,
|
|
455
|
+
"sevro.claude.explicit-invocation",
|
|
456
|
+
"Claude explicit invocation capability was not negotiated",
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function validateUndeclaredPlaceholder(placeholders: number): void {
|
|
461
|
+
if (placeholders)
|
|
462
|
+
throw new EvaluationConfigurationError(
|
|
463
|
+
"skill invocation placeholder requires a declaration",
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function validateSelectedSkillInvocation(
|
|
468
|
+
options: EvaluationOptions,
|
|
469
|
+
context: PackagePlan,
|
|
470
|
+
selected: SelectedSkillInvocation,
|
|
471
|
+
placeholders: number,
|
|
472
|
+
): void {
|
|
473
|
+
switch (selected.kind) {
|
|
474
|
+
case "codex-plugin":
|
|
475
|
+
validateCodexPluginInvocation(
|
|
476
|
+
options,
|
|
477
|
+
context,
|
|
478
|
+
selected.value,
|
|
479
|
+
placeholders,
|
|
480
|
+
);
|
|
481
|
+
break;
|
|
482
|
+
case "codex-repository":
|
|
483
|
+
validateCodexRepositoryInvocation(
|
|
484
|
+
options,
|
|
485
|
+
context,
|
|
486
|
+
selected.value,
|
|
487
|
+
placeholders,
|
|
488
|
+
);
|
|
489
|
+
break;
|
|
490
|
+
case "claude-repository":
|
|
491
|
+
validateClaudeRepositoryInvocation(
|
|
492
|
+
options,
|
|
493
|
+
context,
|
|
494
|
+
selected.value,
|
|
495
|
+
placeholders,
|
|
496
|
+
);
|
|
497
|
+
break;
|
|
498
|
+
case "claude-plugin":
|
|
499
|
+
validateClaudePluginInvocation(
|
|
500
|
+
options,
|
|
501
|
+
context,
|
|
502
|
+
selected.value,
|
|
503
|
+
placeholders,
|
|
504
|
+
);
|
|
505
|
+
break;
|
|
506
|
+
case "none":
|
|
507
|
+
validateUndeclaredPlaceholder(placeholders);
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function prepareSkillInvocation<T extends PackagePlan>(
|
|
513
|
+
options: EvaluationOptions,
|
|
514
|
+
state: T,
|
|
515
|
+
) {
|
|
516
|
+
const declarations = skillInvocationDeclarations(state.extensionPreparation);
|
|
517
|
+
const metadata = invocationMetadata(declarations);
|
|
518
|
+
const invocationToken = invocationTokenFor(declarations);
|
|
519
|
+
const placeholderCount =
|
|
520
|
+
promptPlaceholderCount(options.case, INVOCATION_PLACEHOLDER) +
|
|
521
|
+
promptPlaceholderCount(options.case, LEGACY_CODEX_PLACEHOLDER);
|
|
522
|
+
validateOnlyOneInvocation(declarations);
|
|
523
|
+
validateSelectedSkillInvocation(
|
|
524
|
+
options,
|
|
525
|
+
state,
|
|
526
|
+
selectedSkillInvocation(declarations),
|
|
527
|
+
placeholderCount,
|
|
528
|
+
);
|
|
529
|
+
return {
|
|
530
|
+
...state,
|
|
531
|
+
...declarations,
|
|
532
|
+
...metadata,
|
|
533
|
+
invocationToken,
|
|
534
|
+
invocationPlaceholder: INVOCATION_PLACEHOLDER,
|
|
535
|
+
legacyCodexPlaceholder: LEGACY_CODEX_PLACEHOLDER,
|
|
536
|
+
placeholderCount,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export function prepareInvocationPlan<T extends InvocationArtifacts>(
|
|
541
|
+
options: EvaluationOptions,
|
|
542
|
+
state: T,
|
|
543
|
+
) {
|
|
544
|
+
return prepareSkillInvocation(
|
|
545
|
+
options,
|
|
546
|
+
preparePackageArtifacts(options, state),
|
|
547
|
+
);
|
|
548
|
+
}
|