@jwilger/pi-development-system 0.46.0 → 0.46.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jwilger/pi-development-system",
3
- "version": "0.46.0",
3
+ "version": "0.46.1",
4
4
  "description": "A pi extension package representing a seasoned approach to software development using a full AI SDLC.",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -47,7 +47,7 @@ const direct = (matrix: ModelMatrix, tier: Tier): string[] =>
47
47
  * frontier but lives in strong). Undefined when it is in none of them.
48
48
  */
49
49
  export function tierOf(matrix: ModelMatrix, model: string): Tier | undefined {
50
- return [...TIERS].reverse().find((tier) => matches(direct(matrix, tier), model));
50
+ return TIERS.findLast((tier) => matches(direct(matrix, tier), model));
51
51
  }
52
52
 
53
53
  /** The best tier that lists the model at all: what a slot resolving to it is asking for. */
@@ -144,8 +144,11 @@ export function adoptSeverity(
144
144
  };
145
145
  }
146
146
 
147
- const where = (f: Finding): string =>
148
- f.path === undefined ? "" : ` \`${f.path}${f.line === undefined ? "" : `:${f.line}`}\``;
147
+ const where = (f: Finding): string => {
148
+ if (f.path === undefined) return "";
149
+ const line = f.line === undefined ? "" : `:${f.line}`;
150
+ return ` \`${f.path}${line}\``;
151
+ };
149
152
 
150
153
  /**
151
154
  * Nits are never stored. Each is reported back so the coordinator fixes it now or drops it
@@ -10,11 +10,7 @@ export type ReviewPacket = {
10
10
  readonly verdict: "no-blocking" | "blocking";
11
11
  };
12
12
 
13
- const SEP = "[—–-]";
14
- const HEADER = new RegExp(
15
- `^##\\s+Review\\s+${SEP}\\s+(.+?)\\s+${SEP}\\s+round\\s+(\\S+)\\s+${SEP}\\s+lenses:\\s*(.*)$`,
16
- "m",
17
- );
13
+ const HEADER = /^##\s+Review\s+[—–-]\s+(.+?)\s+[—–-]\s+round\s+(\S+)\s+[—–-]\s+lenses:\s*(.*)$/m;
18
14
  // Reviewers add text after the location (`fn`, a second location); the first backticked one is the finding's.
19
15
  const FINDING = /^-\s*\[([^\]]+)\]\s+(\S+)\s+(?:`([^`]+)`[^—–]*?\s+)?[—–-]\s+(.+)$/;
20
16
  // An indented line under a finding is its detail (trigger, fix), unless it is itself a finding.
@@ -24,8 +20,11 @@ const isDetail = (line: string): boolean =>
24
20
  // `until` ends a section; by default any heading does. Findings ends only at a known section so a stray
25
21
  // heading inside it (### Nits) makes its lines errors instead of silently cutting the findings off.
26
22
  const section = (text: string, name: string, until = /^###?\s/m): string | undefined => {
27
- const match = new RegExp(`^###\\s+${name}\\s*$`, "im").exec(text);
28
- if (match === null) return undefined;
23
+ const wanted = name.toLowerCase();
24
+ const match = [...text.matchAll(/^###\s+(.+?)\s*$/gim)].find(
25
+ (m) => m[1]?.toLowerCase() === wanted,
26
+ );
27
+ if (match === undefined) return undefined;
29
28
  const rest = text.slice(match.index + match[0].length);
30
29
  const next = until.exec(rest);
31
30
  return next === null ? rest : rest.slice(0, next.index);
@@ -94,8 +93,7 @@ export function parseReviewPacket(text: string): ReviewPacket | ParseError {
94
93
  }
95
94
  const lines = findingsText
96
95
  .split("\n")
97
- .filter((l) => !isDetail(l))
98
- .map((l) => l.trim())
96
+ .flatMap((l) => (isDetail(l) ? [] : [l.trim()]))
99
97
  .filter((l) => l !== "" && !/^(?:-\s*)?[([]?(?:none|no findings?)[)\]]?\.?$/i.test(l));
100
98
  for (const [i, line] of lines.entries()) {
101
99
  const finding = parseFinding(line, lenses, i + 1);
@@ -174,7 +174,7 @@ const stagedThenEdited = (
174
174
  // re-staged from the work tree, which was reviewed. Message text is one argument and never equals a path.
175
175
  const named = upto
176
176
  .filter((i) => (i.sub === "commit" || i.sub === "add") && !isDryRun(i) && inThisDir(i, cwd))
177
- .flatMap((i) => i.args.filter((a) => !a.startsWith("-")).map(cleanPath));
177
+ .flatMap((i) => i.args.flatMap((a) => (a.startsWith("-") ? [] : [cleanPath(a)])));
178
178
  const covered = (name: string) => named.some((n) => name === n || name.startsWith(`${n}/`));
179
179
  return names.staged.filter(
180
180
  (name) => names.unstaged.includes(name) && !covered(name) && !DECISION_LOG.test(name),