gentle-pi 2.2.0 → 2.4.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 (160) hide show
  1. package/README.md +76 -79
  2. package/assets/agents/review-readability.md +0 -2
  3. package/assets/agents/review-reliability.md +0 -2
  4. package/assets/agents/review-resilience.md +0 -2
  5. package/assets/agents/review-risk.md +0 -2
  6. package/assets/agents/sdd-apply.md +5 -3
  7. package/assets/agents/sdd-explore.md +1 -0
  8. package/assets/agents/sdd-proposal.md +2 -0
  9. package/assets/agents/sdd-research.md +54 -0
  10. package/assets/agents/sdd-status.md +4 -4
  11. package/assets/agents/sdd-tasks.md +2 -3
  12. package/assets/agents/sdd-verify.md +21 -1
  13. package/assets/chains/sdd-full.chain.md +1 -1
  14. package/assets/chains/sdd-verify.chain.md +1 -1
  15. package/assets/orchestrator-delegation.md +56 -249
  16. package/assets/orchestrator-memory.md +2 -0
  17. package/assets/orchestrator.md +20 -40
  18. package/assets/sdd-orchestrator-workflow.md +30 -37
  19. package/assets/support/sdd-status-contract.md +7 -7
  20. package/contracts/review-integration/v1/schemas/transition-execution.schema.json +42 -0
  21. package/contracts/review-integration/v2/schemas/last-event-closure.schema.json +66 -0
  22. package/contracts/review-integration/v2/schemas/opencode-provider-role.schema.json +14 -0
  23. package/contracts/review-provider-contract-mirror/provider-contract.lock.json +8 -7
  24. package/contracts/review-provider-contract-mirror/{v1.1.0 → v1.2.0}/bundle/README.md +10 -0
  25. package/contracts/review-provider-contract-mirror/v1.2.0/bundle/manifest.json +74 -0
  26. package/contracts/review-provider-contract-mirror/v1.2.0/bundle/orchestration/pi.md +53 -0
  27. package/contracts/review-provider-contract-mirror/v1.2.0/bundle/schemas/targeted-validator.schema.json +1 -0
  28. package/contracts/review-provider-contract-mirror/{v1.1.0 → v1.2.0}/generated/provider-capabilities.baseline.json +9 -2
  29. package/contracts/review-provider-contract-mirror/{v1.1.0 → v1.2.0}/generated/provider-roles.baseline.json +2 -2
  30. package/docs/native-authority-architecture.md +9 -11
  31. package/docs/review-integration.md +27 -373
  32. package/extensions/ask-user-choice.ts +151 -0
  33. package/extensions/gentle-ai.ts +2349 -3785
  34. package/extensions/quiet-tools.ts +515 -32
  35. package/extensions/sdd-init.ts +4 -8
  36. package/lib/agent-home.ts +8 -0
  37. package/lib/gentle-ai-renderer.ts +70 -0
  38. package/lib/model-routing-authority.ts +133 -0
  39. package/lib/native-review-cli.ts +387 -940
  40. package/lib/opaque-pi-reviewer-adapter.ts +284 -0
  41. package/lib/provider-contract-bundle.ts +88 -6
  42. package/lib/review-candidate-view.ts +341 -132
  43. package/lib/review-host-relay.ts +324 -96
  44. package/lib/review-integration-v2.ts +868 -307
  45. package/lib/review-last-event-controller.ts +35 -0
  46. package/lib/sdd-preflight.ts +179 -68
  47. package/lib/sdd-status.ts +66 -111
  48. package/lib/terminal-theme.ts +1 -1
  49. package/package.json +83 -82
  50. package/runtime/gentle-ai-binary.mjs +1 -1
  51. package/runtime/native-review-cli.mjs +337 -890
  52. package/runtime/review-integration-v2.mjs +816 -255
  53. package/runtime/review-relay-contract.mjs +1 -1
  54. package/scripts/{build-git-commit-transaction-runner.mjs → build-runtime-modules.mjs} +4 -5
  55. package/scripts/gentle-ai-installer.mjs +75 -22
  56. package/scripts/maintainer/provider-relay-matrix.mjs +195 -11
  57. package/scripts/test-packed-runner.mjs +4 -7
  58. package/scripts/verify-package-files.mjs +23 -23
  59. package/skills/_shared/review-ledger-contract.md +14 -14
  60. package/skills/chained-pr/SKILL.md +3 -0
  61. package/skills/cognitive-doc-design/SKILL.md +1 -1
  62. package/skills/comment-writer/SKILL.md +1 -1
  63. package/skills/gentle-ai/SKILL.md +7 -74
  64. package/skills/issue-creation/SKILL.md +53 -93
  65. package/skills/judgment-day/SKILL.md +5 -7
  66. package/skills/rdd-defect-workflow/SKILL.md +3 -3
  67. package/skills/release/SKILL.md +3 -3
  68. package/skills/skill-registry/SKILL.md +1 -1
  69. package/skills/work-unit-commits/SKILL.md +3 -1
  70. package/tests/artifact-language.test.ts +24 -11
  71. package/tests/ask-user-choice.test.ts +264 -0
  72. package/tests/codegraph-tools.test.ts +3 -3
  73. package/tests/crosslane/cross-lane.mjs +15 -1168
  74. package/tests/delegated-key-learnings-contract.test.ts +8 -6
  75. package/tests/devbinary/native-review-parity.devtest.ts +167 -250
  76. package/tests/devbinary/pi-host-relay.devtest.ts +867 -0
  77. package/tests/fixtures/devbinary/last-event-capture-correction-plan.captured.json +10 -0
  78. package/tests/fixtures/devbinary/last-event-capture-refuter-approved.captured.json +20 -0
  79. package/tests/fixtures/devbinary/last-event-capture-refuter-correction-required.captured.json +26 -0
  80. package/tests/fixtures/devbinary/last-event-capture-result-approved.captured.json +8 -0
  81. package/tests/fixtures/devbinary/last-event-capture-result-correction-required.captured.json +26 -0
  82. package/tests/fixtures/devbinary/last-event-capture-validation-approved.captured.json +8 -0
  83. package/tests/fixtures/devbinary/last-event-closure.provenance.md +13 -0
  84. package/tests/fixtures/devbinary/review-acknowledged-v1.captured.json +9 -0
  85. package/tests/fixtures/devbinary/review-acknowledged.provenance.md +31 -0
  86. package/tests/fixtures/devbinary/start-v3-zero-lens-closed.captured.json +21 -0
  87. package/tests/fixtures/native-review-cli/v2.5.0-rc.1/PROVENANCE.txt +15 -0
  88. package/tests/fixtures/provider-contract-bundle/v1.2.0/README.md +22 -0
  89. package/{contracts/review-provider-contract-mirror/v1.1.0/bundle → tests/fixtures/provider-contract-bundle/v1.2.0}/manifest.json +11 -2
  90. package/tests/fixtures/provider-contract-bundle/v1.2.0/orchestration/pi.md +97 -0
  91. package/tests/fixtures/provider-contract-bundle/v1.2.0/schemas/lens.schema.json +16 -0
  92. package/tests/fixtures/provider-contract-bundle/v1.2.0/schemas/refuter.schema.json +1 -0
  93. package/tests/fixtures/provider-contract-bundle/v1.2.0/vectors/lens.json +1 -0
  94. package/tests/fixtures/provider-contract-bundle/v1.2.0/vectors/refuter.json +1 -0
  95. package/tests/fixtures/provider-contract-bundle/v1.2.0/vectors/targeted-validator.json +1 -0
  96. package/tests/gentle-ai-binary.test.ts +83 -13
  97. package/tests/gentle-ai-dev-binary.test.ts +51 -228
  98. package/tests/gentle-ai-installer.test.ts +137 -47
  99. package/tests/gentle-ai.test.ts +821 -131
  100. package/tests/gentle-theme.test.ts +133 -0
  101. package/tests/issue-creation-skill.test.ts +103 -0
  102. package/tests/maintainer/provider-relay.maintest.ts +340 -4
  103. package/tests/model-routing-authority.test.ts +257 -0
  104. package/tests/native-review-capability-contract.test.ts +45 -1
  105. package/tests/native-review-cli.test.ts +586 -962
  106. package/tests/native-review-consent.test.ts +150 -66
  107. package/tests/native-review-parity-runtime.test.ts +80 -359
  108. package/tests/native-review-parity.test.ts +674 -925
  109. package/tests/opaque-pi-reviewer-adapter.test.ts +266 -0
  110. package/tests/orchestrator-budget.test.ts +132 -88
  111. package/tests/orchestrator-rdd-ownership.test.ts +103 -0
  112. package/tests/package-manifest.test.ts +152 -36
  113. package/tests/provider-contract-bundle.test.ts +76 -0
  114. package/tests/provider-contract-mirror.test.ts +19 -0
  115. package/tests/provider-defect-handoff.test.ts +15 -118
  116. package/tests/quiet-tool-rendering.test.ts +1055 -28
  117. package/tests/review-agent-end-preflight.test.ts +408 -0
  118. package/tests/review-authority-recovery-docs.test.ts +1 -2
  119. package/tests/review-candidate-view.test.ts +409 -3
  120. package/tests/review-compact-contract.test.ts +4 -30
  121. package/tests/review-contract-prompt.test.ts +139 -0
  122. package/tests/review-controller-lock-status.test.ts +2 -2
  123. package/tests/review-controller-native-recovery.test.ts +363 -1450
  124. package/tests/review-controller-native-routing.test.ts +1251 -5642
  125. package/tests/review-controller-retired-ops.test.ts +1 -1
  126. package/tests/review-controller-workspace-root.test.ts +222 -71
  127. package/tests/review-controller.test.ts +26 -816
  128. package/tests/review-corrected-finalize-binding.test.ts +112 -153
  129. package/tests/review-dispatch-hydration-gap.test.ts +1 -53
  130. package/tests/review-gate.test.ts +0 -45
  131. package/tests/review-host-relay-restart-parity.test.ts +360 -0
  132. package/tests/review-host-relay-routing.test.ts +328 -91
  133. package/tests/review-host-relay.test.ts +436 -14
  134. package/tests/review-integration-v2-forward.test.ts +623 -553
  135. package/tests/review-integration-v2.test.ts +239 -165
  136. package/tests/review-last-event-closure.test.ts +408 -0
  137. package/tests/review-ledger-contract.test.ts +97 -35
  138. package/tests/review-recovered-lineage-routing.test.ts +0 -47
  139. package/tests/review-relay-transport-agent.test.ts +119 -46
  140. package/tests/review-snapshot.test.ts +3 -2
  141. package/tests/runtime-harness.mjs +362 -196
  142. package/tests/sdd-agent-tools.test.ts +36 -0
  143. package/tests/sdd-preflight.test.ts +81 -15
  144. package/tests/sdd-status.test.ts +109 -110
  145. package/tests/skill-collision-prefixes.test.ts +5 -8
  146. package/tests/writer-edit-surface-scope.test.ts +366 -0
  147. package/themes/Gentleman-Cute.json +94 -0
  148. package/themes/Gentleman-Sexy.json +92 -0
  149. package/lib/git-commit-transaction.ts +0 -861
  150. package/runtime/git-commit-transaction.mjs +0 -862
  151. package/scripts/run-git-commit-transaction.mjs +0 -35
  152. package/tests/fixtures/native-review-cli/v2.1.3/sdd-status-engram.json +0 -139
  153. package/tests/fixtures/native-review-cli/v2.1.3/sdd-status.json +0 -200
  154. package/tests/git-commit-transaction.test.ts +0 -530
  155. /package/contracts/review-provider-contract-mirror/{v1.1.0 → v1.2.0}/bundle/schemas/lens.schema.json +0 -0
  156. /package/contracts/review-provider-contract-mirror/{v1.1.0 → v1.2.0}/bundle/schemas/refuter.schema.json +0 -0
  157. /package/contracts/review-provider-contract-mirror/{v1.1.0 → v1.2.0}/bundle/vectors/lens.json +0 -0
  158. /package/contracts/review-provider-contract-mirror/{v1.1.0 → v1.2.0}/bundle/vectors/refuter.json +0 -0
  159. /package/contracts/review-provider-contract-mirror/{v1.1.0 → v1.2.0}/bundle/vectors/targeted-validator.json +0 -0
  160. /package/{contracts/review-provider-contract-mirror/v1.1.0/bundle → tests/fixtures/provider-contract-bundle/v1.2.0}/schemas/targeted-validator.schema.json +0 -0
