@nklisch/pi-enhanced 0.1.3 → 0.1.4

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 (235) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/node_modules/@nklisch/pi-clearance/README.md +10 -5
  3. package/node_modules/@nklisch/pi-clearance/docs/ARCHITECTURE.md +8 -5
  4. package/node_modules/@nklisch/pi-clearance/docs/CONFIGURATION.md +25 -35
  5. package/node_modules/@nklisch/pi-clearance/docs/DEVELOPER_GUIDE.md +13 -11
  6. package/node_modules/@nklisch/pi-clearance/docs/PACK_AUTHORING.md +5 -4
  7. package/node_modules/@nklisch/pi-clearance/docs/PRINCIPLES.md +14 -10
  8. package/node_modules/@nklisch/pi-clearance/docs/REFERENCE_PATTERNS.md +1 -1
  9. package/node_modules/@nklisch/pi-clearance/docs/REVIEWER_PROMPTS.md +12 -8
  10. package/node_modules/@nklisch/pi-clearance/docs/RULE_PACKS.md +1 -1
  11. package/node_modules/@nklisch/pi-clearance/docs/SPEC.md +7 -6
  12. package/node_modules/@nklisch/pi-clearance/docs/TUNE.md +2 -2
  13. package/node_modules/@nklisch/pi-clearance/docs/USER_GUIDE.md +7 -3
  14. package/node_modules/@nklisch/pi-clearance/docs/VISION.md +3 -3
  15. package/node_modules/@nklisch/pi-clearance/native/clearance-core.darwin-x64.node +0 -0
  16. package/node_modules/@nklisch/pi-clearance/native/clearance-core.linux-arm64-gnu.node +0 -0
  17. package/node_modules/@nklisch/pi-clearance/native/clearance-core.win32-arm64-msvc.node +0 -0
  18. package/node_modules/@nklisch/pi-clearance/native/clearance-core.win32-x64-msvc.node +0 -0
  19. package/node_modules/@nklisch/pi-clearance/package.json +9 -5
  20. package/node_modules/@nklisch/pi-clearance/src/config/config-command-plans.ts +79 -3
  21. package/node_modules/@nklisch/pi-clearance/src/config/config-command-writer.ts +7 -1
  22. package/node_modules/@nklisch/pi-clearance/src/config/defaults.ts +42 -0
  23. package/node_modules/@nklisch/pi-clearance/src/config/gated-tools.ts +7 -0
  24. package/node_modules/@nklisch/pi-clearance/src/config/loader.ts +7 -1
  25. package/node_modules/@nklisch/pi-clearance/src/config/pack-enablement-writer.ts +1 -0
  26. package/node_modules/@nklisch/pi-clearance/src/config/paths.ts +14 -3
  27. package/node_modules/@nklisch/pi-clearance/src/config/persistence.ts +135 -0
  28. package/node_modules/@nklisch/pi-clearance/src/config/schema.ts +74 -26
  29. package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCase.ts +1 -1
  30. package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCaseCategory.ts +1 -1
  31. package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCaseExpectation.ts +1 -1
  32. package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCaseResult.ts +1 -1
  33. package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCaseResultOutcome.ts +1 -1
  34. package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCaseSource.ts +1 -1
  35. package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialValidationReport.ts +1 -1
  36. package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialValidationStatus.ts +1 -1
  37. package/node_modules/@nklisch/pi-clearance/src/contracts/BashBlock.ts +1 -1
  38. package/node_modules/@nklisch/pi-clearance/src/contracts/BashCommandShape.ts +1 -1
  39. package/node_modules/@nklisch/pi-clearance/src/contracts/BashConditionalArm.ts +1 -1
  40. package/node_modules/@nklisch/pi-clearance/src/contracts/BashControlConstruct.ts +1 -1
  41. package/node_modules/@nklisch/pi-clearance/src/contracts/BashFlag.ts +1 -1
  42. package/node_modules/@nklisch/pi-clearance/src/contracts/BashForLoopKeywordSpans.ts +1 -1
  43. package/node_modules/@nklisch/pi-clearance/src/contracts/BashIteratorEntry.ts +1 -1
  44. package/node_modules/@nklisch/pi-clearance/src/contracts/BashIteratorEntryKind.ts +1 -1
  45. package/node_modules/@nklisch/pi-clearance/src/contracts/BashListOperator.ts +1 -1
  46. package/node_modules/@nklisch/pi-clearance/src/contracts/BashLoopVariableReference.ts +1 -1
  47. package/node_modules/@nklisch/pi-clearance/src/contracts/BashPathFact.ts +1 -1
  48. package/node_modules/@nklisch/pi-clearance/src/contracts/BashPathFactContext.ts +1 -1
  49. package/node_modules/@nklisch/pi-clearance/src/contracts/BashPathFactProvenance.ts +1 -1
  50. package/node_modules/@nklisch/pi-clearance/src/contracts/BashPathFactProvenanceEntry.ts +1 -1
  51. package/node_modules/@nklisch/pi-clearance/src/contracts/BashPathFacts.ts +1 -1
  52. package/node_modules/@nklisch/pi-clearance/src/contracts/BashPipeline.ts +1 -1
  53. package/node_modules/@nklisch/pi-clearance/src/contracts/BashStage.ts +1 -1
  54. package/node_modules/@nklisch/pi-clearance/src/contracts/BashStageProgram.ts +1 -1
  55. package/node_modules/@nklisch/pi-clearance/src/contracts/BlockOperator.ts +1 -1
  56. package/node_modules/@nklisch/pi-clearance/src/contracts/CapturedOutcome.ts +1 -1
  57. package/node_modules/@nklisch/pi-clearance/src/contracts/CommandFamilyKey.ts +1 -1
  58. package/node_modules/@nklisch/pi-clearance/src/contracts/CommandFamilySummary.ts +1 -1
  59. package/node_modules/@nklisch/pi-clearance/src/contracts/CompileError.ts +1 -1
  60. package/node_modules/@nklisch/pi-clearance/src/contracts/CompositionOperator.ts +1 -1
  61. package/node_modules/@nklisch/pi-clearance/src/contracts/CompoundBodyReason.ts +1 -1
  62. package/node_modules/@nklisch/pi-clearance/src/contracts/CompoundFeatureReason.ts +1 -1
  63. package/node_modules/@nklisch/pi-clearance/src/contracts/CompoundForm.ts +1 -1
  64. package/node_modules/@nklisch/pi-clearance/src/contracts/CompoundIteratorReason.ts +1 -1
  65. package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusEntry.ts +1 -1
  66. package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusExpectedLabel.ts +1 -1
  67. package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusFidelity.ts +1 -1
  68. package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusQueryModel.ts +1 -1
  69. package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusQuerySummary.ts +1 -1
  70. package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusQuerySummarySnapshot.ts +1 -1
  71. package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusRecord.ts +1 -1
  72. package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusSource.ts +1 -1
  73. package/node_modules/@nklisch/pi-clearance/src/contracts/CountByLabel.ts +1 -1
  74. package/node_modules/@nklisch/pi-clearance/src/contracts/Decision.ts +1 -1
  75. package/node_modules/@nklisch/pi-clearance/src/contracts/DecisionEffect.ts +1 -1
  76. package/node_modules/@nklisch/pi-clearance/src/contracts/DecisionProvenance.ts +1 -1
  77. package/node_modules/@nklisch/pi-clearance/src/contracts/DecisionSource.ts +1 -1
  78. package/node_modules/@nklisch/pi-clearance/src/contracts/DiagnosticSeverity.ts +1 -1
  79. package/node_modules/@nklisch/pi-clearance/src/contracts/EffectivePolicy.ts +1 -1
  80. package/node_modules/@nklisch/pi-clearance/src/contracts/EmbeddedShellProjection.ts +1 -1
  81. package/node_modules/@nklisch/pi-clearance/src/contracts/EnvironmentAssignment.ts +1 -1
  82. package/node_modules/@nklisch/pi-clearance/src/contracts/IteratorSourceKind.ts +1 -1
  83. package/node_modules/@nklisch/pi-clearance/src/contracts/LoopQuoteKind.ts +1 -1
  84. package/node_modules/@nklisch/pi-clearance/src/contracts/LoopVariableUnknownReason.ts +1 -1
  85. package/node_modules/@nklisch/pi-clearance/src/contracts/MatcherExpr.ts +1 -1
  86. package/node_modules/@nklisch/pi-clearance/src/contracts/MutationShapeKind.ts +1 -1
  87. package/node_modules/@nklisch/pi-clearance/src/contracts/MutationTrustBoundaryClassification.ts +1 -1
  88. package/node_modules/@nklisch/pi-clearance/src/contracts/MutationTrustBoundaryKind.ts +1 -1
  89. package/node_modules/@nklisch/pi-clearance/src/contracts/PackCompileResult.ts +1 -1
  90. package/node_modules/@nklisch/pi-clearance/src/contracts/PackWarningLevel.ts +1 -1
  91. package/node_modules/@nklisch/pi-clearance/src/contracts/ParsedEvidence.ts +1 -1
  92. package/node_modules/@nklisch/pi-clearance/src/contracts/ParsedShapeSummary.ts +1 -1
  93. package/node_modules/@nklisch/pi-clearance/src/contracts/PathAccess.ts +1 -1
  94. package/node_modules/@nklisch/pi-clearance/src/contracts/PathFactProjectScope.ts +1 -1
  95. package/node_modules/@nklisch/pi-clearance/src/contracts/PathFactsRequirement.ts +1 -1
  96. package/node_modules/@nklisch/pi-clearance/src/contracts/PathFactsResolvedConfig.ts +1 -1
  97. package/node_modules/@nklisch/pi-clearance/src/contracts/PathNormalization.ts +1 -1
  98. package/node_modules/@nklisch/pi-clearance/src/contracts/PathScope.ts +1 -1
  99. package/node_modules/@nklisch/pi-clearance/src/contracts/PathScopeMatcherExpr.ts +1 -1
  100. package/node_modules/@nklisch/pi-clearance/src/contracts/PathScopeMatcherMode.ts +1 -1
  101. package/node_modules/@nklisch/pi-clearance/src/contracts/PathUnknownReason.ts +1 -1
  102. package/node_modules/@nklisch/pi-clearance/src/contracts/PathUsageKind.ts +1 -1
  103. package/node_modules/@nklisch/pi-clearance/src/contracts/PiBuiltinToolOperation.ts +1 -1
  104. package/node_modules/@nklisch/pi-clearance/src/contracts/PiBuiltinToolPathInput.ts +1 -1
  105. package/node_modules/@nklisch/pi-clearance/src/contracts/PiBuiltinToolShape.ts +1 -1
  106. package/node_modules/@nklisch/pi-clearance/src/contracts/PiBuiltinToolSpec.ts +1 -1
  107. package/node_modules/@nklisch/pi-clearance/src/contracts/PiFileMutationToolName.ts +1 -1
  108. package/node_modules/@nklisch/pi-clearance/src/contracts/PiToolMutationFacts.ts +1 -1
  109. package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyPack.ts +1 -1
  110. package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyPackDocLink.ts +1 -1
  111. package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyPackExample.ts +1 -1
  112. package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyPackMetadata.ts +1 -1
  113. package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyPackWarning.ts +1 -1
  114. package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyRule.ts +1 -1
  115. package/node_modules/@nklisch/pi-clearance/src/contracts/ProposalNotRunReason.ts +1 -1
  116. package/node_modules/@nklisch/pi-clearance/src/contracts/ProposalNotRunSeverity.ts +1 -1
  117. package/node_modules/@nklisch/pi-clearance/src/contracts/QuoteKind.ts +1 -1
  118. package/node_modules/@nklisch/pi-clearance/src/contracts/Redirect.ts +1 -1
  119. package/node_modules/@nklisch/pi-clearance/src/contracts/RedirectStream.ts +1 -1
  120. package/node_modules/@nklisch/pi-clearance/src/contracts/RedirectTargetKind.ts +1 -1
  121. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayCorpus.ts +1 -1
  122. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDelta.ts +1 -1
  123. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaBlockedSummary.ts +1 -1
  124. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaChangedRecord.ts +1 -1
  125. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaFamily.ts +1 -1
  126. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaImprovement.ts +1 -1
  127. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaRegression.ts +1 -1
  128. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaStatus.ts +1 -1
  129. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaTransitionCount.ts +1 -1
  130. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayPathFacts.ts +1 -1
  131. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayReviewerMode.ts +1 -1
  132. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayReviewerOutcome.ts +1 -1
  133. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayStatus.ts +1 -1
  134. package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayedDecision.ts +1 -1
  135. package/node_modules/@nklisch/pi-clearance/src/contracts/ShapeDiagnostic.ts +1 -1
  136. package/node_modules/@nklisch/pi-clearance/src/contracts/SourceFidelity.ts +1 -1
  137. package/node_modules/@nklisch/pi-clearance/src/contracts/SourceSpan.ts +1 -1
  138. package/node_modules/@nklisch/pi-clearance/src/contracts/Substitution.ts +1 -1
  139. package/node_modules/@nklisch/pi-clearance/src/contracts/SubstitutionKind.ts +1 -1
  140. package/node_modules/@nklisch/pi-clearance/src/contracts/ToolCallIdentity.ts +1 -1
  141. package/node_modules/@nklisch/pi-clearance/src/contracts/ToolPathAccess.ts +1 -1
  142. package/node_modules/@nklisch/pi-clearance/src/contracts/ToolPathFact.ts +1 -1
  143. package/node_modules/@nklisch/pi-clearance/src/contracts/ToolPathFactContext.ts +1 -1
  144. package/node_modules/@nklisch/pi-clearance/src/contracts/ToolPathFacts.ts +1 -1
  145. package/node_modules/@nklisch/pi-clearance/src/contracts/ToolPathUsage.ts +1 -1
  146. package/node_modules/@nklisch/pi-clearance/src/contracts/ToolShape.ts +1 -1
  147. package/node_modules/@nklisch/pi-clearance/src/contracts/UnknownPathBehavior.ts +1 -1
  148. package/node_modules/@nklisch/pi-clearance/src/contracts/UnknownToolShape.ts +1 -1
  149. package/node_modules/@nklisch/pi-clearance/src/contracts/index.ts +1 -1
  150. package/node_modules/@nklisch/pi-clearance/src/index.ts +33 -2
  151. package/node_modules/@nklisch/pi-clearance/src/native/loader.ts +12 -6
  152. package/node_modules/@nklisch/pi-clearance/src/replay/reviewer-config-proposals.ts +7 -4
  153. package/node_modules/@nklisch/pi-clearance/src/runtime/allow-request-message.ts +21 -0
  154. package/node_modules/@nklisch/pi-clearance/src/runtime/auto-reviewer-read-models.ts +165 -8
  155. package/node_modules/@nklisch/pi-clearance/src/runtime/command-registry.ts +1 -1
  156. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/allow.ts +26 -2
  157. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/packs.ts +6 -6
  158. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/scope.ts +5 -5
  159. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/actions.ts +11 -0
  160. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/dispatcher.ts +274 -1
  161. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/model-options.ts +52 -0
  162. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/native-ui.ts +54 -67
  163. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/panels/reviewer.ts +19 -3
  164. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/panels/scope.ts +2 -11
  165. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/panels.ts +10 -1
  166. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/read-model.ts +47 -13
  167. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings.ts +32 -37
  168. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/status.ts +3 -0
  169. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/types.ts +14 -5
  170. package/node_modules/@nklisch/pi-clearance/src/runtime/handler.ts +36 -0
  171. package/node_modules/@nklisch/pi-clearance/src/runtime/mode-prompt.ts +0 -1
  172. package/node_modules/@nklisch/pi-clearance/src/runtime/model-adapter.ts +5 -1
  173. package/node_modules/@nklisch/pi-clearance/src/runtime/reviewer-context.ts +73 -10
  174. package/node_modules/@nklisch/pi-clearance/src/runtime/reviewer-prompts.ts +186 -175
  175. package/node_modules/@nklisch/pi-clearance/src/runtime/reviewer.ts +26 -6
  176. package/node_modules/@nklisch/pi-plugins/dist/infrastructure/state/local-lock-filesystem.d.ts +23 -1
  177. package/node_modules/@nklisch/pi-plugins/dist/infrastructure/state/local-lock-filesystem.js +46 -50
  178. package/node_modules/@nklisch/pi-plugins/dist/infrastructure/state/local-lock-filesystem.js.map +1 -1
  179. package/node_modules/@nklisch/pi-plugins/dist/runtime/mcp/pi-mcp-adapter-package.js +2 -2
  180. package/node_modules/@nklisch/pi-plugins/dist/runtime/mcp/pi-mcp-adapter-package.js.map +1 -1
  181. package/node_modules/@nklisch/pi-plugins/dist/runtime/mcp/pi-mcp-adapter-runtime.js +2 -2
  182. package/node_modules/@nklisch/pi-plugins/dist/runtime/mcp/pi-mcp-adapter-runtime.js.map +1 -1
  183. package/node_modules/@nklisch/pi-plugins/dist/runtime/subagents/pi-subagents-lifecycle.js +1 -1
  184. package/node_modules/@nklisch/pi-plugins/dist/runtime/subagents/pi-subagents-package.js +2 -2
  185. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/README.md +41 -31
  186. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/dist/public.d.ts +2 -1
  187. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/FORK-MAINTENANCE.md +17 -11
  188. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/VISION.md +14 -7
  189. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/architecture/architecture.md +11 -19
  190. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/comparison-with-upstream.md +58 -53
  191. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/package.json +2 -2
  192. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/agent-type-resolution.ts +43 -0
  193. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/agent-types.ts +11 -6
  194. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/custom-agents.ts +13 -6
  195. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/default-agents.ts +0 -52
  196. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/thinking-levels.ts +12 -0
  197. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/handlers/interrupt.ts +5 -2
  198. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/handlers/lifecycle.ts +3 -3
  199. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/index.ts +7 -6
  200. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/create-subagent-session.ts +7 -2
  201. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/parent-snapshot.ts +11 -3
  202. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-manager.ts +26 -56
  203. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-session.ts +48 -9
  204. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-state.ts +32 -0
  205. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent.ts +105 -17
  206. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/composite-subagent-observer.ts +4 -0
  207. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/notification.ts +50 -46
  208. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/renderer.ts +1 -1
  209. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/subagent-events-observer.ts +15 -0
  210. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/runtime.ts +2 -0
  211. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service-adapter.ts +35 -6
  212. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service.ts +1 -0
  213. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/model-label.ts +19 -0
  214. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/prompts.ts +24 -1
  215. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/session-config.ts +11 -6
  216. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/settings.ts +70 -3
  217. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/agent-tool.ts +27 -10
  218. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/background-spawner.ts +6 -2
  219. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/foreground-runner.ts +12 -3
  220. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-report.ts +17 -3
  221. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-tool.ts +13 -20
  222. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/result-renderer.ts +6 -1
  223. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/spawn-config.ts +16 -16
  224. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/steer-tool.ts +12 -4
  225. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/types.ts +2 -2
  226. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/agent-widget.ts +24 -11
  227. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/display.ts +10 -7
  228. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/glyphs.ts +7 -0
  229. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigation.ts +34 -25
  230. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigator.ts +30 -10
  231. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/subagents-settings.ts +58 -13
  232. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/widget-renderer.ts +32 -19
  233. package/node_modules/@nklisch/pi-plugins/package.json +3 -3
  234. package/package.json +1 -1
  235. package/test/verify-bundle.mjs +4 -0
