@piagent/platform 1.5.5 → 1.6.1

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 (323) hide show
  1. package/CHANGELOG.md +166 -0
  2. package/README.md +25 -21
  3. package/README.vi.md +34 -5
  4. package/adapters/web-frontend/profile.json +2 -4
  5. package/architecture/layers.json +18 -3
  6. package/benchmarks/deep-logic-v1/SPECIALIST_PROTOCOL.vi.md +122 -0
  7. package/benchmarks/deep-logic-v1/grade.mjs +272 -10
  8. package/benchmarks/deep-logic-v1/project/apps/admin/src/billing-summary.js +3 -0
  9. package/benchmarks/deep-logic-v1/project/benchmark-contract/public-smoke.test.js +166 -0
  10. package/benchmarks/deep-logic-v1/project/package.json +1 -1
  11. package/benchmarks/deep-logic-v1/project/packages/billing/src/close-period.js +3 -0
  12. package/benchmarks/deep-logic-v1/project/packages/billing/src/plan-timeline.js +3 -0
  13. package/benchmarks/deep-logic-v1/project/test/smoke.test.js +7 -1
  14. package/benchmarks/deep-logic-v1/prompts/budgeted-context-graph.md +2 -0
  15. package/benchmarks/deep-logic-v1/prompts/fair-dependency-scheduler.md +2 -0
  16. package/benchmarks/deep-logic-v1/prompts/layered-policy-resolution.md +2 -0
  17. package/benchmarks/deep-logic-v1/prompts/resumable-stream-assembly.md +3 -1
  18. package/benchmarks/deep-logic-v1/prompts/revision-event-reconciliation.md +2 -0
  19. package/benchmarks/deep-logic-v1/prompts/temporal-usage-billing-close.md +123 -0
  20. package/benchmarks/deep-logic-v1/prompts/transactional-config-merge.md +2 -0
  21. package/benchmarks/deep-logic-v1/suite.json +51 -3
  22. package/benchmarks/deep-logic-v1/variant.mjs +22 -1
  23. package/benchmarks/production-v1/spend-control.v1.json +92 -0
  24. package/benchmarks/production-v1/suite.json +46 -3
  25. package/catalog/capabilities.json +18 -18
  26. package/docs/authority-manifest.md +1 -1
  27. package/docs/auto-delegation-policy.md +38 -73
  28. package/docs/command-reference-vietnamese.md +27 -35
  29. package/docs/context-engine.md +12 -4
  30. package/docs/context-window-policy.md +37 -1
  31. package/docs/distribution-standard.md +7 -7
  32. package/docs/en/architecture.md +27 -13
  33. package/docs/languages.json +4 -4
  34. package/docs/model-options.md +8 -5
  35. package/docs/operator-manual-vietnamese.md +27 -45
  36. package/docs/project-adapters.md +2 -2
  37. package/docs/publishing-for-teams.md +10 -0
  38. package/docs/quality-benchmark.md +427 -62
  39. package/docs/release-install-policy.md +10 -9
  40. package/docs/runtime-harness-standard.md +3 -3
  41. package/docs/runtime-policy-design.md +4 -4
  42. package/docs/runtime-quality-baseline.md +13 -6
  43. package/docs/security-threat-model.md +2 -2
  44. package/docs/subagent-orchestration-capabilities.md +19 -51
  45. package/docs/subagents-and-multiagent.md +21 -47
  46. package/docs/task-implementation-contract.md +3 -3
  47. package/docs/task-lifecycle-vietnamese.md +3 -3
  48. package/docs/team-onboarding.md +2 -2
  49. package/docs/usage-observability.md +7 -2
  50. package/docs/vi/architecture.md +27 -13
  51. package/docs-site/architecture.html +1 -1
  52. package/docs-site/benchmark.html +89 -95
  53. package/docs-site/commands.html +1 -1
  54. package/docs-site/content/benchmark.html +88 -94
  55. package/docs-site/content/en/benchmark.html +134 -90
  56. package/docs-site/content/en/index.html +19 -19
  57. package/docs-site/content/en/runtime.html +4 -4
  58. package/docs-site/content/en/whats-new.html +12 -1
  59. package/docs-site/content/en/workflows.html +2 -2
  60. package/docs-site/content/index.html +19 -19
  61. package/docs-site/content/runtime.html +4 -4
  62. package/docs-site/content/whats-new.html +12 -1
  63. package/docs-site/content/workflows.html +2 -2
  64. package/docs-site/context-engine.html +1 -1
  65. package/docs-site/en/architecture.html +1 -1
  66. package/docs-site/en/benchmark.html +135 -91
  67. package/docs-site/en/commands.html +1 -1
  68. package/docs-site/en/context-engine.html +1 -1
  69. package/docs-site/en/index.html +20 -20
  70. package/docs-site/en/mcp-approval.html +1 -1
  71. package/docs-site/en/mcp-auth.html +1 -1
  72. package/docs-site/en/mcp-servers.html +1 -1
  73. package/docs-site/en/mcp.html +1 -1
  74. package/docs-site/en/permissions.html +1 -1
  75. package/docs-site/en/profiles.html +1 -1
  76. package/docs-site/en/quickstart.html +1 -1
  77. package/docs-site/en/runtime.html +5 -5
  78. package/docs-site/en/scope.html +1 -1
  79. package/docs-site/en/security.html +1 -1
  80. package/docs-site/en/team.html +1 -1
  81. package/docs-site/en/whats-new.html +13 -2
  82. package/docs-site/en/workflows.html +3 -3
  83. package/docs-site/index.html +20 -20
  84. package/docs-site/mcp-approval.html +1 -1
  85. package/docs-site/mcp-auth.html +1 -1
  86. package/docs-site/mcp-servers.html +1 -1
  87. package/docs-site/mcp.html +1 -1
  88. package/docs-site/permissions.html +1 -1
  89. package/docs-site/profiles.html +1 -1
  90. package/docs-site/quickstart.html +1 -1
  91. package/docs-site/runtime.html +5 -5
  92. package/docs-site/scope.html +1 -1
  93. package/docs-site/security.html +1 -1
  94. package/docs-site/team.html +1 -1
  95. package/docs-site/whats-new.html +13 -2
  96. package/docs-site/workflows.html +3 -3
  97. package/evals/fixtures/benchmark-assurance-evidence.invalid.json +1 -1
  98. package/evals/fixtures/benchmark-assurance-evidence.valid.json +1 -1
  99. package/evals/fixtures/codex-relative-efficiency-v1.invalid.json +4 -0
  100. package/evals/fixtures/codex-relative-efficiency-v1.valid.json +94 -0
  101. package/evals/fixtures/helper-request.invalid.json +1 -1
  102. package/evals/fixtures/helper-request.valid.json +1 -1
  103. package/evals/fixtures/piagent-webui/session-live-state-v1.invalid.json +18 -0
  104. package/evals/fixtures/piagent-webui/session-live-state-v1.valid.json +27 -0
  105. package/evals/fixtures/piagent-webui/subagent-tree-v1.valid.json +7 -0
  106. package/evals/fixtures/task-authority-snapshot.valid.json +4 -4
  107. package/evals/fs4-readiness-matrix.v1.json +2 -2
  108. package/evals/fs5-causal-arm.v1.json +3 -3
  109. package/evals/fs5-pilot-protocol.v1.json +3 -3
  110. package/evals/fs5-pilot-protocol.v2.json +8 -8
  111. package/evals/fs5-pilot-protocol.v3.json +8 -8
  112. package/evals/fs5-pilot-protocol.v4.json +7 -6
  113. package/evals/fs5-pilot-protocol.v5.json +9 -7
  114. package/evals/private-holdout-v1/public-exposure.v1.json +1 -1
  115. package/evals/runtime-conformance-v1/README.md +43 -0
  116. package/evals/runtime-conformance-v1/evaluate-paid-canary.mjs +198 -0
  117. package/evals/runtime-conformance-v1/lane.json +57 -0
  118. package/evals/runtime-conformance-v1/paid-canary.json +31 -0
  119. package/evals/runtime-conformance-v1/runner.mjs +456 -0
  120. package/package.json +3 -1
  121. package/packages/piagent-core/README.md +13 -4
  122. package/packages/piagent-core/benchmark/benchmark-assurance.js +4 -1
  123. package/packages/piagent-core/benchmark/benchmark-bootstrap.js +91 -9
  124. package/packages/piagent-core/benchmark/benchmark-claim-restrictions.js +38 -7
  125. package/packages/piagent-core/benchmark/benchmark-cli.js +7 -7
  126. package/packages/piagent-core/benchmark/benchmark-codex-relative-efficiency.js +698 -0
  127. package/packages/piagent-core/benchmark/benchmark-codex.js +3 -1
  128. package/packages/piagent-core/benchmark/benchmark-comparison.js +271 -2
  129. package/packages/piagent-core/benchmark/benchmark-core.js +736 -664
  130. package/packages/piagent-core/benchmark/benchmark-execution-guard.js +7 -5
  131. package/packages/piagent-core/benchmark/benchmark-forensics.js +441 -4
  132. package/packages/piagent-core/benchmark/benchmark-host-readiness.js +639 -0
  133. package/packages/piagent-core/benchmark/benchmark-matrix.js +22 -4
  134. package/packages/piagent-core/benchmark/benchmark-normalized-cost.js +317 -0
  135. package/packages/piagent-core/benchmark/benchmark-preflight.js +5 -1
  136. package/packages/piagent-core/benchmark/benchmark-process.js +6 -5
  137. package/packages/piagent-core/benchmark/benchmark-provider-free-evidence.js +345 -0
  138. package/packages/piagent-core/benchmark/benchmark-provider-wire.js +126 -0
  139. package/packages/piagent-core/benchmark/benchmark-record-validation.js +252 -0
  140. package/packages/piagent-core/benchmark/benchmark-report.js +130 -12
  141. package/packages/piagent-core/benchmark/benchmark-resume-recovery.js +14 -0
  142. package/packages/piagent-core/benchmark/benchmark-runner-policy.js +26 -0
  143. package/packages/piagent-core/benchmark/benchmark-runtime-causal.js +244 -0
  144. package/packages/piagent-core/benchmark/benchmark-stage-diagnostic.js +979 -0
  145. package/packages/piagent-core/benchmark/benchmark-statistics.js +64 -0
  146. package/packages/piagent-core/benchmark/benchmark-stop-policy.js +8 -5
  147. package/packages/piagent-core/benchmark/benchmark-suite-identity.js +31 -0
  148. package/packages/piagent-core/benchmark/benchmark-suite-runtime.js +13 -9
  149. package/packages/piagent-core/benchmark/benchmark-suite.js +149 -2
  150. package/packages/piagent-core/benchmark/benchmark-summary-support.js +380 -0
  151. package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +971 -0
  152. package/packages/piagent-core/benchmark/benchmark-usage.js +322 -0
  153. package/packages/piagent-core/benchmark/benchmark-workflow.js +166 -0
  154. package/packages/piagent-core/capabilities/runtime-integrity.js +3 -0
  155. package/packages/piagent-core/docs/context-efficiency-improvement-plan.md +1080 -0
  156. package/packages/piagent-core/extensions/acceptance-behavior-proof.js +806 -0
  157. package/packages/piagent-core/extensions/acceptance-contract-semantics.js +83 -69
  158. package/packages/piagent-core/extensions/acceptance-error-classes.js +160 -0
  159. package/packages/piagent-core/extensions/acceptance-executable-evidence.js +12 -9
  160. package/packages/piagent-core/extensions/acceptance-receipt.js +123 -59
  161. package/packages/piagent-core/extensions/acceptance-state-machine-evidence.js +518 -0
  162. package/packages/piagent-core/extensions/acceptance-test-binding-evidence.js +60 -0
  163. package/packages/piagent-core/extensions/context-efficiency-metrics.js +302 -0
  164. package/packages/piagent-core/extensions/context-efficiency-report.js +167 -0
  165. package/packages/piagent-core/extensions/context-engine.js +149 -156
  166. package/packages/piagent-core/extensions/context-evidence.js +48 -0
  167. package/packages/piagent-core/extensions/context-import-links.js +296 -0
  168. package/packages/piagent-core/extensions/context-index-policy.js +4 -0
  169. package/packages/piagent-core/extensions/context-query-paths.js +57 -0
  170. package/packages/piagent-core/extensions/context-telemetry-integrity.js +65 -0
  171. package/packages/piagent-core/extensions/criterion-context-pack.js +435 -7
  172. package/packages/piagent-core/extensions/criterion-graph.js +82 -9
  173. package/packages/piagent-core/extensions/fallback-base-policy.ts +101 -0
  174. package/packages/piagent-core/extensions/guard-types.ts +6 -0
  175. package/packages/piagent-core/extensions/javascript-regex-evidence.js +32 -0
  176. package/packages/piagent-core/extensions/piagent-guard.ts +420 -260
  177. package/packages/piagent-core/extensions/task-contract-view.js +17 -3
  178. package/packages/piagent-core/extensions/task-lifecycle.js +39 -2
  179. package/packages/piagent-core/extensions/task-state.js +109 -142
  180. package/packages/piagent-core/extensions/verification-intelligence.js +52 -13
  181. package/packages/piagent-core/extensions/workspace-evidence-roots.js +193 -0
  182. package/packages/piagent-core/package.json +1 -1
  183. package/packages/piagent-core/policies/base-policy.json +44 -2
  184. package/packages/piagent-core/policy/authority-manifest.v1.json +3 -3
  185. package/packages/piagent-core/prompts/be-to-fe.md +2 -8
  186. package/packages/piagent-core/prompts/plan.md +1 -1
  187. package/packages/piagent-core/prompts/platform-improve.md +2 -6
  188. package/packages/piagent-core/prompts/review.md +2 -7
  189. package/packages/piagent-core/prompts/scout.md +1 -1
  190. package/packages/piagent-core/prompts/task.md +4 -3
  191. package/packages/piagent-core/runtime/context/context-delivery.ts +103 -0
  192. package/packages/piagent-core/runtime/context/context-delta-shadow.ts +53 -0
  193. package/packages/piagent-core/runtime/context/context-efficiency-format.ts +47 -0
  194. package/packages/piagent-core/runtime/context/context-evidence-qualification.ts +32 -0
  195. package/packages/piagent-core/runtime/context/prefix-telemetry.ts +47 -0
  196. package/packages/piagent-core/runtime/context/repository-memory-hints.ts +27 -0
  197. package/packages/piagent-core/runtime/hooks/agent-prompt-telemetry.ts +56 -0
  198. package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +162 -102
  199. package/packages/piagent-core/runtime/hooks/completion-hook.ts +12 -12
  200. package/packages/piagent-core/runtime/hooks/input-hook.ts +17 -1
  201. package/packages/piagent-core/runtime/hooks/session-hooks.ts +22 -2
  202. package/packages/piagent-core/runtime/hooks/session-start-hook.ts +107 -3
  203. package/packages/piagent-core/runtime/hooks/tool-result-content-guards.ts +95 -0
  204. package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +134 -166
  205. package/packages/piagent-core/runtime/hooks/tool-result-value-helpers.ts +66 -0
  206. package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +4 -2
  207. package/packages/piagent-core/runtime/inspection/activity-recovery.ts +104 -0
  208. package/packages/piagent-core/runtime/inspection/bounded-emission-guard.ts +286 -0
  209. package/packages/piagent-core/runtime/inspection/runtime-event-store.ts +37 -7
  210. package/packages/piagent-core/runtime/inspection/task-compaction-history.ts +1 -1
  211. package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +1 -1
  212. package/packages/piagent-core/runtime/inspection/task-subagent-tree.ts +27 -4
  213. package/packages/piagent-core/runtime/inspection/tool-failure-classification.ts +70 -0
  214. package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +73 -9
  215. package/packages/piagent-core/runtime/model/authenticated-catalog.ts +17 -9
  216. package/packages/piagent-core/runtime/model/openai-codex-reasoning.ts +83 -0
  217. package/packages/piagent-core/runtime/model/provider-wire-fingerprint.ts +238 -0
  218. package/packages/piagent-core/runtime/orchestration/helper-lifecycle.ts +16 -12
  219. package/packages/piagent-core/runtime/orchestration/minimal-delegation-policy.ts +71 -0
  220. package/packages/piagent-core/runtime/orchestration/owned-work-budget.ts +28 -20
  221. package/packages/piagent-core/runtime/orchestration/role-policy.ts +27 -9
  222. package/packages/piagent-core/runtime/orchestration/subagent-tool-policy.ts +329 -0
  223. package/packages/piagent-core/runtime/policy/block-remedy.ts +0 -4
  224. package/packages/piagent-core/runtime/product/activity-inspector.ts +7 -2
  225. package/packages/piagent-core/runtime/product/efficiency-metrics.ts +7 -2
  226. package/packages/piagent-core/runtime/quality/edit-freshness-guard.ts +102 -0
  227. package/packages/piagent-core/runtime/quality/exact-output-contract.ts +22 -11
  228. package/packages/piagent-core/runtime/quality/performance-assurance-signals.ts +23 -0
  229. package/packages/piagent-core/runtime/quality/performance-assurance.ts +9 -5
  230. package/packages/piagent-core/runtime/recovery/continuation-budget.ts +1 -1
  231. package/packages/piagent-core/runtime/recovery/edit-recovery-context.ts +113 -0
  232. package/packages/piagent-core/runtime/recovery/edit-recovery-delivery.ts +42 -0
  233. package/packages/piagent-core/runtime/recovery/handoff-projection.ts +4 -1
  234. package/packages/piagent-core/runtime/recovery/pristine-task-policy-refresh.ts +91 -0
  235. package/packages/piagent-core/runtime/recovery/recovery-policy.ts +7 -4
  236. package/packages/piagent-core/runtime/recovery/resume-state.ts +112 -14
  237. package/packages/piagent-core/runtime/recovery/semantic-repair-handshake.ts +60 -13
  238. package/packages/piagent-core/runtime/recovery/semantic-repair-runtime.ts +55 -2
  239. package/packages/piagent-core/runtime/recovery/task-evidence-coverage-refresh.ts +217 -0
  240. package/packages/piagent-core/runtime/registration/context-commands.ts +82 -7
  241. package/packages/piagent-core/runtime/registration/knowledge-tools.ts +9 -5
  242. package/packages/piagent-core/runtime/registration/operator-request-intake.ts +49 -0
  243. package/packages/piagent-core/runtime/registration/policy-tools.ts +50 -15
  244. package/packages/piagent-core/runtime/registration/session-commands.ts +1 -1
  245. package/packages/piagent-core/runtime/registration/task-completion-tools.ts +61 -25
  246. package/packages/piagent-core/runtime/registration/task-evidence-tools.ts +21 -12
  247. package/packages/piagent-core/runtime/registration/task-start-guidance.ts +169 -0
  248. package/packages/piagent-core/runtime/registration/task-start-manifest.ts +54 -0
  249. package/packages/piagent-core/runtime/registration/task-start-retry-helpers.ts +37 -0
  250. package/packages/piagent-core/runtime/registration/task-start-tool.ts +108 -103
  251. package/packages/piagent-core/runtime/runtime-limits.ts +16 -2
  252. package/packages/piagent-core/runtime/session/adaptive-context-analysis.ts +461 -0
  253. package/packages/piagent-core/runtime/session/adaptive-context-governor.ts +464 -0
  254. package/packages/piagent-core/runtime/session/adaptive-context-ledger.ts +265 -0
  255. package/packages/piagent-core/runtime/session/message-signals.ts +7 -3
  256. package/packages/piagent-core/runtime/session/operator-request-carry.ts +44 -0
  257. package/packages/piagent-core/runtime/session/runtime-state.ts +161 -5
  258. package/packages/piagent-core/runtime/session/source-checkout-read-grants.ts +35 -0
  259. package/packages/piagent-core/runtime/session/system-prompt.ts +76 -14
  260. package/packages/piagent-core/runtime/session/task-contract-presentation.ts +39 -0
  261. package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +500 -0
  262. package/packages/piagent-core/runtime/tools/phase-tools.ts +8 -8
  263. package/packages/piagent-core/runtime/tools/tool-groups.ts +12 -2
  264. package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +2 -1
  265. package/packages/piagent-core/runtime/verification/exact-verifier-reuse.ts +101 -0
  266. package/packages/piagent-core/runtime/workflows/runtime-intake-compaction.ts +164 -0
  267. package/packages/piagent-core/runtime/workflows/task-intake.ts +207 -38
  268. package/packages/piagent-core/security/sensitive-data.js +13 -218
  269. package/packages/piagent-core/security/sensitive-project-file.js +42 -0
  270. package/packages/piagent-core/security/sensitive-source-expression.js +330 -0
  271. package/packages/piagent-core/security/sensitive-source-formats.js +394 -0
  272. package/packages/piagent-core/security/sensitive-text.js +234 -0
  273. package/packages/piagent-core/subagents/piagent-oracle.md +5 -3
  274. package/packages/piagent-core/subagents/piagent-planner.md +6 -4
  275. package/packages/piagent-core/subagents/piagent-reviewer.md +5 -3
  276. package/packages/piagent-core/subagents/piagent-scout.md +4 -2
  277. package/packages/piagent-core/subagents/piagent-worker.md +7 -5
  278. package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-rD9WJKxs.js → MarkdownMessage-B4XehTCU.js} +1 -1
  279. package/packages/piagent-webui/dist/client/assets/index-CgOEyRPG.js +176 -0
  280. package/packages/piagent-webui/dist/client/index.html +1 -1
  281. package/packages/piagent-webui/extension/piagent-webui.ts +3 -1
  282. package/packages/piagent-webui/extension/same-session-bridge.ts +1 -1
  283. package/packages/piagent-webui/extension/session-stream-adapter.ts +33 -10
  284. package/packages/piagent-webui/gateway/gateway-events.ts +109 -5
  285. package/packages/piagent-webui/gateway/gateway-service.ts +3 -0
  286. package/packages/piagent-webui/gateway/gateway-session-stream.ts +122 -20
  287. package/packages/piagent-webui/gateway/session-command-controller.ts +18 -3
  288. package/packages/piagent-webui/gateway/session-effective-options.ts +47 -0
  289. package/packages/piagent-webui/gateway/session-live-state.ts +21 -0
  290. package/packages/piagent-webui/gateway/session-operation-lifecycle.ts +237 -0
  291. package/packages/piagent-webui/gateway/session-operation-retry-control.ts +38 -0
  292. package/packages/piagent-webui/gateway/session-operation-start.ts +5 -1
  293. package/packages/piagent-webui/gateway/session-operation-watchdog.ts +165 -0
  294. package/packages/piagent-webui/gateway/session-runtime-factory.ts +45 -0
  295. package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +141 -125
  296. package/packages/piagent-webui/ownership/session-lease-store.ts +5 -2
  297. package/packages/piagent-webui/server/core-inspection-provider.ts +2 -1
  298. package/packages/piagent-webui/server/loopback-server.ts +8 -0
  299. package/packages/piagent-webui/server/transcript-projection.ts +113 -9
  300. package/packages/piagent-webui/shared/text-visibility.ts +10 -0
  301. package/schemas/codex-relative-efficiency-v1.schema.json +155 -0
  302. package/schemas/piagent-webui/catalog-v1.json +9 -0
  303. package/schemas/piagent-webui/gateway-protocol-v1.schema.json +53 -3
  304. package/schemas/piagent-webui/runtime-event-v2.schema.json +15 -5
  305. package/schemas/piagent-webui/session-live-state-v1.schema.json +76 -0
  306. package/schemas/piagent-webui/subagent-tree-v1.schema.json +11 -1
  307. package/schemas/project-profile.schema.json +1 -1
  308. package/schemas/task-contract.schema.json +27 -1
  309. package/scripts/benchmark-runner-core.mjs +367 -363
  310. package/scripts/benchmark-runner-finalization.mjs +313 -0
  311. package/scripts/benchmark-runner-host-readiness.mjs +94 -0
  312. package/scripts/benchmark-runner-support.mjs +200 -0
  313. package/scripts/benchmark-session.mjs +95 -41
  314. package/scripts/configure-model-scope.sh +4 -3
  315. package/scripts/configure-subagents.sh +42 -34
  316. package/scripts/helper-evaluation.mjs +2 -2
  317. package/scripts/install-global.sh +2 -2
  318. package/scripts/pi-usage-history.mjs +37 -10
  319. package/scripts/setup.sh +2 -2
  320. package/scripts/team-doctor.sh +1 -1
  321. package/scripts/verify-local.sh +10 -1
  322. package/templates/global/settings.json +2 -1
  323. package/packages/piagent-webui/dist/client/assets/index-BZRFw1u6.js +0 -174
