gentle-pi 2.2.0 → 2.3.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.
- package/README.md +51 -80
- package/assets/agents/review-readability.md +0 -2
- package/assets/agents/review-reliability.md +0 -2
- package/assets/agents/review-resilience.md +0 -2
- package/assets/agents/review-risk.md +0 -2
- package/assets/agents/sdd-apply.md +5 -3
- package/assets/agents/sdd-proposal.md +2 -0
- package/assets/agents/sdd-research.md +54 -0
- package/assets/agents/sdd-status.md +4 -4
- package/assets/agents/sdd-tasks.md +2 -3
- package/assets/agents/sdd-verify.md +21 -1
- package/assets/chains/sdd-full.chain.md +1 -1
- package/assets/chains/sdd-verify.chain.md +1 -1
- package/assets/orchestrator-delegation.md +54 -248
- package/assets/orchestrator-memory.md +2 -0
- package/assets/orchestrator.md +22 -38
- package/assets/sdd-orchestrator-workflow.md +30 -37
- package/assets/support/sdd-status-contract.md +7 -7
- package/contracts/review-integration/v1/schemas/transition-execution.schema.json +42 -0
- package/contracts/review-integration/v2/schemas/last-event-closure.schema.json +66 -0
- package/contracts/review-integration/v2/schemas/opencode-provider-role.schema.json +14 -0
- package/docs/native-authority-architecture.md +9 -11
- package/docs/review-integration.md +27 -373
- package/extensions/ask-user-choice.ts +151 -0
- package/extensions/gentle-ai.ts +1778 -3673
- package/extensions/quiet-tools.ts +515 -32
- package/extensions/sdd-init.ts +4 -8
- package/lib/gentle-ai-renderer.ts +70 -0
- package/lib/model-routing-authority.ts +133 -0
- package/lib/native-review-cli.ts +372 -940
- package/lib/opaque-pi-reviewer-adapter.ts +284 -0
- package/lib/review-candidate-view.ts +341 -132
- package/lib/review-host-relay.ts +210 -68
- package/lib/review-integration-v2.ts +839 -307
- package/lib/review-last-event-controller.ts +35 -0
- package/lib/sdd-preflight.ts +177 -66
- package/lib/sdd-status.ts +66 -111
- package/lib/terminal-theme.ts +1 -1
- package/package.json +83 -82
- package/runtime/gentle-ai-binary.mjs +1 -1
- package/runtime/native-review-cli.mjs +322 -890
- package/runtime/review-integration-v2.mjs +789 -257
- package/runtime/review-relay-contract.mjs +1 -1
- package/scripts/{build-git-commit-transaction-runner.mjs → build-runtime-modules.mjs} +4 -5
- package/scripts/gentle-ai-installer.mjs +75 -22
- package/scripts/maintainer/provider-relay-matrix.mjs +195 -11
- package/scripts/test-packed-runner.mjs +4 -7
- package/scripts/verify-package-files.mjs +12 -13
- package/skills/_shared/review-ledger-contract.md +8 -14
- package/skills/chained-pr/SKILL.md +3 -0
- package/skills/cognitive-doc-design/SKILL.md +1 -1
- package/skills/comment-writer/SKILL.md +1 -1
- package/skills/gentle-ai/SKILL.md +7 -74
- package/skills/judgment-day/SKILL.md +5 -7
- package/skills/rdd-defect-workflow/SKILL.md +3 -3
- package/skills/release/SKILL.md +3 -3
- package/skills/skill-registry/SKILL.md +1 -1
- package/skills/work-unit-commits/SKILL.md +3 -1
- package/tests/artifact-language.test.ts +24 -11
- package/tests/ask-user-choice.test.ts +264 -0
- package/tests/codegraph-tools.test.ts +3 -3
- package/tests/crosslane/cross-lane.mjs +15 -1168
- package/tests/delegated-key-learnings-contract.test.ts +8 -6
- package/tests/devbinary/native-review-parity.devtest.ts +167 -250
- package/tests/devbinary/pi-host-relay.devtest.ts +867 -0
- package/tests/fixtures/devbinary/last-event-capture-correction-plan.captured.json +10 -0
- package/tests/fixtures/devbinary/last-event-capture-refuter-approved.captured.json +20 -0
- package/tests/fixtures/devbinary/last-event-capture-refuter-correction-required.captured.json +26 -0
- package/tests/fixtures/devbinary/last-event-capture-result-approved.captured.json +8 -0
- package/tests/fixtures/devbinary/last-event-capture-result-correction-required.captured.json +26 -0
- package/tests/fixtures/devbinary/last-event-capture-validation-approved.captured.json +8 -0
- package/tests/fixtures/devbinary/last-event-closure.provenance.md +13 -0
- package/tests/fixtures/devbinary/review-acknowledged-v1.captured.json +9 -0
- package/tests/fixtures/devbinary/review-acknowledged.provenance.md +31 -0
- package/tests/fixtures/devbinary/start-v3-zero-lens-closed.captured.json +21 -0
- package/tests/fixtures/native-review-cli/v2.5.0-rc.1/PROVENANCE.txt +15 -0
- package/tests/gentle-ai-binary.test.ts +83 -13
- package/tests/gentle-ai-dev-binary.test.ts +51 -228
- package/tests/gentle-ai-installer.test.ts +137 -47
- package/tests/gentle-ai.test.ts +820 -131
- package/tests/gentle-theme.test.ts +133 -0
- package/tests/maintainer/provider-relay.maintest.ts +340 -4
- package/tests/model-routing-authority.test.ts +257 -0
- package/tests/native-review-capability-contract.test.ts +28 -1
- package/tests/native-review-cli.test.ts +586 -962
- package/tests/native-review-consent.test.ts +150 -66
- package/tests/native-review-parity-runtime.test.ts +80 -359
- package/tests/native-review-parity.test.ts +674 -925
- package/tests/opaque-pi-reviewer-adapter.test.ts +266 -0
- package/tests/orchestrator-budget.test.ts +132 -88
- package/tests/orchestrator-rdd-ownership.test.ts +103 -0
- package/tests/package-manifest.test.ts +37 -35
- package/tests/provider-defect-handoff.test.ts +15 -118
- package/tests/quiet-tool-rendering.test.ts +1055 -28
- package/tests/review-authority-recovery-docs.test.ts +1 -2
- package/tests/review-candidate-view.test.ts +409 -3
- package/tests/review-compact-contract.test.ts +4 -30
- package/tests/review-controller-lock-status.test.ts +2 -2
- package/tests/review-controller-native-recovery.test.ts +363 -1450
- package/tests/review-controller-native-routing.test.ts +1251 -5642
- package/tests/review-controller-retired-ops.test.ts +1 -1
- package/tests/review-controller-workspace-root.test.ts +222 -71
- package/tests/review-controller.test.ts +26 -816
- package/tests/review-corrected-finalize-binding.test.ts +112 -153
- package/tests/review-dispatch-hydration-gap.test.ts +1 -53
- package/tests/review-gate.test.ts +0 -45
- package/tests/review-host-relay-restart-parity.test.ts +360 -0
- package/tests/review-host-relay-routing.test.ts +117 -82
- package/tests/review-host-relay.test.ts +242 -8
- package/tests/review-integration-v2-forward.test.ts +576 -553
- package/tests/review-integration-v2.test.ts +239 -165
- package/tests/review-last-event-closure.test.ts +408 -0
- package/tests/review-ledger-contract.test.ts +97 -35
- package/tests/review-recovered-lineage-routing.test.ts +0 -47
- package/tests/review-relay-transport-agent.test.ts +119 -46
- package/tests/review-snapshot.test.ts +3 -2
- package/tests/runtime-harness.mjs +361 -196
- package/tests/sdd-agent-tools.test.ts +36 -0
- package/tests/sdd-preflight.test.ts +81 -15
- package/tests/sdd-status.test.ts +109 -110
- package/tests/skill-collision-prefixes.test.ts +5 -8
- package/tests/writer-edit-surface-scope.test.ts +230 -0
- package/themes/Gentleman-Cute.json +94 -0
- package/themes/Gentleman-Sexy.json +92 -0
- package/lib/git-commit-transaction.ts +0 -861
- package/runtime/git-commit-transaction.mjs +0 -862
- package/scripts/run-git-commit-transaction.mjs +0 -35
- package/tests/fixtures/native-review-cli/v2.1.3/sdd-status-engram.json +0 -139
- package/tests/fixtures/native-review-cli/v2.1.3/sdd-status.json +0 -200
- package/tests/git-commit-transaction.test.ts +0 -530
|
@@ -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
|
+
}
|