@mjasnikovs/pi-task 0.40.50 → 0.41.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.
Files changed (123) hide show
  1. package/README.md +7 -4
  2. package/dist/config/config.d.ts +61 -18
  3. package/dist/config/config.js +50 -6
  4. package/dist/config/register.js +18 -5
  5. package/dist/shared/content-tokens.d.ts +16 -0
  6. package/dist/shared/content-tokens.js +137 -0
  7. package/dist/task/accept-debt.d.ts +15 -1
  8. package/dist/task/accept-debt.js +4 -0
  9. package/dist/task/artifact-closure.js +7 -1
  10. package/dist/task/auto-io.d.ts +59 -7
  11. package/dist/task/auto-io.js +140 -47
  12. package/dist/task/auto-orchestrator.d.ts +22 -19
  13. package/dist/task/auto-orchestrator.js +126 -112
  14. package/dist/task/child-runner.d.ts +18 -0
  15. package/dist/task/child-runner.js +7 -8
  16. package/dist/task/command-run.d.ts +4 -0
  17. package/dist/task/command-run.js +4 -2
  18. package/dist/task/constraint-policy.d.ts +52 -0
  19. package/dist/task/constraint-policy.js +66 -0
  20. package/dist/task/context-silence.d.ts +5 -4
  21. package/dist/task/context-silence.js +13 -5
  22. package/dist/task/coverage-loop.d.ts +7 -4
  23. package/dist/task/coverage-loop.js +16 -138
  24. package/dist/task/debug-log.d.ts +25 -2
  25. package/dist/task/debug-log.js +64 -10
  26. package/dist/task/decompose-fidelity.d.ts +17 -4
  27. package/dist/task/decompose-fidelity.js +95 -55
  28. package/dist/task/decompose-granularity.d.ts +7 -7
  29. package/dist/task/decompose-granularity.js +8 -8
  30. package/dist/task/env-notes.d.ts +65 -19
  31. package/dist/task/env-notes.js +152 -50
  32. package/dist/task/external-context.js +25 -5
  33. package/dist/task/fix-context.d.ts +39 -0
  34. package/dist/task/fix-context.js +58 -0
  35. package/dist/task/gate-deps.d.ts +49 -0
  36. package/dist/task/gate-deps.js +199 -38
  37. package/dist/task/gate-evidence.d.ts +51 -0
  38. package/dist/task/gate-evidence.js +90 -0
  39. package/dist/task/gate-resolution.d.ts +119 -0
  40. package/dist/task/gate-resolution.js +120 -0
  41. package/dist/task/git-state-guard.js +3 -26
  42. package/dist/task/handoff.d.ts +35 -0
  43. package/dist/task/handoff.js +100 -0
  44. package/dist/task/health-baseline.d.ts +87 -0
  45. package/dist/task/health-baseline.js +158 -0
  46. package/dist/task/ledger.d.ts +10 -0
  47. package/dist/task/ledger.js +22 -11
  48. package/dist/task/lint-fix.d.ts +11 -0
  49. package/dist/task/lint-fix.js +14 -8
  50. package/dist/task/loop-detector.d.ts +52 -3
  51. package/dist/task/loop-detector.js +81 -5
  52. package/dist/task/mentions.d.ts +17 -0
  53. package/dist/task/mentions.js +86 -0
  54. package/dist/task/orchestrator.d.ts +53 -9
  55. package/dist/task/orchestrator.js +104 -28
  56. package/dist/task/orientation.d.ts +135 -29
  57. package/dist/task/orientation.js +259 -67
  58. package/dist/task/owned-freeze-reassign.d.ts +7 -3
  59. package/dist/task/owned-freeze-reassign.js +13 -5
  60. package/dist/task/parsers.d.ts +6 -1
  61. package/dist/task/parsers.js +21 -4
  62. package/dist/task/phases.d.ts +1 -1
  63. package/dist/task/phases.js +125 -153
  64. package/dist/task/plan-orchestrator.js +5 -6
  65. package/dist/task/plan-rounds.d.ts +1 -0
  66. package/dist/task/plan-rounds.js +8 -1
  67. package/dist/task/prohibition-probe.d.ts +6 -1
  68. package/dist/task/prohibition-probe.js +26 -6
  69. package/dist/task/prompts.js +13 -2
  70. package/dist/task/qa-transcript.d.ts +17 -0
  71. package/dist/task/qa-transcript.js +28 -0
  72. package/dist/task/question-source.d.ts +16 -2
  73. package/dist/task/question-source.js +21 -8
  74. package/dist/task/repo-health-check.d.ts +27 -0
  75. package/dist/task/repo-health-check.js +39 -5
  76. package/dist/task/requirements.d.ts +67 -13
  77. package/dist/task/requirements.js +129 -67
  78. package/dist/task/research-worker.d.ts +43 -2
  79. package/dist/task/research-worker.js +103 -8
  80. package/dist/task/run-bracket.d.ts +9 -4
  81. package/dist/task/run-bracket.js +9 -0
  82. package/dist/task/run-context.d.ts +152 -0
  83. package/dist/task/run-context.js +277 -0
  84. package/dist/task/spec-doc.d.ts +78 -0
  85. package/dist/task/spec-doc.js +205 -0
  86. package/dist/task/spec-model.d.ts +70 -0
  87. package/dist/task/spec-model.js +139 -0
  88. package/dist/task/stall-detector.d.ts +1 -1
  89. package/dist/task/stall-detector.js +9 -5
  90. package/dist/task/state-dir.d.ts +29 -0
  91. package/dist/task/state-dir.js +80 -0
  92. package/dist/task/suppression-probe.d.ts +67 -0
  93. package/dist/task/suppression-probe.js +78 -0
  94. package/dist/task/task-gates.d.ts +39 -57
  95. package/dist/task/task-gates.js +115 -195
  96. package/dist/task/task-io.d.ts +10 -0
  97. package/dist/task/task-io.js +69 -18
  98. package/dist/task/task-parsers.js +6 -6
  99. package/dist/task/task-types.d.ts +7 -0
  100. package/dist/task/timings.d.ts +11 -0
  101. package/dist/task/timings.js +21 -0
  102. package/dist/task/tree-hash.d.ts +8 -0
  103. package/dist/task/tree-hash.js +55 -0
  104. package/dist/task/verify-reconcile.d.ts +4 -3
  105. package/dist/task/verify-reconcile.js +7 -8
  106. package/dist/task/verify-resolution.d.ts +28 -5
  107. package/dist/task/verify-resolution.js +70 -13
  108. package/dist/task/verify-work.d.ts +98 -35
  109. package/dist/task/verify-work.js +227 -60
  110. package/dist/task/yolo.d.ts +0 -13
  111. package/dist/task/yolo.js +9 -21
  112. package/dist/workers/pi-worker-core.d.ts +20 -0
  113. package/dist/workers/pi-worker-core.js +16 -11
  114. package/dist/workers/pi-worker-docs.d.ts +6 -5
  115. package/dist/workers/pi-worker-docs.js +8 -7
  116. package/dist/workers/pi-worker-fetch.d.ts +3 -2
  117. package/dist/workers/pi-worker-fetch.js +5 -4
  118. package/dist/workers/pi-worker-search.js +5 -4
  119. package/dist/workers/research-cache.d.ts +23 -1
  120. package/dist/workers/research-cache.js +63 -3
  121. package/dist/workers/shared.d.ts +18 -0
  122. package/dist/workers/shared.js +38 -22
  123. package/package.json +1 -1
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The shipped rows. Each `re` is a LINE test, so a pattern that appears inside a
3
+ * string literal or a comment still counts — the point is the suppression's
4
+ * presence in the shipped file, and deciding what is "really" a suppression would
5
+ * need a parser per language to answer worse.
6
+ */
7
+ export const SUPPRESSION_PATTERNS = [
8
+ { id: '@ts-expect-error', re: /@ts-expect-error/, ecosystems: ['npm'] },
9
+ { id: '@ts-ignore', re: /@ts-ignore/, ecosystems: ['npm'] },
10
+ { id: 'eslint-disable', re: /eslint-disable/, ecosystems: ['npm'] },
11
+ { id: 'as unknown as', re: /\bas\s+unknown\s+as\b/, ecosystems: ['npm'] },
12
+ { id: '#[allow(', re: /#\[allow\(/, ecosystems: ['cargo'] },
13
+ { id: '# noqa', re: /#\s*noqa\b/i },
14
+ { id: '# type: ignore', re: /#\s*type:\s*ignore\b/ },
15
+ { id: '//nolint', re: /\/\/\s*nolint\b/, ecosystems: ['go'] },
16
+ { id: '@SuppressWarnings', re: /@SuppressWarnings\b/ },
17
+ { id: '#pragma warning disable', re: /#pragma\s+warning\s+disable\b/ }
18
+ ];
19
+ /**
20
+ * Compile the extra patterns a project configures. An unparseable source is
21
+ * dropped rather than thrown: a hand-edited config may not break the gate, and a
22
+ * pattern nobody can compile finds nothing either way.
23
+ */
24
+ export function compileSuppressionPatterns(sources) {
25
+ const out = [];
26
+ for (const source of sources) {
27
+ try {
28
+ out.push({ id: source, re: new RegExp(source) });
29
+ }
30
+ catch {
31
+ // an invalid regex is a config defect, not a gate failure
32
+ }
33
+ }
34
+ return out;
35
+ }
36
+ /** The rows in force for a project: the shipped ones its ecosystems claim, plus
37
+ * every configured one (a user pattern is never ecosystem-gated — they wrote it
38
+ * for this repo). */
39
+ export function suppressionPatternsFor(ecosystems, extra = []) {
40
+ const shipped = SUPPRESSION_PATTERNS.filter(p => !p.ecosystems
41
+ || ecosystems.length === 0
42
+ || p.ecosystems.some(e => ecosystems.includes(e)));
43
+ return [...shipped, ...extra];
44
+ }
45
+ /**
46
+ * Net-new suppressions per file and pattern, in a stable order (file, then
47
+ * registry order) so two runs over the same diff produce the same findings.
48
+ */
49
+ export function findSuppressionWidening(lines, patterns = SUPPRESSION_PATTERNS) {
50
+ // Keyed by path then pattern rather than by a joined string: any separator
51
+ // would have to be a character no path can contain, and `\0` — the honest
52
+ // choice — is a byte prettier rewrites and plain grep cannot see.
53
+ const byPath = new Map();
54
+ const hits = [];
55
+ for (const line of lines) {
56
+ for (const pattern of patterns) {
57
+ if (!pattern.re.test(line.text))
58
+ continue;
59
+ let byPattern = byPath.get(line.path);
60
+ if (!byPattern) {
61
+ byPattern = new Map();
62
+ byPath.set(line.path, byPattern);
63
+ }
64
+ let hit = byPattern.get(pattern.id);
65
+ if (!hit) {
66
+ hit = { path: line.path, patternId: pattern.id, net: 0 };
67
+ byPattern.set(pattern.id, hit);
68
+ hits.push(hit);
69
+ }
70
+ hit.net += line.added ? 1 : -1;
71
+ }
72
+ }
73
+ return hits.filter(h => h.net > 0).sort((a, b) => a.path.localeCompare(b.path));
74
+ }
75
+ /** The verify prompt's finding lines for the suppression-widening row. */
76
+ export function suppressionVerifyFindings(hits) {
77
+ return hits.map(h => `${h.path} — ${h.net} net-new \`${h.patternId}\` line${h.net === 1 ? '' : 's'} added by this task`);
78
+ }
@@ -6,11 +6,11 @@
6
6
  * just-finished work:
7
7
  *
8
8
  * 1. VERIFY — RUN the composed spec's VERIFY block in the real workspace and
9
- * judge a PASS/FAIL. On a FAIL a fresh read-only child recommends AUTOFIX or
10
- * ACCEPT: an AUTOFIX recommendation re-runs the implementation turn UNATTENDED
11
- * (no prompt) and loops back to the gate, bounded by MAX_AUTO_AUTOFIX; the user
12
- * is shown the boxed picker only when the recommendation is ACCEPT (blessing the
13
- * artifact as-is) or when that unattended-autofix cap is reached.
9
+ * judge a PASS/FAIL. A FAIL goes to gate-resolution.ts's decision table,
10
+ * which returns one of three actions: re-run the implementation turn
11
+ * UNATTENDED and loop back, accept the artifact and write the defect to the
12
+ * debt ledger, or show the user the boxed picker. This module owns none of
13
+ * that policy it only carries the actions out.
14
14
  * 2. ENFORCE — hold the committed work to the project's AGENTS.md / CLAUDE.md
15
15
  * rules. Runs in `edit` mode (fix in place) only when the verify gate produced
16
16
  * a genuine clean pass to guard the edits against; otherwise `flag` mode
@@ -34,8 +34,11 @@ import type { CommitResult } from './auto-commit.js';
34
34
  import { type VerifyOutcome } from './verify-work.js';
35
35
  import type { EnforceOutcome } from './enforce-guidelines.js';
36
36
  import { type ResolutionOutcome, type ResolutionChoice } from './verify-resolution.js';
37
+ import { type HealthBaseline, type HealthSignal } from './health-baseline.js';
38
+ import type { LintFixResult } from './lint-fix.js';
37
39
  import { type RepairCandidate } from './root-cause-repair.js';
38
40
  import { type DebtOrigin } from './accept-debt.js';
41
+ import type { FixContext } from './fix-context.js';
39
42
  /**
40
43
  * The deps the gate sequence drives. A superset of these is built once per command
41
44
  * by buildGateDeps; AutoDeps extends this with the planning-only `runChild`. Every
@@ -53,7 +56,9 @@ export interface GateDeps {
53
56
  resumeId?: string;
54
57
  onStart?: (taskId: string) => void | Promise<void>;
55
58
  planContext?: string;
56
- fixInstruction?: string;
59
+ planKey?: string;
60
+ fixContext?: FixContext;
61
+ healthBaseline?: (ctx: ExtensionCommandContext) => Promise<HealthBaseline | null>;
57
62
  }) => Promise<RunSingleTaskResult>;
58
63
  /** Snapshot the working tree into one commit after a task passes. */
59
64
  commit: (cwd: string, message: string) => Promise<CommitResult>;
@@ -80,9 +85,10 @@ export interface GateDeps {
80
85
  */
81
86
  enforce?: (ctx: ExtensionCommandContext, cwd: string, taskTitle: string, mode: 'edit' | 'flag') => Promise<EnforceOutcome>;
82
87
  /**
83
- * After a verify FAIL, research whether to recommend AUTOFIX or ACCEPT — only
84
- * sets which card the picker tints RECOMMENDED; the user always decides. Absent
85
- * the picker defaults the recommendation to AUTOFIX.
88
+ * After a verify FAIL, research whether the work is genuinely wrong (AUTOFIX),
89
+ * good as-is (ACCEPT), or blocked by a contradiction in its own spec. One input
90
+ * to the decision table, which alone decides what happens next. Absent → the
91
+ * table sees the conservative AUTOFIX default.
86
92
  */
87
93
  recommend?: (ctx: ExtensionCommandContext, cwd: string, taskTitle: string, taskId: string, failReason: string) => Promise<ResolutionOutcome>;
88
94
  /**
@@ -96,13 +102,11 @@ export interface GateDeps {
96
102
  * exactly the static findings (revert-guarded — see lint-fix.ts), instead of the
97
103
  * full implementation re-run AUTOFIX reaches for. Smallest tool first: a static
98
104
  * finding does not need the whole turn re-run to fix it. Runs at most once per
99
- * gate sequence; not-applied falls through to the picker. Absent → the loop goes
100
- * straight to recommend/picker.
105
+ * gate sequence; a `frozen-path` result mints the SpecContradiction that ends
106
+ * the loop, anything else falls through to the decision table unchanged. Absent
107
+ * → the loop goes straight to the judge and the table.
101
108
  */
102
- lintFix?: (ctx: ExtensionCommandContext, cwd: string, taskTitle: string, taskId: string, failReason: string) => Promise<{
103
- ok: boolean;
104
- reason?: string;
105
- }>;
109
+ lintFix?: (ctx: ExtensionCommandContext, cwd: string, taskTitle: string, taskId: string, failReason: string) => Promise<LintFixResult>;
106
110
  /**
107
111
  * Deterministic whole-repo static check (repo-health), used as the PRE-COMMIT
108
112
  * gate on an edit-mode enforce pass: an enforce edit that breaks the project's
@@ -118,7 +122,16 @@ export interface GateDeps {
118
122
  ok: boolean;
119
123
  reason: string;
120
124
  output?: string;
121
- }>;
125
+ } & HealthSignal>;
126
+ /**
127
+ * Record what the same static checks say about the tree RIGHT NOW, as the
128
+ * baseline a later verify differential attributes against (health-baseline.ts).
129
+ * Called where the tree is committed and the task has not started — the
130
+ * `/task-auto` pre-task checkpoint, and `/task`'s own start. Null when the
131
+ * capture could not run; absent in tests → no baseline is written and the
132
+ * verify gate establishes one lazily.
133
+ */
134
+ captureHealthBaseline?: (ctx: ExtensionCommandContext, cwd: string, label: string) => Promise<HealthBaseline | null>;
122
135
  /** Does the working tree hold changes (excluding .pi-tasks)? Lets the pre-commit
123
136
  * health check run only when the enforce pass actually edited something. */
124
137
  dirty?: (cwd: string) => Promise<boolean>;
@@ -140,12 +153,13 @@ export interface GateDeps {
140
153
  * see accept-debt.ts), stamped with the DebtOrigin that says how it was reached.
141
154
  * The final integration gate re-checks every recorded debt at run end and surfaces
142
155
  * the ones still open, so a defect the gate found is never lost by whatever the
143
- * loop then did with the WORK — accepted by a human ('accepted'), auto-picked
144
- * unattended by yolo mode ('yolo-accepted'), reverted with the enforce commit
145
- * ('enforce-revert'), kept because the enforce diff could not have caused it
146
- * ('enforce-kept'), blocked by a spec-frozen path ('frozen-blocked'), a sibling's
147
- * deliverable deleted and accepted ('cross-task-deletion'), or another task's
148
- * pre-existing bug this one merely tripped over ('root-cause').
156
+ * loop then did with the WORK — accepted by a human ('accepted'), dismissed at
157
+ * the picker ('dismissed'), accepted unattended by yolo mode ('yolo-accepted'),
158
+ * reverted with the enforce commit ('enforce-revert'), kept because the enforce
159
+ * diff could not have caused it ('enforce-kept'), unreachable under the task's
160
+ * own spec ('spec-contradiction'), a sibling's deliverable deleted and accepted
161
+ * ('cross-task-deletion'), or another task's pre-existing bug this one merely
162
+ * tripped over ('root-cause').
149
163
  *
150
164
  * The ORIGIN is load-bearing, not a label: the final gate reports by class, and
151
165
  * an unattended auto-pick may never be recorded as the 'accepted' class, which
@@ -261,38 +275,6 @@ export type GateResult = {
261
275
  ctx: ExtensionCommandContext;
262
276
  reason?: string;
263
277
  };
264
- /**
265
- * How many times a verify FAIL may be auto-fixed UNATTENDED (the research
266
- * recommended AUTOFIX, so pi re-runs the impl turn without prompting) before the
267
- * loop falls back to the human picker. Each AUTOFIX is a full implementation
268
- * re-run, so a non-converging loop must not run forever with nobody able to break
269
- * it — after this many consecutive auto attempts that still FAIL, the picker is
270
- * shown so a person can decide. A recommendation to ACCEPT always shows the picker
271
- * regardless of this count (blessing an artifact as-is is a human's call).
272
- */
273
- export declare const MAX_AUTO_AUTOFIX = 3;
274
- /** Which of the four disjoint branches sent a FAIL to the terminal YOLO ACCEPT. */
275
- export interface YoloAcceptContext {
276
- /** Rule 5c: the spec-required check could not run (tooling absent). */
277
- isUnobserved: boolean;
278
- /** Cross-task contradiction: the repo-health fix needs a spec-frozen path. */
279
- isFrozenBlocked: boolean;
280
- /** What the resolution research recommended, when it was consulted at all. */
281
- recommend: ResolutionOutcome['recommend'];
282
- /** Unattended AUTOFIX attempts already spent on this task. */
283
- autoFixCount: number;
284
- }
285
- /**
286
- * The reason an auto-ACCEPT is being written — NAMED, not assumed.
287
- *
288
- * Four disjoint branches reach the terminal auto-ACCEPT, and only ONE of them has
289
- * spent the autofix budget. An UNOBSERVED FAIL never consults the research; a
290
- * frozen-blocked one is a contradiction no re-run can resolve; an ACCEPT
291
- * recommendation can arrive with the budget untouched. A single "autofix budget
292
- * spent" line would be false on three of the four, and a durable trail that
293
- * misstates why a defect shipped reads as an exhausted fixer that never tried.
294
- */
295
- export declare function yoloAcceptReason(c: YoloAcceptContext): string;
296
278
  /**
297
279
  * Show the boxed two-choice picker after a verify FAIL and return what the user
298
280
  * decided. The model-recommended card is placed first so the renderer tints it
@@ -340,9 +322,9 @@ type VerifyGateStep = {
340
322
  };
341
323
  /**
342
324
  * The VERIFY resolution loop: run the task's verification against the finished
343
- * work, and negotiate a FAIL through the graduated ladder (bounded lint fix
344
- * recommendation unattended autofix picker) until it verifies, is accepted,
345
- * or terminates.
325
+ * work, and carry out what gate-resolution.ts's decision table says to do with a
326
+ * FAIL (bounded lint fix first, then the table's autofix / accept / ask) until it
327
+ * verifies, is accepted, or terminates.
346
328
  *
347
329
  * Split from `runGatesForTask` at the single boolean that crosses to the ENFORCE
348
330
  * half (`cleanPass`). This loop has four terminal exits and carries the whole