@@ -6,8 +6,9 @@ import {
6
6
  acceptanceCriticalRecoveryProjection,
7
7
  applyAcceptanceRecoveryProvenance
8
8
  } from "../../extensions/acceptance-receipt.js";
9
+ import { hasDurableContextEvidence } from "../../extensions/context-evidence.js";
9
10
  import type { TaskContract } from "../../extensions/guard-types.js";
10
- import { runtimeLifecycleMode, workingTreeEvidenceDigest } from "../../extensions/task-lifecycle.js";
11
+ import { applyAssistedReadOnlyFinalHandoff, runtimeLifecycleMode, workingTreeEvidenceDigest } from "../../extensions/task-lifecycle.js";
11
12
  import { recordCompletionAudit } from "../../extensions/task-runtime-audit.js";
12
13
  import { workingTreeSnapshot } from "../../extensions/task-state.js";
13
14
  import { taskDeltaFilesFromSnapshot } from "../../extensions/task-contract-view.js";
@@ -18,8 +19,7 @@ import {
18
19
  looksLikeCompletionClaim,
19
20
  looksLikeIncompleteHandoff
20
21
  } from "../session/message-signals.ts";
21
- import { RuntimeSessionState } from "../session/runtime-state.ts";
22
- import type { ObservedTaskContext } from "../session/runtime-state.ts";
22
+ import { RuntimeSessionState, type ObservedTaskContext } from "../session/runtime-state.ts";
23
23
  import type { RecoveryDecision } from "../recovery/recovery-policy.ts";