package/lib/sdd-status.ts CHANGED
@@ -6,7 +6,10 @@ import {
6
6
  type DomainCollision,
7
7
  } from "./openspec-guardrails.ts";
8
8
 
9
- export type SddArtifactStore = "openspec" | "engram" | "both" | "none";
9
+ // Canonical names match gentle-ai, which owns this contract. The dual-store
10
+ // mode was called "both" here; "hybrid" is the provider's name for the same
11
+ // thing, and normalizeSddArtifactStore keeps already-persisted "both" loading.
12
+ export type SddArtifactStore = "openspec" | "engram" | "hybrid" | "none";
10
13
  export type ArtifactState = "missing" | "done" | "partial";
11
14
  export type DependencyState = "blocked" | "ready" | "all_done" | "not_applicable";
12
15
  export type ApplyState = "blocked" | "ready" | "all_done" | "not_applicable";
@@ -98,6 +101,12 @@ export interface SddStatus {
98
101
  relationships: SddRelationships;
99
102
  collisions: SddDomainCollisionReport[];
100
103
  legacyFlatSpec?: { path: string; hasDomainSpecs: boolean };
104
+ /**
105
+ * Positive terminal projection: the change was archived. `path` is the
106
+ * repo-relative archive folder (openspec/changes/archive/YYYY-MM-DD-<change>).
107
+ * When set, `nextRecommended` is "archived" and no further phase is recommended.
108
+ */
109
+ archived?: { path: string };
101
110
  nextRecommended: string;
102
111
  instructions?: SddPhaseInstructions;
103
112
  blockedReasons: string[];
@@ -111,36 +120,12 @@ export interface SddStatus {
111
120
  isNonAuthoritative: boolean;
112
121
  }
113
122
 
114
- export interface ValidatedReviewAuthorityResolution {
115
- activeAuthorityId: string;
116
- }
117
-
118
- /**
119
- * Optional controller-owned recovery overlay. Status never infers authority from
120
- * OpenSpec artifacts: callers opt in only when a repository review binding exists.
121
- */
122
- export interface SddReviewAuthorityOverlay {
123
- expected: boolean;
124
- resolve: () => ValidatedReviewAuthorityResolution | undefined;
125
- }
126
-
127
- /** Read-only native bound-change evidence supplied by the controller. */
128
- export interface NativeReviewReadinessOverlay {
129
- expected: boolean;
130
- ready: boolean;
131
- lineageId?: string;
132
- bindingRevision?: string;
133
- reason?: string;
134
- }
135
-
136
123
  export interface ResolveSddStatusOptions {
137
124
  cwd: string;
138
125
  changeName?: string;
139
126
  includeInstructions?: boolean;
140
127
  workspaceRoot?: string;
141
128
  artifactStore?: SddArtifactStore;
142
- reviewAuthority?: SddReviewAuthorityOverlay;
143
- nativeReviewReadiness?: NativeReviewReadinessOverlay;
144
129
  }
145
130
 
146
131
  const EMPTY_PATHS: SddArtifactPaths = {
@@ -273,43 +258,7 @@ function reportIsClearlyPassing(path: string | undefined): boolean {
273
258
  return hasPassSignal && !hasBlocker;
274
259
  }
275
260
 
276
- function withRecoveryBlock(status: SddStatus, reviewAuthority?: SddReviewAuthorityOverlay, nativeReviewReadiness?: NativeReviewReadinessOverlay): SddStatus {
277
- if (nativeReviewReadiness?.expected && !nativeReviewReadiness.ready) {
278
- const reason = `resolve-review: ${nativeReviewReadiness.reason ?? "native bound review readiness is unavailable."}`;
279
- return {
280
- ...status,
281
- applyState: "blocked",
282
- dependencies: { apply: "blocked", verify: "blocked", sync: "blocked", archive: "blocked" },
283
- nextRecommended: "resolve-review",
284
- blockedReasons: status.blockedReasons.includes(reason) ? status.blockedReasons : [...status.blockedReasons, reason],
285
- };
286
- }
287
- if (!reviewAuthority?.expected) return status;
288
- try {
289
- const resolved = reviewAuthority.resolve();
290
- if (resolved?.activeAuthorityId) return status;
291
- } catch (error) {
292
- const message = error instanceof Error ? error.message : String(error);
293
- const reason = `resolve-review: ${message}`;
294
- return {
295
- ...status,
296
- applyState: "blocked",
297
- dependencies: { apply: "blocked", verify: "blocked", sync: "blocked", archive: "blocked" },
298
- nextRecommended: "resolve-review",
299
- blockedReasons: status.blockedReasons.includes(reason) ? status.blockedReasons : [...status.blockedReasons, reason],
300
- };
301
- }
302
- const reason = "resolve-review: validated active review authority is missing.";
303
- return {
304
- ...status,
305
- applyState: "blocked",
306
- dependencies: { apply: "blocked", verify: "blocked", sync: "blocked", archive: "blocked" },
307
- nextRecommended: "resolve-review",
308
- blockedReasons: status.blockedReasons.includes(reason) ? status.blockedReasons : [...status.blockedReasons, reason],
309
- };
310
- }
311
-
312
- function emptyStatus(cwd: string, changeName: string | null, blockedReasons: string[], artifactStore: SddArtifactStore = "openspec", isNonAuthoritative = false, reviewAuthority?: SddReviewAuthorityOverlay): SddStatus {
261
+ function emptyStatus(cwd: string, changeName: string | null, blockedReasons: string[], artifactStore: SddArtifactStore = "openspec", isNonAuthoritative = false): SddStatus {
313
262
  const root = resolve(cwd);
314
263
  const changesDir = join(root, "openspec", "changes");
315
264
  const actionContext: SddActionContext = {
@@ -318,7 +267,7 @@ function emptyStatus(cwd: string, changeName: string | null, blockedReasons: str
318
267
  allowedEditRoots: [root],
319
268
  warnings: [],
320
269
  };
321
- return withRecoveryBlock({
270
+ return {
322
271
  schemaName: "gentle-pi.sdd-status",
323
272
  schemaVersion: 1,
324
273
  changeName,
@@ -353,7 +302,32 @@ function emptyStatus(cwd: string, changeName: string | null, blockedReasons: str
353
302
  nextRecommended: blockedReasons[0] ?? "Start an SDD change.",
354
303
  blockedReasons,
355
304
  isNonAuthoritative,
356
- }, reviewAuthority, undefined);
305
+ };
306
+ }
307
+
308
+ /**
309
+ * Find the newest archive entry for a change. Archive folders are named
310
+ * `YYYY-MM-DD-<change>`; only an exact `-<change>` suffix after a full date
311
+ * prefix matches (change "foo-bar" never matches "2026-01-01-foo-bar-baz").
312
+ * safeDirectories sorts lexicographically, so the last match is the newest date.
313
+ */
314
+ function findArchivedChangeEntry(root: string, changeName: string): string | undefined {
315
+ return safeDirectories(join(root, "openspec", "changes", "archive"))
316
+ .filter(
317
+ (entry) =>
318
+ /^\d{4}-\d{2}-\d{2}-$/.test(entry.slice(0, 11)) && entry.slice(11) === changeName,
319
+ )
320
+ .at(-1);
321
+ }
322
+
323
+ /** Positive terminal projection for a change whose folder moved to the archive. */
324
+ function archivedStatus(cwd: string, changeName: string, archiveEntry: string, artifactStore: SddArtifactStore): SddStatus {
325
+ const status = emptyStatus(cwd, changeName, [], artifactStore);
326
+ status.applyState = "all_done";
327
+ status.dependencies = { apply: "all_done", verify: "all_done", sync: "all_done", archive: "all_done" };
328
+ status.archived = { path: join("openspec", "changes", "archive", archiveEntry) };
329
+ status.nextRecommended = "archived";
330
+ return status;
357
331
  }
358
332
 
359
333
  export function listActiveOpenSpecChanges(cwd: string): string[] {
@@ -482,7 +456,7 @@ export function resolveSddStatus(options: ResolveSddStatusOptions): SddStatus {
482
456
  // - store engram or none: always non-authoritative (no disk backing)
483
457
  // - store both, no openspec/ dir: non-authoritative (no disk to scan)
484
458
  // The both-with-openspec cases are handled below after listing active changes.
485
- if (store === "engram" || store === "none" || (store === "both" && !hasOpenSpecDir)) {
459
+ if (store === "engram" || store === "none" || (store === "hybrid" && !hasOpenSpecDir)) {
486
460
  const changeName = options.changeName?.trim() || null;
487
461
  return nonAuthoritativeStatus(options.cwd, changeName, store, options.includeInstructions);
488
462
  }
@@ -500,16 +474,16 @@ export function resolveSddStatus(options: ResolveSddStatusOptions): SddStatus {
500
474
  // store both + openspec/ present + zero active changes + no changeName:
501
475
  // The change may live only in Engram — non-authoritative, not a false block.
502
476
  // Pure openspec with zero changes is a real block (run sdd-new).
503
- if (store === "both") {
477
+ if (store === "hybrid") {
504
478
  return nonAuthoritativeStatus(options.cwd, null, store, options.includeInstructions);
505
479
  }
506
- return emptyStatus(root, null, ["No active SDD changes found."], store, false, options.reviewAuthority);
480
+ return emptyStatus(root, null, ["No active SDD changes found."], store);
507
481
  } else {
508
482
  // Multiple active changes and no changeName: legit selection prompt (changes DO exist
509
483
  // on disk). Keep the existing authoritative ambiguous-selection behavior for both stores.
510
484
  return emptyStatus(root, null, [
511
485
  `Change selection is ambiguous: ${activeChanges.join(", ")}.`,
512
- ], store, false, options.reviewAuthority);
486
+ ], store);
513
487
  }
514
488
  }
515
489
 
@@ -517,10 +491,16 @@ export function resolveSddStatus(options: ResolveSddStatusOptions): SddStatus {
517
491
  // store both + openspec/ present + named change NOT found on disk:
518
492
  // The change may live only in Engram — non-authoritative.
519
493
  // Pure openspec still blocks (legit "run sdd-new").
520
- if (store === "both") {
494
+ if (store === "hybrid") {
521
495
  return nonAuthoritativeStatus(options.cwd, changeName, store, options.includeInstructions);
522
496
  }
523
- return emptyStatus(root, changeName, [`Active change not found: ${changeName}.`], store, false, options.reviewAuthority);
497
+ // Issue #535: an absent active folder may mean the change was archived.
498
+ // Project explicit completion instead of a false "run sdd-new" block.
499
+ const archiveEntry = findArchivedChangeEntry(root, changeName);
500
+ if (archiveEntry) {
501
+ return archivedStatus(root, changeName, archiveEntry, store);
502
+ }
503
+ return emptyStatus(root, changeName, [`Active change not found: ${changeName}.`], store);
524
504
  }
525
505
 
526
506
  const changeRoot = join(changesDir, changeName);
@@ -587,33 +567,13 @@ export function resolveSddStatus(options: ResolveSddStatusOptions): SddStatus {
587
567
  blockedReasons.push(`Legacy flat spec is present without domain specs: ${legacyFlatSpec.path}.`);
588
568
  }
589
569
 
590
- // Planning-only status remains filesystem-read-only: do not invoke a resolver
591
- // unless the controller has established that review authority is expected.
592
- if (options.reviewAuthority?.expected) {
593
- try {
594
- const resolved = options.reviewAuthority.resolve();
595
- if (!resolved || typeof resolved.activeAuthorityId !== "string" || resolved.activeAuthorityId.length === 0) {
596
- blockedReasons.push("resolve-review: validated active review authority is missing.");
597
- }
598
- } catch (error) {
599
- const message = error instanceof Error ? error.message : String(error);
600
- blockedReasons.push(`resolve-review: ${message}`);
601
- }
602
- }
603
- if (options.nativeReviewReadiness?.expected && !options.nativeReviewReadiness.ready) {
604
- blockedReasons.push(`resolve-review: ${options.nativeReviewReadiness.reason ?? "native bound review readiness is unavailable."}`);
605
- }
606
-
607
570
  const coreArtifactsReady = artifacts.proposal === "done" && artifacts.specs === "done" && artifacts.design === "done" && artifacts.tasks === "done" && taskProgress.total > 0 && !flatOnly;
608
- const reviewBlocked = blockedReasons.some((reason) => reason.startsWith("resolve-review:"));
609
571
  const taskArtifactBlocked = taskAccounting.errors.length > 0;
610
- const reviewApproved = Boolean((options.reviewAuthority?.expected || options.nativeReviewReadiness?.expected) && !reviewBlocked);
611
- const applyState: ApplyState = !coreArtifactsReady || reviewBlocked || taskArtifactBlocked
572
+ const applyState: ApplyState = !coreArtifactsReady || taskArtifactBlocked
612
573
  ? "blocked"
613
574
  : taskProgress.remaining === 0
614
575
  ? "all_done"
615
576
  : "ready";
616
- const parentLifecycleRequired = applyState === "all_done" && !reviewApproved;
617
577
  const verifyClean = reportIsClearlyPassing(artifactPaths.verifyReport[0]);
618
578
  const syncClean = reportIsClearlyPassing(artifactPaths.syncReport[0]);
619
579
  const syncPrerequisitesReady = coreArtifactsReady && verifyClean && collisions.length === 0 && !flatOnly;
@@ -624,31 +584,27 @@ export function resolveSddStatus(options: ResolveSddStatusOptions): SddStatus {
624
584
  : "blocked";
625
585
  const verifyState: DependencyState = verifyClean
626
586
  ? "all_done"
627
- : reviewApproved && artifacts.tasks === "done" && taskProgress.total > 0 && (artifacts.applyProgress === "done" || applyState === "all_done")
587
+ : artifacts.tasks === "done" && taskProgress.total > 0 && (artifacts.applyProgress === "done" || applyState === "all_done")
628
588
  ? "ready"
629
589
  : "blocked";
630
590
  const dependencies: SddStatus["dependencies"] = {
631
591
  apply: applyState === "blocked" ? "blocked" : applyState,
632
592
  verify: verifyState,
633
593
  sync: syncState,
634
- archive: coreArtifactsReady && reviewApproved && verifyClean && syncClean && taskProgress.remaining === 0 && taskAccounting.parent.remaining === 0 && !reviewBlocked && !taskArtifactBlocked ? "ready" : "blocked",
594
+ archive: coreArtifactsReady && verifyClean && syncClean && taskProgress.remaining === 0 && !taskArtifactBlocked ? "ready" : "blocked",
635
595
  };
636
596
  const archiveReady = dependencies.archive === "ready";
637
- const nextRecommended = reviewBlocked
638
- ? "resolve-review"
639
- : taskArtifactBlocked
640
- ? "fix-task-ownership-marker"
641
- : parentLifecycleRequired
642
- ? "parent-lifecycle"
643
- : dependencies.apply === "ready"
644
- ? "sdd-apply"
645
- : dependencies.verify === "ready"
646
- ? "sdd-verify"
647
- : dependencies.sync === "ready"
648
- ? "sdd-sync"
649
- : archiveReady
650
- ? "sdd-archive"
651
- : blockedReasons[0] ?? "Resolve blockers.";
597
+ const nextRecommended = taskArtifactBlocked
598
+ ? "fix-task-ownership-marker"
599
+ : dependencies.apply === "ready"
600
+ ? "sdd-apply"
601
+ : dependencies.verify === "ready"
602
+ ? "sdd-verify"
603
+ : dependencies.sync === "ready"
604
+ ? "sdd-sync"
605
+ : archiveReady
606
+ ? "sdd-archive"
607
+ : blockedReasons[0] ?? "Resolve blockers.";
652
608
 
653
609
  const status: SddStatus = {
654
610
  schemaName: "gentle-pi.sdd-status",
@@ -681,9 +637,8 @@ export function resolveSddStatus(options: ResolveSddStatusOptions): SddStatus {
681
637
  blockedReasons,
682
638
  isNonAuthoritative: false,
683
639
  };
684
- const resolvedStatus = withRecoveryBlock(status, options.reviewAuthority, options.nativeReviewReadiness);
685
- if (options.includeInstructions) resolvedStatus.instructions = renderPhaseInstructions(resolvedStatus);
686
- return resolvedStatus;
640
+ if (options.includeInstructions) status.instructions = renderPhaseInstructions(status);
641
+ return status;
687
642
  }
688
643
 
689
644
  export function isNonAuthoritativeStatus(status: SddStatus): boolean {
@@ -1,6 +1,6 @@
1
1
  const NON_OSC_ANSI_ESCAPE_PATTERN =
2
2
  /\x1B\[[0-?]*[ -/]*[@-~]|\x1B[@-Z\\-_]|\x9B[0-?]*[ -/]*[@-~]/g;
3
- const CONTROL_CHAR_PATTERN = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g;
3
+ const CONTROL_CHAR_PATTERN = /[\u0000-\u0008\u000b-\u000d\u000e-\u001f\u007f-\u009f]/g;
4
4
  const OSC_ESCAPE_PATTERN = /(?:\x1B\]|\x9D)[\s\S]*?(?:\x07|\x1B\\|\x9C|$)/g;
5
5
 
6
6
  export function stripAnsi(value: string): string {
package/package.json CHANGED
@@ -1,84 +1,85 @@
1
1
  {
2
- "name": "gentle-pi",
3
- "version": "2.2.0",
4
- "description": "Turn Pi into el Gentleman: a senior-architect development harness with SDD/OpenSpec, subagents, strict TDD evidence, review guardrails, and skill discovery.",
5
- "license": "MIT",
6
- "type": "module",
7
- "keywords": [
8
- "pi-package",
9
- "pi",
10
- "pi-coding-agent",
11
- "gentle-pi",
12
- "gentle-ai",
13
- "sdd",
14
- "openspec",
15
- "subagents",
16
- "tdd",
17
- "code-review",
18
- "ai-coding-agent",
19
- "agent-harness"
20
- ],
21
- "repository": {
22
- "type": "git",
23
- "url": "git+https://github.com/Gentleman-Programming/gentle-pi.git"
24
- },
25
- "files": [
26
- "assets/",
27
- "contracts/",
28
- "docs/",
29
- "extensions/",
30
- "lib/",
31
- "prompts/",
32
- "runtime/",
33
- "skills/",
34
- "scripts/",
35
- "tests/",
36
- "themes/",
37
- "README.md"
38
- ],
39
- "scripts": {
40
- "build:transaction-runner": "node scripts/build-git-commit-transaction-runner.mjs --write",
41
- "check:transaction-runner": "node scripts/build-git-commit-transaction-runner.mjs --check",
42
- "check:provider-contract": "node scripts/check-provider-contract.mjs",
43
- "postinstall": "node scripts/install-gentle-ai.mjs",
44
- "test": "node --experimental-strip-types --test tests/*.test.ts && pnpm run check:provider-contract && pnpm run test:harness",
45
- "test:harness": "node --experimental-strip-types tests/runtime-harness.mjs",
46
- "test:dev-binary": "node --experimental-strip-types --test tests/devbinary/*.devtest.ts",
47
- "test:cross-lane": "node tests/crosslane/cross-lane.mjs",
48
- "test:maintainer": "node --experimental-strip-types --test tests/maintainer/*.maintest.ts",
49
- "test:packed-runner": "node scripts/test-packed-runner.mjs",
50
- "prepack": "pnpm test && node scripts/verify-package-files.mjs",
51
- "prepublishOnly": "pnpm test && node scripts/verify-package-files.mjs && pnpm run test:packed-runner"
52
- },
53
- "pi": {
54
- "image": "https://cdn.jsdelivr.net/npm/gentle-pi/assets/gentle-logo-only.png",
55
- "extensions": [
56
- "./extensions"
57
- ],
58
- "themes": [
59
- "./themes"
60
- ],
61
- "prompts": [
62
- "./prompts"
63
- ],
64
- "skills": [
65
- "./skills"
66
- ]
67
- },
68
- "dependencies": {
69
- "@earendil-works/pi-tui": "*",
70
- "@heyhuynhgiabuu/pi-pretty": "0.6.14"
71
- },
72
- "peerDependencies": {
73
- "@earendil-works/pi-coding-agent": "*"
74
- },
75
- "peerDependenciesMeta": {
76
- "@earendil-works/pi-coding-agent": {
77
- "optional": true
78
- }
79
- },
80
- "devDependencies": {
81
- "@earendil-works/pi-coding-agent": "*"
82
- },
83
- "packageManager": "pnpm@11.1.1"
2
+ "name": "gentle-pi",
3
+ "version": "2.4.0",
4
+ "description": "Turn Pi into el Gentleman: a senior-architect development harness with SDD/OpenSpec, subagents, strict TDD evidence, review guardrails, and skill discovery.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "keywords": [
8
+ "pi-package",
9
+ "pi",
10
+ "pi-coding-agent",
11
+ "gentle-pi",
12
+ "gentle-ai",
13
+ "sdd",
14
+ "openspec",
15
+ "subagents",
16
+ "tdd",
17
+ "code-review",
18
+ "ai-coding-agent",
19
+ "agent-harness"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/Gentleman-Programming/gentle-pi.git"
24
+ },
25
+ "files": [
26
+ "assets/",
27
+ "contracts/",
28
+ "docs/",
29
+ "extensions/",
30
+ "lib/",
31
+ "prompts/",
32
+ "runtime/",
33
+ "skills/",
34
+ "scripts/",
35
+ "tests/",
36
+ "themes/",
37
+ "README.md"
38
+ ],
39
+ "scripts": {
40
+ "check:provider-contract": "node scripts/check-provider-contract.mjs",
41
+ "postinstall": "node scripts/install-gentle-ai.mjs",
42
+ "test": "node --experimental-strip-types --test tests/*.test.ts && pnpm run check:provider-contract && pnpm run test:harness",
43
+ "test:harness": "node --experimental-strip-types tests/runtime-harness.mjs",
44
+ "test:dev-binary": "node --experimental-strip-types --test tests/devbinary/*.devtest.ts",
45
+ "test:cross-lane": "node tests/crosslane/cross-lane.mjs",
46
+ "test:maintainer": "node --experimental-strip-types --test tests/maintainer/*.maintest.ts",
47
+ "build:runtime-modules": "node scripts/build-runtime-modules.mjs --write",
48
+ "check:runtime-modules": "node scripts/build-runtime-modules.mjs --check",
49
+ "test:packed-package": "node scripts/test-packed-runner.mjs",
50
+ "prepack": "pnpm test && pnpm run check:runtime-modules && node scripts/verify-package-files.mjs",
51
+ "prepublishOnly": "pnpm test && pnpm run check:runtime-modules && node scripts/verify-package-files.mjs && pnpm run test:packed-package"
52
+ },
53
+ "pi": {
54
+ "image": "https://cdn.jsdelivr.net/npm/gentle-pi/assets/gentle-logo-only.png",
55
+ "extensions": [
56
+ "./extensions"
57
+ ],
58
+ "themes": [
59
+ "./themes"
60
+ ],
61
+ "prompts": [
62
+ "./prompts"
63
+ ],
64
+ "skills": [
65
+ "./skills"
66
+ ]
67
+ },
68
+ "dependencies": {
69
+ "@earendil-works/pi-tui": "*",
70
+ "@heyhuynhgiabuu/pi-pretty": "0.6.14"
71
+ },
72
+ "peerDependencies": {
73
+ "@earendil-works/pi-coding-agent": "*",
74
+ "typebox": "*"
75
+ },
76
+ "peerDependenciesMeta": {
77
+ "@earendil-works/pi-coding-agent": {
78
+ "optional": true
79
+ }
80
+ },
81
+ "devDependencies": {
82
+ "@earendil-works/pi-coding-agent": "*"
83
+ },
84
+ "packageManager": "pnpm@11.1.1"
84
85
  }
@@ -1,4 +1,4 @@
1
- // Generated by scripts/build-git-commit-transaction-runner.mjs. Do not edit.
1
+ // Generated by scripts/build-runtime-modules.mjs. Do not edit.
2
2
  import { createHash } from "node:crypto";
3
3
  import { existsSync, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { homedir } from "node:os";