@mjasnikovs/pi-task 0.42.6 → 0.42.7

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.
@@ -24,14 +24,19 @@ const FAILURE = /\b(?:fail\w*|red|broken|breaks?|breakage|errors?)\b/i;
24
24
  /** Before a phrase in its clause: the phrase is rejected. */
25
25
  const NOT_A_DECISION = /\b(?:not|never|no|don't|do not|doesn't|does not|rather than|instead of|isn't|is not|without|avoid|avoiding)\b/i;
26
26
  /**
27
- * A modal cancels a phrase only where the condition's own half of the sentence
28
- * poses an option for it to weigh: "IF NOT EXISTS would still leave the test
29
- * failing" describes what a rejected option does. A bare hedge does not — "I
30
- * would flag it as a known issue" is the decision, and treating every modal as
31
- * hypothetical let the guard be rephrased away.
27
+ * A modal cancels a phrase only where the sentence poses an option for it to
28
+ * weigh: "IF NOT EXISTS would still leave the test failing" describes what a
29
+ * rejected option does. A bare hedge does not — "I would flag it as a known
30
+ * issue" is the decision, and treating every modal as hypothetical let the guard
31
+ * be rephrased away.
32
32
  */
33
33
  const MODAL = /\b(?:would|could|might)\b/i;
34
- const HYPOTHETICAL = /\b(?:if|unless|either|whether|option|alternative|otherwise)\b/i;
34
+ /** A condition governs its own half of a semicolon and reaches no further. */
35
+ const CONDITION = /\b(?:if|unless)\b/i;
36
+ /** Options are posed once and weighed in any later clause of the sentence. */
37
+ const OPTION = /\b(?:either|whether|option|alternative|otherwise)\b/i;
38
+ /** Whatever the sentence weighs, "I would …" is the answer's own decision. */
39
+ const FIRST_PERSON = /\b(?:i|we)\s+(?:would|could|might)\b/i;
35
40
  /** Where one clause ends and the next begins. A semicolon joins clauses of ONE
36
41
  * thought, so the breakage a clause defers may sit in the other half. */
37
42
  const CLAUSE_BOUNDARY = /[,:;()]|\s[—–-]\s|\b(?:and|but|so|then|while|whereas|although|though|because|since|however)\b/gi;
@@ -54,10 +59,11 @@ const PHRASES = [
54
59
  // Handing the work to an unnamed someone is the deferral itself, whatever the
55
60
  // clause is about; bare `whoever` below still needs a check to be one.
56
61
  { re: /\bwhoever\s+(?:owns|revisits|maintains|touches)\b/i, needs: 'alone' },
57
- // Ownership handed to a ROLE is handed to nobody. Handed to a named team it is
58
- // handed to someone, so it counts only where the clause is about a check.
62
+ // Ownership handed to a ROLE is handed to nobody: no release manager exists in
63
+ // a /task-auto run. A named team is someone, so the lookahead hands those to
64
+ // the `check` rule below rather than listing every job title here.
59
65
  {
60
- re: /\bownership\s+(?:belongs|lies|rests)\s+(?:to|with)\s+(?:whoever|someone|somebody|another\b|a\s+later\b|the\s+(?:\w+\s+)?(?:owners?|maintainers?)\b)/i,
66
+ re: /\bownership\s+(?:belongs|lies|rests)\s+(?:to|with)\b(?!.*\b(?:teams?|groups?|squads?|guilds?|crews?)\b)/i,
61
67
  needs: 'alone'
62
68
  },
63
69
  { re: /\bownership\s+(?:belongs|lies|rests)\s+(?:to|with)\b/i, needs: 'check' },
@@ -100,11 +106,12 @@ function clauses(sentence) {
100
106
  export function defersBreakage(answer) {
101
107
  for (const sentence of prose(answer).split(SENTENCE_BOUNDARY)) {
102
108
  const sentenceBreaks = aboutACheck(sentence) && FAILURE.test(sentence);
103
- // A condition governs its own half of a semicolon. It joins two independent
104
- // clauses, so "the test fails only if X; I would flag it as known" states a
105
- // condition and then decides the decision is not one of X's options.
109
+ const posesOptions = OPTION.test(sentence);
110
+ // A semicolon joins two independent clauses, so "the test fails only if X;
111
+ // it could be flagged as known" states a condition and then decides. The
112
+ // options the sentence posed reach across it; the condition does not.
106
113
  for (const half of sentence.split(';')) {
107
- const weighsOptions = HYPOTHETICAL.test(half);
114
+ const weighsOptions = posesOptions || CONDITION.test(half);
108
115
  for (const clause of clauses(half)) {
109
116
  for (const { re, needs } of PHRASES) {
110
117
  const hit = re.exec(clause);
@@ -113,7 +120,7 @@ export function defersBreakage(answer) {
113
120
  const before = clause.slice(0, hit.index);
114
121
  if (NOT_A_DECISION.test(before))
115
122
  continue;
116
- if (MODAL.test(before) && weighsOptions)
123
+ if (MODAL.test(before) && weighsOptions && !FIRST_PERSON.test(before))
117
124
  continue;
118
125
  if (needs === 'check' && !aboutACheck(clause))
119
126
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mjasnikovs/pi-task",
3
- "version": "0.42.6",
3
+ "version": "0.42.7",
4
4
  "description": "Deterministic task planning and spec-orchestration for local models — crash-safe /task pipelines with verify/enforce gates, a real-time remote web view, and web/docs/fetch/worker subagent tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",