cortad 0.3.0-rc.12 → 0.3.0-rc.13
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/lib/read-text.mjs +3 -1
- package/lib/text.mjs +5 -2
- package/local.mjs +7 -2
- package/package.json +1 -1
- package/skill/references/results.md +1 -1
package/lib/read-text.mjs
CHANGED
|
@@ -16,7 +16,9 @@ const ruleLine = (e) => ` ${at(e.path, e.line)} "${clip(e.text, 300)}"`;
|
|
|
16
16
|
const headOf = (label, parts) => (parts.some(Boolean) ? `${label}: ${parts.filter(Boolean).join(", ")}.` : `${label}:`);
|
|
17
17
|
const standardsHead = (m) => headOf("Engineering standards", [has(m.decided) && `${num(m.decided)} decided`, has(m.met) && `${num(m.met)} met`, has(m.missed) && `${num(m.missed)} missed`]);
|
|
18
18
|
const standardLine = (x) => ` ${x.path ? `${at(x.path, x.line)} ` : ""}${x.standard}${x.detail ? `: ${clip(x.detail, 240)}` : ""}${x.decidedBy ? ` (decided by ${x.decidedBy === "code" ? "code" : "a model"})` : ""}`;
|
|
19
|
-
|
|
19
|
+
// Which trials can be played is decided when a run knocks: a read that said "21 playable, none held
|
|
20
|
+
// back" was followed by a run that held 28 back, and three agents called the counts contradictory.
|
|
21
|
+
const trialsHead = (t) => headOf("Trials", [has(t.written) && `${num(t.written)} written`]);
|
|
20
22
|
const heldWhy = (h) => `${SIDE[h.side] ? `, ${SIDE[h.side]}` : ""}${h.why ? `: ${clip(h.why, 300)}` : ""}`;
|
|
21
23
|
const named = (label, group, max = 12) => {
|
|
22
24
|
if (!group) return null;
|
package/lib/text.mjs
CHANGED
|
@@ -77,7 +77,10 @@ function runLines(d, prefix = "") {
|
|
|
77
77
|
// to every agent that got it. What was measured leads, then the rate on what was measured.
|
|
78
78
|
if (done && has(d.questionsAsked) && has(d.questionsOf) && d.questionsOf > 0) lines.push(coverageLine(d));
|
|
79
79
|
if (done && d.blocked) lines.push(d.blocked);
|
|
80
|
-
if (done &&
|
|
80
|
+
if (done && d.notCounted) lines.push(d.notCounted);
|
|
81
|
+
// A verify is a move, not a score: "100 of 100" on a replay whose run before decided nothing read
|
|
82
|
+
// as a clean bill to bloom's agent, beside "zero verified fixes".
|
|
83
|
+
if (done && typeof d.score === "number" && d.kind !== "verify") lines.push(scoreLine(d));
|
|
81
84
|
if (done && d.halted) lines.push(haltLine(d.halted));
|
|
82
85
|
if (done && has(d.readingsHeld) && has(d.readings) && d.readings > 0) lines.push(`The question readings held in ${num(d.readingsHeld)} of ${num(d.readings)}, ${Math.round((100 * d.readingsHeld) / d.readings)}%; the score is the case checks' pass rate on the checks measured.`);
|
|
83
86
|
if (done && has(d.findings)) lines.push(`${plural(d.findings, "finding")}.`);
|
|
@@ -136,7 +139,7 @@ export function runText(d) {
|
|
|
136
139
|
export function startedText(d, kind, findingId) {
|
|
137
140
|
const verify = (d.kind ?? kind) === "verify";
|
|
138
141
|
const what = verify ? `Verify${findingId && !d.joined ? ` of ${findingId}` : ""}` : "Run";
|
|
139
|
-
return `${what} ${d.joined ? "already playing" : "started"}: ${d.jobId}
|
|
142
|
+
return `${what} ${d.joined ? "already playing" : "started"}: ${d.jobId}.${d.note ? `\n${d.note}` : ""}\nnext: run_status ${d.jobId}`;
|
|
140
143
|
}
|
|
141
144
|
|
|
142
145
|
export const waitingText = (p, now, limitMs) =>
|
package/local.mjs
CHANGED
|
@@ -712,9 +712,14 @@ async function freePortAbove(port) {
|
|
|
712
712
|
for (let next = port + 1; next < port + 30; next++) if (!lost.has(next) && !(await listenerOn(next))) return next;
|
|
713
713
|
return null;
|
|
714
714
|
}
|
|
715
|
+
// The port a bind failure names, in the app's own words: uvicorn's "('127.0.0.1', 8105): address
|
|
716
|
+
// already in use", Node's "EADDRINUSE: address already in use :::3000".
|
|
717
|
+
const portInError = (said) => Number(/(\d{4,5})\)?:?\s*address already in use/i.exec(said)?.[1] ?? /(?:EADDRINUSE|address already in use)\D{0,40}?(\d{4,5})\b/i.exec(said)?.[1] ?? 0);
|
|
715
718
|
async function freed(cmd, lifted) {
|
|
716
719
|
const m = /(--port[= ]|-p |\bPORT=)(\d{4,5})\b/.exec(cmd);
|
|
717
|
-
|
|
720
|
+
// The app's own env file names its port too: yunqiao's PORT=8105 sat in .env, and a stale copy
|
|
721
|
+
// on that port was reported as "your app stopped" instead of moved past.
|
|
722
|
+
const named = m ? Number(m[2]) : Number(lifted.PORT) || Number(envExports(envFiles).PORT) || 0;
|
|
718
723
|
if (!named || (!lost.has(named) && !(await listenerOn(named)))) return { cmd, lifted };
|
|
719
724
|
const port = await freePortAbove(named);
|
|
720
725
|
if (!port) return { cmd, lifted };
|
|
@@ -749,7 +754,7 @@ async function start(waitMs) {
|
|
|
749
754
|
await stopApp(mine.pid);
|
|
750
755
|
// The port this start named was taken between the check and the bind: the next free one, at
|
|
751
756
|
// most three times, before the failure is theirs to read.
|
|
752
|
-
const named = /(?:--port[= ]|-p |\bPORT=)(\d{4,5})\b/.exec(cmd)?.[1] ?? lifted.PORT;
|
|
757
|
+
const named = /(?:--port[= ]|-p |\bPORT=)(\d{4,5})\b/.exec(cmd)?.[1] ?? lifted.PORT ?? envExports(envFiles).PORT ?? (portInError(seen) || undefined);
|
|
753
758
|
if (/EADDRINUSE|address already in use/i.test(seen) && named && lost.size < 3) { lost.add(Number(named)); return start(waitMs); }
|
|
754
759
|
return { port: null, exited: 1, tail: tail() };
|
|
755
760
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cortad",
|
|
3
|
-
"version": "0.3.0-rc.
|
|
3
|
+
"version": "0.3.0-rc.13",
|
|
4
4
|
"description": "Connects the AI app on your machine to Cortad for test conversations, and gives your coding agent the MCP and skill to run them. No dependencies.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"cortad": "local.mjs"
|
|
@@ -35,7 +35,7 @@ Engineering standards: 38 decided, 35 met, 3 missed.
|
|
|
35
35
|
apps/api/src/agent/system.ts:30 User text stays out of the system prompt: the student's name is written into the system prompt (decided by a model)
|
|
36
36
|
apps/api/src/tools/search.ts:51 Tool errors reach the model as errors: search returns an empty list when the index is down (decided by a model)
|
|
37
37
|
Questions: 112; 40 asked in every conversation, 72 placed in the situations they fit.
|
|
38
|
-
Trials: 58 written
|
|
38
|
+
Trials: 58 written.
|
|
39
39
|
POST /api/homework/upload: 7 trials held back, on the app's side: the route needs a signed file URL, and no test account can make one
|
|
40
40
|
Latest run 8f2a1c4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b: running, 14 of 51 trials played.
|
|
41
41
|
410 readings of 112 questions.
|