24
24
  import { buildHandoffProjection, handoffProjectionPath, writeHandoffProjection } from "../recovery/handoff-projection.ts";
25
25
  import { evaluateExactFinalOutputContract } from "../quality/exact-output-contract.ts";
@@ -177,7 +177,7 @@ export function registerCompletionHook(pi: ExtensionAPI, dependencies: Completio
177
177
  let task = flushObservedTaskContext(
178
178
  pi,
179
179
  ctx,
180
- state.observedContext(ctx),
180
+ state.qualifiedTaskContext(ctx),
181
181
  maxManifestFiles,
182
182
  "context_observed_before_handoff"
183
183
  ) ?? activeTask(ctx);
@@ -187,7 +187,7 @@ export function registerCompletionHook(pi: ExtensionAPI, dependencies: Completio
187
187
  const completionClaim = looksLikeCompletionClaim(text);
188
188
  const incompleteHandoff = looksLikeIncompleteHandoff(text);
189
189
  if (task.trace.outcome !== "pending") return;
190
- const readOnlyEvidenceObserved = task.changeMode === "read-only" && task.contextManifest.length > 0;
190
+ const readOnlyEvidenceObserved = (task.changeMode === "read-only" || task.mutationPolicy === "forbidden") && hasDurableContextEvidence(task);
191
191
  const latestExactVerifier = latestObservedVerification(task.verifyEvidence.filter((evidence) => evidence.matchedProfileCommand === true));
192
192
  const potentiallyFinalEvidence = task.observedChangedFiles.length > 0
193
193
  || latestExactVerifier?.exitCode === 0
@@ -203,6 +203,7 @@ export function registerCompletionHook(pi: ExtensionAPI, dependencies: Completio
203
203
  );
204
204
  let completionGate: CompletionGate | undefined;
205
205
  if (handoffAttempt) {
206
+ if (applyAssistedReadOnlyFinalHandoff(task, { durableReadEvidence: readOnlyEvidenceObserved, finalHandoffObserved: true }).changed) task = writeTask(ctx.cwd, task);
206
207
  let projected = completionProjection(ctx.cwd, task, currentDigests);
207
208
  const baseProjectedGate = evaluateGate(ctx.cwd, projected, currentDigests, currentDigest);
208
209
  const exactOutput = evaluateExactFinalOutputContract(projected, text, ctx.cwd);
@@ -298,7 +299,6 @@ export function registerCompletionHook(pi: ExtensionAPI, dependencies: Completio
298
299
  projected = withRecoveryProvenance(ctx, projected, projectedGate, currentDigests, null);
299
300
  task = writeTask(ctx.cwd, projected);
300
301
  observeTrajectorySync(ctx, syncTrajectory?.(ctx, task, { sourceHook: "completion" }), telemetry);
301
- state.cacheTaskIdentity(ctx, task);
302
302
  state.clearPerformanceReview(task.taskRunId);
303
303
  state.clearObservedContext(ctx);
304
304
  activateBaseTools(ctx);
@@ -378,20 +378,20 @@ export function registerCompletionHook(pi: ExtensionAPI, dependencies: Completio
378
378
  ? [
379
379
  "Continue the same bounded task with one acceptance-proof repair pass.",
380
380
  ...criticalRecoveryGuidance,
381
- "Add or correct focused in-scope tests for every missing critical obligation. Assert exact boundary partitions and requested error classes; if a focused test exposes a defect, repair the in-scope source before rerunning verification.",
381
+ "Add or correct focused tests for every missing critical obligation. Assert exact boundary partitions and requested error classes; if a focused test exposes a defect, repair the evidence-backed source before rerunning verification.",
382
382
  ...verifierInstructions(gate.missingVerifyCommands),
383
- "Do not broaden task scope, repeat a failed hypothesis, expand permission, or perform an external action."
383
+ "Do not repeat a failed hypothesis, expand permission, or perform an external action."
384
384
  ]
385
385
  : [
386
- "Continue the same bounded task with one targeted in-scope source repair, then run every exact configured verifier.",
386
+ "Continue the same bounded task with one targeted evidence-backed source repair, then run every exact configured verifier.",
387
387
  ...verifierInstructions(gate.missingVerifyCommands),
388
- "Do not broaden task scope, repeat a failed hypothesis, expand permission, or perform an external action."
388
+ "Do not repeat a failed hypothesis, expand permission, or perform an external action."
389
389
  ]
390
- : selectedRecovery.reasonCodes.includes("unknown-diagnostic-pass") || task.changeMode === "read-only"
390
+ : selectedRecovery.reasonCodes.includes("unknown-diagnostic-pass") || task.changeMode === "read-only" || task.mutationPolicy === "forbidden"
391
391
  ? [
392
392
  ...(gate.missingVerifyCommands.length > 0
393
393
  ? ["Run only the missing exact verifier commands against the current working tree.", ...verifierInstructions(gate.missingVerifyCommands)]
394
- : ["Run one bounded diagnostic pass using targeted reads and report the concrete evidence or unknown."]),
394
+ : [(task.changeMode === "read-only" || task.mutationPolicy === "forbidden") && gate.missing.length > 0 && gate.missing.every((item) => /^completed work plan\b/i.test(item)) ? "Complete only the pending read-only review checkpoint, then re-emit the complete substantive assessment from the immediately preceding response; do not repeat repository reads or replace it with checkpoint evidence." : "Run one bounded diagnostic pass using targeted reads and report the concrete evidence or unknown."]),
395
395
  "Do not mutate project source, expand permission, or perform an external action."
396
396
  ]
397
397
  : [
@@ -9,8 +9,10 @@ import { LONG_INPUT_CHARS } from "../runtime-limits.ts";
9
9
  import type { AuthorityResumeDecision } from "../policy/authority-resume-policy.ts";
10
10
  import { buildHandoffProjection, writeHandoffProjection } from "../recovery/handoff-projection.ts";
11
11
  import { buildContextPreflight, buildUsageSnapshot } from "../session/usage.ts";
12
+ import { registerAdaptiveContextGovernor } from "../session/adaptive-context-governor.ts";
12
13
  import { activeTaskToolGroups, toolGroupsForPrompt } from "../tools/tool-groups.ts";
13
14
  import type { PiagentToolGroup } from "../tools/tool-groups.ts";
15
+ import type { RuntimeSessionState } from "../session/runtime-state.ts";
14
16
  import {
15
17
  buildFreshCommand,
16
18
  chooseFreshWorkflow,
@@ -26,6 +28,7 @@ import {
26
28
  } from "../workflows/task-intake.ts";
27
29
 
28
30
  type InputHookDependencies = {
31
+ state: RuntimeSessionState;
29
32
  boilerplateCollapseChars: number;
30
33
  activeTask: (ctx: ExtensionContext) => TaskContract | undefined;
31
34
  authorityPolicy: (ctx: ExtensionContext, task: TaskContract) => AuthorityResumeDecision;
@@ -36,6 +39,11 @@ type InputHookDependencies = {
36
39
  };
37
40
 
38
41
  export function registerInputHook(pi: ExtensionAPI, dependencies: InputHookDependencies): void {
42
+ registerAdaptiveContextGovernor(pi, {
43
+ activeTask: dependencies.activeTask,
44
+ telemetry: dependencies.telemetry
45
+ });
46
+
39
47
  pi.on("input", async (event, ctx) => {
40
48
  const text = event.text.trim();
41
49
  if (!text || isFreshOrUtilityInput(text)) return { action: "continue" };
@@ -44,7 +52,14 @@ export function registerInputHook(pi: ExtensionAPI, dependencies: InputHookDepen
44
52
  }
45
53
 
46
54
  const taskSignal = classifyContextTask(text);
47
- const activeTask = dependencies.activeTask(ctx);
55
+ const sessionTask = dependencies.activeTask(ctx);
56
+ if (sessionTask && sessionTask.trace.outcome !== "pending") dependencies.state.clearTaskBoundary(ctx, sessionTask.taskRunId);
57
+ else if (!sessionTask) {
58
+ const cachedTask = dependencies.state.taskIdentity(ctx);
59
+ if (cachedTask) dependencies.state.clearTaskBoundary(ctx, cachedTask.taskRunId);
60
+ }
61
+ const activeTask = sessionTask?.trace.outcome === "pending" ? sessionTask : undefined;
62
+ const turn = dependencies.state.beginTurn(ctx, taskSignal.promptHash);
48
63
  const authorityPolicy = activeTask?.trace.outcome === "pending" ? dependencies.authorityPolicy(ctx, activeTask) : undefined;
49
64
  let authorityHandoffReady = false;
50
65
  if (activeTask && authorityPolicy?.disposition === "new-attempt-required") {
@@ -79,6 +94,7 @@ export function registerInputHook(pi: ExtensionAPI, dependencies: InputHookDepen
79
94
  : promptGroups);
80
95
  dependencies.telemetry(ctx, {
81
96
  event: "user_input",
97
+ turnId: turn.turnId,
82
98
  source: event.source,
83
99
  promptHash: taskSignal.promptHash,
84
100
  promptChars: taskSignal.promptChars,
@@ -4,6 +4,7 @@ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-a
4
4
  import type { TaskContract } from "../../extensions/guard-types.js";
5
5
  import { RuntimeSessionState } from "../session/runtime-state.ts";
6
6
  import type { ObservedTaskContext } from "../session/runtime-state.ts";
7
+ import { confirmContextDelivery, contextDeliveryIdFromDetails } from "../context/context-delivery.ts";
7
8
 
8
9
  type TelemetryWriter = (ctx: ExtensionContext, payload: Record<string, unknown>) => void;
9
10
 
@@ -39,6 +40,20 @@ export function registerSessionHooks(pi: ExtensionAPI, dependencies: SessionHook
39
40
  flushObservedTaskContext
40
41
  } = dependencies;
41
42
 
43
+ pi.on("message_start", async (event, ctx) => {
44
+ const message = event.message as unknown as { role?: unknown; details?: unknown };
45
+ if (message.role !== "custom") return;
46
+ const deliveryId = contextDeliveryIdFromDetails(message.details);
47
+ if (!deliveryId) return;
48
+ confirmContextDelivery(pi, ctx, deliveryId, {
49
+ state,
50
+ maxManifestFiles,
51
+ activeTask: (deliveryContext) => activeTask(deliveryContext.cwd, deliveryContext.sessionManager.getSessionId()),
52
+ flushObservedTaskContext,
53
+ telemetry
54
+ });
55
+ });
56
+
42
57
  pi.on("session_info_changed", async (event, ctx) => {
43
58
  const sessionId = ctx.sessionManager.getSessionId();
44
59
  const task = activeTask(ctx.cwd, sessionId);
@@ -58,6 +73,7 @@ export function registerSessionHooks(pi: ExtensionAPI, dependencies: SessionHook
58
73
 
59
74
  pi.on("turn_end", async (event, ctx) => {
60
75
  const message = event.message as unknown as { usage?: unknown; stopReason?: unknown; role?: unknown };
76
+ const task = activeTask(ctx.cwd, ctx.sessionManager.getSessionId());
61
77
  telemetry(ctx, {
62
78
  event: "turn_end",
63
79
  turnIndex: event.turnIndex,
@@ -65,9 +81,13 @@ export function registerSessionHooks(pi: ExtensionAPI, dependencies: SessionHook
65
81
  role: message.role,
66
82
  stopReason: message.stopReason,
67
83
  usage: message.usage,
68
- contextUsage: ctx.getContextUsage()
84
+ contextUsage: ctx.getContextUsage(),
85
+ taskId: task?.taskId,
86
+ taskRunId: task?.taskRunId,
87
+ taskOutcome: task?.trace.outcome
69
88
  });
70
89
  dependencies.onTurnEnd?.(ctx);
90
+ if (task && task.trace.outcome !== "pending") state.clearTaskBoundary(ctx, task.taskRunId);
71
91
  });
72
92
 
73
93
  pi.on("agent_settled", async (_event, ctx) => {
@@ -96,7 +116,7 @@ export function registerSessionHooks(pi: ExtensionAPI, dependencies: SessionHook
96
116
  flushObservedTaskContext(
97
117
  pi,
98
118
  ctx,
99
- state.observedContext(ctx),
119
+ state.qualifiedTaskContext(ctx),
100
120
  maxManifestFiles,
101
121
  "context_observed_before_shutdown"
102
122
  );
@@ -21,6 +21,8 @@ import { buildContextPreflight, buildUsageSnapshot } from "../session/usage.ts";
21
21
  import { toolResultCaptureRoot } from "../session/tool-result-compaction.ts";
22
22
  import { ensureTaskAuthorityResumePolicy } from "../policy/authority-resume-policy.ts";
23
23
  import { buildHandoffProjection, writeHandoffProjection } from "../recovery/handoff-projection.ts";
24
+ import { refreshPristineRuntimeTaskVerification } from "../recovery/pristine-task-policy-refresh.ts";
25
+ import { refreshLegacyHiddenWorkspaceEvidenceCoverage } from "../recovery/task-evidence-coverage-refresh.ts";
24
26
  import { activeTaskToolGroups } from "../tools/tool-groups.ts";
25
27
  import type { PiagentToolGroup } from "../tools/tool-groups.ts";
26
28
  import { observeTrajectorySync } from "../trajectory/trajectory-observability.ts";
@@ -40,6 +42,7 @@ type SessionStartHookDependencies = {
40
42
  resolveTaskAny: (cwd: string, reference: string) => TaskContract | undefined;
41
43
  bindTask: (cwd: string, sessionId: string, sessionName: string | undefined, task: TaskContract) => unknown;
42
44
  writeTask: (cwd: string, task: TaskContract) => TaskContract;
45
+ appendTrace: (cwd: string, payload: Record<string, unknown>) => void;
43
46
  capabilityState: (ctx: ExtensionContext) => { ok: boolean; reason?: string; repinned?: string };
44
47
  permissionProfile: (ctx: ExtensionContext, profile: ProjectProfile) => { mode: string; warning?: string };
45
48
  legacyProjectWarning: (cwd: string) => string | undefined;
@@ -138,9 +141,107 @@ export function registerSessionStartHook(pi: ExtensionAPI, dependencies: Session
138
141
  resumedTask = dependencies.writeTask(ctx.cwd, resumedTask);
139
142
  dependencies.bindTask(ctx.cwd, sessionId, sessionName, resumedTask);
140
143
  }
144
+ const capabilityState = dependencies.capabilityState(ctx);
145
+ if (resumedTask?.trace.outcome === "pending"
146
+ && authorityPolicy?.disposition === "resume-pinned"
147
+ && capabilityState.ok) {
148
+ // Re-read from the durable session binding immediately before the
149
+ // synchronous pristine-tree check and write. This prevents an earlier
150
+ // session-start projection from overwriting newer same-process task
151
+ // evidence or work-plan state.
152
+ const latestTask = dependencies.activeTask(ctx.cwd, sessionId);
153
+ if (latestTask?.taskRunId === resumedTask.taskRunId) {
154
+ resumedTask = latestTask;
155
+ let refreshTask = latestTask;
156
+ // Coverage reconciliation must precede resume inspection. Otherwise a
157
+ // path newly visible to the evidence collector looks like a task delta
158
+ // and can incorrectly block a valid dirty-task resume.
159
+ const coverage = refreshLegacyHiddenWorkspaceEvidenceCoverage(ctx.cwd, refreshTask);
160
+ if (coverage.refreshed) {
161
+ try {
162
+ resumedTask = dependencies.writeTask(ctx.cwd, coverage.task);
163
+ refreshTask = resumedTask;
164
+ try {
165
+ dependencies.appendTrace(ctx.cwd, {
166
+ event: "task_evidence_coverage_expanded",
167
+ taskId: resumedTask.taskId,
168
+ taskRunId: resumedTask.taskRunId,
169
+ sessionId,
170
+ sessionName,
171
+ reason: coverage.reason,
172
+ addedPathCount: coverage.addedPaths.length,
173
+ addedPathExamples: coverage.addedPaths.slice(0, 20),
174
+ retainedMutationPathCount: coverage.retainedMutationPaths.length,
175
+ retainedMutationPathExamples: coverage.retainedMutationPaths.slice(0, 20),
176
+ ambiguousPathCount: coverage.ambiguousPaths.length,
177
+ ambiguousPathExamples: coverage.ambiguousPaths.slice(0, 20),
178
+ previousBaselineDigest: coverage.previousBaselineDigest,
179
+ nextBaselineDigest: coverage.nextBaselineDigest
180
+ });
181
+ } catch (error) {
182
+ try {
183
+ ctx.ui.notify(`Piagent expanded legacy task evidence coverage, but its auxiliary trace could not be written: ${error instanceof Error ? error.message : String(error)}`, "warning");
184
+ } catch {
185
+ // UI availability is not part of the durable coverage commit.
186
+ }
187
+ }
188
+ } catch (error) {
189
+ try {
190
+ ctx.ui.notify(`Piagent kept the existing task baseline because its evidence-coverage refresh could not be persisted: ${error instanceof Error ? error.message : String(error)}`, "warning");
191
+ } catch {
192
+ // Continue startup with the last durably readable task.
193
+ }
194
+ refreshTask = dependencies.activeTask(ctx.cwd, sessionId) ?? latestTask;
195
+ resumedTask = refreshTask;
196
+ }
197
+ }
198
+ const refreshResume = dependencies.inspectResume(ctx.cwd, refreshTask, sessionId);
199
+ const refreshAllowed = refreshResume.enforcementSafe
200
+ && refreshResume.decision !== "blocked"
201
+ && refreshResume.decision !== "paused";
202
+ if (refreshAllowed) {
203
+ const refresh = refreshPristineRuntimeTaskVerification(ctx.cwd, refreshTask, profile);
204
+ if (refresh.refreshed) {
205
+ try {
206
+ resumedTask = dependencies.writeTask(ctx.cwd, refresh.task);
207
+ try {
208
+ dependencies.appendTrace(ctx.cwd, {
209
+ event: "task_pristine_verifier_refreshed",
210
+ taskId: resumedTask.taskId,
211
+ taskRunId: resumedTask.taskRunId,
212
+ sessionId,
213
+ sessionName,
214
+ reason: refresh.reason,
215
+ verifyGroup: refresh.verifyGroup,
216
+ previousCommands: refresh.previousCommands,
217
+ verifyCommands: refresh.nextCommands
218
+ });
219
+ } catch (error) {
220
+ // The contract write and its task journal entry are already
221
+ // durable. An auxiliary trace/notice failure must not abort
222
+ // session startup or roll the task back to stale commands.
223
+ try {
224
+ ctx.ui.notify(`Piagent refreshed the task verifier, but its auxiliary trace could not be written: ${error instanceof Error ? error.message : String(error)}`, "warning");
225
+ } catch {
226
+ // UI availability is not part of the durable refresh commit.
227
+ }
228
+ }
229
+ } catch (error) {
230
+ try {
231
+ ctx.ui.notify(`Piagent kept the existing task verifier because its pristine refresh could not be persisted: ${error instanceof Error ? error.message : String(error)}`, "warning");
232
+ } catch {
233
+ // Continue startup with the last durably readable task.
234
+ }
235
+ resumedTask = dependencies.activeTask(ctx.cwd, sessionId) ?? refreshTask;
236
+ }
237
+ }
238
+ }
239
+ }
240
+ }
141
241
  if (resumedTask?.workingTreeDigestMigration && resumedTask.workingTreeDigestMigration.status !== "refreshed") dependencies.state.clearDigestMigrationState(ctx, resumedTask.taskRunId, resumedTask.taskId);
142
- dependencies.state.cacheTaskIdentity(ctx, resumedTask);
143
- const resumeState = resumedTask ? dependencies.inspectResume(ctx.cwd, resumedTask, sessionId) : undefined;
242
+ if (resumedTask?.trace.outcome === "pending") dependencies.state.cacheTaskIdentity(ctx, resumedTask);
243
+ else dependencies.state.clearSession(ctx);
244
+ const resumeState = resumedTask?.trace.outcome === "pending" ? dependencies.inspectResume(ctx.cwd, resumedTask, sessionId) : undefined;
144
245
  if (resumeState) dependencies.state.rememberResumeState(resumeState);
145
246
  if (resumedTask && resumeState?.enforcementSafe) observeTrajectorySync(ctx, dependencies.syncTrajectory?.(ctx, resumedTask), dependencies.telemetry);
146
247
  let taskRecovery: Record<string, unknown> | undefined;
@@ -179,7 +280,6 @@ export function registerSessionStartHook(pi: ExtensionAPI, dependencies: Session
179
280
  : " (run /onboard to select a profile)";
180
281
  const snapshot = buildUsageSnapshot(ctx, String(pi.getThinkingLevel()));
181
282
  const preflight = buildContextPreflight(snapshot, "task", 0);
182
- const capabilityState = dependencies.capabilityState(ctx);
183
283
  const permissionProfile = dependencies.permissionProfile(ctx, profile);
184
284
  const executionBackend = resolveExecutionBackend();
185
285
  const contextHint = preflight.recommendation === "fresh-session"
@@ -217,6 +317,10 @@ export function registerSessionStartHook(pi: ExtensionAPI, dependencies: Session
217
317
  }
218
318
  dependencies.telemetry(ctx, {
219
319
  event: "session_start",
320
+ // Benchmark and efficiency projections must be able to distinguish a
321
+ // genuine zero-recovery session from telemetry produced before this
322
+ // receipt/result protocol existed.
323
+ editRecoveryContextTelemetryVersion: 1,
220
324
  activeTools: pi.getActiveTools().length,
221
325
  index: engineStatus,
222
326
  taskMigration: migration,
@@ -0,0 +1,95 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+
4
+ import { matchesProtectedPath } from "../../extensions/policy-core.js";
5
+
6
+ function normalizeRelative(cwd: string, candidate: unknown): string | undefined {
7
+ if (typeof candidate !== "string" || candidate.trim().length === 0) return undefined;
8
+ let raw = candidate.trim();
9
+ try {
10
+ raw = decodeURIComponent(raw);
11
+ } catch {
12
+ return undefined;
13
+ }
14
+ if (/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(raw)) {
15
+ if (!raw.toLowerCase().startsWith("file://")) return undefined;
16
+ try {
17
+ raw = fileURLToPath(raw);
18
+ } catch {
19
+ return undefined;
20
+ }
21
+ }
22
+ const absolute = path.isAbsolute(raw) ? raw : path.resolve(cwd, raw);
23
+ return path.relative(cwd, absolute).split(path.sep).join("/");
24
+ }
25
+
26
+ function filterTextBlocks(
27
+ content: unknown,
28
+ blocked: (line: string) => boolean,
29
+ emptyText: string,
30
+ noticeText: (count: number) => string
31
+ ): { changed: boolean; content?: unknown; redactedLines: number } {
32
+ if (!Array.isArray(content)) return { changed: false, redactedLines: 0 };
33
+ let changed = false;
34
+ let redactedLines = 0;
35
+ const filtered = content.map((block) => {
36
+ if (!block || typeof block !== "object") return block;
37
+ const text = (block as { type?: unknown; text?: unknown }).text;
38
+ if ((block as { type?: unknown }).type !== "text" || typeof text !== "string") return block;
39
+ const kept: string[] = [];
40
+ let blockRedactedLines = 0;
41
+ for (const line of text.split(/\r?\n/)) {
42
+ if (blocked(line)) {
43
+ changed = true;
44
+ redactedLines += 1;
45
+ blockRedactedLines += 1;
46
+ } else {
47
+ kept.push(line);
48
+ }
49
+ }
50
+ if (blockRedactedLines === 0) return block;
51
+ const notice = noticeText(blockRedactedLines);
52
+ const nextText = kept.join("\n").trim().length > 0
53
+ ? `${kept.join("\n")}\n${notice}`
54
+ : `${emptyText}\n${notice}`;
55
+ return { ...block, text: nextText };
56
+ });
57
+ return { changed, content: filtered, redactedLines };
58
+ }
59
+
60
+ export function filterGrepProtectedContent(content: unknown, protectedPatterns: string[]) {
61
+ return filterTextBlocks(
62
+ content,
63
+ (line) => {
64
+ const linePath = line.match(/^(.+?)(?::\d+:|-\d+-)/)?.[1];
65
+ return Boolean(linePath && matchesProtectedPath(linePath, protectedPatterns));
66
+ },
67
+ "No matches found in non-protected paths.",
68
+ (count) => `[Piagent Pi guard redacted ${count} protected grep line${count === 1 ? "" : "s"}.]`
69
+ );
70
+ }
71
+
72
+ export function filterProtectedPathListContent(
73
+ cwd: string,
74
+ content: unknown,
75
+ protectedPatterns: string[],
76
+ basePath: string,
77
+ toolName: string
78
+ ) {
79
+ return filterTextBlocks(
80
+ content,
81
+ (line) => {
82
+ const trimmed = line.trim();
83
+ if (!trimmed || trimmed.startsWith("[") || trimmed.startsWith("No ") || trimmed === "(empty directory)") return false;
84
+ const entry = trimmed.replace(/[\\/]+$/, "");
85
+ const candidates = new Set<string>();
86
+ const direct = normalizeRelative(cwd, entry);
87
+ const underBase = normalizeRelative(cwd, path.posix.join(basePath || ".", entry));
88
+ if (direct !== undefined) candidates.add(direct);
89
+ if (underBase !== undefined) candidates.add(underBase);
90
+ return [...candidates].some((candidate) => matchesProtectedPath(candidate, protectedPatterns));
91
+ },
92
+ "No entries found in non-protected paths.",
93
+ (count) => `[Piagent Pi guard redacted ${count} protected ${toolName} line${count === 1 ? "" : "s"}.]`
94
+ );
95
+ }