@golden-frijoles/kit 0.33.0 → 0.34.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.
|
@@ -54,10 +54,10 @@ export const AGENT_BIN = {
|
|
|
54
54
|
// Harmless here since AGY_MODEL/AGY_FALLBACK_MODEL below are always valid, listed model names (checked via
|
|
55
55
|
// `agy models`), but it means a future typo in either constant would silently review with the WRONG model
|
|
56
56
|
// instead of failing loud — watch for that if either constant is ever edited.
|
|
57
|
-
// agy-doctor: last verified 2026-10-
|
|
57
|
+
// agy-doctor: last verified 2026-10-07 against 1.3.1.
|
|
58
58
|
// ^ machine-managed marker — `node scripts/cross-agent-doctor.mjs agy --fix` rewrites it (with the constant
|
|
59
59
|
// below) after a green live contract probe. Don't hand-edit the marker's shape.
|
|
60
|
-
export const AGY_PINNED = '1.3.
|
|
60
|
+
export const AGY_PINNED = '1.3.1';
|
|
61
61
|
|
|
62
62
|
// agy's `--print` mode prints NOTHING unless `--model` names a model — and, crucially, it ALSO prints
|
|
63
63
|
// nothing (exit 0, empty stdout — the error lands only in agy's log, see --log-file) when the model is
|
|
@@ -140,6 +140,25 @@ export function validateResultFields(fm) {
|
|
|
140
140
|
return offenses;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
// one-epic-page D11 — the epic's flag, decided at groom Stage 6b and copied into the README by the scaffold. The SDK's
|
|
144
|
+
// flag-key grammar (`FLAG_KEY` in apps/web/lib/flag-admin-operation.ts). Optional: `flag_key: null` (no flag) is the
|
|
145
|
+
// default and never an error; a value that is not a key is named, never pushed (the extract sends null for it).
|
|
146
|
+
export const FLAG_KEY_RE = /^[a-z][a-z0-9_.-]{0,127}$/;
|
|
147
|
+
|
|
148
|
+
/** `flag_key:` → offenses (`contract-flag-key-invalid`). Absent or null is fine. */
|
|
149
|
+
export function validateFlagKey(fm) {
|
|
150
|
+
const v = fm.flag_key;
|
|
151
|
+
if (v === undefined || v === null) return [];
|
|
152
|
+
// The string "null" fits the grammar but means "no flag": named here as the push schema refuses it (codex, #297).
|
|
153
|
+
if (typeof v === 'string' && v !== 'null' && FLAG_KEY_RE.test(v)) return [];
|
|
154
|
+
return [
|
|
155
|
+
{
|
|
156
|
+
rule: 'contract-flag-key-invalid',
|
|
157
|
+
detail: `flag_key: "${v}" is not a flag key (a lowercase letter, then a-z 0-9 _ . -; at most 128) — or null`,
|
|
158
|
+
},
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
|
|
143
162
|
// live-build-view D10 — `locked_at:` is stamped by `scripts/epic-phase.mjs lock` when the architecture lock is written;
|
|
144
163
|
// the build view reads its absence as "Locking architecture". Optional (no epic before it has one), an ISO date-time
|
|
145
164
|
// string when present: the command writes `"2026-10-03T20:34:34Z"` (quoted, so the frontmatter parser keeps the colons).
|
|
@@ -355,6 +374,7 @@ export function validateEpicFrontmatter(parsed, ctx = {}) {
|
|
|
355
374
|
}
|
|
356
375
|
offenses.push(...validateFinopsFields(fm));
|
|
357
376
|
offenses.push(...validateResultFields(fm));
|
|
377
|
+
offenses.push(...validateFlagKey(fm));
|
|
358
378
|
offenses.push(...validateLockedAt(fm));
|
|
359
379
|
if (isInt(fm.sprints_total) && isInt(ctx.sprintCount) && fm.sprints_total !== ctx.sprintCount)
|
|
360
380
|
offenses.push({
|
package/dist/roadmap-extract.mjs
CHANGED
|
@@ -73,6 +73,7 @@ import {
|
|
|
73
73
|
FINOPS_NUMERIC_FIELDS,
|
|
74
74
|
RESULT_DAY_FIELDS,
|
|
75
75
|
RESULT_FIELDS,
|
|
76
|
+
FLAG_KEY_RE,
|
|
76
77
|
RESULT_NUMERIC_FIELDS,
|
|
77
78
|
VERDICTS,
|
|
78
79
|
} from './lib/roadmap-contract.mjs';
|
|
@@ -161,6 +162,21 @@ export function resultFields(fm, shippedAt) {
|
|
|
161
162
|
return out;
|
|
162
163
|
}
|
|
163
164
|
|
|
165
|
+
/**
|
|
166
|
+
* one-epic-page D11 — an epic's flag: `flag_key` off its README frontmatter (the SDK's key grammar, else null — the
|
|
167
|
+
* contract names a bad one) and `flag_note`, the README's own `**Flag:** …` line, which is where an epic with no flag
|
|
168
|
+
* says why. Both null when absent; nothing is inferred from prose about a flag the frontmatter does not name.
|
|
169
|
+
*/
|
|
170
|
+
export function flagFields(fm, readme) {
|
|
171
|
+
const raw = typeof fm.flag_key === 'string' ? fm.flag_key.trim() : '';
|
|
172
|
+
// A QUOTED `flag_key: "null"` (or `~`) arrives as a string, and "null" fits the key grammar — so the blank
|
|
173
|
+
// spellings are refused before the pattern is asked. (Unquoted `null` is already null from this file's reader.)
|
|
174
|
+
const blank = raw === '' || raw === 'null' || raw === '~';
|
|
175
|
+
const line = /^\*\*Flag:\*\*[ \t]*(.+)$/m.exec(readme ?? '');
|
|
176
|
+
const note = line ? line[1].replace(/[*`]/g, '').trim().slice(0, 280) : '';
|
|
177
|
+
return { flag_key: !blank && FLAG_KEY_RE.test(raw) ? raw : null, flag_note: note || null };
|
|
178
|
+
}
|
|
179
|
+
|
|
164
180
|
function parseFrontmatter(md) {
|
|
165
181
|
if (!md.startsWith('---')) return {};
|
|
166
182
|
const end = md.indexOf('\n---', 3);
|
|
@@ -583,6 +599,7 @@ export function buildRows({
|
|
|
583
599
|
}
|
|
584
600
|
}
|
|
585
601
|
|
|
602
|
+
const readme = readFileSync(join(e.path, 'README.md'), 'utf8');
|
|
586
603
|
// Epic row
|
|
587
604
|
rows.push({
|
|
588
605
|
name: epicTitle(e.path, e.slug),
|
|
@@ -605,7 +622,7 @@ export function buildRows({
|
|
|
605
622
|
build_order_num: buildOrderNum(buildOrder),
|
|
606
623
|
doc_link: readmePath,
|
|
607
624
|
epic_slug: null,
|
|
608
|
-
goal: firstParagraph(
|
|
625
|
+
goal: firstParagraph(readme, ['Why', 'Goal', 'Problem']),
|
|
609
626
|
sprints: boardSprints.map((sp) => ({ n: sp.n, title: sp.title, done: sp.done, total: sp.total })),
|
|
610
627
|
links: {
|
|
611
628
|
readme: readmePath,
|
|
@@ -618,6 +635,7 @@ export function buildRows({
|
|
|
618
635
|
shipped_at: stage === 'Shipped' ? statusDay : null,
|
|
619
636
|
...finopsFields(epicFm),
|
|
620
637
|
...resultFields(epicFm, stage === 'Shipped' ? statusDay : null),
|
|
638
|
+
...flagFields(epicFm, readme),
|
|
621
639
|
});
|
|
622
640
|
|
|
623
641
|
// Sprint rows (one per sprint-N.md), related to the Epic by slug. boardSprints already carries
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@golden-frijoles/kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "The scripts the Golden Frijoles skills run, packaged so they work in any repo: planning, build-order, reporting and verification rails. Zero dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|