gentle-pi 3.7.0 → 4.0.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 +37 -6
- package/assets/agents/gentle-ai-explore.md +4 -4
- package/assets/agents/gentle-ai-verify.md +6 -4
- package/assets/agents/gentle-ai-worker.md +7 -9
- package/assets/orchestrator-delegation.md +40 -41
- package/assets/orchestrator-memory.md +1 -22
- package/assets/orchestrator-skills.md +1 -1
- package/assets/orchestrator.md +12 -24
- package/assets/support/strict-tdd-verify.md +4 -266
- package/assets/support/strict-tdd.md +8 -360
- package/bin/gentle-shell.mjs +254 -29
- package/docs/delegated-verification.md +26 -1
- package/docs/gentle-agents-activity.md +24 -0
- package/docs/gentle-shell.md +92 -28
- package/docs/native-authority-architecture.md +2 -2
- package/docs/prompt-history.md +280 -0
- package/docs/readme-reference.md +112 -206
- package/docs/telemetry.md +1 -1
- package/docs/yolo-mode.md +86 -0
- package/extensions/child-context.ts +26 -0
- package/extensions/child-safety.ts +23 -0
- package/extensions/gentle-agents.ts +429 -262
- package/extensions/gentle-ai.ts +781 -683
- package/extensions/gentle-shell.ts +1375 -88
- package/extensions/gentle-stats.ts +101 -0
- package/extensions/gentle-todo.ts +18 -7
- package/extensions/history/atomic-write.ts +38 -0
- package/extensions/history/hide-prompts.ts +183 -0
- package/extensions/history/index.ts +1419 -0
- package/extensions/history/load-shared-history.ts +39 -0
- package/extensions/history/selector-helpers.ts +538 -0
- package/extensions/history/session-scan.ts +233 -0
- package/extensions/history/store.ts +1119 -0
- package/extensions/nan-provider.ts +6 -0
- package/extensions/quiet-tools.ts +179 -87
- package/extensions/resume-hint.ts +60 -0
- package/extensions/skill-registry.ts +16 -12
- package/extensions/startup-banner.ts +60 -31
- package/lib/agent-assets.ts +604 -0
- package/lib/agent-profile-pin.ts +12 -0
- package/lib/agents-message-delivery.ts +181 -0
- package/lib/agents-protocol.ts +60 -0
- package/lib/agents-runner.ts +96 -98
- package/lib/agents-view.ts +26 -3
- package/lib/agents-widget.ts +16 -9
- package/lib/append-system-prompt.ts +21 -0
- package/lib/bounded-writer-admission.ts +147 -0
- package/lib/card-style-policy.ts +60 -0
- package/lib/child-context-files.ts +166 -0
- package/lib/codemode-renderer.ts +185 -0
- package/lib/command-palette-catalog.ts +3 -9
- package/lib/command-palette.ts +25 -14
- package/lib/destructive-command-guard.ts +144 -0
- package/lib/gentle-ai-elapsed-store.ts +87 -0
- package/lib/gentle-ai-renderer.ts +196 -39
- package/lib/gentle-shell-launcher.ts +24 -13
- package/lib/gentle-shell-resume-hint.ts +176 -0
- package/lib/history-capture-policy.ts +95 -0
- package/lib/model-routing-authority.ts +5 -1
- package/lib/nan-provider.ts +227 -0
- package/lib/native-review-cli.ts +49 -108
- package/lib/odd-phase-inference.ts +231 -0
- package/lib/odd-phase.ts +141 -0
- package/lib/overlay-repaint.ts +26 -0
- package/lib/pi-tui-keys.ts +53 -0
- package/lib/review-candidate-view-owner.ts +67 -17
- package/lib/review-candidate-view.ts +112 -25
- package/lib/review-reminder-receipt.ts +48 -8
- package/lib/review-risk-assessment.ts +156 -11
- package/lib/review-sidebar-state.ts +223 -0
- package/lib/selection-engine.ts +515 -0
- package/lib/session-messaging-grants.ts +135 -0
- package/lib/session-worktree-registry.ts +14 -2
- package/lib/shell-bar.ts +179 -24
- package/lib/shell-card.ts +287 -18
- package/lib/shell-changes-view.ts +2 -1
- package/lib/shell-prompt.ts +102 -6
- package/lib/shell-sidebar-layout.ts +78 -14
- package/lib/shell-sidebar.ts +15 -1
- package/lib/shell-todo.ts +23 -13
- package/lib/shell-usage-view.ts +9 -4
- package/lib/shell-usage.ts +66 -10
- package/lib/stats-collector.ts +381 -0
- package/lib/stats-view.ts +431 -0
- package/lib/theme-customization.ts +52 -0
- package/lib/vim-editor-adapter.ts +379 -0
- package/lib/vim-normal-engine.ts +154 -0
- package/lib/vim-operator-engine.ts +416 -0
- package/lib/vim-policy.ts +49 -0
- package/lib/vim-visual-engine.ts +107 -0
- package/lib/visual-customization-policy.ts +108 -0
- package/lib/visual-customize-view.ts +330 -0
- package/lib/visual-profiles.ts +228 -0
- package/lib/yolo-session-policy.ts +240 -0
- package/package.json +20 -8
- package/runtime/gentle-shell-launcher.mjs +23 -12
- package/runtime/gentle-shell-resume-hint.mjs +177 -0
- package/runtime/native-review-cli.mjs +49 -108
- package/runtime/review-risk-assessment.mjs +154 -9
- package/scripts/build-runtime-modules.mjs +1 -0
- package/scripts/gentle-ai-installer.mjs +14 -13
- package/scripts/mirror-odd-routing.mjs +2 -2
- package/scripts/run-test-suite.mjs +76 -0
- package/scripts/test-packed-runner.mjs +31 -14
- package/scripts/verify-package-files.mjs +11 -22
- package/skills/branch-pr/SKILL.md +24 -52
- package/skills/chained-pr/SKILL.md +31 -15
- package/skills/chained-pr/references/chaining-details.md +31 -20
- package/skills/gentle-ai/SKILL.md +9 -15
- package/skills/issue-creation/SKILL.md +8 -2
- package/skills/issue-creation/references/delegated-workflow-actions.md +19 -0
- package/skills/work-unit-commits/SKILL.md +4 -3
- package/tests/agent-profiles.test.ts +18 -0
- package/tests/agents-fake-child.ts +2 -2
- package/tests/agents-message-delivery.test.ts +106 -0
- package/tests/agents-protocol.test.ts +40 -0
- package/tests/agents-runner.test.ts +378 -89
- package/tests/agents-view-thread-identity.test.ts +169 -0
- package/tests/agents-view.test.ts +8 -2
- package/tests/agents-widget.test.ts +154 -15
- package/tests/append-system-prompt-route.test.ts +160 -0
- package/tests/append-system-prompt.test.ts +46 -0
- package/tests/artifact-language.test.ts +19 -213
- package/tests/ask-user-question.test.ts +44 -1
- package/tests/asset-installation-runtime.test.ts +5 -16
- package/tests/autonomous-guard.test.ts +69 -1
- package/tests/bounded-writer-admission.test.ts +95 -0
- package/tests/branch-pr-skill.test.ts +43 -0
- package/tests/card-style-policy.test.ts +55 -0
- package/tests/chained-pr-skill.test.ts +124 -0
- package/tests/child-context-files.test.ts +255 -0
- package/tests/child-safety.test.ts +82 -0
- package/tests/codemode-rendering.test.ts +491 -0
- package/tests/command-palette.test.ts +39 -3
- package/tests/delegated-key-learnings-contract.test.ts +0 -76
- package/tests/destructive-command-guard.test.ts +84 -0
- package/tests/devbinary/native-review-parity.devtest.ts +170 -2
- package/tests/devbinary/non-git-subagent-bootstrap.devtest.ts +193 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +7 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +3 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T08-00-00-000Z_ddd.jsonl +2 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T09-00-00-000Z_eee.jsonl +3 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/run-1/session.jsonl +2 -0
- package/tests/fixtures/stats/sessions/--work-beta--/2026-09-01T12-00-00-000Z_ccc.jsonl +2 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +2 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +4 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-gamma--/2026-09-20T09-00-00-000Z_fff.jsonl +3 -0
- package/tests/generic-agent-tools.test.ts +54 -0
- package/tests/gentle-agents.test.ts +1047 -252
- package/tests/gentle-ai-binary.test.ts +3 -3
- package/tests/gentle-ai-elapsed-store.test.ts +68 -0
- package/tests/gentle-ai-installer.test.ts +68 -54
- package/tests/gentle-ai-renderer.test.ts +487 -8
- package/tests/gentle-ai.test.ts +288 -65
- package/tests/gentle-card-text.ts +2 -1
- package/tests/gentle-shell-bin.test.ts +651 -114
- package/tests/gentle-shell-launcher.test.ts +99 -52
- package/tests/gentle-shell-resume-hint.test.ts +270 -0
- package/tests/gentle-shell.test.ts +3839 -187
- package/tests/gentle-stats.test.ts +152 -0
- package/tests/gentle-theme.test.ts +4 -1
- package/tests/gentle-todo.test.ts +80 -8
- package/tests/history-atomic-write.test.ts +57 -0
- package/tests/history-capture-policy.test.ts +102 -0
- package/tests/history-command-registration.test.ts +164 -0
- package/tests/history-dedupe-entries.test.ts +123 -0
- package/tests/history-delete-backfill.test.ts +190 -0
- package/tests/history-delete-confirm.test.ts +460 -0
- package/tests/history-dispatch.test.ts +180 -0
- package/tests/history-drain-hidden.test.ts +110 -0
- package/tests/history-drain-order.test.ts +98 -0
- package/tests/history-expanded-globals.test.ts +62 -0
- package/tests/history-gc.test.ts +832 -0
- package/tests/history-header-layout.test.ts +265 -0
- package/tests/history-hide-prompts.test.ts +275 -0
- package/tests/history-lazy-windowing.test.ts +508 -0
- package/tests/history-legacy-migrate-v2.test.ts +297 -0
- package/tests/history-load-shared-history.test.ts +53 -0
- package/tests/history-max-results-cap.test.ts +76 -0
- package/tests/history-multi-reader.test.ts +203 -0
- package/tests/history-off-path.test.ts +170 -0
- package/tests/history-openflow-integration.test.ts +173 -0
- package/tests/history-overlay-margin.test.ts +326 -0
- package/tests/history-preview-layout.test.ts +93 -0
- package/tests/history-registry.test.ts +143 -0
- package/tests/history-scope-delete.test.ts +411 -0
- package/tests/history-search-caret-keys.test.ts +142 -0
- package/tests/history-seed-bootstrap.test.ts +170 -0
- package/tests/history-seed-regen.test.ts +129 -0
- package/tests/history-selector-windowing.test.ts +94 -0
- package/tests/history-session-scan-directory.test.ts +87 -0
- package/tests/history-session-scan-extract.test.ts +583 -0
- package/tests/history-session-writer.test.ts +351 -0
- package/tests/history-store-paths.test.ts +79 -0
- package/tests/history-tombstone-exact.test.ts +139 -0
- package/tests/history-wheel-mouse.test.ts +242 -0
- package/tests/inprocess-reviewer.test.ts +29 -19
- package/tests/issue-creation-skill.test.ts +61 -0
- package/tests/model-routing-authority.test.ts +16 -0
- package/tests/nan-provider.test.ts +471 -0
- package/tests/native-review-capability-contract.test.ts +7 -1
- package/tests/native-review-cli.test.ts +6 -120
- package/tests/native-review-parity-runtime.test.ts +100 -3
- package/tests/odd-integration.test.ts +67 -0
- package/tests/odd-phase-inference.test.ts +213 -0
- package/tests/odd-phase-loader.test.ts +253 -0
- package/tests/odd-phase.test.ts +307 -0
- package/tests/odd-routing-canonical-ratchet.test.ts +11 -6
- package/tests/odd-routing-contract.test.ts +86 -35
- package/tests/orchestrator-budget.test.ts +14 -39
- package/tests/orchestrator-rdd-ownership.test.ts +3 -3
- package/tests/overlay-repaint.test.ts +74 -0
- package/tests/package-manifest.test.ts +252 -115
- package/tests/packed-runner-owned-path.test.ts +46 -0
- package/tests/persona-single-channel.test.ts +6 -6
- package/tests/provider-defect-handoff.test.ts +3 -11
- package/tests/quiet-bash-runtime.test.ts +76 -0
- package/tests/quiet-tool-rendering.test.ts +409 -184
- package/tests/rdd-aware-verification-contract.test.ts +76 -1
- package/tests/rdd-status-line.test.ts +9 -4
- package/tests/resume-hint-extension.test.ts +122 -0
- package/tests/review-agent-end-preflight.test.ts +176 -12
- package/tests/review-candidate-owner-retry.test.ts +22 -1
- package/tests/review-candidate-view.test.ts +298 -0
- package/tests/review-contract-prompt.test.ts +108 -43
- package/tests/review-controller-lock-status.test.ts +0 -1
- package/tests/review-controller-native-routing.test.ts +611 -5
- package/tests/review-controller-workspace-root.test.ts +163 -4
- package/tests/review-host-relay-routing.test.ts +338 -2
- package/tests/review-integration-v2-forward.test.ts +200 -0
- package/tests/review-ledger-contract.test.ts +10 -34
- package/tests/review-reminder-receipt.test.ts +47 -1
- package/tests/review-risk-assessment.test.ts +498 -6
- package/tests/review-sidebar-state.test.ts +402 -0
- package/tests/run-test-suite.test.ts +124 -0
- package/tests/runtime-harness.mjs +145 -786
- package/tests/runtime-metrics-children.test.ts +16 -23
- package/tests/selection-engine.test.ts +421 -0
- package/tests/session-messaging-grants.test.ts +255 -0
- package/tests/session-worktree-registry.test.ts +77 -0
- package/tests/shell-bar.test.ts +382 -1
- package/tests/shell-card.test.ts +353 -1
- package/tests/shell-changes-view.test.ts +52 -0
- package/tests/shell-prompt.test.ts +94 -2
- package/tests/shell-sidebar-layout.test.ts +325 -21
- package/tests/shell-sidebar-scroll-benchmark.test.ts +255 -0
- package/tests/shell-todo.test.ts +87 -1
- package/tests/shell-usage-view.test.ts +27 -0
- package/tests/shell-usage.test.ts +73 -0
- package/tests/skill-registry.test.ts +50 -1
- package/tests/startup-banner.test.ts +130 -2
- package/tests/stats-collector.test.ts +195 -0
- package/tests/stats-view.test.ts +202 -0
- package/tests/telemetry-trigger.test.ts +81 -20
- package/tests/theme-customization.test.ts +72 -0
- package/tests/vim-editor-adapter-host-resolution.test.ts +37 -0
- package/tests/vim-editor-adapter.test.ts +804 -0
- package/tests/vim-normal-engine.test.ts +101 -0
- package/tests/vim-operator-engine.test.ts +215 -0
- package/tests/vim-policy.test.ts +19 -0
- package/tests/vim-visual-engine.test.ts +52 -0
- package/tests/visual-customization-policy.test.ts +110 -0
- package/tests/visual-customize-view.test.ts +418 -0
- package/tests/visual-profiles.test.ts +87 -0
- package/tests/yolo-customize.test.ts +256 -0
- package/tests/yolo-mode-runtime.test.ts +161 -0
- package/tests/yolo-mode.test.ts +261 -0
- package/tests/yolo-session-policy.test.ts +59 -0
- package/themes/Gentle.json +2 -1
- package/themes/Gentleman-Cute.json +2 -1
- package/themes/Gentleman-Sexy.json +2 -1
- package/assets/agents/sdd-apply.md +0 -159
- package/assets/agents/sdd-archive.md +0 -228
- package/assets/agents/sdd-design.md +0 -49
- package/assets/agents/sdd-explore.md +0 -48
- package/assets/agents/sdd-init.md +0 -56
- package/assets/agents/sdd-onboard.md +0 -52
- package/assets/agents/sdd-proposal.md +0 -64
- package/assets/agents/sdd-remediate.md +0 -37
- package/assets/agents/sdd-research.md +0 -49
- package/assets/agents/sdd-spec.md +0 -192
- package/assets/agents/sdd-status.md +0 -54
- package/assets/agents/sdd-tasks.md +0 -108
- package/assets/agents/sdd-verify.md +0 -124
- package/assets/chains/sdd-full.chain.md +0 -83
- package/assets/chains/sdd-plan.chain.md +0 -56
- package/assets/chains/sdd-verify.chain.md +0 -43
- package/assets/sdd-orchestrator-workflow.md +0 -319
- package/assets/support/sdd-status-contract.md +0 -77
- package/docs/assets/diagrams/sdd-cycle.svg +0 -14
- package/extensions/sdd-init.ts +0 -816
- package/lib/openspec-deltas.ts +0 -156
- package/lib/sdd-preflight.ts +0 -1066
- package/lib/sdd-research-capabilities.ts +0 -94
- package/lib/sdd-status.ts +0 -26
- package/tests/fixtures/legacy/sdd-research-v2.5.0.md +0 -54
- package/tests/fixtures/native-review-cli/v2.1.3/bind-sdd.json +0 -25
- package/tests/fixtures/v0.10.7/assets/agents/sdd-apply.md +0 -132
- package/tests/openspec-deltas.test.ts +0 -209
- package/tests/sdd-agent-tools.test.ts +0 -156
- package/tests/sdd-archive-replay.test.ts +0 -82
- package/tests/sdd-classical-continuation.test.ts +0 -74
- package/tests/sdd-execution-routing-contract.test.ts +0 -44
- package/tests/sdd-managed-runtime-settlement.test.ts +0 -155
- package/tests/sdd-native-managed-uptake.test.ts +0 -243
- package/tests/sdd-no-attempts-contract.test.ts +0 -15
- package/tests/sdd-odd-integration.test.ts +0 -33
- package/tests/sdd-optional-research.test.ts +0 -124
- package/tests/sdd-planning-routing-contract.test.ts +0 -45
- package/tests/sdd-preflight-rpc-input.test.ts +0 -125
- package/tests/sdd-preflight.test.ts +0 -541
- package/tests/sdd-research-capabilities.test.ts +0 -114
- package/tests/sdd-research-live.test.ts +0 -241
- package/tests/sdd-selection-transport.test.ts +0 -653
- package/tests/sdd-status.test.ts +0 -9
- package/tests/sdd-task-truth.test.ts +0 -43
|
@@ -45,7 +45,7 @@ test("research uses adaptive evidence gathering and existing general workers onl
|
|
|
45
45
|
"recommendation, tradeoffs, open questions, and implementation implications",
|
|
46
46
|
"Forward these research instructions",
|
|
47
47
|
"existing fresh general exploration/research worker",
|
|
48
|
-
"do not create a specialized agent or
|
|
48
|
+
"do not create a specialized agent or create a new workflow",
|
|
49
49
|
"no new persistence or readiness machinery",
|
|
50
50
|
]);
|
|
51
51
|
});
|
|
@@ -129,7 +129,7 @@ test("ODD closes each task with a work-unit commit and reviews the commit or PR
|
|
|
129
129
|
"keep a running count from work-unit commits",
|
|
130
130
|
"`ask-on-risk` (default), `auto-chain`, `single-pr`, or `exception-ok`",
|
|
131
131
|
"apply the chosen strategy before the next commit",
|
|
132
|
-
"`ask-on-risk` asks once
|
|
132
|
+
"`ask-on-risk` asks once using the ordered oversized-delivery menu",
|
|
133
133
|
"`auto-chain` asks only for a missing chain strategy and slices automatically",
|
|
134
134
|
"Cache both choices, and record slice boundaries",
|
|
135
135
|
"Resolve the `work-unit-commits` and `chained-pr` skills by registry name",
|
|
@@ -145,10 +145,38 @@ test("ODD closes each task with a work-unit commit and reviews the commit or PR
|
|
|
145
145
|
"Close task with a work-unit commit",
|
|
146
146
|
"RDD enabled at work-unit commit boundary",
|
|
147
147
|
"Running authored lines over 400",
|
|
148
|
-
"Apply delivery strategy
|
|
148
|
+
"Apply selected delivery strategy",
|
|
149
|
+
"Single PR; no chain artifacts",
|
|
149
150
|
]);
|
|
150
151
|
});
|
|
151
152
|
|
|
153
|
+
test("delivery instructions and docs preserve localized ordered outcomes and override chaining", () => {
|
|
154
|
+
for (const text of [delegation, read("docs/readme-reference.md")]) {
|
|
155
|
+
// English prose is documentation evidence, not mandatory runtime UI copy.
|
|
156
|
+
const outcomes = ["chain_strategy=feature-branch-chain", "chain_strategy=stacked-to-main", "delivery_strategy=single-pr"];
|
|
157
|
+
let previous = -1;
|
|
158
|
+
for (const outcome of outcomes) {
|
|
159
|
+
const index = text.indexOf(outcome);
|
|
160
|
+
assert.ok(index > previous, `missing or out-of-order semantic outcome: ${outcome}`);
|
|
161
|
+
previous = index;
|
|
162
|
+
}
|
|
163
|
+
assert.match(text, /1\. .*feature\/tracker.*feature-branch-chain/i);
|
|
164
|
+
assert.match(text, /2\. .*verified default\/main.*stacked-to-main/i);
|
|
165
|
+
assert.match(text, /3\. .*single PR.*least recommended.*delivery_strategy=single-pr/i);
|
|
166
|
+
containsAll(text, [
|
|
167
|
+
"delivery_strategy=single-pr", "not a `chain_strategy` token",
|
|
168
|
+
"overrides the pending chaining path", "clear the chain choice",
|
|
169
|
+
"suppress later chain prompts", "not automatically select `exception-ok`",
|
|
170
|
+
"destination repository's documented contribution/size policy",
|
|
171
|
+
"not a universal label requirement", "no tracker, child dependency diagram, or Chain Context",
|
|
172
|
+
"complete user-facing question", "every option label, description, and recommendation marker",
|
|
173
|
+
"active user's conversation language", "unchanged and untranslated",
|
|
174
|
+
"English examples are illustrative and localizable, not mandatory copy",
|
|
175
|
+
]);
|
|
176
|
+
assert.doesNotMatch(text, /single-pr.*requires? `size:exception`/i);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
152
180
|
test("user documentation shows recovery and candidate-level consent without claiming model proof", () => {
|
|
153
181
|
const docs = read("docs/readme-reference.md");
|
|
154
182
|
containsAll(docs, [
|
|
@@ -184,24 +212,26 @@ test("one feature document carries intent, accepted rationale and worker context
|
|
|
184
212
|
]);
|
|
185
213
|
});
|
|
186
214
|
|
|
187
|
-
test("ODD
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
"
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
]);
|
|
204
|
-
|
|
215
|
+
test("ODD defaults to applicable test-first without chat or TUI activation", () => {
|
|
216
|
+
const worker = read("assets/agents/gentle-ai-worker.md");
|
|
217
|
+
const verify = read("assets/agents/gentle-ai-verify.md");
|
|
218
|
+
const support = read("assets/support/strict-tdd.md") + read("assets/support/strict-tdd-verify.md");
|
|
219
|
+
const skill = read("skills/gentle-ai/SKILL.md");
|
|
220
|
+
for (const text of [core, delegation, worker, verify, support, skill, wrapper]) {
|
|
221
|
+
containsAll(text, ["applicable", "RED", "GREEN"]);
|
|
222
|
+
assert.doesNotMatch(text, /(?:configured TDD mode|Strict TDD Mode is enabled|explicit user choice|test presence does not enable it|tests existing does not activate it)/i);
|
|
223
|
+
}
|
|
224
|
+
for (const [actor, text] of [["core", core], ["delegation", delegation], ["extension", wrapper], ["skill", skill]] as const) {
|
|
225
|
+
assert.match(text, /behavior changes with applicable runnable deterministic tests and a clear expected outcome/i, `${actor} must require applicability, not test presence`);
|
|
226
|
+
assert.match(text, /passive documentation/i, `${actor} must handle passive docs`);
|
|
227
|
+
assert.match(text, /unavailable runner/i, `${actor} must handle unavailable runners`);
|
|
228
|
+
assert.match(text, /ordinary functional or structural verification/i, `${actor} must specify fallback checks`);
|
|
229
|
+
}
|
|
230
|
+
containsAll(delegation, ["by default", "Forward this policy"]);
|
|
231
|
+
containsAll(worker, ["before implementation", "ordinary functional or structural verification", "no meaningful RED"]);
|
|
232
|
+
containsAll(verify, ["observed RED", "observed GREEN", "exception"]);
|
|
233
|
+
assert.doesNotMatch(skill, /SDD|OpenSpec/i, "the ODD-only skill must not prime SDD");
|
|
234
|
+
assert.doesNotMatch(core + delegation + worker + support + skill + wrapper, /If tests exist, use strict TDD/i);
|
|
205
235
|
});
|
|
206
236
|
|
|
207
237
|
test("mandatory delegation triggers are behavioral in the lazy canonical port and the always-on ODD step", () => {
|
|
@@ -212,12 +242,12 @@ test("mandatory delegation triggers are behavioral in the lazy canonical port an
|
|
|
212
242
|
"**Mapping trigger",
|
|
213
243
|
"**Writer trigger",
|
|
214
244
|
"**Preparation trigger:**",
|
|
215
|
-
"**
|
|
245
|
+
"**Context backstop:**",
|
|
216
246
|
"pause and delegate the next bounded unit of work",
|
|
217
247
|
"**Route declaration:**",
|
|
218
248
|
"record the chosen route per task",
|
|
219
249
|
"so skipped delegation is observable instead of silent",
|
|
220
|
-
"These triggers
|
|
250
|
+
"These triggers only choose between direct inline and delegated direct inside ODD",
|
|
221
251
|
]) {
|
|
222
252
|
assert.ok(delegation.includes(clause), `lazy canonical port is missing mandatory delegation clause: ${clause}`);
|
|
223
253
|
}
|
|
@@ -233,19 +263,19 @@ test("mandatory delegation triggers are behavioral in the lazy canonical port an
|
|
|
233
263
|
|
|
234
264
|
test("core and lazy canonical trigger lists agree in numbering and semantics", () => {
|
|
235
265
|
for (const entry of [
|
|
236
|
-
"1. **
|
|
266
|
+
"1. **Evidence-budget rule**",
|
|
237
267
|
"2. **Multi-file write rule**",
|
|
238
268
|
"3. **Incident rule**",
|
|
239
|
-
"4. **
|
|
269
|
+
"4. **Context backstop**",
|
|
240
270
|
"5. **Verification rule**",
|
|
241
271
|
]) {
|
|
242
272
|
assert.ok(core.includes(entry), `always-on core trigger list is missing: ${entry}`);
|
|
243
273
|
}
|
|
244
274
|
for (const entry of [
|
|
245
|
-
"1. **Mapping trigger (
|
|
275
|
+
"1. **Mapping trigger (Evidence-budget rule):**",
|
|
246
276
|
"2. **Writer trigger (Multi-file write rule):**",
|
|
247
277
|
"3. **Incident rule:**",
|
|
248
|
-
"4. **
|
|
278
|
+
"4. **Context backstop:**",
|
|
249
279
|
"5. **Verification rule**",
|
|
250
280
|
]) {
|
|
251
281
|
assert.ok(delegation.includes(entry), `lazy canonical trigger list is missing: ${entry}`);
|
|
@@ -255,17 +285,41 @@ test("core and lazy canonical trigger lists agree in numbering and semantics", (
|
|
|
255
285
|
"**Write rule**",
|
|
256
286
|
"**Context rule**",
|
|
257
287
|
"**Per-action rule**",
|
|
258
|
-
"**Optional SDD rule**",
|
|
259
288
|
]) {
|
|
260
289
|
assert.ok(!delegation.includes(stale), `reconciled canonical list retains stale trigger framing: ${stale}`);
|
|
261
290
|
}
|
|
262
291
|
});
|
|
263
292
|
|
|
293
|
+
// Evidence-budget rule (gentle-shell#1587, measured in gentle-ai#5139): every
|
|
294
|
+
// routing surface states the same numbers, and the retired file-count and
|
|
295
|
+
// tool-call triggers are gone from all of them.
|
|
296
|
+
test("evidence-budget numbers agree across routing surfaces and retired triggers are gone", () => {
|
|
297
|
+
const surfaces: Record<string, string> = {
|
|
298
|
+
"assets/orchestrator.md": core,
|
|
299
|
+
"assets/orchestrator-delegation.md": delegation,
|
|
300
|
+
"skills/gentle-ai/SKILL.md": read("skills/gentle-ai/SKILL.md"),
|
|
301
|
+
};
|
|
302
|
+
for (const [path, text] of Object.entries(surfaces)) {
|
|
303
|
+
containsAll(text, [
|
|
304
|
+
"**Evidence-budget rule**",
|
|
305
|
+
"at most 3 calls",
|
|
306
|
+
"~10k tokens",
|
|
307
|
+
"at most ~2k tokens",
|
|
308
|
+
"`path:line`",
|
|
309
|
+
"~150k tokens",
|
|
310
|
+
"Context backstop",
|
|
311
|
+
]);
|
|
312
|
+
assert.doesNotMatch(text, /4-file rule|20 tool calls|5 exploratory (?:file )?reads/, `${path} keeps a retired trigger`);
|
|
313
|
+
}
|
|
314
|
+
for (const agent of ["assets/agents/gentle-ai-explore.md", "assets/agents/gentle-ai-verify.md"]) {
|
|
315
|
+
containsAll(read(agent), ["at most ~2k tokens", "`path:line`"]);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
264
319
|
test("ODD protocol is always-on in the rendered system prompt and runs by default", () => {
|
|
265
320
|
const orderedClauses = [
|
|
266
321
|
"Default workflow: Organic Driven Development (MANDATORY)",
|
|
267
322
|
"predefined workflow of this orchestrator",
|
|
268
|
-
"SDD is a branch inside ODD",
|
|
269
323
|
"Never describe this workflow only when asked about it: run it.",
|
|
270
324
|
"1. **Authorize.**",
|
|
271
325
|
"2. **Explore.**",
|
|
@@ -277,6 +331,7 @@ test("ODD protocol is always-on in the rendered system prompt and runs by defaul
|
|
|
277
331
|
"Tell the user in one line which feature document was created and how many tasks it holds",
|
|
278
332
|
"6. **Implement task by task.**",
|
|
279
333
|
"7. **Close.**",
|
|
334
|
+
"call `gentle_odd_phase` only when the primary session's ODD phase actually changes",
|
|
280
335
|
"Harness principles:",
|
|
281
336
|
"# el Gentleman Orchestrator",
|
|
282
337
|
];
|
|
@@ -298,15 +353,11 @@ test("ODD protocol is always-on in the rendered system prompt and runs by defaul
|
|
|
298
353
|
wrapper.includes("Organic Driven Development (ODD) is the predefined workflow for every request"),
|
|
299
354
|
"missing contract: extensions/gentle-ai.ts harness principle",
|
|
300
355
|
);
|
|
301
|
-
|
|
302
|
-
wrapper.includes(
|
|
303
|
-
"I run Organic Driven Development by default and SDD/OpenSpec when explicitly selected",
|
|
304
|
-
),
|
|
305
|
-
"missing contract: extensions/gentle-ai.ts identity sentence",
|
|
306
|
-
);
|
|
356
|
+
// The parent owns the injected identity; its migration is outside this suite's edit surface.
|
|
307
357
|
assert.ok(
|
|
308
358
|
core.includes("ODD (Default Workflow, harness section above) is mandatory on every request"),
|
|
309
359
|
"missing contract: assets/orchestrator.md pointer sentence",
|
|
310
360
|
);
|
|
311
361
|
containsAll(core, ["orchestrator-delegation.md", "orchestrator-memory.md"]);
|
|
362
|
+
assert.doesNotMatch(core + delegation + memory, /SDD|sdd-|OpenSpec|openspec/i);
|
|
312
363
|
});
|
|
@@ -35,7 +35,6 @@ const MIN_CONTROLLED_LONG_ASSETS_ROOT_CHARS = 93;
|
|
|
35
35
|
|
|
36
36
|
const LAZY_ASSET_NAMES = [
|
|
37
37
|
"orchestrator.md",
|
|
38
|
-
"sdd-orchestrator-workflow.md",
|
|
39
38
|
"orchestrator-delegation.md",
|
|
40
39
|
"orchestrator-memory.md",
|
|
41
40
|
"orchestrator-skills.md",
|
|
@@ -193,16 +192,17 @@ const TARGET_FILE: Record<Target, string> = {
|
|
|
193
192
|
// Line numbers below are 1-indexed against tests/fixtures/orchestrator.pre-diet.md
|
|
194
193
|
// (frozen byte-identical copy of assets/orchestrator.md at 23,047 B / 312 lines).
|
|
195
194
|
const DISPOSITION_MAP: DispositionRange[] = [
|
|
196
|
-
{ lines: [1, 4], target: "
|
|
195
|
+
{ lines: [1, 4], target: "replaced", label: "Header + bind: retired phase qualification" },
|
|
197
196
|
{ lines: [5, 8], target: "core", label: "Identity Contract" },
|
|
198
197
|
{ lines: [9, 13], target: "core", label: "Core Role" },
|
|
199
198
|
{ lines: [15, 15], target: "core", label: "Language Boundary heading" },
|
|
200
199
|
{ lines: [17, 17], target: "core", label: "Language Boundary LB1 pointer" },
|
|
201
200
|
{ lines: [19, 19], target: "delegation", label: "Language Boundary LB2 (subagent-English)" },
|
|
202
|
-
{ lines: [21, 21], target: "
|
|
201
|
+
{ lines: [21, 21], target: "replaced", label: "Language Boundary LB3: retired artifact types" },
|
|
203
202
|
{ lines: [23, 23], target: "core", label: "Language Boundary LB4 (public comment language)" },
|
|
204
|
-
{ lines: [25,
|
|
205
|
-
{ lines: [
|
|
203
|
+
{ lines: [25, 28], target: "delegation", label: "Language Boundary LB5 (exceptions)" },
|
|
204
|
+
{ lines: [29, 29], target: "obsolete", label: "Retired artifact exception" },
|
|
205
|
+
{ lines: [31, 40], target: "replaced", label: "Mental Model: ODD-only" },
|
|
206
206
|
{ lines: [42, 42], target: "core", label: "Work Routing Ladder heading" },
|
|
207
207
|
{
|
|
208
208
|
lines: [44, 97],
|
|
@@ -251,7 +251,7 @@ const DISPOSITION_MAP: DispositionRange[] = [
|
|
|
251
251
|
target: "obsolete",
|
|
252
252
|
label: "Parent-selected review lens table replaced by native RAR lens ownership (#312)",
|
|
253
253
|
},
|
|
254
|
-
{ lines: [183, 191], target: "
|
|
254
|
+
{ lines: [183, 191], target: "obsolete", label: "Retired workflow pointer" },
|
|
255
255
|
{ lines: [193, 193], target: "core", label: "Memory Contract heading" },
|
|
256
256
|
{
|
|
257
257
|
lines: [195, 195],
|
|
@@ -263,9 +263,9 @@ const DISPOSITION_MAP: DispositionRange[] = [
|
|
|
263
263
|
target: "replaced",
|
|
264
264
|
label: "Verbose non-SDD memory forwarding replaced by compact ownership (#3417)",
|
|
265
265
|
},
|
|
266
|
-
{ lines: [203, 230], target: "
|
|
266
|
+
{ lines: [203, 230], target: "replaced", label: "Retired phase keys; memory lifecycle remains" },
|
|
267
267
|
{ lines: [232, 232], target: "core", label: "Skill Registry Protocol heading" },
|
|
268
|
-
{ lines: [234, 253], target: "
|
|
268
|
+
{ lines: [234, 253], target: "replaced", label: "Skill resolution retained without phase roles" },
|
|
269
269
|
{ lines: [255, 255], target: "core", label: "Intent-Driven Skill Discovery heading" },
|
|
270
270
|
{ lines: [257, 276], target: "skills", label: "Intent-Driven Skill Discovery detail" },
|
|
271
271
|
{ lines: [278, 283], target: "core", label: "Safety" },
|
|
@@ -284,8 +284,6 @@ const fixtureLines = readFileSync(FIXTURE_PATH, "utf8").split("\n");
|
|
|
284
284
|
// Fixture line 36 is superseded by ODD (#1035); 187 and 191 predate
|
|
285
285
|
// root-relative lazy assets and canonical-authority resolution. Keep coverage by asserting the
|
|
286
286
|
// intentionally updated production wording instead of weakening the range.
|
|
287
|
-
const CURRENT_SDD_WORKFLOW_PATH = "`sdd-orchestrator-workflow.md`";
|
|
288
|
-
const CURRENT_HARD_PREFLIGHT_INVARIANT = "Hard preflight invariant: `openspec/config.yaml`, existing SDD changes, installed `.pi`/global SDD assets, or a todo named \"preflight\" are not session preflight. Do not mark SDD preflight complete, start `sdd-init`, launch SDD subagents/chains, or move to explore/proposal/spec/design/tasks until this session has an injected `## SDD Session Preflight` block or a canonical-authority resolution. Defaults and capability constraints may resolve fields without confirmation prompts; preserve unresolved-choice and safety gates.";
|
|
289
287
|
const SUPERSEDED_LIFECYCLE_REVIEW_LINES = new Set([
|
|
290
288
|
70,
|
|
291
289
|
// 74/77: the loose mode-choice background lines were replaced by the
|
|
@@ -321,25 +319,7 @@ for (const range of DISPOSITION_MAP) {
|
|
|
321
319
|
const trimmed = raw.trim();
|
|
322
320
|
const expected =
|
|
323
321
|
ln === 36 ? "- Substantial authorized work: use ODD; track feature progress automatically." :
|
|
324
|
-
|
|
325
|
-
ln === 221 ? "do not switch the selected store" :
|
|
326
|
-
// Research returns findings; other phases keep direct backend ownership.
|
|
327
|
-
ln === 205 ? trimmed.replace("Each SDD phase", "Except for output-only `sdd-research`, each SDD phase") :
|
|
328
|
-
ln === 185 ? trimmed.replace("apply/verify/sync/archive", "apply/verify/archive") :
|
|
329
|
-
ln === 187
|
|
330
|
-
? CURRENT_SDD_WORKFLOW_PATH
|
|
331
|
-
: ln === 191
|
|
332
|
-
? CURRENT_HARD_PREFLIGHT_INVARIANT
|
|
333
|
-
: trimmed;
|
|
334
|
-
// #1051 retires the standalone sync row and its artifact key, not
|
|
335
|
-
// the surrounding memory/recovery contract or historical fixture.
|
|
336
|
-
if (ln === 216 || ln === 220) {
|
|
337
|
-
assert.ok(!targetContent.includes(trimmed), `retired sync contract remains at fixture:${ln}`);
|
|
338
|
-
assert.match(targetContent, /sdd\/<change>\/archive-report/);
|
|
339
|
-
assert.match(targetContent, /sdd\/<change>\/verify-report/);
|
|
340
|
-
assert.doesNotMatch(targetContent, /sdd\/<change>\/sync-report|\| `sdd-sync`/);
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
322
|
+
trimmed;
|
|
343
323
|
if (SUPERSEDED_LIFECYCLE_REVIEW_LINES.has(ln)) {
|
|
344
324
|
assert.ok(
|
|
345
325
|
!targetContent.includes(trimmed),
|
|
@@ -370,11 +350,11 @@ for (const range of DISPOSITION_MAP) {
|
|
|
370
350
|
|
|
371
351
|
test("core-alone: load-bearing direct-delegation tokens remain without lazy union", () => {
|
|
372
352
|
const core = readRealAsset("orchestrator.md");
|
|
373
|
-
assert.match(core, /
|
|
353
|
+
assert.match(core, /Evidence-budget rule/);
|
|
374
354
|
assert.match(core, /Multi-file write rule/);
|
|
375
355
|
assert.match(core, /Incident rule/);
|
|
376
356
|
assert.match(core, /Verification rule/);
|
|
377
|
-
assert.match(core, /
|
|
357
|
+
assert.match(core, /Context backstop/);
|
|
378
358
|
});
|
|
379
359
|
|
|
380
360
|
test("core-alone: dynamic Gentle AI ownership replaces package lifecycle instructions", () => {
|
|
@@ -420,7 +400,7 @@ test("relocated lazy bodies are not double-delivered in the always-on core", ()
|
|
|
420
400
|
);
|
|
421
401
|
assert.doesNotMatch(
|
|
422
402
|
rendered,
|
|
423
|
-
/###
|
|
403
|
+
/### Organic feature continuity/,
|
|
424
404
|
"memory-only body leaked into the always-on core",
|
|
425
405
|
);
|
|
426
406
|
assert.doesNotMatch(
|
|
@@ -472,7 +452,7 @@ test("every compressed lazy-file pointer in the core still names the material it
|
|
|
472
452
|
},
|
|
473
453
|
{
|
|
474
454
|
file: "orchestrator-memory.md",
|
|
475
|
-
mustName: ["
|
|
455
|
+
mustName: ["ODD task continuity", "memory lifecycle"],
|
|
476
456
|
},
|
|
477
457
|
{
|
|
478
458
|
file: "orchestrator-skills.md",
|
|
@@ -497,10 +477,5 @@ test("every compressed lazy-file pointer in the core still names the material it
|
|
|
497
477
|
);
|
|
498
478
|
}
|
|
499
479
|
}
|
|
500
|
-
|
|
501
|
-
// surrounding paragraphs already name the material at length.
|
|
502
|
-
assert.match(
|
|
503
|
-
core,
|
|
504
|
-
/SDD phases, native dispatcher rules, status contract, preflight\/init guards, artifact-store policy, execution mode, Strict TDD forwarding, phase result contract, and review workload guard/,
|
|
505
|
-
);
|
|
480
|
+
assert.doesNotMatch(core, /SDD|sdd-|OpenSpec|openspec/i);
|
|
506
481
|
});
|
|
@@ -72,18 +72,18 @@ test("rendered parent prompt keeps the RDD boundary while omitting lifecycle mir
|
|
|
72
72
|
assert.ok(Buffer.byteLength(rendered, "utf8") <= 8192, "the rendered parent prompt must stay below the reduced 8 KiB budget");
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
test("static prompts retain
|
|
76
|
-
for (const heading of ["##
|
|
75
|
+
test("static prompts retain ODD and delegated-work guidance without SDD", () => {
|
|
76
|
+
for (const heading of ["## Memory Contract", "## Work Routing Ladder"]) {
|
|
77
77
|
assert.ok(core.includes(heading), `core lost ${heading}`);
|
|
78
78
|
}
|
|
79
79
|
for (const heading of [
|
|
80
80
|
"### Delegation Rules",
|
|
81
81
|
"#### Background Subagent Policy",
|
|
82
82
|
"#### Allowed edit surfaces (MANDATORY)",
|
|
83
|
-
"### 3. SDD (optional)",
|
|
84
83
|
]) {
|
|
85
84
|
assert.ok(delegation.includes(heading), `delegation lost ${heading}`);
|
|
86
85
|
}
|
|
86
|
+
assert.doesNotMatch(staticPrompts, /SDD|sdd-|OpenSpec|openspec/i);
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
test("always-on parent prompt requires a narrow writer edit surface before launch", () => {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { withOverlayRepaint } from "../lib/overlay-repaint.ts";
|
|
4
|
+
import type { TUI } from "@earendil-works/pi-tui";
|
|
5
|
+
|
|
6
|
+
// Overlay close repaint: wrapping an overlay's done callback must tear the
|
|
7
|
+
// overlay down first (done), then force a FULL terminal repaint
|
|
8
|
+
// (invalidate + requestRender) so a fullscreen overlay's stale cell state
|
|
9
|
+
// cannot survive the close. Paint failures are swallowed; done failures are not.
|
|
10
|
+
|
|
11
|
+
function fakeTui() {
|
|
12
|
+
const calls: string[] = [];
|
|
13
|
+
const tui = {
|
|
14
|
+
invalidate: () => {
|
|
15
|
+
calls.push("invalidate");
|
|
16
|
+
},
|
|
17
|
+
requestRender: () => {
|
|
18
|
+
calls.push("requestRender");
|
|
19
|
+
},
|
|
20
|
+
} as unknown as TUI;
|
|
21
|
+
return { tui, calls };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
test("withOverlayRepaint: forces a full render (requestRender(true)) after done", () => {
|
|
25
|
+
const calls: string[] = [];
|
|
26
|
+
const tui = {
|
|
27
|
+
requestRender: (force?: boolean) => {
|
|
28
|
+
calls.push(`requestRender:${force === true}`);
|
|
29
|
+
},
|
|
30
|
+
} as unknown as TUI;
|
|
31
|
+
const close = withOverlayRepaint<string | null>(tui, (result) => {
|
|
32
|
+
calls.push(`done:${String(result)}`);
|
|
33
|
+
});
|
|
34
|
+
close(null);
|
|
35
|
+
assert.deepEqual(calls, ["done:null", "requestRender:true"]);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("withOverlayRepaint: forwards null results (plain close)", () => {
|
|
39
|
+
const calls: string[] = [];
|
|
40
|
+
const tui = {
|
|
41
|
+
requestRender: (force?: boolean) => {
|
|
42
|
+
calls.push(`requestRender:${force === true}`);
|
|
43
|
+
},
|
|
44
|
+
} as unknown as TUI;
|
|
45
|
+
const seen: Array<string | null> = [];
|
|
46
|
+
const close = withOverlayRepaint<string | null>(tui, (result) => {
|
|
47
|
+
seen.push(result);
|
|
48
|
+
});
|
|
49
|
+
close(null);
|
|
50
|
+
assert.deepEqual(seen, [null]);
|
|
51
|
+
assert.deepEqual(calls, ["requestRender:true"]);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("withOverlayRepaint: paint failure is swallowed, done result still delivered", () => {
|
|
55
|
+
const seen: Array<string | null> = [];
|
|
56
|
+
const tui = {
|
|
57
|
+
requestRender: () => {
|
|
58
|
+
throw new Error("EIO");
|
|
59
|
+
},
|
|
60
|
+
} as unknown as TUI;
|
|
61
|
+
const close = withOverlayRepaint<string | null>(tui, (result) => {
|
|
62
|
+
seen.push(result);
|
|
63
|
+
});
|
|
64
|
+
assert.doesNotThrow(() => close(null));
|
|
65
|
+
assert.deepEqual(seen, [null]);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("withOverlayRepaint: done failure propagates (overlay contract, not paint)", () => {
|
|
69
|
+
const { tui } = fakeTui();
|
|
70
|
+
const close = withOverlayRepaint<string | null>(tui, () => {
|
|
71
|
+
throw new Error("overlay teardown failed");
|
|
72
|
+
});
|
|
73
|
+
assert.throws(() => close(null), /overlay teardown failed/);
|
|
74
|
+
});
|