shapeup-sdlc 3.9.1 → 3.9.2
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shapeup-sdlc-plugin",
|
|
3
3
|
"displayName": "ShapeUp SDLC Plugin",
|
|
4
|
-
"version": "3.9.
|
|
4
|
+
"version": "3.9.2",
|
|
5
5
|
"description": "Shape Up SDLC harness for Claude Code: shaping, intake, orient, scope-mapping, building (T0-verified, sandboxed, scope-contracted), evaluation and QA skills orchestrated by a tech-lead.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Liberty Nguyen",
|
package/kernel/lib/contract.mjs
CHANGED
|
@@ -263,6 +263,28 @@ function splitList(body) {
|
|
|
263
263
|
* @returns {{meta:Object<string,*>, body:string}} Parsed scalars/lists and the remaining body
|
|
264
264
|
* ({}/whole document when there is no leading `---` block).
|
|
265
265
|
*/
|
|
266
|
+
/**
|
|
267
|
+
* Whether a flow sequence is closed: every `[` outside a quoted run has met its `]`.
|
|
268
|
+
*
|
|
269
|
+
* Quotes are tracked because a bracket inside a quoted path is a character, not structure — and a
|
|
270
|
+
* scope substrate glob is exactly the kind of value that can carry one.
|
|
271
|
+
*
|
|
272
|
+
* @param {string} text - The accumulated text, starting at the opening bracket.
|
|
273
|
+
* @returns {boolean} True once depth returns to zero, i.e. the sequence is complete.
|
|
274
|
+
*/
|
|
275
|
+
function flowClosed(text) {
|
|
276
|
+
let depth = 0;
|
|
277
|
+
let quote = null;
|
|
278
|
+
for (let i = 0; i < text.length; i++) {
|
|
279
|
+
const ch = text[i];
|
|
280
|
+
if (quote) { if (ch === quote && text[i - 1] !== "\\") quote = null; continue; }
|
|
281
|
+
if (ch === '"' || ch === "'") { quote = ch; continue; }
|
|
282
|
+
if (ch === "[") depth++;
|
|
283
|
+
else if (ch === "]") { depth--; if (depth === 0) return true; }
|
|
284
|
+
}
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
|
|
266
288
|
export function splitFrontmatter(md) {
|
|
267
289
|
const m = String(md ?? "").match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
268
290
|
if (!m) return { meta: {}, body: String(md ?? "") };
|
|
@@ -275,7 +297,29 @@ export function splitFrontmatter(md) {
|
|
|
275
297
|
const c = line.indexOf(":");
|
|
276
298
|
if (c === -1) continue;
|
|
277
299
|
const key = line.slice(0, c).trim();
|
|
278
|
-
|
|
300
|
+
let inline = line.slice(c + 1).trim();
|
|
301
|
+
|
|
302
|
+
// A FLOW SEQUENCE MAY SPAN LINES, and it used to parse as the single character "[".
|
|
303
|
+
//
|
|
304
|
+
// `field: [` followed by one quoted member per line and a closing `]` is the form a model
|
|
305
|
+
// reaches for the moment a list is too long to read on one line, and this dialect took only
|
|
306
|
+
// the text after the colon — so the value became the string "[", the members were counted as
|
|
307
|
+
// unreadable strays, and every reader downstream saw a string where an array was declared.
|
|
308
|
+
// Measured on a live run: three of five scope contracts were written this way, and each one
|
|
309
|
+
// then failed its own envelope schema at compile — the run could not dispatch those scopes at
|
|
310
|
+
// all. Accepted now: the lines are joined until the brackets balance and the whole thing is
|
|
311
|
+
// coerced as the list it is. A sequence that never closes is still reported, never guessed at.
|
|
312
|
+
if (inline.startsWith("[") && !flowClosed(inline)) {
|
|
313
|
+
let buf = inline;
|
|
314
|
+
let k = i + 1;
|
|
315
|
+
for (; k < lines.length && !flowClosed(buf); k++) buf += " " + lines[k].trim();
|
|
316
|
+
i = k - 1;
|
|
317
|
+
if (flowClosed(buf)) { meta[key] = coerce(buf); continue; }
|
|
318
|
+
meta[key] = null;
|
|
319
|
+
unreadable.push({ field: key, expected_heading: `${key}: [a, b] (or an indented \`- item\` list)`,
|
|
320
|
+
found_under: "a flow sequence that is never closed", rows: k - (i + 1) });
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
279
323
|
|
|
280
324
|
// An indented run beneath a key is a YAML BLOCK SEQUENCE, and it used to be skipped
|
|
281
325
|
// entirely — so `e2e_verification_fixtures:` followed by two `- "node …"` lines parsed to
|
package/kernel/verify/trace.mjs
CHANGED
|
@@ -320,7 +320,13 @@ export function scopeReachability(contracts, reachable, sources) {
|
|
|
320
320
|
for (const found of contracts) {
|
|
321
321
|
const c = found?.contract || found || {};
|
|
322
322
|
const id = c.scope_id || found?.id;
|
|
323
|
-
|
|
323
|
+
// A CONTRACT THIS CANNOT READ IS SKIPPED, NEVER THROWN OVER. The whole oracle runs advisory, so
|
|
324
|
+
// a throw here takes out covers-closure too and the run gets no report at all — one malformed
|
|
325
|
+
// contract silencing every arm. A substrate that is not a list of globs is simply a scope this
|
|
326
|
+
// arm has nothing to say about.
|
|
327
|
+
const declared = c.allowed_file_substrate;
|
|
328
|
+
if (!Array.isArray(declared) || !declared.length) continue;
|
|
329
|
+
const globs = declared.filter((g) => typeof g === "string").map(globToRegExp);
|
|
324
330
|
if (!globs.length) continue;
|
|
325
331
|
const owned = sources.filter((f) => globs.some((r) => r.test(f)));
|
|
326
332
|
if (!owned.length) continue;
|
package/package.json
CHANGED