gentle-pi 4.2.0 → 4.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.
Files changed (202) hide show
  1. package/README.md +336 -137
  2. package/assets/agents/gentle-ai-explore.md +1 -0
  3. package/assets/agents/gentle-ai-verify.md +6 -4
  4. package/assets/agents/gentle-ai-worker.md +7 -1
  5. package/assets/orchestrator-delegation-reference.md +163 -0
  6. package/assets/orchestrator-delegation.md +25 -176
  7. package/assets/orchestrator-tracking.md +1 -1
  8. package/assets/orchestrator-verification.md +14 -8
  9. package/assets/orchestrator-writer.md +5 -1
  10. package/assets/orchestrator.md +9 -9
  11. package/bin/gentle-shell.mjs +170 -22
  12. package/contracts/review-provider-contract-mirror/provider-contract.lock.json +8 -7
  13. package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/README.md +7 -0
  14. package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/manifest.json +11 -2
  15. package/contracts/review-provider-contract-mirror/v1.4.0/bundle/routing/pi.md +92 -0
  16. package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/generated/provider-capabilities.baseline.json +8 -1
  17. package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/generated/provider-roles.baseline.json +1 -1
  18. package/docs/assets/diagrams/agent-orchestration.svg +54 -15
  19. package/docs/assets/diagrams/gentleman-workflow.svg +69 -11
  20. package/docs/assets/diagrams/measured-routing.svg +49 -0
  21. package/docs/assets/diagrams/native-review.svg +52 -12
  22. package/docs/assets/diagrams/odd-workflow.svg +128 -66
  23. package/docs/assets/diagrams/permission-modes.svg +51 -0
  24. package/docs/assets/features/audio-notifications.png +0 -0
  25. package/docs/assets/features/command-palette.png +0 -0
  26. package/docs/bundled-install.md +33 -3
  27. package/docs/delegated-verification.md +10 -8
  28. package/docs/gentle-agents-activity.md +11 -5
  29. package/docs/gentle-shell-uninstall.md +8 -1
  30. package/docs/gentle-shell.md +5 -4
  31. package/docs/install-wizard.md +8 -1
  32. package/docs/permission-modes.md +1 -1
  33. package/docs/readme-reference.md +107 -19
  34. package/docs/yolo-mode.md +21 -8
  35. package/extensions/codegraph-tools.ts +68 -6
  36. package/extensions/gentle-agents.ts +99 -12
  37. package/extensions/gentle-ai.ts +284 -52
  38. package/extensions/gentle-herdr-activity.ts +2 -3
  39. package/extensions/gentle-shell.ts +27 -12
  40. package/extensions/gentle-todo.ts +43 -9
  41. package/extensions/quiet-tools.ts +1 -1
  42. package/extensions/session-scratch.ts +365 -0
  43. package/extensions/startup-banner.ts +2 -3
  44. package/lib/agent-home.ts +8 -3
  45. package/lib/agents-protocol.ts +3 -0
  46. package/lib/agents-runner.ts +55 -6
  47. package/lib/agents-view.ts +3 -1
  48. package/lib/bounded-writer-admission.ts +51 -0
  49. package/lib/command-palette-catalog.ts +0 -4
  50. package/lib/commit-slice-signal.ts +100 -0
  51. package/lib/context-backstop.ts +84 -0
  52. package/lib/delivered-test-lint.ts +80 -0
  53. package/lib/destructive-command-guard.ts +120 -9
  54. package/lib/gauge-theme.ts +146 -0
  55. package/lib/gentle-ai-binary.ts +28 -7
  56. package/lib/gentle-shell-bundled.ts +39 -3
  57. package/lib/gentle-shell-import-pi.ts +233 -0
  58. package/lib/gentle-shell-launcher.ts +145 -11
  59. package/lib/gentle-shell-uninstall.ts +18 -1
  60. package/lib/herdr-activity.ts +24 -0
  61. package/lib/native-review-cli.ts +9 -1
  62. package/lib/orchestrator-discovery.ts +5 -1
  63. package/lib/orchestrator-presence.ts +9 -0
  64. package/lib/orchestrator-scope.ts +21 -3
  65. package/lib/provider-contract-bundle.ts +99 -53
  66. package/lib/review-candidate-view-owner.ts +29 -19
  67. package/lib/review-candidate-view.ts +36 -2
  68. package/lib/review-risk-assessment.ts +43 -38
  69. package/lib/review-session-standing-permission.ts +3 -1
  70. package/lib/session-profile-freeze.ts +30 -1
  71. package/lib/session-scratch.ts +474 -0
  72. package/lib/shell-bar.ts +25 -25
  73. package/lib/shell-changes-view.ts +80 -13
  74. package/lib/shell-gauge.ts +49 -6
  75. package/lib/shell-todo.ts +23 -4
  76. package/lib/shell-usage-view.ts +5 -1
  77. package/lib/shell-usage.ts +7 -7
  78. package/lib/verifier-admission.ts +29 -0
  79. package/lib/yolo-temp-scratch.ts +69 -0
  80. package/package.json +1 -2
  81. package/runtime/gentle-ai-binary.mjs +28 -7
  82. package/runtime/gentle-shell-bundled.mjs +38 -2
  83. package/runtime/gentle-shell-import-pi.mjs +234 -0
  84. package/runtime/gentle-shell-launcher.mjs +143 -9
  85. package/runtime/gentle-shell-uninstall.mjs +18 -1
  86. package/runtime/native-review-cli.mjs +8 -0
  87. package/runtime/review-risk-assessment.mjs +43 -38
  88. package/scripts/build-runtime-modules.mjs +1 -0
  89. package/scripts/bundled-engram-migration.mjs +125 -0
  90. package/scripts/gentle-ai-installer.mjs +10 -10
  91. package/scripts/installer-server.mjs +14 -4
  92. package/scripts/main-channel.mjs +3 -2
  93. package/scripts/run-test-suite.mjs +5 -0
  94. package/scripts/verify-package-files.mjs +19 -13
  95. package/skills/gentle-ai/SKILL.md +3 -3
  96. package/skills/work-unit-commits/SKILL.md +5 -3
  97. package/tests/agent-risk-escalation.test.ts +37 -10
  98. package/tests/agents-runner.test.ts +260 -3
  99. package/tests/autonomous-guard.test.ts +122 -0
  100. package/tests/bounded-writer-admission.test.ts +11 -3
  101. package/tests/card-content-policy.test.ts +19 -9
  102. package/tests/child-safety.test.ts +39 -0
  103. package/tests/codegraph-tools.test.ts +123 -2
  104. package/tests/command-palette.test.ts +14 -4
  105. package/tests/commit-slice-signal.test.ts +162 -0
  106. package/tests/context-backstop.test.ts +159 -0
  107. package/tests/delegate-for-reason-contract.test.ts +91 -24
  108. package/tests/delivered-test-lint.test.ts +105 -0
  109. package/tests/destructive-command-guard.test.ts +85 -1
  110. package/tests/engram-safety.test.ts +1 -1
  111. package/tests/fixtures/primary-session-prompt/gentleman.golden.md +143 -0
  112. package/tests/fixtures/provider-contract-bundle/v1.4.0/README.md +29 -0
  113. package/tests/fixtures/provider-contract-bundle/v1.4.0/manifest.json +83 -0
  114. package/tests/fixtures/provider-contract-bundle/v1.4.0/orchestration/pi.md +70 -0
  115. package/tests/fixtures/provider-contract-bundle/v1.4.0/routing/pi.md +92 -0
  116. package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/lens.schema.json +16 -0
  117. package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/refuter.schema.json +1 -0
  118. package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/targeted-validator.schema.json +1 -0
  119. package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/lens.json +1 -0
  120. package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/refuter.json +1 -0
  121. package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/targeted-validator.json +1 -0
  122. package/tests/gauge-theme.test.ts +120 -0
  123. package/tests/gentle-agents.test.ts +282 -3
  124. package/tests/gentle-ai-binary.test.ts +1 -1
  125. package/tests/gentle-ai-child-guards.test.ts +61 -0
  126. package/tests/gentle-ai-doctor-herdr.test.ts +94 -0
  127. package/tests/gentle-ai-installer.test.ts +51 -51
  128. package/tests/gentle-shell-bin.test.ts +163 -0
  129. package/tests/gentle-shell-bundled.test.ts +169 -6
  130. package/tests/gentle-shell-import-pi.test.ts +262 -0
  131. package/tests/gentle-shell-launcher.test.ts +79 -0
  132. package/tests/gentle-shell-uninstall.test.ts +30 -0
  133. package/tests/gentle-shell.test.ts +42 -9
  134. package/tests/gentle-todo.test.ts +179 -0
  135. package/tests/headless-delivery-question.test.ts +58 -0
  136. package/tests/herdr-activity.test.ts +34 -1
  137. package/tests/installer-server.test.ts +10 -2
  138. package/tests/installer-windows-bootstrap.test.ts +33 -4
  139. package/tests/native-review-capability-contract.test.ts +7 -1
  140. package/tests/native-review-parity.test.ts +22 -1
  141. package/tests/no-self-pause-contract.test.ts +5 -2
  142. package/tests/odd-integration.test.ts +5 -1
  143. package/tests/odd-routing-canonical-ratchet.test.ts +127 -162
  144. package/tests/odd-routing-contract.test.ts +115 -30
  145. package/tests/orchestrator-budget.test.ts +19 -8
  146. package/tests/orchestrator-discovery.test.ts +29 -0
  147. package/tests/orchestrator-rdd-ownership.test.ts +3 -1
  148. package/tests/orchestrator-scope.test.ts +66 -0
  149. package/tests/orchestrator-status-publication-contract.test.ts +12 -8
  150. package/tests/package-manifest.test.ts +24 -20
  151. package/tests/pi-update-launcher.test.ts +21 -2
  152. package/tests/primary-session-prompt.test.ts +101 -0
  153. package/tests/provider-contract-bundle.test.ts +118 -0
  154. package/tests/provider-contract-mirror.test.ts +24 -0
  155. package/tests/quiet-tool-rendering.test.ts +23 -0
  156. package/tests/rdd-aware-verification-contract.test.ts +29 -11
  157. package/tests/rdd-status-line.test.ts +79 -0
  158. package/tests/review-agent-end-preflight.test.ts +6 -0
  159. package/tests/review-candidate-view.test.ts +49 -0
  160. package/tests/review-contract-prompt.test.ts +5 -2
  161. package/tests/review-controller-native-routing.test.ts +14 -1
  162. package/tests/review-controller.test.ts +1 -1
  163. package/tests/review-host-relay-routing.test.ts +59 -2
  164. package/tests/review-loadout-rdd-off-sdk.test.ts +237 -0
  165. package/tests/review-owner-identity.test.ts +132 -0
  166. package/tests/review-risk-assessment.test.ts +163 -76
  167. package/tests/review-session-standing-permission-controller.test.ts +14 -1
  168. package/tests/review-session-standing-permission.test.ts +27 -1
  169. package/tests/run-test-suite.test.ts +15 -0
  170. package/tests/runtime-harness.mjs +16 -6
  171. package/tests/session-changes-shell.test.ts +1 -1
  172. package/tests/session-profile-freeze.test.ts +23 -0
  173. package/tests/session-scratch.test.ts +945 -0
  174. package/tests/session-subject-routing-contract.test.ts +2 -1
  175. package/tests/shell-bar.test.ts +7 -0
  176. package/tests/shell-changes-view.test.ts +137 -1
  177. package/tests/shell-gauge.test.ts +42 -0
  178. package/tests/small-task-inline-contract.test.ts +37 -0
  179. package/tests/standalone-config-home.test.ts +324 -0
  180. package/tests/startup-banner.test.ts +5 -4
  181. package/tests/startup-home-repo.test.ts +34 -0
  182. package/tests/support/orchestrator-modules.ts +1 -0
  183. package/tests/task-size-routing-contract.test.ts +69 -9
  184. package/tests/test-scratch-contract.test.ts +102 -0
  185. package/tests/test-strength-contract.test.ts +36 -1
  186. package/tests/tool-batching-contract.test.ts +64 -0
  187. package/tests/verification-proportionality.test.ts +46 -0
  188. package/tests/verifier-admission.test.ts +137 -0
  189. package/tests/verify-agent-contract.test.ts +8 -8
  190. package/tests/windows-hidden-processes.test.ts +5 -0
  191. package/tests/writer-edit-surface-scope.test.ts +3 -0
  192. package/tests/writer-feature-document-admission.test.ts +156 -0
  193. package/tests/yolo-mode.test.ts +18 -0
  194. package/tests/yolo-temp-scratch.test.ts +71 -0
  195. package/scripts/mirror-odd-routing.mjs +0 -242
  196. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/orchestration/pi.md +0 -0
  197. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/lens.schema.json +0 -0
  198. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/refuter.schema.json +0 -0
  199. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/targeted-validator.schema.json +0 -0
  200. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/lens.json +0 -0
  201. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/refuter.json +0 -0
  202. /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/targeted-validator.json +0 -0
