self-bench 0.3.4 → 0.3.6
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/README.md +16 -14
- package/biome.json +7 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +7 -7
- package/dist/api.js.map +1 -1
- package/dist/build-metadata.js +1 -1
- package/dist/cli.js +75 -15
- package/dist/cli.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/contracts.d.ts +1 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +6 -5
- package/dist/contracts.js.map +1 -1
- package/dist/extensions/discovery.d.ts.map +1 -1
- package/dist/extensions/discovery.js +12 -5
- package/dist/extensions/discovery.js.map +1 -1
- package/dist/harbor-task.d.ts.map +1 -1
- package/dist/harbor-task.js +3 -1
- package/dist/harbor-task.js.map +1 -1
- package/dist/project-paths.d.ts +2 -0
- package/dist/project-paths.d.ts.map +1 -0
- package/dist/project-paths.js +15 -0
- package/dist/project-paths.js.map +1 -0
- package/dist/provenance-associations.d.ts +49 -0
- package/dist/provenance-associations.d.ts.map +1 -0
- package/dist/provenance-associations.js +220 -0
- package/dist/provenance-associations.js.map +1 -0
- package/dist/provenance.d.ts +34 -13
- package/dist/provenance.d.ts.map +1 -1
- package/dist/provenance.js +81 -9
- package/dist/provenance.js.map +1 -1
- package/dist/reaudit-main.js +3 -3
- package/dist/reaudit-main.js.map +1 -1
- package/dist/repair-main.js +4 -4
- package/dist/repair-main.js.map +1 -1
- package/dist/{sandbox.d.ts → sandbox/contracts.d.ts} +5 -3
- package/dist/sandbox/contracts.d.ts.map +1 -0
- package/dist/sandbox/contracts.js +9 -0
- package/dist/sandbox/contracts.js.map +1 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/{sandbox.js → sandbox/index.js} +6 -5
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/programs/author.d.ts +3 -0
- package/dist/sandbox/programs/author.d.ts.map +1 -0
- package/dist/{sandbox-author.js → sandbox/programs/author.js} +2 -2
- package/dist/sandbox/programs/author.js.map +1 -0
- package/dist/sandbox/programs/prepare-repair.d.ts +7 -0
- package/dist/sandbox/programs/prepare-repair.d.ts.map +1 -0
- package/dist/sandbox/programs/prepare-repair.js +30 -0
- package/dist/sandbox/programs/prepare-repair.js.map +1 -0
- package/dist/sandbox/programs/repair.d.ts +3 -0
- package/dist/sandbox/programs/repair.d.ts.map +1 -0
- package/dist/{sandbox-repair.js → sandbox/programs/repair.js} +7 -28
- package/dist/sandbox/programs/repair.js.map +1 -0
- package/dist/sandbox/programs/review.d.ts +2 -0
- package/dist/sandbox/programs/review.d.ts.map +1 -0
- package/dist/{sandbox-review.js → sandbox/programs/review.js} +2 -2
- package/dist/sandbox/programs/review.js.map +1 -0
- package/dist/sandbox/programs/validation-repair.d.ts +3 -0
- package/dist/sandbox/programs/validation-repair.d.ts.map +1 -0
- package/dist/{sandbox-validation-repair.js → sandbox/programs/validation-repair.js} +7 -28
- package/dist/sandbox/programs/validation-repair.js.map +1 -0
- package/dist/{docker-executor.d.ts → sandbox/providers/docker/executor.d.ts} +3 -3
- package/dist/sandbox/providers/docker/executor.d.ts.map +1 -0
- package/dist/{docker-executor.js → sandbox/providers/docker/executor.js} +2 -2
- package/dist/sandbox/providers/docker/executor.js.map +1 -0
- package/dist/{modal-executor.d.ts → sandbox/providers/modal/executor.d.ts} +3 -3
- package/dist/sandbox/providers/modal/executor.d.ts.map +1 -0
- package/dist/{modal-executor.js → sandbox/providers/modal/executor.js} +50 -19
- package/dist/sandbox/providers/modal/executor.js.map +1 -0
- package/dist/{vercel-command.d.ts → sandbox/providers/vercel/command.d.ts} +3 -3
- package/dist/sandbox/providers/vercel/command.d.ts.map +1 -0
- package/dist/{vercel-command.js → sandbox/providers/vercel/command.js} +3 -3
- package/dist/sandbox/providers/vercel/command.js.map +1 -0
- package/dist/{vercel-executor.d.ts → sandbox/providers/vercel/executor.d.ts} +3 -3
- package/dist/sandbox/providers/vercel/executor.d.ts.map +1 -0
- package/dist/{vercel-executor.js → sandbox/providers/vercel/executor.js} +5 -5
- package/dist/sandbox/providers/vercel/executor.js.map +1 -0
- package/dist/{vercel-fetch.d.ts → sandbox/providers/vercel/fetch.d.ts} +1 -1
- package/dist/sandbox/providers/vercel/fetch.d.ts.map +1 -0
- package/dist/{vercel-fetch.js → sandbox/providers/vercel/fetch.js} +1 -1
- package/dist/sandbox/providers/vercel/fetch.js.map +1 -0
- package/dist/{sandbox-timeout.d.ts → sandbox/timeout.d.ts} +2 -2
- package/dist/sandbox/timeout.d.ts.map +1 -0
- package/dist/{sandbox-timeout.js → sandbox/timeout.js} +1 -1
- package/dist/sandbox/timeout.js.map +1 -0
- package/dist/sandbox-author.bundle.js +11 -8
- package/dist/sandbox-repair.bundle.js +43 -35
- package/dist/sandbox-review.bundle.js +2 -2
- package/dist/sandbox-validation-repair.bundle.js +50 -41
- package/dist/{vercel-cli.d.ts → setup/vercel/cli.d.ts} +2 -2
- package/dist/setup/vercel/cli.d.ts.map +1 -0
- package/dist/{vercel-cli.js → setup/vercel/cli.js} +2 -2
- package/dist/setup/vercel/cli.js.map +1 -0
- package/dist/setup/vercel/index.d.ts +4 -0
- package/dist/setup/vercel/index.d.ts.map +1 -0
- package/dist/setup/vercel/index.js +3 -0
- package/dist/setup/vercel/index.js.map +1 -0
- package/dist/{vercel-setup-probe.d.ts → setup/vercel/probe.d.ts} +2 -2
- package/dist/setup/vercel/probe.d.ts.map +1 -0
- package/dist/{vercel-setup-probe.js → setup/vercel/probe.js} +2 -2
- package/dist/setup/vercel/probe.js.map +1 -0
- package/dist/{vercel-profile.d.ts → setup/vercel/profile.d.ts} +1 -1
- package/dist/setup/vercel/profile.d.ts.map +1 -0
- package/dist/{vercel-profile.js → setup/vercel/profile.js} +2 -2
- package/dist/setup/vercel/profile.js.map +1 -0
- package/dist/{vercel-runtime-image.d.ts → setup/vercel/runtime-image.d.ts} +5 -5
- package/dist/setup/vercel/runtime-image.d.ts.map +1 -0
- package/dist/{vercel-runtime-image.js → setup/vercel/runtime-image.js} +2 -2
- package/dist/setup/vercel/runtime-image.js.map +1 -0
- package/dist/{vercel-setup.d.ts → setup/vercel/setup.d.ts} +8 -8
- package/dist/setup/vercel/setup.d.ts.map +1 -0
- package/dist/{vercel-setup.js → setup/vercel/setup.js} +8 -8
- package/dist/setup/vercel/setup.js.map +1 -0
- package/dist/temporal/activities.d.ts +12 -0
- package/dist/temporal/activities.d.ts.map +1 -1
- package/dist/temporal/activities.js +80 -33
- package/dist/temporal/activities.js.map +1 -1
- package/dist/temporal/workflow.d.ts +1 -1
- package/dist/temporal/workflow.d.ts.map +1 -1
- package/dist/temporal/workflow.js +90 -65
- package/dist/temporal/workflow.js.map +1 -1
- package/docs/operations.md +39 -5
- package/docs/task-construction.md +3 -1
- package/package.json +7 -5
- package/review/index.html +14 -0
- package/review/src/App.tsx +338 -0
- package/review/src/export-loader.test.ts +57 -0
- package/review/src/export-loader.ts +151 -0
- package/review/src/main.tsx +15 -0
- package/review/src/styles.css +162 -0
- package/review/src/types.ts +47 -0
- package/review/tsconfig.json +16 -0
- package/review/vite.config.ts +20 -0
- package/scripts/build-sandbox-programs.ts +22 -0
- package/scripts/verify-package.ts +52 -7
- package/scripts/write-build-metadata.ts +1 -1
- package/src/api.ts +7 -6
- package/src/cli.ts +99 -15
- package/src/config.ts +1 -1
- package/src/contracts.ts +7 -5
- package/src/extensions/discovery.ts +14 -5
- package/src/harbor-task.ts +6 -1
- package/src/project-paths.ts +15 -0
- package/src/provenance-associations.ts +311 -0
- package/src/provenance.ts +132 -28
- package/src/reaudit-main.ts +3 -3
- package/src/repair-main.ts +4 -4
- package/src/{sandbox.ts → sandbox/contracts.ts} +11 -20
- package/src/sandbox/index.ts +23 -0
- package/src/{sandbox-author.ts → sandbox/programs/author.ts} +1 -1
- package/src/sandbox/programs/prepare-repair.ts +44 -0
- package/src/{sandbox-repair.ts → sandbox/programs/repair.ts} +7 -31
- package/src/{sandbox-review.ts → sandbox/programs/review.ts} +1 -1
- package/src/{sandbox-validation-repair.ts → sandbox/programs/validation-repair.ts} +6 -30
- package/src/{docker-executor.ts → sandbox/providers/docker/executor.ts} +3 -3
- package/src/{modal-executor.ts → sandbox/providers/modal/executor.ts} +66 -25
- package/src/{vercel-command.ts → sandbox/providers/vercel/command.ts} +3 -3
- package/src/{vercel-executor.ts → sandbox/providers/vercel/executor.ts} +5 -5
- package/src/{sandbox-timeout.ts → sandbox/timeout.ts} +1 -1
- package/src/{vercel-cli.ts → setup/vercel/cli.ts} +1 -1
- package/src/setup/vercel/index.ts +3 -0
- package/src/{vercel-setup-probe.ts → setup/vercel/probe.ts} +5 -2
- package/src/{vercel-profile.ts → setup/vercel/profile.ts} +4 -1
- package/src/{vercel-runtime-image.ts → setup/vercel/runtime-image.ts} +5 -5
- package/src/{vercel-setup.ts → setup/vercel/setup.ts} +8 -8
- package/src/temporal/activities.ts +164 -63
- package/src/temporal/workflow.ts +120 -71
- package/tsconfig.json +1 -1
- package/dist/docker-executor.d.ts.map +0 -1
- package/dist/docker-executor.js.map +0 -1
- package/dist/modal-executor.d.ts.map +0 -1
- package/dist/modal-executor.js.map +0 -1
- package/dist/sandbox-author.d.ts +0 -3
- package/dist/sandbox-author.d.ts.map +0 -1
- package/dist/sandbox-author.js.map +0 -1
- package/dist/sandbox-repair.d.ts +0 -3
- package/dist/sandbox-repair.d.ts.map +0 -1
- package/dist/sandbox-repair.js.map +0 -1
- package/dist/sandbox-review.d.ts +0 -2
- package/dist/sandbox-review.d.ts.map +0 -1
- package/dist/sandbox-review.js.map +0 -1
- package/dist/sandbox-timeout.d.ts.map +0 -1
- package/dist/sandbox-timeout.js.map +0 -1
- package/dist/sandbox-validation-repair.d.ts +0 -3
- package/dist/sandbox-validation-repair.d.ts.map +0 -1
- package/dist/sandbox-validation-repair.js.map +0 -1
- package/dist/sandbox.d.ts.map +0 -1
- package/dist/sandbox.js.map +0 -1
- package/dist/vercel-cli.d.ts.map +0 -1
- package/dist/vercel-cli.js.map +0 -1
- package/dist/vercel-command.d.ts.map +0 -1
- package/dist/vercel-command.js.map +0 -1
- package/dist/vercel-executor.d.ts.map +0 -1
- package/dist/vercel-executor.js.map +0 -1
- package/dist/vercel-fetch.d.ts.map +0 -1
- package/dist/vercel-fetch.js.map +0 -1
- package/dist/vercel-profile.d.ts.map +0 -1
- package/dist/vercel-profile.js.map +0 -1
- package/dist/vercel-runtime-image.d.ts.map +0 -1
- package/dist/vercel-runtime-image.js.map +0 -1
- package/dist/vercel-setup-probe.d.ts.map +0 -1
- package/dist/vercel-setup-probe.js.map +0 -1
- package/dist/vercel-setup.d.ts.map +0 -1
- package/dist/vercel-setup.js.map +0 -1
- /package/src/{vercel-fetch.ts → sandbox/providers/vercel/fetch.ts} +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--bg: #f4f5f7;
|
|
3
|
+
--surface: #ffffff;
|
|
4
|
+
--border: #d8dce3;
|
|
5
|
+
--text: #1a1d23;
|
|
6
|
+
--muted: #6b7280;
|
|
7
|
+
--accent: #2563eb;
|
|
8
|
+
--danger: #dc2626;
|
|
9
|
+
--success: #059669;
|
|
10
|
+
--code-bg: #f1f3f5;
|
|
11
|
+
--font: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
|
|
12
|
+
--mono: "SF Mono", "Cascadia Code", "Fira Code", monospace;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@media (prefers-color-scheme: dark) {
|
|
16
|
+
:root {
|
|
17
|
+
--bg: #0d1117;
|
|
18
|
+
--surface: #161b22;
|
|
19
|
+
--border: #30363d;
|
|
20
|
+
--text: #e6edf3;
|
|
21
|
+
--muted: #8b949e;
|
|
22
|
+
--accent: #58a6ff;
|
|
23
|
+
--danger: #f85149;
|
|
24
|
+
--success: #3fb950;
|
|
25
|
+
--code-bg: #1c2128;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
30
|
+
|
|
31
|
+
body {
|
|
32
|
+
font-family: var(--font);
|
|
33
|
+
background: var(--bg);
|
|
34
|
+
color: var(--text);
|
|
35
|
+
font-size: 14px;
|
|
36
|
+
line-height: 1.5;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.app-shell { min-height: 100vh; display: flex; flex-direction: column; }
|
|
40
|
+
|
|
41
|
+
.topbar {
|
|
42
|
+
display: flex; justify-content: space-between; align-items: center;
|
|
43
|
+
padding: 16px 24px; border-bottom: 1px solid var(--border);
|
|
44
|
+
background: var(--surface);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.eyebrow {
|
|
48
|
+
font-size: 11px; font-weight: 600; letter-spacing: 0.08em;
|
|
49
|
+
text-transform: uppercase; color: var(--muted);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.topbar h1 { font-size: 18px; font-weight: 600; margin-top: 2px; }
|
|
53
|
+
.topbar-actions { display: flex; gap: 8px; align-items: center; }
|
|
54
|
+
.token-input {
|
|
55
|
+
padding: 6px 10px; border: 1px solid var(--border); border-radius: 6px;
|
|
56
|
+
background: var(--surface); color: var(--text); font-size: 12px; width: 180px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.error-banner {
|
|
60
|
+
padding: 12px 24px; background: var(--danger); color: #fff; font-size: 13px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.workspace {
|
|
64
|
+
flex: 1; display: grid; grid-template-columns: 280px 1fr; gap: 16px;
|
|
65
|
+
padding: 16px 24px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.surface { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; }
|
|
69
|
+
|
|
70
|
+
.run-list { padding: 16px; overflow-y: auto; max-height: calc(100vh - 100px); }
|
|
71
|
+
|
|
72
|
+
.section-heading {
|
|
73
|
+
display: flex; justify-content: space-between; align-items: baseline;
|
|
74
|
+
margin-bottom: 12px; padding-bottom: 8px; border-bottom: 1px solid var(--border);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.section-heading h2 { font-size: 13px; font-weight: 600; }
|
|
78
|
+
.section-heading span { font-size: 11px; color: var(--muted); }
|
|
79
|
+
|
|
80
|
+
.run-row {
|
|
81
|
+
width: 100%; display: flex; flex-direction: column; gap: 2px;
|
|
82
|
+
padding: 10px 12px; margin-bottom: 6px; border: 1px solid var(--border);
|
|
83
|
+
border-radius: 6px; background: var(--surface); cursor: pointer; text-align: left;
|
|
84
|
+
font: inherit; color: inherit;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.run-row:hover { border-color: var(--accent); }
|
|
88
|
+
.run-row.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
|
|
89
|
+
.run-row strong { font-size: 13px; }
|
|
90
|
+
.run-row span { font-size: 11px; color: var(--muted); }
|
|
91
|
+
.run-row small { font-size: 10px; color: var(--muted); }
|
|
92
|
+
|
|
93
|
+
.content { display: flex; flex-direction: column; gap: 16px; }
|
|
94
|
+
|
|
95
|
+
.empty {
|
|
96
|
+
padding: 64px 32px; text-align: center; display: flex; flex-direction: column;
|
|
97
|
+
align-items: center; gap: 8px; min-height: 400px; justify-content: center;
|
|
98
|
+
}
|
|
99
|
+
.empty h2 { font-size: 16px; font-weight: 600; }
|
|
100
|
+
.empty p { color: var(--muted); }
|
|
101
|
+
|
|
102
|
+
.summary {
|
|
103
|
+
display: flex; justify-content: space-between; align-items: center;
|
|
104
|
+
padding: 16px 20px;
|
|
105
|
+
}
|
|
106
|
+
.summary h2 { font-size: 16px; font-weight: 600; }
|
|
107
|
+
.summary .muted { font-size: 12px; color: var(--muted); margin-top: 2px; }
|
|
108
|
+
|
|
109
|
+
.review-grid { display: grid; grid-template-columns: 240px 1fr; gap: 16px; }
|
|
110
|
+
|
|
111
|
+
.task-list { padding: 16px; max-height: calc(100vh - 280px); overflow-y: auto; }
|
|
112
|
+
|
|
113
|
+
.task-row {
|
|
114
|
+
width: 100%; display: flex; justify-content: space-between; align-items: center;
|
|
115
|
+
padding: 8px 10px; margin-bottom: 4px; border: 1px solid var(--border);
|
|
116
|
+
border-radius: 5px; background: var(--surface); cursor: pointer; text-align: left;
|
|
117
|
+
font: inherit; color: inherit; font-size: 12px;
|
|
118
|
+
}
|
|
119
|
+
.task-row:hover { border-color: var(--accent); }
|
|
120
|
+
.task-row.selected { border-color: var(--accent); }
|
|
121
|
+
.task-row.removed { opacity: 0.5; }
|
|
122
|
+
.task-row.removed strong { text-decoration: line-through; }
|
|
123
|
+
.task-row span { font-size: 10px; color: var(--muted); }
|
|
124
|
+
|
|
125
|
+
.task-detail { padding: 20px 24px; max-height: calc(100vh - 280px); overflow-y: auto; }
|
|
126
|
+
|
|
127
|
+
.detail-header {
|
|
128
|
+
display: flex; justify-content: space-between; align-items: flex-start;
|
|
129
|
+
margin-bottom: 20px; padding-bottom: 16px; border-bottom: 1px solid var(--border);
|
|
130
|
+
}
|
|
131
|
+
.detail-header h2 { font-size: 18px; font-weight: 600; }
|
|
132
|
+
|
|
133
|
+
.detail-block { margin-bottom: 20px; }
|
|
134
|
+
.detail-block h3 {
|
|
135
|
+
font-size: 12px; font-weight: 600; letter-spacing: 0.04em;
|
|
136
|
+
text-transform: uppercase; color: var(--muted); margin-bottom: 6px;
|
|
137
|
+
}
|
|
138
|
+
.detail-block pre {
|
|
139
|
+
padding: 12px 16px; background: var(--code-bg); border-radius: 6px;
|
|
140
|
+
font-family: var(--mono); font-size: 12px; white-space: pre-wrap;
|
|
141
|
+
word-break: break-all; max-height: 400px; overflow-y: auto; line-height: 1.6;
|
|
142
|
+
}
|
|
143
|
+
.patch-files {
|
|
144
|
+
display: grid; gap: 10px; padding: 8px; max-height: 600px; overflow: auto;
|
|
145
|
+
background: var(--code-bg); border-radius: 6px;
|
|
146
|
+
}
|
|
147
|
+
.patch-files > div { overflow: hidden; border: 1px solid var(--border); border-radius: 4px; }
|
|
148
|
+
|
|
149
|
+
.button {
|
|
150
|
+
padding: 7px 14px; border: 1px solid var(--border); border-radius: 6px;
|
|
151
|
+
background: var(--surface); color: var(--text); font-size: 12px; font-weight: 500;
|
|
152
|
+
cursor: pointer; font-family: var(--font);
|
|
153
|
+
}
|
|
154
|
+
.button:hover { border-color: var(--accent); color: var(--accent); }
|
|
155
|
+
.button.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
|
|
156
|
+
.button.primary:hover { opacity: 0.9; color: #fff; }
|
|
157
|
+
.button.danger { color: var(--danger); border-color: var(--danger); }
|
|
158
|
+
.button.danger:hover { background: var(--danger); color: #fff; }
|
|
159
|
+
.button.undo { color: var(--success); border-color: var(--success); }
|
|
160
|
+
.button.undo:hover { background: var(--success); color: #fff; }
|
|
161
|
+
|
|
162
|
+
.muted { color: var(--muted); }
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface RunSummary {
|
|
2
|
+
runId: string;
|
|
3
|
+
status: string;
|
|
4
|
+
startedAt: string;
|
|
5
|
+
closedAt?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface TaskProgress {
|
|
9
|
+
taskId: string;
|
|
10
|
+
candidateId: string;
|
|
11
|
+
difficulty: "easy" | "medium" | "hard";
|
|
12
|
+
status: string;
|
|
13
|
+
reason?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface RunStatus {
|
|
17
|
+
runId: string;
|
|
18
|
+
phase: string;
|
|
19
|
+
requested: number;
|
|
20
|
+
accepted: number;
|
|
21
|
+
rejected: number;
|
|
22
|
+
tasks: TaskProgress[];
|
|
23
|
+
export?: { uri: string; sizeBytes: number; contentType: string };
|
|
24
|
+
error?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ExportManifest {
|
|
28
|
+
schemaVersion: number;
|
|
29
|
+
runId: string;
|
|
30
|
+
candidateCounts: Record<string, number>;
|
|
31
|
+
repository: { url: string; commit: string };
|
|
32
|
+
version: Record<string, unknown>;
|
|
33
|
+
acceptedCount: number;
|
|
34
|
+
tasks: { taskId: string; sha256: string }[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ExportTask {
|
|
38
|
+
taskId: string;
|
|
39
|
+
files: Map<string, Uint8Array>;
|
|
40
|
+
textFiles: Map<string, string>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface LoadedExport {
|
|
44
|
+
manifest: ExportManifest;
|
|
45
|
+
tasks: ExportTask[];
|
|
46
|
+
taskArchives: Map<string, Uint8Array>;
|
|
47
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"allowSyntheticDefaultImports": true,
|
|
4
|
+
"esModuleInterop": true,
|
|
5
|
+
"jsx": "react-jsx",
|
|
6
|
+
"lib": ["DOM", "DOM.Iterable", "ES2023"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"moduleResolution": "Bundler",
|
|
9
|
+
"noEmit": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"target": "ES2022",
|
|
13
|
+
"types": ["bun", "vite/client"]
|
|
14
|
+
},
|
|
15
|
+
"include": ["src", "vite.config.ts"]
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import react from "@vitejs/plugin-react";
|
|
2
|
+
import { defineConfig } from "vite";
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
root: "review",
|
|
6
|
+
plugins: [react()],
|
|
7
|
+
build: {
|
|
8
|
+
outDir: "../dist/review",
|
|
9
|
+
emptyOutDir: true,
|
|
10
|
+
},
|
|
11
|
+
server: {
|
|
12
|
+
allowedHosts: ["avyays-mac-mini.tailf3cee5.ts.net"],
|
|
13
|
+
proxy: {
|
|
14
|
+
"/v1": "http://127.0.0.1:8080",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
preview: {
|
|
18
|
+
allowedHosts: ["avyays-mac-mini.tailf3cee5.ts.net"],
|
|
19
|
+
},
|
|
20
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
const root = resolve(import.meta.dir, "..");
|
|
5
|
+
const outputDirectory = join(root, "dist");
|
|
6
|
+
|
|
7
|
+
const programs = ["author", "review", "repair", "validation-repair"] as const;
|
|
8
|
+
|
|
9
|
+
await mkdir(outputDirectory, { recursive: true });
|
|
10
|
+
await Promise.all(
|
|
11
|
+
programs.map(async (program) => {
|
|
12
|
+
const result = await Bun.build({
|
|
13
|
+
entrypoints: [join(root, "src/sandbox/programs", `${program}.ts`)],
|
|
14
|
+
outdir: outputDirectory,
|
|
15
|
+
naming: `sandbox-${program}.bundle.js`,
|
|
16
|
+
target: "node",
|
|
17
|
+
});
|
|
18
|
+
if (!result.success) {
|
|
19
|
+
throw new AggregateError(result.logs, `failed to bundle sandbox ${program} program`);
|
|
20
|
+
}
|
|
21
|
+
}),
|
|
22
|
+
);
|
|
@@ -2,8 +2,14 @@ import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
|
|
5
|
+
const options = process.argv.slice(2);
|
|
6
|
+
const dockerBuild = options.length === 1 && options[0] === "--docker-build";
|
|
7
|
+
if (options.length > 0 && !dockerBuild) {
|
|
8
|
+
throw new Error(`unknown verify-package argument: ${options.join(" ")}`);
|
|
9
|
+
}
|
|
5
10
|
const root = resolve(import.meta.dir, "..");
|
|
6
11
|
const temporary = await mkdtemp(join(tmpdir(), "self-bench-package-"));
|
|
12
|
+
|
|
7
13
|
async function run(command: string, args: string[], cwd = root): Promise<string> {
|
|
8
14
|
const child = Bun.spawn([command, ...args], {
|
|
9
15
|
cwd,
|
|
@@ -26,12 +32,15 @@ try {
|
|
|
26
32
|
const tarballs = (await Array.fromAsync(new Bun.Glob("*.tgz").scan({ cwd: temporary }))).map(
|
|
27
33
|
(name) => join(temporary, name),
|
|
28
34
|
);
|
|
29
|
-
const tarball =
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
const tarball =
|
|
36
|
+
tarballs[0] ??
|
|
37
|
+
(() => {
|
|
38
|
+
throw new Error("bun pm pack did not create a tarball");
|
|
39
|
+
})();
|
|
32
40
|
const packageJson = JSON.parse(await readFile(join(root, "package.json"), "utf8")) as {
|
|
33
41
|
name: string;
|
|
34
42
|
version: string;
|
|
43
|
+
bin: Record<string, string>;
|
|
35
44
|
};
|
|
36
45
|
const installRoot = join(temporary, "install");
|
|
37
46
|
await run("mkdir", ["-p", installRoot]);
|
|
@@ -42,15 +51,51 @@ try {
|
|
|
42
51
|
if (!help.includes("self-bench up")) {
|
|
43
52
|
throw new Error("installed self-bench did not print the expected CLI help");
|
|
44
53
|
}
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
const installedRoot = join(installRoot, "node_modules", packageJson.name);
|
|
55
|
+
for (const [name, target] of Object.entries(packageJson.bin)) {
|
|
56
|
+
await readFile(join(installedRoot, target));
|
|
57
|
+
await readFile(join(installRoot, "node_modules", ".bin", name));
|
|
58
|
+
}
|
|
59
|
+
for (const asset of [
|
|
60
|
+
"dist/api-main.js",
|
|
61
|
+
"dist/temporal/worker-main.js",
|
|
62
|
+
"dist/sandbox-author.bundle.js",
|
|
63
|
+
"dist/sandbox-review.bundle.js",
|
|
64
|
+
"dist/sandbox-repair.bundle.js",
|
|
65
|
+
"dist/sandbox-validation-repair.bundle.js",
|
|
66
|
+
"dist/review/index.html",
|
|
67
|
+
]) {
|
|
68
|
+
await readFile(join(installedRoot, asset));
|
|
69
|
+
}
|
|
70
|
+
for (const asset of [
|
|
71
|
+
".dockerignore",
|
|
72
|
+
"compose.yaml",
|
|
73
|
+
"Dockerfile",
|
|
74
|
+
"Dockerfile.sandbox",
|
|
75
|
+
"review/index.html",
|
|
76
|
+
"review/src/App.tsx",
|
|
77
|
+
"review/vite.config.ts",
|
|
78
|
+
"src/extensions/authoring.ts",
|
|
79
|
+
"src/skills/selfbench/SKILL.md",
|
|
80
|
+
]) {
|
|
81
|
+
await readFile(join(installedRoot, asset));
|
|
47
82
|
}
|
|
48
83
|
const installedPackage = JSON.parse(
|
|
49
|
-
await readFile(join(
|
|
84
|
+
await readFile(join(installedRoot, "package.json"), "utf8"),
|
|
50
85
|
) as { name: string; version: string };
|
|
51
|
-
if (
|
|
86
|
+
if (
|
|
87
|
+
installedPackage.name !== packageJson.name ||
|
|
88
|
+
installedPackage.version !== packageJson.version
|
|
89
|
+
) {
|
|
52
90
|
throw new Error("installed package metadata does not match the workspace package");
|
|
53
91
|
}
|
|
92
|
+
if (dockerBuild) {
|
|
93
|
+
await run(
|
|
94
|
+
"docker",
|
|
95
|
+
["build", "--target", "build", "--file", join(installedRoot, "Dockerfile"), installedRoot],
|
|
96
|
+
installedRoot,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
54
99
|
console.log(`verified ${installedPackage.name}@${installedPackage.version}`);
|
|
55
100
|
} finally {
|
|
56
101
|
await rm(temporary, { recursive: true, force: true });
|
package/src/api.ts
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { timingSafeEqual } from "node:crypto";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
|
|
4
|
-
import {
|
|
4
|
+
import { join } from "node:path";
|
|
5
5
|
import { pipeline } from "node:stream/promises";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
6
|
import { Client } from "@temporalio/client";
|
|
8
7
|
import { z } from "zod";
|
|
9
8
|
import { createArtifactStore } from "./artifacts.js";
|
|
10
9
|
import type { SelfBenchConfig } from "./config.js";
|
|
11
10
|
import {
|
|
12
11
|
artifactRefSchema,
|
|
12
|
+
MAX_CANDIDATES_PER_RUN,
|
|
13
13
|
type RunPhase,
|
|
14
14
|
type RunRequest,
|
|
15
15
|
type RunStatus,
|
|
16
16
|
repositoryRefSchema,
|
|
17
17
|
runRequestSchema,
|
|
18
18
|
} from "./contracts.js";
|
|
19
|
+
import { projectRoot } from "./project-paths.js";
|
|
19
20
|
import { connectTemporalClient } from "./temporal/connection.js";
|
|
20
21
|
import { selfBenchRunWorkflow, statusQuery } from "./temporal/workflow.js";
|
|
21
22
|
|
|
@@ -24,9 +25,9 @@ const submissionSchema = z.object({
|
|
|
24
25
|
repository: repositoryRefSchema,
|
|
25
26
|
provenance: artifactRefSchema,
|
|
26
27
|
candidateCounts: z.object({
|
|
27
|
-
easy: z.number().int().min(0).max(
|
|
28
|
-
medium: z.number().int().min(0).max(
|
|
29
|
-
hard: z.number().int().min(0).max(
|
|
28
|
+
easy: z.number().int().min(0).max(MAX_CANDIDATES_PER_RUN),
|
|
29
|
+
medium: z.number().int().min(0).max(MAX_CANDIDATES_PER_RUN),
|
|
30
|
+
hard: z.number().int().min(0).max(MAX_CANDIDATES_PER_RUN),
|
|
30
31
|
}),
|
|
31
32
|
authoringModel: z.string().min(1).default("gpt-5.6-sol"),
|
|
32
33
|
selfbenchCommit: z.string().regex(/^[0-9a-f]{40}$/i),
|
|
@@ -254,7 +255,7 @@ function authorized(request: IncomingMessage, token: string | undefined): boolea
|
|
|
254
255
|
|
|
255
256
|
async function sendReviewAsset(response: ServerResponse, pathname: string): Promise<void> {
|
|
256
257
|
const relativePath = pathname === "/" ? "index.html" : pathname.slice(1);
|
|
257
|
-
const root = join(
|
|
258
|
+
const root = join(projectRoot(import.meta.url), "dist/review");
|
|
258
259
|
const path = join(root, relativePath);
|
|
259
260
|
if (!path.startsWith(`${root}/`)) {
|
|
260
261
|
sendJson(response, 400, { error: "invalid asset path" });
|
package/src/cli.ts
CHANGED
|
@@ -11,13 +11,23 @@ import { fileURLToPath } from "node:url";
|
|
|
11
11
|
import { parseArgs } from "node:util";
|
|
12
12
|
import { buildCommit } from "./build-metadata.js";
|
|
13
13
|
import { loadWorkerConfig } from "./config.js";
|
|
14
|
+
import { MAX_CANDIDATES_PER_RUN } from "./contracts.js";
|
|
14
15
|
import { runCommand } from "./process.js";
|
|
15
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
collectRepositoryProvenance,
|
|
18
|
+
collectRepositoryProvenanceWithMetadata,
|
|
19
|
+
} from "./provenance.js";
|
|
20
|
+
import {
|
|
21
|
+
applyProvenanceAssociationManifests,
|
|
22
|
+
associationSessionSummaries,
|
|
23
|
+
createProvenanceAssociationManifest,
|
|
24
|
+
resolveMergedPullRequest,
|
|
25
|
+
writeProvenanceAssociationManifest,
|
|
26
|
+
} from "./provenance-associations.js";
|
|
16
27
|
import { isExecutionBackend, isHarborEnvironment, matchingHarborEnvironment } from "./providers.js";
|
|
17
28
|
import { type PolledRunStatus, waitForRun } from "./run-wait.js";
|
|
29
|
+
import { applyVercelProfile, setupVercel } from "./setup/vercel/index.js";
|
|
18
30
|
import { SetupCanceledError } from "./terminal-prompts.js";
|
|
19
|
-
import { applyVercelProfile } from "./vercel-profile.js";
|
|
20
|
-
import { setupVercel } from "./vercel-setup.js";
|
|
21
31
|
|
|
22
32
|
const [command, ...rest] = process.argv.slice(2);
|
|
23
33
|
switch (command) {
|
|
@@ -30,6 +40,9 @@ switch (command) {
|
|
|
30
40
|
case "run":
|
|
31
41
|
await run(rest);
|
|
32
42
|
break;
|
|
43
|
+
case "associate":
|
|
44
|
+
await associate(rest);
|
|
45
|
+
break;
|
|
33
46
|
case "down":
|
|
34
47
|
await down();
|
|
35
48
|
break;
|
|
@@ -162,6 +175,57 @@ async function down(): Promise<void> {
|
|
|
162
175
|
await runCommand("docker", ["compose", "--file", resolve(projectRoot, "compose.yaml"), "down"]);
|
|
163
176
|
}
|
|
164
177
|
|
|
178
|
+
async function associate(args: string[]): Promise<void> {
|
|
179
|
+
const parsed = parseArgs({
|
|
180
|
+
args,
|
|
181
|
+
options: {
|
|
182
|
+
repo: { type: "string", short: "r" },
|
|
183
|
+
pr: { type: "string" },
|
|
184
|
+
session: { type: "string", multiple: true },
|
|
185
|
+
output: { type: "string", short: "o" },
|
|
186
|
+
"list-sessions": { type: "boolean", default: false },
|
|
187
|
+
},
|
|
188
|
+
strict: true,
|
|
189
|
+
});
|
|
190
|
+
const repositoryPath = resolve(parsed.values.repo ?? fail("--repo is required"));
|
|
191
|
+
const [repository, collected] = await Promise.all([
|
|
192
|
+
resolveRepository(repositoryPath),
|
|
193
|
+
collectRepositoryProvenanceWithMetadata(repositoryPath, process.env.HOME ?? homedir()),
|
|
194
|
+
]);
|
|
195
|
+
const localMessages = collected.messages;
|
|
196
|
+
const sessions = associationSessionSummaries(localMessages, collected.sessions);
|
|
197
|
+
if (parsed.values["list-sessions"]) {
|
|
198
|
+
console.log(JSON.stringify({ repository: repository.url, sessions }, null, 2));
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const sourcePr = positiveInteger(parsed.values.pr ?? fail("--pr is required"), "--pr");
|
|
203
|
+
const output = resolve(parsed.values.output ?? fail("--output is required"));
|
|
204
|
+
const selectors = parsed.values.session ?? [];
|
|
205
|
+
const pullRequest = await resolveMergedPullRequest(repository.url, sourcePr);
|
|
206
|
+
const manifest = createProvenanceAssociationManifest({
|
|
207
|
+
repositoryUrl: repository.url,
|
|
208
|
+
pullRequest,
|
|
209
|
+
messages: localMessages,
|
|
210
|
+
sessionSelectors: selectors,
|
|
211
|
+
});
|
|
212
|
+
await writeProvenanceAssociationManifest(output, manifest);
|
|
213
|
+
console.log(
|
|
214
|
+
JSON.stringify(
|
|
215
|
+
{
|
|
216
|
+
output,
|
|
217
|
+
repository: manifest.repository,
|
|
218
|
+
sourcePr: manifest.sourcePr,
|
|
219
|
+
sourceUrl: manifest.sourceUrl,
|
|
220
|
+
sessions: selectors.length,
|
|
221
|
+
messages: manifest.messages.length,
|
|
222
|
+
},
|
|
223
|
+
null,
|
|
224
|
+
2,
|
|
225
|
+
),
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
165
229
|
async function run(args: string[]): Promise<void> {
|
|
166
230
|
const parsed = parseArgs({
|
|
167
231
|
args,
|
|
@@ -174,6 +238,7 @@ async function run(args: string[]): Promise<void> {
|
|
|
174
238
|
model: { type: "string", default: "gpt-5.6-sol" },
|
|
175
239
|
wait: { type: "boolean", default: false },
|
|
176
240
|
output: { type: "string", short: "o" },
|
|
241
|
+
association: { type: "string", multiple: true },
|
|
177
242
|
},
|
|
178
243
|
strict: true,
|
|
179
244
|
});
|
|
@@ -184,21 +249,25 @@ async function run(args: string[]): Promise<void> {
|
|
|
184
249
|
hard: nonnegativeInteger(parsed.values["hard-count"] ?? "0", "--hard-count"),
|
|
185
250
|
};
|
|
186
251
|
const totalCandidates = candidateCounts.easy + candidateCounts.medium + candidateCounts.hard;
|
|
187
|
-
if (totalCandidates < 1 || totalCandidates >
|
|
188
|
-
fail(
|
|
252
|
+
if (totalCandidates < 1 || totalCandidates > MAX_CANDIDATES_PER_RUN) {
|
|
253
|
+
fail(`the total candidate count must be between 1 and ${MAX_CANDIDATES_PER_RUN}`);
|
|
189
254
|
}
|
|
190
255
|
const runId = parsed.values["run-id"] ?? defaultRunId();
|
|
191
|
-
const [repository,
|
|
256
|
+
const [repository, collectedMessages, selfbenchCommit] = await Promise.all([
|
|
192
257
|
resolveRepository(repositoryPath),
|
|
193
258
|
collectRepositoryProvenance(repositoryPath, process.env.HOME ?? homedir()),
|
|
194
259
|
resolveSelfBenchCommit(),
|
|
195
260
|
]);
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const corpus = Buffer.from(
|
|
261
|
+
const localMessages = await applyProvenanceAssociationManifests(
|
|
262
|
+
collectedMessages,
|
|
263
|
+
repository.url,
|
|
264
|
+
parsed.values.association ?? [],
|
|
265
|
+
);
|
|
266
|
+
const corpus = Buffer.from(
|
|
267
|
+
localMessages.length > 0
|
|
268
|
+
? `${localMessages.map((message) => JSON.stringify(message)).join("\n")}\n`
|
|
269
|
+
: "",
|
|
270
|
+
);
|
|
202
271
|
const provenance = await requestJson(`/v1/provenance?runId=${encodeURIComponent(runId)}`, {
|
|
203
272
|
method: "POST",
|
|
204
273
|
body: corpus,
|
|
@@ -222,9 +291,8 @@ async function run(args: string[]): Promise<void> {
|
|
|
222
291
|
JSON.stringify(
|
|
223
292
|
{
|
|
224
293
|
...response,
|
|
225
|
-
provenanceMessages: messages.length,
|
|
226
294
|
localProvenanceMessages: localMessages.length,
|
|
227
|
-
|
|
295
|
+
associationManifests: parsed.values.association?.length ?? 0,
|
|
228
296
|
},
|
|
229
297
|
null,
|
|
230
298
|
2,
|
|
@@ -377,6 +445,14 @@ function asPolledRunStatus(value: Record<string, unknown>): PolledRunStatus {
|
|
|
377
445
|
return { ...value, phase: value.phase };
|
|
378
446
|
}
|
|
379
447
|
|
|
448
|
+
function positiveInteger(value: string, label: string): number {
|
|
449
|
+
const parsed = Number(value);
|
|
450
|
+
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
451
|
+
throw new Error(`${label} must be a positive integer`);
|
|
452
|
+
}
|
|
453
|
+
return parsed;
|
|
454
|
+
}
|
|
455
|
+
|
|
380
456
|
function nonnegativeInteger(value: string, label: string): number {
|
|
381
457
|
const parsed = Number(value);
|
|
382
458
|
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
@@ -401,8 +477,12 @@ Usage:
|
|
|
401
477
|
self-bench up [--backend docker|modal|vercel] [--harbor-environment docker|modal]
|
|
402
478
|
[--modal-config PATH] [--vercel-profile NAME]
|
|
403
479
|
self-bench down
|
|
480
|
+
self-bench associate --repo PATH --list-sessions
|
|
481
|
+
self-bench associate --repo PATH --pr NUMBER --session TYPE:SESSION_ID [...]
|
|
482
|
+
--output ASSOCIATION.json
|
|
404
483
|
self-bench run --repo PATH [--easy-count N] [--medium-count N] [--hard-count N]
|
|
405
|
-
[--model MODEL] [--
|
|
484
|
+
[--model MODEL] [--association ASSOCIATION.json ...]
|
|
485
|
+
[--run-id ID] [--wait] [--output OUTPUT.tar.gz]
|
|
406
486
|
self-bench status RUN_ID
|
|
407
487
|
self-bench cancel RUN_ID
|
|
408
488
|
self-bench download RUN_ID OUTPUT.tar.gz
|
|
@@ -413,6 +493,10 @@ requires --harbor-environment because Harbor does not support Vercel. Modal gene
|
|
|
413
493
|
~/.modal.toml unless --modal-config overrides it. Run self-bench setup vercel once to create or select a
|
|
414
494
|
project, publish the pinned runtime image, verify access, and save an owner-only local profile.
|
|
415
495
|
|
|
496
|
+
The associate command runs locally. --list-sessions prints selectors, counts, local paths, and modification
|
|
497
|
+
times, but never request text. Association writes a create-only, text-free manifest; it never uploads or
|
|
498
|
+
starts a run. Pass the manifest to run with --association (repeatable). No LLM participates in association.
|
|
499
|
+
|
|
416
500
|
The tier counts are candidate authoring budgets, not accepted-task targets. Rejected candidates are not
|
|
417
501
|
replaced, and the export contains only accepted tasks. The run command performs only repository metadata
|
|
418
502
|
and sanitized provenance upload locally; discovery, authoring, validation, review, and audit run remotely.
|
package/src/config.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type HarborEnvironment,
|
|
7
7
|
matchingHarborEnvironment,
|
|
8
8
|
} from "./providers.js";
|
|
9
|
-
import { parseSandboxTimeoutCapText, STANDARD_VERCEL_TIMEOUT_CAP_MS } from "./sandbox
|
|
9
|
+
import { parseSandboxTimeoutCapText, STANDARD_VERCEL_TIMEOUT_CAP_MS } from "./sandbox/timeout.js";
|
|
10
10
|
|
|
11
11
|
const emptyStringAsUndefined = (value: unknown): unknown =>
|
|
12
12
|
typeof value === "string" && value.trim() === "" ? undefined : value;
|
package/src/contracts.ts
CHANGED
|
@@ -22,17 +22,19 @@ export type ArtifactRef = z.infer<typeof artifactRefSchema>;
|
|
|
22
22
|
export const difficultySchema = z.enum(["easy", "medium", "hard"]);
|
|
23
23
|
export type Difficulty = z.infer<typeof difficultySchema>;
|
|
24
24
|
|
|
25
|
+
export const MAX_CANDIDATES_PER_RUN = 10_000;
|
|
26
|
+
|
|
25
27
|
const candidateCountsSchema = z
|
|
26
28
|
.object({
|
|
27
|
-
easy: z.number().int().min(0).max(
|
|
28
|
-
medium: z.number().int().min(0).max(
|
|
29
|
-
hard: z.number().int().min(0).max(
|
|
29
|
+
easy: z.number().int().min(0).max(MAX_CANDIDATES_PER_RUN),
|
|
30
|
+
medium: z.number().int().min(0).max(MAX_CANDIDATES_PER_RUN),
|
|
31
|
+
hard: z.number().int().min(0).max(MAX_CANDIDATES_PER_RUN),
|
|
30
32
|
})
|
|
31
33
|
.refine(({ easy, medium, hard }) => easy + medium + hard >= 1, {
|
|
32
34
|
message: "at least one candidate must be requested",
|
|
33
35
|
})
|
|
34
|
-
.refine(({ easy, medium, hard }) => easy + medium + hard <=
|
|
35
|
-
message:
|
|
36
|
+
.refine(({ easy, medium, hard }) => easy + medium + hard <= MAX_CANDIDATES_PER_RUN, {
|
|
37
|
+
message: `at most ${MAX_CANDIDATES_PER_RUN} candidates may be requested`,
|
|
36
38
|
});
|
|
37
39
|
|
|
38
40
|
const runVersionSchema = z
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { writeFileSync } from "node:fs";
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { Type } from "@sinclair/typebox";
|
|
4
4
|
|
|
@@ -22,7 +22,6 @@ export default function discoveryExtension(pi: ExtensionAPI): void {
|
|
|
22
22
|
sourceUrl: Type.String({ minLength: 1 }),
|
|
23
23
|
baseCommit: Type.String({ pattern: "^[0-9a-fA-F]{40}$" }),
|
|
24
24
|
completedCommit: Type.String({ pattern: "^[0-9a-fA-F]{40}$" }),
|
|
25
|
-
request: Type.String({ minLength: 1 }),
|
|
26
25
|
provenance: Type.Object({
|
|
27
26
|
sourceType: Type.Union([
|
|
28
27
|
Type.Literal("pi"),
|
|
@@ -51,10 +50,20 @@ export default function discoveryExtension(pi: ExtensionAPI): void {
|
|
|
51
50
|
if (!candidates) {
|
|
52
51
|
throw new Error("submit_discovery received no candidates");
|
|
53
52
|
}
|
|
54
|
-
|
|
53
|
+
const exclusionsPath = process.env.SELFBENCH_DISCOVERY_EXCLUSIONS;
|
|
54
|
+
if (!exclusionsPath) {
|
|
55
|
+
throw new Error("SELFBENCH_DISCOVERY_EXCLUSIONS is not configured");
|
|
56
|
+
}
|
|
57
|
+
const excluded = new Set<number>(JSON.parse(readFileSync(exclusionsPath, "utf8")));
|
|
58
|
+
const accepted = candidates.filter(
|
|
59
|
+
({ sourcePr }) => sourcePr !== undefined && !excluded.has(sourcePr),
|
|
60
|
+
);
|
|
61
|
+
writeFileSync(output, `${JSON.stringify({ candidates: accepted }, null, 2)}\n`, {
|
|
62
|
+
flag: "wx",
|
|
63
|
+
});
|
|
55
64
|
return {
|
|
56
|
-
content: [{ type: "text", text: `Submitted ${
|
|
57
|
-
details: { candidates },
|
|
65
|
+
content: [{ type: "text", text: `Submitted ${accepted.length} new candidates.` }],
|
|
66
|
+
details: { candidates: accepted },
|
|
58
67
|
};
|
|
59
68
|
},
|
|
60
69
|
});
|