@@ -1,5 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
 
3
+ import { DEFAULT_PROJECT_SCOPE_BEHAVIOR } from "./defaults.ts";
4
+ import { isExactNonBashToolName } from "./gated-tools.ts";
3
5
  import type { JsonPatchOperation } from "../replay/proposal-schema.ts";
4
6
  import { isHighCostReviewerModel } from "../runtime/reviewer-model.ts";
5
7
  import type {
@@ -91,10 +93,12 @@ export function inferScopePreset(
91
93
  const fields = SCOPE_PRESET_FIELDS[preset];
92
94
  if (
93
95
  scope.safeHomeUseDefaults === fields.safeHomeUseDefaults &&
94
- (scope.agentSupportUseDefaults ?? true) ===
96
+ (scope.agentSupportUseDefaults !== false) ===
95
97
  fields.agentSupportUseDefaults &&
96
- (scope.homePathBehavior ?? "allow") === fields.homePathBehavior &&
97
- (scope.sensitivePathBehavior ?? "review") ===
98
+ (scope.homePathBehavior ?? DEFAULT_PROJECT_SCOPE_BEHAVIOR.homePathBehavior) ===
99
+ fields.homePathBehavior &&
100
+ (scope.sensitivePathBehavior ??
101
+ DEFAULT_PROJECT_SCOPE_BEHAVIOR.sensitivePathBehavior) ===
98
102
  fields.sensitivePathBehavior &&
99
103
  scope.unknownPathBehavior === fields.unknownPathBehavior
100
104
  ) {
@@ -137,6 +141,10 @@ export type ReviewNoteDisplayCommandChange =
137
141
  | { readonly kind: "show-model-label"; readonly enabled: boolean }
138
142
  | { readonly kind: "accent"; readonly enabled: boolean };
139
143
 
144
+ export type GatedToolCommandChange =
145
+ | { readonly kind: "add"; readonly toolName: string }
146
+ | { readonly kind: "remove"; readonly toolName: string };
147
+
140
148
  export type ReviewerCommandChange =
141
149
  | { readonly kind: "prompt-posture"; readonly promptPosture: string }
142
150
  | { readonly kind: "context-mode"; readonly contextMode: ReviewerContextMode }
@@ -181,6 +189,74 @@ export type PlanProjectScopeCommandChangeResult =
181
189
  }
182
190
  | { readonly ok: false; readonly reason: string };
183
191
 
192
+ export function planGatedToolCommandChange(input: {
193
+ readonly change: GatedToolCommandChange;
194
+ readonly resolvedConfig: ResolvedConfig;
195
+ }):
196
+ | { readonly ok: true; readonly plan: ConfigCommandPlan }
197
+ | { readonly ok: false; readonly reason: string } {
198
+ const toolName = input.change.toolName;
199
+ if (!isExactNonBashToolName(toolName)) {
200
+ return {
201
+ ok: false,
202
+ reason:
203
+ "gatedTools accepts exact non-Bash tool names only; wildcards, whitespace, and bash are not allowed",
204
+ };
205
+ }
206
+
207
+ const snapshots = input.resolvedConfig.sourceSnapshots;
208
+ if (snapshots === undefined) {
209
+ return {
210
+ ok: false,
211
+ reason:
212
+ "resolved config did not include source snapshots; reload config before planning a gated-tool write",
213
+ };
214
+ }
215
+
216
+ const before = cloneJsonish({
217
+ ...snapshots.global,
218
+ gatedTools: [...(snapshots.global.gatedTools ?? [])],
219
+ });
220
+ const after = cloneJsonish(before) as Mutable<GlobalConfig>;
221
+ const current = [...before.gatedTools];
222
+ const next =
223
+ input.change.kind === "add"
224
+ ? current.includes(toolName)
225
+ ? current
226
+ : [...current, toolName]
227
+ : current.filter((candidate) => candidate !== toolName);
228
+ after.gatedTools = next;
229
+ const patch = fieldPatch("/gatedTools", current, next);
230
+ const title =
231
+ input.change.kind === "add"
232
+ ? `Gate non-Bash tool ${toolName}`
233
+ : `Stop gating non-Bash tool ${toolName}`;
234
+ const planWithoutId = {
235
+ target: { kind: "global", path: snapshots.paths.globalConfigFile },
236
+ title,
237
+ summary:
238
+ patch.length === 0
239
+ ? `${title}; no config write is needed.`
240
+ : `${title}; only this exact tool name will use Clearance analysis and policy.`,
241
+ patch,
242
+ before,
243
+ after,
244
+ requiredAcknowledgementCodes: [],
245
+ warnings: [],
246
+ } satisfies Omit<ConfigCommandPlan, "id">;
247
+
248
+ return {
249
+ ok: true,
250
+ plan: {
251
+ id: deterministicPlanId({
252
+ gatedToolChange: input.change,
253
+ ...planWithoutId,
254
+ }),
255
+ ...planWithoutId,
256
+ },
257
+ };
258
+ }
259
+
184
260
  export function planModeCommandChange(input: {
185
261
  readonly mode: ClearanceMode;
186
262
  readonly resolvedConfig: ResolvedConfig;
@@ -12,6 +12,10 @@ import type { TSchema } from "@sinclair/typebox";
12
12
 
13
13
  import type { JsonPatchOperation } from "../replay/proposal-schema.ts";
14
14
  import type { ResolvedConfig } from "./loader.ts";
15
+ import {
16
+ type ConfigPersistenceKind,
17
+ serializeSparseConfigText,
18
+ } from "./persistence.ts";
15
19
  import {
16
20
  type GlobalConfig,
17
21
  GlobalConfigSchema,
@@ -101,6 +105,7 @@ export type ConfigCommandApplyResult =
101
105
  interface AtomicConfigWriteInput {
102
106
  readonly planId: string;
103
107
  readonly targetPath: string;
108
+ readonly configKind: ConfigPersistenceKind;
104
109
  readonly value: GlobalConfig | ProjectOverlayConfig;
105
110
  readonly hadExistingFile: boolean;
106
111
  readonly reloadConfig: () => Promise<ResolvedConfig>;
@@ -184,6 +189,7 @@ export async function applyConfigCommandPlan(
184
189
  return await writeConfigTargetAndValidate({
185
190
  planId: plan.id,
186
191
  targetPath: plan.target.path,
192
+ configKind: plan.target.kind,
187
193
  value: patched.value,
188
194
  hadExistingFile: readResult.exists,
189
195
  reloadConfig: dependencies.reloadConfig,
@@ -207,7 +213,7 @@ export async function writeConfigTargetAndValidate(
207
213
  await mkdir(path.dirname(input.targetPath), { recursive: true });
208
214
  await writeFile(
209
215
  tempPath,
210
- `${JSON.stringify(input.value, null, 2)}\n`,
216
+ serializeSparseConfigText(input.configKind, input.value),
211
217
  "utf8",
212
218
  );
213
219
  tempPresent = true;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * User-visible defaults shared by schema normalization and status/read models.
3
+ * Keeping these values in one module prevents a new schema default from being
4
+ * mistaken for a customization by diagnostics.
5
+ */
6
+ export const DEFAULT_REVIEWER_PROMPT_POSTURE = "reviewer.default" as const;
7
+ export const DEFAULT_REVIEWER_CONTEXT_MODE = "recentContext" as const;
8
+
9
+ export const DEFAULT_REVIEWER_TOKEN_BUDGET = {
10
+ window: "24h",
11
+ limit: null,
12
+ } as const;
13
+
14
+ export const DEFAULT_REVIEWER_RECENT_CONTEXT = {
15
+ decisionLimit: 25,
16
+ decisionWindow: "2h",
17
+ conversationTurns: 3,
18
+ userTurns: 5,
19
+ conversationCharLimit: 6000,
20
+ } as const;
21
+
22
+ export const DEFAULT_REVIEWER_ESCALATION = {
23
+ enabled: true,
24
+ denialLimit: 3,
25
+ window: "10m",
26
+ } as const;
27
+
28
+ export const DEFAULT_UNKNOWN_TOOL_POSTURE = "allow" as const;
29
+
30
+ export const DEFAULT_PROJECT_SCOPE_BEHAVIOR = {
31
+ safeHomeUseDefaults: true,
32
+ agentSupportUseDefaults: true,
33
+ unknownPathBehavior: "review",
34
+ sensitivePathBehavior: "review",
35
+ homePathBehavior: "allow",
36
+ } as const;
37
+
38
+ export const DEFAULT_REVIEW_NOTE_DISPLAY = {
39
+ mode: "reason+accent",
40
+ showModelLabel: false,
41
+ accent: true,
42
+ } as const;
@@ -0,0 +1,7 @@
1
+ /** Exact-name syntax for the global non-Bash Clearance opt-in list. */
2
+ export const EXACT_NON_BASH_TOOL_NAME_PATTERN =
3
+ "^(?!bash$)[^\\s*?\\[\\]{}]+$" as const;
4
+
5
+ export function isExactNonBashToolName(value: string): boolean {
6
+ return value.length > 0 && new RegExp(EXACT_NON_BASH_TOOL_NAME_PATTERN).test(value);
7
+ }
@@ -3,6 +3,7 @@ import { homedir, tmpdir } from "node:os";
3
3
  import path from "node:path";
4
4
  import type { Static, TSchema } from "@sinclair/typebox";
5
5
  import type { DecisionEffect } from "../policy/core.ts";
6
+ import { DEFAULT_UNKNOWN_TOOL_POSTURE } from "./defaults.ts";
6
7
  import {
7
8
  isHighCostReviewerModel,
8
9
  parseModelSpec,
@@ -69,6 +70,7 @@ export interface ResolvedReviewerConfig {
69
70
  readonly decisionLimit: number;
70
71
  readonly decisionWindow: string;
71
72
  readonly conversationTurns: number;
73
+ readonly userTurns?: number;
72
74
  readonly conversationCharLimit: number;
73
75
  };
74
76
  readonly escalation: {
@@ -133,6 +135,8 @@ export interface ResolvedConfig {
133
135
  */
134
136
  readonly sourceSnapshots?: ResolvedConfigSourceSnapshots;
135
137
  readonly mode: ClearanceMode;
138
+ /** Exact non-Bash tool names explicitly opted into Clearance gating. */
139
+ readonly gatedTools?: readonly string[];
136
140
  readonly unknownToolPosture: DecisionEffect;
137
141
  readonly projectScope: ResolvedProjectScope;
138
142
  readonly packEnablement: ResolvedPackEnablement;
@@ -250,7 +254,9 @@ export async function loadConfig(
250
254
  repository: repositoryPolicy,
251
255
  },
252
256
  mode,
253
- unknownToolPosture: globalConfig.unknownToolPosture ?? "allow",
257
+ gatedTools: [...globalConfig.gatedTools],
258
+ unknownToolPosture:
259
+ globalConfig.unknownToolPosture ?? DEFAULT_UNKNOWN_TOOL_POSTURE,
254
260
  projectScope: projectScopeResolution.scope,
255
261
  packEnablement,
256
262
  globalPacks: withPackSource(globalConfig.packs, "user-global"),
@@ -113,6 +113,7 @@ export async function applyPackEnablementPlan(
113
113
  return await writeConfigTargetAndValidate({
114
114
  planId: plan.id,
115
115
  targetPath: plan.targetPath,
116
+ configKind: plan.request.scope,
116
117
  value: patched.value,
117
118
  hadExistingFile: readResult.exists,
118
119
  reloadConfig: dependencies.reloadConfig,
@@ -12,12 +12,18 @@ export interface ConfigPaths {
12
12
  }
13
13
 
14
14
  export function resolveUserConfigRoot(): string {
15
- const home = homedir();
15
+ // Read the environment explicitly so isolated callers honor the process
16
+ // environment even when os.homedir() is cached.
17
+ const home = firstNonEmpty(
18
+ process.env.HOME,
19
+ process.env.USERPROFILE,
20
+ ) ?? homedir();
16
21
 
17
22
  switch (process.platform) {
18
23
  case "win32":
19
24
  return path.join(
20
- process.env.LOCALAPPDATA ?? path.join(home, "AppData", "Local"),
25
+ firstNonEmpty(process.env.LOCALAPPDATA) ??
26
+ path.join(home, "AppData", "Local"),
21
27
  "pi",
22
28
  "pi-clearance",
23
29
  );
@@ -31,13 +37,18 @@ export function resolveUserConfigRoot(): string {
31
37
  );
32
38
  default:
33
39
  return path.join(
34
- process.env.XDG_CONFIG_HOME ?? path.join(home, ".config"),
40
+ firstNonEmpty(process.env.XDG_CONFIG_HOME) ??
41
+ path.join(home, ".config"),
35
42
  "pi",
36
43
  "pi-clearance",
37
44
  );
38
45
  }
39
46
  }
40
47
 
48
+ function firstNonEmpty(...values: readonly (string | undefined)[]): string | undefined {
49
+ return values.find((value) => value !== undefined && value.length > 0);
50
+ }
51
+
41
52
  export function projectKeyFor(cwd: string): string {
42
53
  const absolute = path.resolve(cwd);
43
54
  const hash = createHash("sha256").update(absolute).digest("hex").slice(0, 8);
@@ -0,0 +1,135 @@
1
+ import {
2
+ CONFIG_SCHEMA_VERSION,
3
+ type GlobalConfig,
4
+ GlobalConfigSchema,
5
+ normalizeConfig,
6
+ type ProjectOverlayConfig,
7
+ ProjectOverlaySchema,
8
+ } from "./schema.ts";
9
+
10
+ export type ConfigPersistenceKind = "global" | "project";
11
+ export type NormalizedConfig = GlobalConfig | ProjectOverlayConfig;
12
+
13
+ /** The only JSON shape emitted for user-owned Clearance config files. */
14
+ export type SparseConfigDocument = Readonly<Record<string, unknown>> & {
15
+ readonly version: typeof CONFIG_SCHEMA_VERSION;
16
+ };
17
+
18
+ const OMIT = Symbol("omit-default");
19
+
20
+ /**
21
+ * Serialize a schema-normalized runtime config without materializing defaults.
22
+ *
23
+ * Defaults are obtained by normalizing the schema's version-only seed rather
24
+ * than copied here. Objects are compacted recursively; arrays are semantic
25
+ * values and are retained as a whole whenever they differ from their default.
26
+ */
27
+ export function serializeSparseConfig(
28
+ kind: ConfigPersistenceKind,
29
+ config: NormalizedConfig,
30
+ ): SparseConfigDocument {
31
+ const defaults = normalizedDefaults(kind);
32
+ const compacted = compactValue(config, defaults);
33
+ const document: Record<string, unknown> = {
34
+ version: config.version,
35
+ };
36
+
37
+ if (isRecord(compacted)) {
38
+ for (const [key, value] of Object.entries(compacted)) {
39
+ if (key !== "version") {
40
+ document[key] = value;
41
+ }
42
+ }
43
+ }
44
+
45
+ return canonicalize(document) as SparseConfigDocument;
46
+ }
47
+
48
+ /** Return the canonical on-disk representation for a normalized config. */
49
+ export function serializeSparseConfigText(
50
+ kind: ConfigPersistenceKind,
51
+ config: NormalizedConfig,
52
+ ): string {
53
+ return `${JSON.stringify(serializeSparseConfig(kind, config), null, 2)}\n`;
54
+ }
55
+
56
+ function normalizedDefaults(kind: ConfigPersistenceKind): NormalizedConfig {
57
+ const schema = kind === "global" ? GlobalConfigSchema : ProjectOverlaySchema;
58
+ const result = normalizeConfig(schema, { version: CONFIG_SCHEMA_VERSION });
59
+ if (!result.ok) {
60
+ throw new Error(`failed to normalize ${kind} config defaults`);
61
+ }
62
+ return result.value;
63
+ }
64
+
65
+ function compactValue(value: unknown, defaults: unknown): unknown {
66
+ if (jsonEqual(value, defaults)) {
67
+ return OMIT;
68
+ }
69
+
70
+ if (Array.isArray(value)) {
71
+ return value.map((entry) => cloneJsonish(entry));
72
+ }
73
+
74
+ if (isRecord(value)) {
75
+ const defaultRecord = isRecord(defaults) ? defaults : undefined;
76
+ const compacted: Record<string, unknown> = {};
77
+ for (const key of orderedKeys(Object.keys(value))) {
78
+ const child = compactValue(value[key], defaultRecord?.[key]);
79
+ if (child !== OMIT) {
80
+ compacted[key] = child;
81
+ }
82
+ }
83
+ return Object.keys(compacted).length === 0 ? OMIT : compacted;
84
+ }
85
+
86
+ return value;
87
+ }
88
+
89
+ function canonicalize(value: unknown): unknown {
90
+ if (Array.isArray(value)) {
91
+ return value.map(canonicalize);
92
+ }
93
+
94
+ if (isRecord(value)) {
95
+ const result: Record<string, unknown> = {};
96
+ for (const key of orderedKeys(Object.keys(value))) {
97
+ result[key] = canonicalize(value[key]);
98
+ }
99
+ return result;
100
+ }
101
+
102
+ return value;
103
+ }
104
+
105
+ function orderedKeys(keys: readonly string[]): readonly string[] {
106
+ return [...keys].sort((left, right) => {
107
+ if (left === "version") return -1;
108
+ if (right === "version") return 1;
109
+ return left < right ? -1 : left > right ? 1 : 0;
110
+ });
111
+ }
112
+
113
+ function jsonEqual(left: unknown, right: unknown): boolean {
114
+ return (
115
+ JSON.stringify(canonicalize(left)) === JSON.stringify(canonicalize(right))
116
+ );
117
+ }
118
+
119
+ function cloneJsonish<T>(value: T): T {
120
+ if (Array.isArray(value)) {
121
+ return value.map((entry) => cloneJsonish(entry)) as T;
122
+ }
123
+
124
+ if (isRecord(value)) {
125
+ return Object.fromEntries(
126
+ Object.entries(value).map(([key, entry]) => [key, cloneJsonish(entry)]),
127
+ ) as T;
128
+ }
129
+
130
+ return value;
131
+ }
132
+
133
+ function isRecord(value: unknown): value is Record<string, unknown> {
134
+ return typeof value === "object" && value !== null && !Array.isArray(value);
135
+ }
@@ -1,6 +1,18 @@
1
1
  import { type Static, type TSchema, Type } from "@sinclair/typebox";
2
2
  import { Value } from "@sinclair/typebox/value";
3
3
 
4
+ import {
5
+ DEFAULT_PROJECT_SCOPE_BEHAVIOR,
6
+ DEFAULT_REVIEWER_CONTEXT_MODE,
7
+ DEFAULT_REVIEWER_ESCALATION,
8
+ DEFAULT_REVIEWER_PROMPT_POSTURE,
9
+ DEFAULT_REVIEWER_RECENT_CONTEXT,
10
+ DEFAULT_REVIEWER_TOKEN_BUDGET,
11
+ DEFAULT_REVIEW_NOTE_DISPLAY,
12
+ DEFAULT_UNKNOWN_TOOL_POSTURE,
13
+ } from "./defaults.ts";
14
+ import { EXACT_NON_BASH_TOOL_NAME_PATTERN } from "./gated-tools.ts";
15
+
4
16
  export const CONFIG_SCHEMA_VERSION = 1 as const;
5
17
 
6
18
  const STRICT_OBJECT_OPTIONS = { additionalProperties: false } as const;
@@ -148,9 +160,11 @@ export const PolicyPackSchema = Type.Object(
148
160
 
149
161
  export const ReviewNoteDisplaySchema = Type.Object(
150
162
  {
151
- mode: reviewNoteModeLiteral({ default: "reason+accent" }),
152
- showModelLabel: Type.Boolean({ default: false }),
153
- accent: Type.Boolean({ default: true }),
163
+ mode: reviewNoteModeLiteral({ default: DEFAULT_REVIEW_NOTE_DISPLAY.mode }),
164
+ showModelLabel: Type.Boolean({
165
+ default: DEFAULT_REVIEW_NOTE_DISPLAY.showModelLabel,
166
+ }),
167
+ accent: Type.Boolean({ default: DEFAULT_REVIEW_NOTE_DISPLAY.accent }),
154
168
  },
155
169
  { ...STRICT_OBJECT_OPTIONS, default: {} },
156
170
  );
@@ -162,7 +176,7 @@ export const DisplayConfigSchema = Type.Object(
162
176
 
163
177
  export const ReviewerConfigSchema = Type.Object(
164
178
  {
165
- promptPosture: Type.String({ default: "reviewer.default" }),
179
+ promptPosture: Type.String({ default: DEFAULT_REVIEWER_PROMPT_POSTURE }),
166
180
  promptAppends: Type.Array(Type.String(), { default: [] }),
167
181
  projectPromptAppends: Type.Array(Type.String(), { default: [] }),
168
182
  promptOverride: Type.Union([Type.String(), Type.Null()], { default: null }),
@@ -171,41 +185,58 @@ export const ReviewerConfigSchema = Type.Object(
171
185
  }),
172
186
  tokenBudget: Type.Object(
173
187
  {
174
- window: Type.String({ default: "24h" }),
175
- limit: Type.Union([Type.Number(), Type.Null()], { default: null }),
188
+ window: Type.String({ default: DEFAULT_REVIEWER_TOKEN_BUDGET.window }),
189
+ limit: Type.Union([Type.Number(), Type.Null()], {
190
+ default: DEFAULT_REVIEWER_TOKEN_BUDGET.limit,
191
+ }),
192
+ },
193
+ {
194
+ ...STRICT_OBJECT_OPTIONS,
195
+ default: DEFAULT_REVIEWER_TOKEN_BUDGET,
176
196
  },
177
- { ...STRICT_OBJECT_OPTIONS, default: { window: "24h", limit: null } },
178
197
  ),
179
198
  contextMode: Type.Union(
180
199
  [Type.Literal("minimal"), Type.Literal("recentContext")],
181
- { default: "recentContext" },
200
+ { default: DEFAULT_REVIEWER_CONTEXT_MODE },
182
201
  ),
183
202
  recentContext: Type.Object(
184
203
  {
185
- decisionLimit: Type.Integer({ default: 25 }),
186
- decisionWindow: Type.String({ default: "2h" }),
187
- conversationTurns: Type.Integer({ default: 3 }),
188
- conversationCharLimit: Type.Integer({ default: 6000 }),
204
+ decisionLimit: Type.Integer({
205
+ default: DEFAULT_REVIEWER_RECENT_CONTEXT.decisionLimit,
206
+ }),
207
+ decisionWindow: Type.String({
208
+ default: DEFAULT_REVIEWER_RECENT_CONTEXT.decisionWindow,
209
+ }),
210
+ conversationTurns: Type.Integer({
211
+ default: DEFAULT_REVIEWER_RECENT_CONTEXT.conversationTurns,
212
+ }),
213
+ userTurns: Type.Integer({
214
+ default: DEFAULT_REVIEWER_RECENT_CONTEXT.userTurns,
215
+ }),
216
+ conversationCharLimit: Type.Integer({
217
+ default: DEFAULT_REVIEWER_RECENT_CONTEXT.conversationCharLimit,
218
+ }),
189
219
  },
190
220
  {
191
221
  ...STRICT_OBJECT_OPTIONS,
192
222
  default: {
193
- decisionLimit: 25,
194
- decisionWindow: "2h",
195
- conversationTurns: 3,
196
- conversationCharLimit: 6000,
223
+ ...DEFAULT_REVIEWER_RECENT_CONTEXT,
197
224
  },
198
225
  },
199
226
  ),
200
227
  escalation: Type.Object(
201
228
  {
202
- enabled: Type.Boolean({ default: true }),
203
- denialLimit: Type.Integer({ default: 3 }),
204
- window: Type.String({ default: "10m" }),
229
+ enabled: Type.Boolean({
230
+ default: DEFAULT_REVIEWER_ESCALATION.enabled,
231
+ }),
232
+ denialLimit: Type.Integer({
233
+ default: DEFAULT_REVIEWER_ESCALATION.denialLimit,
234
+ }),
235
+ window: Type.String({ default: DEFAULT_REVIEWER_ESCALATION.window }),
205
236
  },
206
237
  {
207
238
  ...STRICT_OBJECT_OPTIONS,
208
- default: { enabled: true, denialLimit: 3, window: "10m" },
239
+ default: DEFAULT_REVIEWER_ESCALATION,
209
240
  },
210
241
  ),
211
242
  },
@@ -227,14 +258,25 @@ export const PackEnablementSchema = Type.Object(
227
258
  { ...STRICT_OBJECT_OPTIONS, default: {} },
228
259
  );
229
260
 
261
+ const GatedToolName = Type.String({
262
+ minLength: 1,
263
+ // Tool opt-in is deliberately exact-name only. Keep the field a strict
264
+ // schema boundary so wildcard/future-tool consent cannot slip into config.
265
+ pattern: EXACT_NON_BASH_TOOL_NAME_PATTERN,
266
+ });
267
+
230
268
  export const GlobalConfigSchema = Type.Object(
231
269
  {
232
270
  version: Type.Literal(CONFIG_SCHEMA_VERSION),
233
271
  mode: ClearanceModeLiteral,
272
+ gatedTools: Type.Array(GatedToolName, {
273
+ default: [],
274
+ uniqueItems: true,
275
+ }),
234
276
  unknownToolPosture: Type.Optional(
235
277
  Type.Union(
236
278
  [Type.Literal("allow"), Type.Literal("deny"), Type.Literal("review")],
237
- { default: "allow" },
279
+ { default: DEFAULT_UNKNOWN_TOOL_POSTURE },
238
280
  ),
239
281
  ),
240
282
  packs: Type.Array(PolicyPackSchema, { default: [] }),
@@ -263,13 +305,19 @@ export const ProjectScopeSchema = Type.Object(
263
305
  tempDirectories: pathListSchema(),
264
306
  deniedDirectories: pathListSchema(),
265
307
  safeHomeDirectories: pathListSchema(),
266
- safeHomeUseDefaults: Type.Boolean({ default: true }),
308
+ safeHomeUseDefaults: Type.Boolean({
309
+ default: DEFAULT_PROJECT_SCOPE_BEHAVIOR.safeHomeUseDefaults,
310
+ }),
267
311
  /** Optional custom Pi support roots; built-in roots remain enabled by default. */
268
312
  agentSupportDirectories: Type.Optional(pathListSchema()),
269
- agentSupportUseDefaults: Type.Optional(Type.Boolean({ default: true })),
313
+ agentSupportUseDefaults: Type.Optional(
314
+ Type.Boolean({
315
+ default: DEFAULT_PROJECT_SCOPE_BEHAVIOR.agentSupportUseDefaults,
316
+ }),
317
+ ),
270
318
  unknownPathBehavior: Type.Union(
271
319
  [Type.Literal("review"), Type.Literal("deny")],
272
- { default: "review" },
320
+ { default: DEFAULT_PROJECT_SCOPE_BEHAVIOR.unknownPathBehavior },
273
321
  ),
274
322
  /**
275
323
  * Behavior for paths the engine classifies as sensitive home
@@ -278,7 +326,7 @@ export const ProjectScopeSchema = Type.Object(
278
326
  */
279
327
  sensitivePathBehavior: Type.Union(
280
328
  [Type.Literal("review"), Type.Literal("deny")],
281
- { default: "review" },
329
+ { default: DEFAULT_PROJECT_SCOPE_BEHAVIOR.sensitivePathBehavior },
282
330
  ),
283
331
  /**
284
332
  * `"review"` claws back baseline home-scope read auto-allows so any
@@ -286,7 +334,7 @@ export const ProjectScopeSchema = Type.Object(
286
334
  */
287
335
  homePathBehavior: Type.Union(
288
336
  [Type.Literal("allow"), Type.Literal("review")],
289
- { default: "allow" },
337
+ { default: DEFAULT_PROJECT_SCOPE_BEHAVIOR.homePathBehavior },
290
338
  ),
291
339
  },
292
340
  { ...STRICT_OBJECT_OPTIONS, default: {} },
@@ -1,4 +1,4 @@
1
- // @generated by ts-rs; do not edit. Run `pnpm contracts:generate`.
1
+ // @generated by ts-rs; do not edit. Run `npm run contracts:generate`.
2
2
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
3
3
  import type { AdversarialCaseCategory } from "./AdversarialCaseCategory.ts";
4
4
  import type { AdversarialCaseExpectation } from "./AdversarialCaseExpectation.ts";
@@ -1,4 +1,4 @@
1
- // @generated by ts-rs; do not edit. Run `pnpm contracts:generate`.
1
+ // @generated by ts-rs; do not edit. Run `npm run contracts:generate`.
2
2
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
3
3
 
4
4
  export type AdversarialCaseCategory =
@@ -1,4 +1,4 @@
1
- // @generated by ts-rs; do not edit. Run `pnpm contracts:generate`.
1
+ // @generated by ts-rs; do not edit. Run `npm run contracts:generate`.
2
2
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
3
3
 
4
4
  export type AdversarialCaseExpectation =
@@ -1,4 +1,4 @@
1
- // @generated by ts-rs; do not edit. Run `pnpm contracts:generate`.
1
+ // @generated by ts-rs; do not edit. Run `npm run contracts:generate`.
2
2
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
3
3
  import type { AdversarialCaseCategory } from "./AdversarialCaseCategory.ts";
4
4
  import type { AdversarialCaseExpectation } from "./AdversarialCaseExpectation.ts";
@@ -1,4 +1,4 @@
1
- // @generated by ts-rs; do not edit. Run `pnpm contracts:generate`.
1
+ // @generated by ts-rs; do not edit. Run `npm run contracts:generate`.
2
2
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
3
3
 
4
4
  export type AdversarialCaseResultOutcome =
@@ -1,4 +1,4 @@
1
- // @generated by ts-rs; do not edit. Run `pnpm contracts:generate`.
1
+ // @generated by ts-rs; do not edit. Run `npm run contracts:generate`.
2
2
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
3
3
 
4
4
  export type AdversarialCaseSource =
@@ -1,4 +1,4 @@
1
- // @generated by ts-rs; do not edit. Run `pnpm contracts:generate`.
1
+ // @generated by ts-rs; do not edit. Run `npm run contracts:generate`.
2
2
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
3
3
  import type { AdversarialCase } from "./AdversarialCase.ts";
4
4
  import type { AdversarialCaseResult } from "./AdversarialCaseResult.ts";
@@ -1,4 +1,4 @@
1
- // @generated by ts-rs; do not edit. Run `pnpm contracts:generate`.
1
+ // @generated by ts-rs; do not edit. Run `npm run contracts:generate`.
2
2
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
3
3
 
4
4
  export type AdversarialValidationStatus = "not-run" | "passed" | "failed";
@@ -1,4 +1,4 @@
1
- // @generated by ts-rs; do not edit. Run `pnpm contracts:generate`.
1
+ // @generated by ts-rs; do not edit. Run `npm run contracts:generate`.
2
2
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
3
3
  import type { BashListOperator } from "./BashListOperator.ts";
4
4
  import type { BashPipeline } from "./BashPipeline.ts";
@@ -1,4 +1,4 @@
1
- // @generated by ts-rs; do not edit. Run `pnpm contracts:generate`.
1
+ // @generated by ts-rs; do not edit. Run `npm run contracts:generate`.
2
2
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
3
3
  import type { BashBlock } from "./BashBlock.ts";
4
4
  import type { BashPathFacts } from "./BashPathFacts.ts";