@afokapu/atdd-bun 0.10.29 → 0.10.31
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.
|
@@ -337,6 +337,7 @@ export function unbuiltWagons(croot, trainId) {
|
|
|
337
337
|
let sourceRoot = "src/wagons";
|
|
338
338
|
try { sourceRoot = Bun.YAML.parse(readText(join(croot, "atdd-bun.yaml")))?.topology?.source_root || sourceRoot; } catch { /* default layout */ }
|
|
339
339
|
const hasSource = (wagon) => [...walkFiles(join(croot, sourceRoot, wagon), isTs)].some((f) => !/\.(test|spec)\.[cm]?[jt]sx?$/.test(f));
|
|
340
|
+
const produces = new Map();
|
|
340
341
|
(function rec(dir) {
|
|
341
342
|
let entries;
|
|
342
343
|
try { entries = readdirSync(dir).sort(); } catch { return; }
|
|
@@ -348,6 +349,8 @@ export function unbuiltWagons(croot, trainId) {
|
|
|
348
349
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
349
350
|
let doc;
|
|
350
351
|
try { doc = Bun.YAML.parse(readText(full)); } catch { continue; }
|
|
352
|
+
if (doc && typeof doc.wagon === "string" && Array.isArray(doc.produce))
|
|
353
|
+
produces.set(doc.wagon.trim(), doc.produce.map((p) => p?.name).filter((name) => typeof name === "string" && name));
|
|
351
354
|
if (!doc || typeof doc.train_id !== "string" || !Array.isArray(doc.sequence)) continue;
|
|
352
355
|
const wagons = new Set(doc.sequence.flatMap((step) => [step?.from, step?.to]).filter((end) => typeof end === "string" && end.startsWith("wagon:")).map((end) => end.slice(6).trim()));
|
|
353
356
|
byTrain.set(doc.train_id, [...wagons]);
|
|
@@ -355,7 +358,18 @@ export function unbuiltWagons(croot, trainId) {
|
|
|
355
358
|
})(join(croot, PLAN_ROOT));
|
|
356
359
|
// Only a repository that keeps wagon code under the source root can show a wagon as not built yet. Where no wagon has
|
|
357
360
|
// source there (the code lives elsewhere, as in decision-os), nothing is pending and every route is judged.
|
|
358
|
-
|
|
361
|
+
// A wagon coded outside the source root is built all the same when Cargo-moving code names an artifact it produces:
|
|
362
|
+
// the wagon-contract rule's own evidence (C1 #lVuJXXe3mM9E). Comments are masked, tests are not read.
|
|
363
|
+
let cargoCode = null;
|
|
364
|
+
const named = (wagon) => {
|
|
365
|
+
const names = produces.get(wagon) ?? [];
|
|
366
|
+
if (!names.length) return false;
|
|
367
|
+
cargoCode ??= [...walkFiles(croot, isTs)].filter((f) => !/\.(test|spec)\.[cm]?[jt]sx?$/.test(f)).map((f) => readText(f) ?? "")
|
|
368
|
+
.filter((text) => /\bCargo\b|\bcargo\s*\.\s*(?:put|get)\s*\(/.test(text))
|
|
369
|
+
.map((text) => text.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:\\])\/\/[^\n]*/g, "$1")).join("\n");
|
|
370
|
+
return names.some((name) => cargoCode.includes(name));
|
|
371
|
+
};
|
|
372
|
+
const built = new Map([...new Set([...byTrain.values()].flat())].map((wagon) => [wagon, hasSource(wagon) || named(wagon)]));
|
|
359
373
|
const layoutInUse = [...built.values()].some(Boolean);
|
|
360
374
|
for (const [trainId, wagons] of byTrain) byTrain.set(trainId, layoutInUse ? wagons.filter((wagon) => !built.get(wagon)) : []);
|
|
361
375
|
pendingCache.set(croot, byTrain);
|
package/integrity.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.10.
|
|
2
|
+
"version": "0.10.31",
|
|
3
3
|
"files": {
|
|
4
4
|
"HOOK_AUDIT.md": "5329d840db37671b1918f688ead26865473b87db73dbc75f7c8b2a8bbe8d6d43",
|
|
5
5
|
"PLANNER_PORT.md": "fb5935bac8b7ac18994de21e43ace3a5ef8cd55f85b0e3349fca261280054f11",
|
|
@@ -379,7 +379,7 @@
|
|
|
379
379
|
"detectors/bun_interlocking_binding/fixtures/dirty_transcribed_runtime/server.ts": "d5bc34c5b1b2b0a511e0c4604ce6f9c77491dca9aee994be720540f3052babc1",
|
|
380
380
|
"detectors/bun_interlocking_binding/fixtures/dirty_transcribed_runtime/src/trains/interlocking.ts": "9bcfdb4ecff6efd1f658b9fd587342615179924e25468c75daa07c2626d4d8ab",
|
|
381
381
|
"detectors/bun_interlocking_binding/fixtures/dirty_transcribed_runtime/src/trains/runner.ts": "0e4b885e50f12cc2a8c8f6740bf83e7b2e7137a28e1e143586e9a8550ea5bd45",
|
|
382
|
-
"detectors/bun_interlocking_coverage/_shared/interlocking.mjs": "
|
|
382
|
+
"detectors/bun_interlocking_coverage/_shared/interlocking.mjs": "448ba5f8561d225eef0e9fd8cc8c7a0bcfc755ad0214ff5758a7aefbbf35283c",
|
|
383
383
|
"detectors/bun_interlocking_coverage/atdd.implementation.yaml": "f160517a8138ba3ca05e3d130e6fbfb796e643376f25743fdef4fc210196525b",
|
|
384
384
|
"detectors/bun_interlocking_coverage/checks/_map.json": "0a218ea319cc6258af7bd721c2154cb9561fe67e80d80ef32d08fc77bc9403c3",
|
|
385
385
|
"detectors/bun_interlocking_coverage/checks/interlocking_production_runner.mjs": "a1edd5aa15892564aa8d46a93dca2d17001901e90085cd660be192a2ec747c1f",
|
|
@@ -977,7 +977,7 @@
|
|
|
977
977
|
"lib/frontend.mjs": "d6d9b29c3d7f2d162cda03bb34b20a3224a82887b6be3db7cab375510913c9a3",
|
|
978
978
|
"lib/imports.mjs": "3db4979269488fa26f6e7aefded6ece9c646be6587a10e249821a5a208109962",
|
|
979
979
|
"lib/interlocking.mjs": "d0803d080ac7d7477c51be70112df1e85213d339fd3c6b71f75f26145fa8accd",
|
|
980
|
-
"lib/scan.mjs": "
|
|
980
|
+
"lib/scan.mjs": "02b0fa864cab24157a8f27b50a87a2bb66a875f90cf6632c753c4627d61456ef",
|
|
981
981
|
"planner-nodes/ENFORCEMENT_SCOPE.yaml": "d8ec7039c219857f3d77af5d4d84612b533b69c1a5fcef935fbf46470adafed4",
|
|
982
982
|
"planner-nodes/nodes/planner.acceptance.abstract-fields-required.convention.yaml": "bd565693f0ae861f0561ad2f7a91a8c55f9a209c3acd59c5750cfcffd96a85d8",
|
|
983
983
|
"planner-nodes/nodes/planner.acceptance.authoring-guidelines.convention.yaml": "16348dceed5868041b832bde766e9c8d4a950d4032f1f3066b357644081a3b17",
|
|
@@ -1202,7 +1202,7 @@
|
|
|
1202
1202
|
"relationships.yaml": "1cb713364aff54fb6e299e0737fe75a5d7b2e1dbd0a79b16b793aa1d269207b5",
|
|
1203
1203
|
"src/agent.ts": "65e4579adb5a54977f557f8c783aba0e2a2a1d5cf3cea9f017b67ffe598b2f65",
|
|
1204
1204
|
"src/board-ui.ts": "16a843705552f8f18e0e328e90e4a2a9148d771ca69f2708fe4a91302947dfad",
|
|
1205
|
-
"src/board.ts": "
|
|
1205
|
+
"src/board.ts": "4b9aa5b356d67c1b4ab4018796f9d09afba6d443dbebbb733b5d6c6a8d5a1c87",
|
|
1206
1206
|
"src/ci.ts": "67e54d2cbfc44a9e42837d5e750af526d6255c539d3c452a4d5fca3226c0d9ac",
|
|
1207
1207
|
"src/cli.ts": "e5ab4d2435fdcbebf462b4c2b67b495bd975d5deb668b088d8cba04a9d8b78a5",
|
|
1208
1208
|
"src/delivery.ts": "2eaaf4fd87aea26dce70b4c88a4e0a2f25b9de165bc2e38330fd7eb449587901",
|
package/lib/scan.mjs
CHANGED
|
@@ -132,6 +132,38 @@ function regexMayStart(text, i) {
|
|
|
132
132
|
return false;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
// The index just past the template literal opening at `start`. A `${ … }` substitution is code: it may hold strings,
|
|
136
|
+
// braces and templates of its own (escaped backticks included), so the template ends only at a backtick outside them.
|
|
137
|
+
function templateEnd(text, start) {
|
|
138
|
+
const n = text.length;
|
|
139
|
+
let j = start + 1;
|
|
140
|
+
while (j < n) {
|
|
141
|
+
const c = text[j];
|
|
142
|
+
if (c === "\\") { j += 2; continue; }
|
|
143
|
+
if (c === "`") return j + 1;
|
|
144
|
+
if (c === "$" && text[j + 1] === "{") {
|
|
145
|
+
let depth = 1;
|
|
146
|
+
j += 2;
|
|
147
|
+
while (j < n && depth > 0) {
|
|
148
|
+
const d = text[j];
|
|
149
|
+
if (d === "`") { j = templateEnd(text, j); continue; }
|
|
150
|
+
if (d === '"' || d === "'") {
|
|
151
|
+
let k = j + 1;
|
|
152
|
+
while (k < n && text[k] !== d && text[k] !== "\n") k += text[k] === "\\" ? 2 : 1;
|
|
153
|
+
j = k + 1;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (d === "{") depth++;
|
|
157
|
+
else if (d === "}") depth--;
|
|
158
|
+
j++;
|
|
159
|
+
}
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
j++;
|
|
163
|
+
}
|
|
164
|
+
return n;
|
|
165
|
+
}
|
|
166
|
+
|
|
135
167
|
export function maskLiteralsAndComments(text) {
|
|
136
168
|
const out = text.split("");
|
|
137
169
|
let i = 0;
|
|
@@ -165,7 +197,11 @@ export function maskLiteralsAndComments(text) {
|
|
|
165
197
|
if (j >= n || text[j] !== "/") { i++; continue; } // no closing slash on the line: not a regex
|
|
166
198
|
blank(i + 1, j);
|
|
167
199
|
i = j + 1;
|
|
168
|
-
} else if (ch ===
|
|
200
|
+
} else if (ch === "`") {
|
|
201
|
+
const j = templateEnd(text, i);
|
|
202
|
+
blank(i + 1, j - 1 >= i + 1 ? j - 1 : i + 1);
|
|
203
|
+
i = j;
|
|
204
|
+
} else if (ch === '"' || ch === "'") {
|
|
169
205
|
let j = i + 1;
|
|
170
206
|
while (j < n) {
|
|
171
207
|
if (text[j] === "\\") { j += 2; continue; }
|
package/package.json
CHANGED
package/src/board.ts
CHANGED
|
@@ -113,9 +113,9 @@ const POLL_LIMIT_MS = 10_000;
|
|
|
113
113
|
|
|
114
114
|
/** What a listener prints when nothing has arrived for a while: the owner's check-in, for the agent to act on (move
|
|
115
115
|
* the work, or tell whoever it waits on), never to answer with a "still here" post. */
|
|
116
|
-
export function checkIn(agent: string, quietSeconds: number): string {
|
|
116
|
+
export function checkIn(agent: string, quietSeconds: number, rearm = false): string {
|
|
117
117
|
const quiet = quietSeconds <= 0 ? "" : quietSeconds < 60 ? ` for ${quietSeconds} s` : ` for ${Math.round(quietSeconds / 60)} min`;
|
|
118
|
-
return `CHECK-IN for ${agent}: no message${quiet}. Where are you? Are you moving forward, or blocked on someone, and do they know? Is your stakeholder informed? Are you avoiding ceremony and rabbit holes, effectiveness first, then efficiency? Act on it: move the work, or post once to whoever you wait on; never post just to say you are still here
|
|
118
|
+
return `CHECK-IN for ${agent}: no message${quiet}. Where are you? Are you moving forward, or blocked on someone, and do they know? Is your stakeholder informed? Are you avoiding ceremony and rabbit holes, effectiveness first, then efficiency? Act on it: move the work, or post once to whoever you wait on; never post just to say you are still here.${rearm ? " Then re-arm this listener." : ""}`;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
export async function waitFor(url: string, topics: string[], agent: string, since = "all", timeoutSeconds = 0, skip: string[] = [], intervalMs = 500, seen: (id: string) => void = () => {}): Promise<Message | null> {
|
|
@@ -177,7 +177,7 @@ export async function chat(args: string[], env: Record<string, string | undefine
|
|
|
177
177
|
// Without --since, continue from where this identity last stopped on these topics; either way, remember the place.
|
|
178
178
|
const file = cursorFile(me, topics, env);
|
|
179
179
|
const message = await waitFor(url, topics, me, flag("since") || loadCursor(file) || seedCursor(me, env) || "all", Number(flag("timeout") ?? 0), list(flag("skip")), 500, id => saveCursor(file, id));
|
|
180
|
-
if (!message) { console.log(checkIn(me, Number(flag("timeout") ?? 0))); return 2; }
|
|
180
|
+
if (!message) { console.log(checkIn(me, Number(flag("timeout") ?? 0), true)); return 2; }
|
|
181
181
|
console.log(format(message, topics.length > 1));
|
|
182
182
|
return 0;
|
|
183
183
|
}
|