@engineeros/connector 0.4.7 → 0.5.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.
- package/package.json +1 -1
- package/src/runner.mjs +105 -10
package/package.json
CHANGED
package/src/runner.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
1
|
import { spawn } from "node:child_process";
|
|
3
2
|
import {
|
|
4
3
|
lstat,
|
|
@@ -106,21 +105,117 @@ export async function executeAssignment(assignment, config, callbacks) {
|
|
|
106
105
|
const changedFiles = await changedFilePaths(runWorkspace);
|
|
107
106
|
if (!changedFiles.length)
|
|
108
107
|
throw new Error("Codex completed without changing any files.");
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
const committed = await commitRunChange(
|
|
109
|
+
runWorkspace,
|
|
110
|
+
assignment.base_revision,
|
|
111
|
+
assignment.run_id,
|
|
112
|
+
);
|
|
113
|
+
const verifier = launchCodexProcess(
|
|
114
|
+
runWorkspace,
|
|
115
|
+
verificationPrompt(assignment, committed.revision, committed.changedFiles),
|
|
116
|
+
"read-only",
|
|
117
|
+
callbacks,
|
|
118
|
+
);
|
|
119
|
+
callbacks.onProcess?.(verifier.child);
|
|
120
|
+
const verification = await verifier.completed;
|
|
121
|
+
const proofEvidence = parseVerificationReport(
|
|
122
|
+
verification.finalMessage,
|
|
123
|
+
assignment.proof_checks,
|
|
124
|
+
config.connector_id,
|
|
125
|
+
assignment.run_id,
|
|
126
|
+
);
|
|
112
127
|
return {
|
|
113
|
-
head_revision: revision,
|
|
128
|
+
head_revision: committed.revision,
|
|
114
129
|
repository_locator: assignment.repository_locator,
|
|
115
130
|
external_reference: `connector:${config.connector_id}/run:${assignment.run_id}`,
|
|
116
|
-
diff_patch: diffPatch,
|
|
117
|
-
changed_files: changedFiles,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
131
|
+
diff_patch: committed.diffPatch,
|
|
132
|
+
changed_files: committed.changedFiles,
|
|
133
|
+
proof_evidence: proofEvidence,
|
|
134
|
+
verification_report: verification.finalMessage,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function commitRunChange(workspace, baseRevision, runId) {
|
|
139
|
+
await run("git", ["add", "-A"], workspace);
|
|
140
|
+
await run(
|
|
141
|
+
"git",
|
|
142
|
+
[
|
|
143
|
+
"-c",
|
|
144
|
+
"user.name=EngineerOS Codex",
|
|
145
|
+
"-c",
|
|
146
|
+
"user.email=codex@engineeros.local",
|
|
147
|
+
"commit",
|
|
148
|
+
"-m",
|
|
149
|
+
`EngineerOS Goal Run ${runId}`,
|
|
150
|
+
],
|
|
151
|
+
workspace,
|
|
152
|
+
);
|
|
153
|
+
const head = await run("git", ["rev-parse", "HEAD"], workspace);
|
|
154
|
+
const revision = head.stdout.trim();
|
|
155
|
+
const diff = await run(
|
|
156
|
+
"git",
|
|
157
|
+
["diff", "--binary", baseRevision, revision, "--"],
|
|
158
|
+
workspace,
|
|
159
|
+
);
|
|
160
|
+
const paths = await run(
|
|
161
|
+
"git",
|
|
162
|
+
["diff", "--name-only", "-z", baseRevision, revision, "--"],
|
|
163
|
+
workspace,
|
|
164
|
+
);
|
|
165
|
+
return {
|
|
166
|
+
revision,
|
|
167
|
+
diffPatch: diff.stdout,
|
|
168
|
+
changedFiles: gitPathList(paths.stdout).sort(),
|
|
121
169
|
};
|
|
122
170
|
}
|
|
123
171
|
|
|
172
|
+
export function verificationPrompt(assignment, revision, changedFiles) {
|
|
173
|
+
const checks = (assignment.proof_checks ?? [])
|
|
174
|
+
.map(
|
|
175
|
+
(proof, index) =>
|
|
176
|
+
`## Proof ${index + 1}\n- Check: ${proof.check ?? ""}\n- Expected: ${proof.expected ?? ""}`,
|
|
177
|
+
)
|
|
178
|
+
.join("\n\n");
|
|
179
|
+
return `# EngineerOS Connected Verification
|
|
180
|
+
|
|
181
|
+
Independently verify the frozen Goal at Git commit \`${revision}\`. Do not modify files. Run the commands or inspections needed for every Proof item, and check the Goal boundaries and constraints in the supplied packet.
|
|
182
|
+
|
|
183
|
+
Changed files:
|
|
184
|
+
${changedFiles.map((item) => `- \`${item}\``).join("\n")}
|
|
185
|
+
|
|
186
|
+
${checks}
|
|
187
|
+
|
|
188
|
+
Return structured Markdown only, with exactly one section per Proof:
|
|
189
|
+
|
|
190
|
+
## Proof 1
|
|
191
|
+
- Status: passed or failed
|
|
192
|
+
- Exit code: integer or none
|
|
193
|
+
- Evidence: concise observed output and command
|
|
194
|
+
|
|
195
|
+
Do not claim a Proof passed unless you observed it directly.`;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function parseVerificationReport(report, proofChecks, connectorId, runId) {
|
|
199
|
+
if (!report?.trim()) throw new Error("Codex returned no connected verification report.");
|
|
200
|
+
return (proofChecks ?? []).map((_, index) => {
|
|
201
|
+
const start = new RegExp(`^## Proof ${index + 1}\\s*$`, "im").exec(report);
|
|
202
|
+
const tail = start ? report.slice(start.index + start[0].length) : "";
|
|
203
|
+
const section = tail.split(/^## Proof \d+\s*$/im)[0] ?? "";
|
|
204
|
+
const status = /^- Status:\s*(passed|failed)\s*$/im.exec(section)?.[1] ?? "failed";
|
|
205
|
+
const exitValue = /^- Exit code:\s*(\d+|none)\s*$/im.exec(section)?.[1] ?? "none";
|
|
206
|
+
const evidence = /^- Evidence:\s*(.+)$/im.exec(section)?.[1]?.trim();
|
|
207
|
+
return {
|
|
208
|
+
proof_index: index,
|
|
209
|
+
status,
|
|
210
|
+
verifier_type: "agent_reported",
|
|
211
|
+
verifier_identity: "Connected Codex CLI verifier",
|
|
212
|
+
locator: `connector:${connectorId}/run:${runId}#proof-${index + 1}`,
|
|
213
|
+
output_excerpt: evidence || "The connected verifier did not provide evidence for this Proof.",
|
|
214
|
+
exit_code: exitValue === "none" ? null : Number(exitValue),
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
124
219
|
export async function executeWorkspaceAssessment(
|
|
125
220
|
assignment,
|
|
126
221
|
config,
|