@@ -123,6 +123,8 @@ console.log("ENV_PROBE=" + JSON.stringify({
123
123
  home,
124
124
  files: home && existsSync(home) ? readdirSync(home) : null,
125
125
  sentinel: process.env.TEST_ENV_SENTINEL,
126
+ tmp: process.env.TMPDIR ?? null,
127
+ tmpExists: process.env.TMPDIR ? existsSync(process.env.TMPDIR) : null,
126
128
  }));
127
129
  `);
128
130
  writeFileSync(stagesPath, JSON.stringify([
@@ -200,3 +202,16 @@ test("direct invocation rejects a malformed stages file with a non-zero exit", (
200
202
  assert.equal(result.status, 1);
201
203
  assert.match(result.stderr ?? "", /stages file must be an array/);
202
204
  });
205
+
206
+ // Harness roadmap T3: each subagent gets its own TMPDIR, and unit fixtures that
207
+ // leave a fake child unfinished would leave it behind; the stage owns them all.
208
+ test("unit stage gets a private TMPDIR removed after the stage; later stages keep the inherited one", (t) => {
209
+ const inherited = mkdtempSync(join(tmpdir(), "gentle-pi-caller-tmp-"));
210
+ t.after(() => rmSync(inherited, { recursive: true, force: true }));
211
+ const [unit, provider] = probeStageEnvironment(t, { TMPDIR: inherited });
212
+ assert.notEqual(unit.tmp, inherited);
213
+ assert.match(unit.tmp, /gentle-pi-unit-tmp-/);
214
+ assert.equal(unit.tmpExists, true, "the private TMPDIR exists while the stage runs");
215
+ assert.equal(existsSync(unit.tmp), false, "the private TMPDIR is removed after the stage");
216
+ assert.equal(provider.tmp, inherited);
217
+ });
@@ -604,9 +604,19 @@ async function run() {
604
604
  assert.equal(writerDispatch.task, task, "writer guard must not mutate child input");
605
605
  }
606
606
 
607
+ // S16: generic writers are admitted only for a task of an existing feature document (or at the measured
608
+ // context backstop); the accepted cases below name one, and an undocumented launch is told to work inline.
609
+ await mkdir(join(toolCwd, "odd", "tasks"), { recursive: true });
610
+ await writeFile(join(toolCwd, "odd", "tasks", "harness.md"), "# Harness\n");
611
+ const undocumentedWriter = await toolHook(
612
+ { toolName: "subagent_run", input: { agent: "gentle-ai-worker", task: "Implement the requested change.\n\n## Allowed edit surfaces\nextensions/gentle-ai.ts", mode: "task" } },
613
+ createCtx(toolCwd),
614
+ );
615
+ assert.equal(undocumentedWriter?.block, true, "an undocumented writer must be blocked before dispatch");
616
+ assert.match(undocumentedWriter?.reason ?? "", /write this unit inline yourself/);
607
617
  const scopedWriterDispatch = {
608
618
  agent: "gentle-ai-worker",
609
- task: "Implement the requested change.\n\n## Allowed edit surfaces\nextensions/gentle-ai.ts\ntests/runtime-harness.mjs",
619
+ task: "Spec: odd/tasks/harness.md, T1. Implement the requested change.\n\n## Allowed edit surfaces\nextensions/gentle-ai.ts\ntests/runtime-harness.mjs",
610
620
  mode: "task",
611
621
  };
612
622
  assert.equal(
@@ -620,7 +630,7 @@ async function run() {
620
630
  toolName: "subagent_run",
621
631
  input: {
622
632
  agent: "worker",
623
- task: "Implement the requested change.",
633
+ task: "Spec: odd/tasks/harness.md, T2. Implement the requested change.",
624
634
  context: "## Allowed edit surfaces\n- assets/orchestrator.md",
625
635
  mode: "task",
626
636
  },
@@ -717,7 +727,7 @@ async function run() {
717
727
  "valid scope followed by a repository-root scope",
718
728
  {
719
729
  agent: "gentle-ai-worker",
720
- task: "## Allowed edit surfaces\nextensions/gentle-ai.ts\n\n## Allowed edit surfaces\n.",
730
+ task: "Spec: odd/tasks/harness.md, T4.\n\n## Allowed edit surfaces\nextensions/gentle-ai.ts\n\n## Allowed edit surfaces\n.",
721
731
  mode: "task",
722
732
  },
723
733
  ],
@@ -725,7 +735,7 @@ async function run() {
725
735
  "valid task scope plus invalid context scope",
726
736
  {
727
737
  agent: "gentle-ai-worker",
728
- task: "## Allowed edit surfaces\nextensions/gentle-ai.ts",
738
+ task: "Spec: odd/tasks/harness.md, T5.\n\n## Allowed edit surfaces\nextensions/gentle-ai.ts",
729
739
  context: "## Allowed edit surfaces\n.",
730
740
  mode: "task",
731
741
  },
@@ -734,7 +744,7 @@ async function run() {
734
744
  "conflicting valid task and context scopes",
735
745
  {
736
746
  agent: "gentle-ai-worker",
737
- task: "## Allowed edit surfaces\nextensions/gentle-ai.ts",
747
+ task: "Spec: odd/tasks/harness.md, T6.\n\n## Allowed edit surfaces\nextensions/gentle-ai.ts",
738
748
  context: "## Allowed edit surfaces\ntests/runtime-harness.mjs",
739
749
  mode: "task",
740
750
  },
@@ -749,7 +759,7 @@ async function run() {
749
759
  toolName: "subagent_run",
750
760
  input: {
751
761
  agent: "gentle-ai-worker",
752
- task: "## Allowed edit surfaces\nextensions/gentle-ai.ts\ntests/runtime-harness.mjs\n\n## Allowed edit surfaces\n- `tests/runtime-harness.mjs`\n- `extensions/gentle-ai.ts`",
762
+ task: "Spec: odd/tasks/harness.md, T3.\n\n## Allowed edit surfaces\nextensions/gentle-ai.ts\ntests/runtime-harness.mjs\n\n## Allowed edit surfaces\n- `tests/runtime-harness.mjs`\n- `extensions/gentle-ai.ts`",
753
763
  mode: "task",
754
764
  },
755
765
  },
@@ -39,7 +39,7 @@ function fixture(entries: any[] = [], options: { root?: string; sessionId?: stri
39
39
  for(let i=0;i<200&&!overlay.view;i++){ if(await Promise.race([opened.then(()=>true),new Promise(r=>setTimeout(()=>r(false),5))])) break; }
40
40
  if(!overlay.view) return undefined;
41
41
  const text=overlay.view.render(200).join("\n");
42
- const trees=(overlay.view.trees as any[]).map(tree=>({root:tree.root as string,branch:tree.branch as string|undefined,files:tree.model.files.map((file:any)=>file.path) as string[],added:tree.model.added as number,deleted:tree.model.deleted as number}));
42
+ const trees=(overlay.view.children[0].trees as any[]).map(tree=>({root:tree.root as string,branch:tree.branch as string|undefined,files:tree.model.files.map((file:any)=>file.path) as string[],added:tree.model.added as number,deleted:tree.model.deleted as number}));
43
43
  overlay.close!(); await opened;
44
44
  return {text,trees,files:trees.flatMap(tree=>tree.files)};
45
45
  };
@@ -295,6 +295,29 @@ test("drift notice: shown once per distinct change of the defaults", () => {
295
295
  assert.equal(readFrozenInheritedProfile("session-a")?.profile?.name, "frontier", "the notice never adopts the new default");
296
296
  });
297
297
 
298
+ test("drift notice: an explicit binding learns its profile definition changed in profiles.json", () => {
299
+ const f = fixture({ team: { worker: { model: "openai/old" } } });
300
+ const opts = options(f, "session-a");
301
+ bindSessionProfile("session-a", "team", { worker: { model: "openai/old" } });
302
+ assert.equal(inheritedProfileDriftNotice(opts), undefined, "no drift while the definition matches the binding");
303
+
304
+ f.editProfile("team", { worker: { model: "openai/new" } });
305
+ const notice = inheritedProfileDriftNotice(opts);
306
+ assert.match(notice ?? "", /the profile definition changed to "team"/);
307
+ assert.match(notice ?? "", /this session keeps the binding from selection/);
308
+ assert.equal(inheritedProfileDriftNotice(opts), undefined, "the same change is not repeated");
309
+
310
+ f.editProfile("team", { worker: { model: "openai/older" } });
311
+ assert.match(inheritedProfileDriftNotice(opts) ?? "", /the profile definition changed to "team"/, "a different edit is a distinct change");
312
+ assert.equal(inheritedProfileDriftNotice(opts), undefined);
313
+ f.editProfile("team", { worker: { model: "openai/old" } });
314
+ assert.equal(inheritedProfileDriftNotice(opts), undefined, "reverting to the bound content is not drift");
315
+
316
+ const childOpts = options(f, "session-b", { GENTLE_PI_AGENTS_CHILD: "1" });
317
+ bindSessionProfile("session-b", "team", { worker: { model: "openai/old" } });
318
+ assert.equal(inheritedProfileDriftNotice(childOpts), undefined, "children never get the notice");
319
+ });
320
+
298
321
  test("drift notice: an edit of the default profile's content counts as a change", () => {
299
322
  const f = fixture();
300
323
  f.setActive("frontier");