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
@@ -0,0 +1,151 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { DynamicBorder } from "@earendil-works/pi-coding-agent";
3
+ import { Container, type SelectItem, SelectList, Text } from "@earendil-works/pi-tui";
4
+ import { type Static, Type } from "typebox";
5
+
6
+ const CHOICE_TOOL_NAME = "ask_user_choice";
7
+ const ASK_USER_CHOICE_BLOCKED_EVENT = "gentle-pi:ask-user-choice:blocked";
8
+
9
+ const ChoiceOptionSchema = Type.Object(
10
+ {
11
+ label: Type.String({ description: "User-facing option label" }),
12
+ description: Type.String({ description: "User-facing option description" }),
13
+ value: Type.String({ description: "Opaque envelope-owned answer token returned only after selection" }),
14
+ },
15
+ { additionalProperties: false },
16
+ );
17
+
18
+ const ChoiceParamsSchema = Type.Object(
19
+ {
20
+ question: Type.String({ description: "The one question to display" }),
21
+ options: Type.Array(ChoiceOptionSchema, {
22
+ minItems: 2,
23
+ maxItems: 4,
24
+ description: "Two to four ordered closed options",
25
+ }),
26
+ },
27
+ { additionalProperties: false },
28
+ );
29
+
30
+ type ChoiceOption = Static<typeof ChoiceOptionSchema>;
31
+ type ChoiceParams = Static<typeof ChoiceParamsSchema>;
32
+
33
+ interface ChoiceSelection {
34
+ value: string;
35
+ label: string;
36
+ index: number;
37
+ }
38
+
39
+ interface ChoiceDetails {
40
+ question: string;
41
+ options: ChoiceOption[];
42
+ selection?: ChoiceSelection;
43
+ cancelled?: true;
44
+ }
45
+
46
+ function reconcileToolAvailability(pi: ExtensionAPI, interactiveTui: boolean): void {
47
+ const active = pi.getActiveTools();
48
+ const isActive = active.includes(CHOICE_TOOL_NAME);
49
+ if (interactiveTui === isActive) return;
50
+ const next = interactiveTui
51
+ ? [...new Set([...active, CHOICE_TOOL_NAME])]
52
+ : active.filter((name) => name !== CHOICE_TOOL_NAME);
53
+ pi.setActiveTools(next);
54
+ }
55
+
56
+ function resultDetails(params: ChoiceParams): ChoiceDetails {
57
+ return { question: params.question, options: params.options };
58
+ }
59
+
60
+ export default function askUserChoice(pi: ExtensionAPI): void {
61
+ pi.registerTool({
62
+ name: CHOICE_TOOL_NAME,
63
+ label: "Ask User Choice",
64
+ description: "Ask one strictly closed single-select question with two to four ordered options. It never accepts free-text or multiple selections.",
65
+ promptGuidelines: [
66
+ "Use ask_user_choice only for one exactly representable closed single-select question with 2-4 ordered options; never use it for free-text or multi-select input.",
67
+ ],
68
+ parameters: ChoiceParamsSchema,
69
+ executionMode: "sequential",
70
+ async execute(_toolCallId, params: ChoiceParams, _signal, _onUpdate, ctx) {
71
+ if (ctx.mode !== "tui") {
72
+ throw new Error("ask_user_choice is unavailable outside the interactive TUI");
73
+ }
74
+
75
+ const items: SelectItem[] = params.options.map((option) => ({
76
+ value: option.value,
77
+ label: option.label,
78
+ description: option.description,
79
+ }));
80
+ let selection: ChoiceSelection | undefined;
81
+ try {
82
+ pi.events.emit(ASK_USER_CHOICE_BLOCKED_EVENT, { active: true });
83
+ selection = await ctx.ui.custom<ChoiceSelection | undefined>((tui, theme, _keybindings, done) => {
84
+ const container = new Container();
85
+ container.addChild(new DynamicBorder((text: string) => theme.fg("accent", text)));
86
+ container.addChild(new Text(theme.fg("accent", theme.bold(params.question)), 1, 0));
87
+ const list = new SelectList(items, items.length, {
88
+ selectedPrefix: (text) => theme.fg("accent", text),
89
+ selectedText: (text) => theme.fg("accent", text),
90
+ description: (text) => theme.fg("muted", text),
91
+ scrollInfo: (text) => theme.fg("dim", text),
92
+ noMatch: (text) => theme.fg("warning", text),
93
+ });
94
+ list.onSelect = (item) => {
95
+ const index = items.indexOf(item);
96
+ done({ value: item.value, label: item.label, index: index + 1 });
97
+ };
98
+ list.onCancel = () => done(undefined);
99
+ container.addChild(list);
100
+ container.addChild(new Text(theme.fg("dim", "↑↓ navigate • Enter select • Esc cancel"), 1, 0));
101
+ container.addChild(new DynamicBorder((text: string) => theme.fg("accent", text)));
102
+ return {
103
+ render: (width) => container.render(width),
104
+ invalidate: () => container.invalidate(),
105
+ handleInput: (data) => {
106
+ list.handleInput(data);
107
+ tui.requestRender();
108
+ },
109
+ };
110
+ });
111
+ } finally {
112
+ pi.events.emit(ASK_USER_CHOICE_BLOCKED_EVENT, { active: false });
113
+ }
114
+
115
+ if (selection === undefined) {
116
+ return {
117
+ content: [{ type: "text", text: "User cancelled the choice" }],
118
+ details: { ...resultDetails(params), cancelled: true },
119
+ };
120
+ }
121
+ return {
122
+ content: [{ type: "text", text: `User selected: ${selection.index}. ${selection.label} (value: ${selection.value})` }],
123
+ details: { ...resultDetails(params), selection },
124
+ };
125
+ },
126
+ renderCall(args, theme) {
127
+ const options = Array.isArray(args.options) ? args.options : [];
128
+ const labels = options
129
+ .map((option) => (typeof option === "object" && option !== null && "label" in option && typeof option.label === "string" ? option.label : ""))
130
+ .filter((label) => label.length > 0);
131
+ return new Text(
132
+ theme.fg("toolTitle", theme.bold("ask_user_choice ")) +
133
+ theme.fg("muted", typeof args.question === "string" ? args.question : "") +
134
+ (labels.length > 0 ? theme.fg("dim", ` (${labels.join(", ")})`) : ""),
135
+ 0,
136
+ 0,
137
+ );
138
+ },
139
+ renderResult(result, _options, theme) {
140
+ const details = result.details as ChoiceDetails | undefined;
141
+ if (details?.selection) {
142
+ return new Text(theme.fg("success", `✓ ${details.selection.index}. ${details.selection.label}`), 0, 0);
143
+ }
144
+ return new Text(theme.fg("warning", "Cancelled"), 0, 0);
145
+ },
146
+ });
147
+
148
+ pi.on("before_agent_start", (_event, ctx) => {
149
+ reconcileToolAvailability(pi, ctx.mode === "tui");
150
+ });
151
+ }