@piagent/platform 1.3.1 → 1.4.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 (329) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/README.md +10 -4
  3. package/README.vi.md +27 -0
  4. package/architecture/layers.json +96 -1
  5. package/docs/README.md +1 -0
  6. package/docs/architecture.md +1 -0
  7. package/docs/authority-manifest.md +1 -0
  8. package/docs/auto-delegation-policy.md +1 -0
  9. package/docs/capability-packs.md +1 -0
  10. package/docs/command-reference-vietnamese.md +5 -4
  11. package/docs/context-engine.md +1 -0
  12. package/docs/context-window-policy.md +1 -0
  13. package/docs/distribution-standard.md +8 -7
  14. package/docs/en/architecture.md +13 -0
  15. package/docs/herdr-workflow.md +1 -0
  16. package/docs/languages.json +20 -4
  17. package/docs/mcp-and-tools.md +125 -9
  18. package/docs/memory-policy.md +1 -0
  19. package/docs/model-options.md +1 -0
  20. package/docs/oauth-providers.md +1 -0
  21. package/docs/operator-manual-vietnamese.md +15 -12
  22. package/docs/package-architecture-notes.md +1 -0
  23. package/docs/project-adapters.md +1 -0
  24. package/docs/project-onboarding.md +1 -0
  25. package/docs/publishing-for-teams.md +37 -0
  26. package/docs/quality-benchmark.md +1 -0
  27. package/docs/quickstart-vietnamese.md +3 -2
  28. package/docs/release-install-policy.md +22 -8
  29. package/docs/runtime-harness-standard.md +2 -1
  30. package/docs/runtime-policy-design.md +1 -0
  31. package/docs/runtime-quality-baseline.md +1 -0
  32. package/docs/security-redaction-benchmark.md +1 -0
  33. package/docs/security-threat-model.md +2 -1
  34. package/docs/subagent-orchestration-capabilities.md +1 -0
  35. package/docs/subagents-and-multiagent.md +1 -0
  36. package/docs/task-implementation-contract.md +12 -4
  37. package/docs/task-lifecycle-vietnamese.md +1 -0
  38. package/docs/team-onboarding.md +3 -2
  39. package/docs/third-party-neutrality.md +26 -0
  40. package/docs/usage-observability.md +71 -0
  41. package/docs/vercel-docs-site.md +1 -0
  42. package/docs/vi/architecture.md +13 -0
  43. package/docs/workflow-recipes.md +1 -0
  44. package/docs-site/architecture.html +5 -1
  45. package/docs-site/benchmark.html +5 -1
  46. package/docs-site/commands.html +5 -1
  47. package/docs-site/content/en/index.html +49 -0
  48. package/docs-site/content/en/runtime.html +13 -0
  49. package/docs-site/content/index.html +49 -0
  50. package/docs-site/content/runtime.html +28 -0
  51. package/docs-site/context-engine.html +5 -1
  52. package/docs-site/en/architecture.html +5 -1
  53. package/docs-site/en/benchmark.html +5 -1
  54. package/docs-site/en/commands.html +5 -1
  55. package/docs-site/en/context-engine.html +5 -1
  56. package/docs-site/en/index.html +54 -1
  57. package/docs-site/en/mcp-approval.html +5 -1
  58. package/docs-site/en/mcp-auth.html +5 -1
  59. package/docs-site/en/mcp-servers.html +5 -1
  60. package/docs-site/en/mcp.html +5 -1
  61. package/docs-site/en/permissions.html +5 -1
  62. package/docs-site/en/profiles.html +5 -1
  63. package/docs-site/en/quickstart.html +5 -1
  64. package/docs-site/en/runtime.html +18 -1
  65. package/docs-site/en/scope.html +5 -1
  66. package/docs-site/en/security.html +5 -1
  67. package/docs-site/en/team.html +5 -1
  68. package/docs-site/en/whats-new.html +5 -1
  69. package/docs-site/en/workflows.html +5 -1
  70. package/docs-site/index.html +54 -1
  71. package/docs-site/mcp-approval.html +5 -1
  72. package/docs-site/mcp-auth.html +5 -1
  73. package/docs-site/mcp-servers.html +5 -1
  74. package/docs-site/mcp.html +5 -1
  75. package/docs-site/permissions.html +5 -1
  76. package/docs-site/profiles.html +5 -1
  77. package/docs-site/quickstart.html +5 -1
  78. package/docs-site/runtime.html +33 -1
  79. package/docs-site/scope.html +5 -1
  80. package/docs-site/security.html +5 -1
  81. package/docs-site/team.html +5 -1
  82. package/docs-site/whats-new.html +5 -1
  83. package/docs-site/workflows.html +5 -1
  84. package/evals/fixtures/mutation-provenance-record.invalid.json +17 -0
  85. package/evals/fixtures/mutation-provenance-record.valid.json +27 -0
  86. package/evals/fixtures/piagent-webui/approval-v1.invalid.json +54 -0
  87. package/evals/fixtures/piagent-webui/approval-v1.valid.json +58 -0
  88. package/evals/fixtures/piagent-webui/attachment-v1.invalid.json +25 -0
  89. package/evals/fixtures/piagent-webui/attachment-v1.valid.json +25 -0
  90. package/evals/fixtures/piagent-webui/capabilities-v1.invalid.json +51 -0
  91. package/evals/fixtures/piagent-webui/capabilities-v1.valid.json +122 -0
  92. package/evals/fixtures/piagent-webui/commit-summary-v1.invalid.json +10 -0
  93. package/evals/fixtures/piagent-webui/commit-summary-v1.valid.json +25 -0
  94. package/evals/fixtures/piagent-webui/control-command-v1.invalid.json +37 -0
  95. package/evals/fixtures/piagent-webui/control-command-v1.valid.json +35 -0
  96. package/evals/fixtures/piagent-webui/diff-v1.invalid.json +13 -0
  97. package/evals/fixtures/piagent-webui/diff-v1.valid.json +141 -0
  98. package/evals/fixtures/piagent-webui/gateway-capabilities-v1.invalid.json +35 -0
  99. package/evals/fixtures/piagent-webui/gateway-capabilities-v1.valid.json +35 -0
  100. package/evals/fixtures/piagent-webui/gateway-protocol-v1.invalid.json +14 -0
  101. package/evals/fixtures/piagent-webui/gateway-protocol-v1.valid.json +14 -0
  102. package/evals/fixtures/piagent-webui/handoff-history-v1.invalid.json +16 -0
  103. package/evals/fixtures/piagent-webui/handoff-history-v1.valid.json +16 -0
  104. package/evals/fixtures/piagent-webui/model-catalog-v1.invalid.json +31 -0
  105. package/evals/fixtures/piagent-webui/model-catalog-v1.valid.json +43 -0
  106. package/evals/fixtures/piagent-webui/queue-v1.invalid.json +29 -0
  107. package/evals/fixtures/piagent-webui/queue-v1.valid.json +44 -0
  108. package/evals/fixtures/piagent-webui/recovery-history-v1.invalid.json +17 -0
  109. package/evals/fixtures/piagent-webui/recovery-history-v1.valid.json +20 -0
  110. package/evals/fixtures/piagent-webui/release-monitor-v1.invalid.json +12 -0
  111. package/evals/fixtures/piagent-webui/release-monitor-v1.valid.json +29 -0
  112. package/evals/fixtures/piagent-webui/review-state-v1.invalid.json +25 -0
  113. package/evals/fixtures/piagent-webui/review-state-v1.valid.json +38 -0
  114. package/evals/fixtures/piagent-webui/runtime-event-v2.invalid.json +49 -0
  115. package/evals/fixtures/piagent-webui/runtime-event-v2.valid.json +49 -0
  116. package/evals/fixtures/piagent-webui/session-catalog-v1.invalid.json +17 -0
  117. package/evals/fixtures/piagent-webui/session-catalog-v1.valid.json +58 -0
  118. package/evals/fixtures/piagent-webui/session-command-v1.invalid.json +19 -0
  119. package/evals/fixtures/piagent-webui/session-command-v1.valid.json +19 -0
  120. package/evals/fixtures/piagent-webui/snapshot-v1.invalid.json +5 -0
  121. package/evals/fixtures/piagent-webui/snapshot-v1.valid.json +191 -0
  122. package/evals/fixtures/piagent-webui/source-change-v1.invalid.json +57 -0
  123. package/evals/fixtures/piagent-webui/source-change-v1.valid.json +98 -0
  124. package/evals/fixtures/piagent-webui/source-mutation-v1.invalid.json +19 -0
  125. package/evals/fixtures/piagent-webui/source-mutation-v1.valid.json +38 -0
  126. package/evals/fixtures/piagent-webui/source-revert-v1.invalid.json +20 -0
  127. package/evals/fixtures/piagent-webui/source-revert-v1.valid.json +62 -0
  128. package/evals/fixtures/piagent-webui/subagent-tree-v1.invalid.json +26 -0
  129. package/evals/fixtures/piagent-webui/subagent-tree-v1.valid.json +39 -0
  130. package/evals/fixtures/piagent-webui/task-index-v1.invalid.json +15 -0
  131. package/evals/fixtures/piagent-webui/task-index-v1.valid.json +15 -0
  132. package/evals/fixtures/piagent-webui/task-timeline-v1.invalid.json +14 -0
  133. package/evals/fixtures/piagent-webui/task-timeline-v1.valid.json +16 -0
  134. package/evals/fixtures/piagent-webui/transcript-v1.invalid.json +35 -0
  135. package/evals/fixtures/piagent-webui/transcript-v1.valid.json +55 -0
  136. package/evals/fixtures/task-baseline-manifest.invalid.json +16 -0
  137. package/evals/fixtures/task-baseline-manifest.valid.json +41 -0
  138. package/evals/fixtures/verifier-file-snapshot.invalid.json +21 -0
  139. package/evals/fixtures/verifier-file-snapshot.valid.json +21 -0
  140. package/package.json +43 -4
  141. package/packages/piagent-core/README.md +3 -2
  142. package/packages/piagent-core/benchmark/benchmark-candidate.d.ts +1 -0
  143. package/packages/piagent-core/benchmark/benchmark-forensics.d.ts +1 -0
  144. package/packages/piagent-core/benchmark/benchmark-ledger.d.ts +4 -0
  145. package/packages/piagent-core/benchmark/benchmark-record-validation.d.ts +1 -0
  146. package/packages/piagent-core/benchmark/benchmark-runtime.d.ts +1 -0
  147. package/packages/piagent-core/capabilities/capability-core.js +2 -2
  148. package/packages/piagent-core/capabilities/capability-verification-cache.js +17 -7
  149. package/packages/piagent-core/capabilities/runtime-integrity.js +190 -0
  150. package/packages/piagent-core/extensions/piagent-guard.ts +80 -272
  151. package/packages/piagent-core/extensions/redaction-core.d.ts +2 -0
  152. package/packages/piagent-core/extensions/runtime-evidence.js +12 -1
  153. package/packages/piagent-core/extensions/shell-reach.ts +250 -0
  154. package/packages/piagent-core/extensions/task-journal.js +30 -1
  155. package/packages/piagent-core/extensions/task-state.js +33 -36
  156. package/packages/piagent-core/mcp/mcp-command-actions.js +1 -1
  157. package/packages/piagent-core/mcp/mcp-server-catalog.js +139 -9
  158. package/packages/piagent-core/package.json +1 -1
  159. package/packages/piagent-core/runtime/hooks/session-start-hook.ts +2 -2
  160. package/packages/piagent-core/runtime/hooks/tool-call-hook.ts +12 -2
  161. package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +20 -19
  162. package/packages/piagent-core/runtime/hooks/tool-result-metadata.ts +13 -0
  163. package/packages/piagent-core/runtime/input/chat-images.ts +2 -2
  164. package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +94 -0
  165. package/packages/piagent-core/runtime/inspection/approval-broker.ts +318 -0
  166. package/packages/piagent-core/runtime/inspection/commit-summary-projection.ts +59 -0
  167. package/packages/piagent-core/runtime/inspection/context-telemetry-inspection.ts +37 -0
  168. package/packages/piagent-core/runtime/inspection/criteria-links.ts +295 -0
  169. package/packages/piagent-core/runtime/inspection/diff-projection.ts +499 -0
  170. package/packages/piagent-core/runtime/inspection/git-filter-safety.ts +38 -0
  171. package/packages/piagent-core/runtime/inspection/git-numstat-adapter.ts +71 -0
  172. package/packages/piagent-core/runtime/inspection/git-status-adapter.ts +493 -0
  173. package/packages/piagent-core/runtime/inspection/git-tree-adapter.ts +108 -0
  174. package/packages/piagent-core/runtime/inspection/mcp-control.ts +10 -0
  175. package/packages/piagent-core/runtime/inspection/mutation-provenance-contract.ts +131 -0
  176. package/packages/piagent-core/runtime/inspection/mutation-provenance-recorder.ts +48 -0
  177. package/packages/piagent-core/runtime/inspection/mutation-provenance-store.ts +161 -0
  178. package/packages/piagent-core/runtime/inspection/project-runtime-inspection.ts +36 -0
  179. package/packages/piagent-core/runtime/inspection/review-state-contract.ts +108 -0
  180. package/packages/piagent-core/runtime/inspection/review-state-projection.ts +93 -0
  181. package/packages/piagent-core/runtime/inspection/review-state-store.ts +112 -0
  182. package/packages/piagent-core/runtime/inspection/runtime-event-store.ts +262 -0
  183. package/packages/piagent-core/runtime/inspection/same-process-bridge-proof.ts +103 -0
  184. package/packages/piagent-core/runtime/inspection/source-change-projection.ts +471 -0
  185. package/packages/piagent-core/runtime/inspection/source-evidence-contract.ts +139 -0
  186. package/packages/piagent-core/runtime/inspection/source-evidence-store.ts +315 -0
  187. package/packages/piagent-core/runtime/inspection/source-handoff-store.ts +70 -0
  188. package/packages/piagent-core/runtime/inspection/source-inspection-plan.ts +34 -0
  189. package/packages/piagent-core/runtime/inspection/source-mutation-projection.ts +164 -0
  190. package/packages/piagent-core/runtime/inspection/source-mutation-store.ts +168 -0
  191. package/packages/piagent-core/runtime/inspection/source-open-target.ts +38 -0
  192. package/packages/piagent-core/runtime/inspection/source-revert-projection.ts +147 -0
  193. package/packages/piagent-core/runtime/inspection/task-baseline-start-capture.ts +22 -0
  194. package/packages/piagent-core/runtime/inspection/task-compaction-history.ts +160 -0
  195. package/packages/piagent-core/runtime/inspection/task-control-journal.ts +131 -0
  196. package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +95 -0
  197. package/packages/piagent-core/runtime/inspection/task-provenance-projection.ts +60 -0
  198. package/packages/piagent-core/runtime/inspection/task-recovery-timeline.ts +88 -0
  199. package/packages/piagent-core/runtime/inspection/task-run-index.ts +87 -0
  200. package/packages/piagent-core/runtime/inspection/task-source-projection.ts +401 -0
  201. package/packages/piagent-core/runtime/inspection/task-subagent-tree.ts +101 -0
  202. package/packages/piagent-core/runtime/inspection/text-diff.ts +60 -0
  203. package/packages/piagent-core/runtime/inspection/verifier-snapshot-contract.ts +114 -0
  204. package/packages/piagent-core/runtime/inspection/verifier-snapshot-store.ts +189 -0
  205. package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +320 -0
  206. package/packages/piagent-core/runtime/inspection/workspace-file-reader.ts +132 -0
  207. package/packages/piagent-core/runtime/inspection/workspace-source-projection.ts +96 -0
  208. package/packages/piagent-core/runtime/inspection/zero-turn-conformance.ts +175 -0
  209. package/packages/piagent-core/runtime/orchestration/owned-work-budget.ts +93 -6
  210. package/packages/piagent-core/runtime/policy/block-remedy.ts +139 -0
  211. package/packages/piagent-core/runtime/policy/source-index-transaction.ts +173 -0
  212. package/packages/piagent-core/runtime/policy/source-mutation-guard-binding.ts +42 -0
  213. package/packages/piagent-core/runtime/policy/source-mutation-guard.ts +184 -0
  214. package/packages/piagent-core/runtime/policy/source-worktree-transaction.ts +105 -0
  215. package/packages/piagent-core/runtime/product/activity-inspector-footer.ts +5 -3
  216. package/packages/piagent-core/runtime/product/activity-inspector.ts +85 -343
  217. package/packages/piagent-core/runtime/recovery/resume-state.ts +38 -1
  218. package/packages/piagent-core/runtime/registration/activity-inspector-command.ts +68 -14
  219. package/packages/piagent-core/runtime/registration/task-start-tool.ts +22 -27
  220. package/packages/piagent-core/runtime/session/model-authorship-state.ts +31 -3
  221. package/packages/piagent-core/runtime/session/runtime-state.ts +11 -1
  222. package/packages/piagent-core/runtime/session/token-economics.js +34 -0
  223. package/packages/piagent-core/runtime/tools/phase-tool-runtime.ts +2 -1
  224. package/packages/piagent-core/runtime/workflows/task-intake.ts +5 -0
  225. package/packages/piagent-core/security/sensitive-data.js +7 -0
  226. package/packages/piagent-webui/dist/client/assets/index-DwKCWbwd.css +1 -0
  227. package/packages/piagent-webui/dist/client/assets/index-bu7XpD9Q.js +172 -0
  228. package/packages/piagent-webui/dist/client/index.html +16 -0
  229. package/packages/piagent-webui/extension/attachment-store.ts +323 -0
  230. package/packages/piagent-webui/extension/held-message-queue.ts +311 -0
  231. package/packages/piagent-webui/extension/lifecycle-controller.ts +423 -0
  232. package/packages/piagent-webui/extension/lifecycle-event-adapter.ts +23 -0
  233. package/packages/piagent-webui/extension/piagent-webui.ts +470 -0
  234. package/packages/piagent-webui/extension/review-controller.ts +160 -0
  235. package/packages/piagent-webui/extension/same-session-bridge.ts +500 -0
  236. package/packages/piagent-webui/extension/session-options-controller.ts +281 -0
  237. package/packages/piagent-webui/extension/session-stream-adapter.ts +249 -0
  238. package/packages/piagent-webui/extension/source-mutation-controller.ts +215 -0
  239. package/packages/piagent-webui/extension/source-open-controller.ts +136 -0
  240. package/packages/piagent-webui/extension/source-revert-controller.ts +189 -0
  241. package/packages/piagent-webui/extension/terminal-session-adapter.ts +73 -0
  242. package/packages/piagent-webui/extension/vscode-handoff.ts +51 -0
  243. package/packages/piagent-webui/gateway/control-socket.ts +92 -0
  244. package/packages/piagent-webui/gateway/extension-authority.ts +47 -0
  245. package/packages/piagent-webui/gateway/gateway-events.ts +60 -0
  246. package/packages/piagent-webui/gateway/gateway-protocol-service.ts +64 -0
  247. package/packages/piagent-webui/gateway/gateway-service.ts +215 -0
  248. package/packages/piagent-webui/gateway/gateway-session-stream.ts +110 -0
  249. package/packages/piagent-webui/gateway/mcp-auth-broker.ts +158 -0
  250. package/packages/piagent-webui/gateway/native-project-picker.ts +29 -0
  251. package/packages/piagent-webui/gateway/pi-host.ts +41 -0
  252. package/packages/piagent-webui/gateway/profile-state.ts +1 -0
  253. package/packages/piagent-webui/gateway/project-registry.ts +108 -0
  254. package/packages/piagent-webui/gateway/provider-auth-broker.ts +172 -0
  255. package/packages/piagent-webui/gateway/session-catalog.ts +128 -0
  256. package/packages/piagent-webui/gateway/session-command-controller.ts +237 -0
  257. package/packages/piagent-webui/gateway/session-command-store.ts +224 -0
  258. package/packages/piagent-webui/gateway/session-inspection-registry.ts +239 -0
  259. package/packages/piagent-webui/gateway/session-lease-store.ts +1 -0
  260. package/packages/piagent-webui/gateway/session-metadata-store.ts +152 -0
  261. package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +489 -0
  262. package/packages/piagent-webui/ownership/gateway-runtime-context.ts +8 -0
  263. package/packages/piagent-webui/ownership/profile-state.ts +117 -0
  264. package/packages/piagent-webui/ownership/session-lease-store.ts +329 -0
  265. package/packages/piagent-webui/ownership/session-refs.ts +8 -0
  266. package/packages/piagent-webui/package.json +33 -0
  267. package/packages/piagent-webui/server/README.md +4 -0
  268. package/packages/piagent-webui/server/benchmark-release-monitor.ts +230 -0
  269. package/packages/piagent-webui/server/core-inspection-provider.ts +403 -0
  270. package/packages/piagent-webui/server/gateway-websocket.ts +143 -0
  271. package/packages/piagent-webui/server/http-security.ts +27 -0
  272. package/packages/piagent-webui/server/ipc-read-model-client.ts +89 -0
  273. package/packages/piagent-webui/server/loopback-server.ts +368 -0
  274. package/packages/piagent-webui/server/read-model-provider.ts +37 -0
  275. package/packages/piagent-webui/server/read-only-router.ts +105 -0
  276. package/packages/piagent-webui/server/session-auth.ts +88 -0
  277. package/packages/piagent-webui/server/sidecar-main.ts +86 -0
  278. package/packages/piagent-webui/server/sse-hub.ts +76 -0
  279. package/packages/piagent-webui/server/static-bundle.ts +40 -0
  280. package/packages/piagent-webui/server/transcript-projection.ts +125 -0
  281. package/schemas/mutation-provenance-record.schema.json +100 -0
  282. package/schemas/piagent-webui/approval-v1.schema.json +654 -0
  283. package/schemas/piagent-webui/attachment-v1.schema.json +267 -0
  284. package/schemas/piagent-webui/capabilities-v1.schema.json +729 -0
  285. package/schemas/piagent-webui/catalog-v1.json +240 -0
  286. package/schemas/piagent-webui/commit-summary-v1.schema.json +63 -0
  287. package/schemas/piagent-webui/common-v1.schema.json +479 -0
  288. package/schemas/piagent-webui/control-command-v1.schema.json +1780 -0
  289. package/schemas/piagent-webui/diff-v1.schema.json +826 -0
  290. package/schemas/piagent-webui/gateway-capabilities-v1.schema.json +136 -0
  291. package/schemas/piagent-webui/gateway-protocol-v1.schema.json +456 -0
  292. package/schemas/piagent-webui/handoff-history-v1.schema.json +92 -0
  293. package/schemas/piagent-webui/model-catalog-v1.schema.json +95 -0
  294. package/schemas/piagent-webui/queue-v1.schema.json +99 -0
  295. package/schemas/piagent-webui/recovery-history-v1.schema.json +144 -0
  296. package/schemas/piagent-webui/release-monitor-v1.schema.json +173 -0
  297. package/schemas/piagent-webui/review-state-v1.schema.json +206 -0
  298. package/schemas/piagent-webui/runtime-event-v2.schema.json +5206 -0
  299. package/schemas/piagent-webui/session-catalog-v1.schema.json +222 -0
  300. package/schemas/piagent-webui/session-command-v1.schema.json +390 -0
  301. package/schemas/piagent-webui/snapshot-v1.schema.json +2622 -0
  302. package/schemas/piagent-webui/source-change-v1.schema.json +763 -0
  303. package/schemas/piagent-webui/source-mutation-v1.schema.json +96 -0
  304. package/schemas/piagent-webui/source-revert-v1.schema.json +130 -0
  305. package/schemas/piagent-webui/subagent-tree-v1.schema.json +88 -0
  306. package/schemas/piagent-webui/task-index-v1.schema.json +74 -0
  307. package/schemas/piagent-webui/task-timeline-v1.schema.json +49 -0
  308. package/schemas/piagent-webui/transcript-v1.schema.json +243 -0
  309. package/schemas/task-baseline-manifest.schema.json +122 -0
  310. package/schemas/verifier-file-snapshot.schema.json +81 -0
  311. package/scripts/build-docs-site.mjs +21 -1
  312. package/scripts/check-architecture.mjs +1 -0
  313. package/scripts/check-doc-languages.mjs +19 -2
  314. package/scripts/check-third-party-neutrality.mjs +43 -0
  315. package/scripts/explain-command.mjs +240 -0
  316. package/scripts/install-global.sh +105 -4
  317. package/scripts/mcp-manage.mjs +17 -4
  318. package/scripts/pi-session-stats.sh +10 -2
  319. package/scripts/piagent-cli.mjs +30 -3
  320. package/scripts/piagent-dashboard.mjs +261 -0
  321. package/scripts/piagent-webui-launcher.mjs +121 -0
  322. package/scripts/setup.sh +69 -33
  323. package/scripts/traffic-snapshot.mjs +214 -0
  324. package/scripts/typescript-loader.mjs +42 -1
  325. package/scripts/uninstall-global.sh +53 -2
  326. package/scripts/update-global.mjs +33 -1
  327. package/scripts/verify-local.sh +257 -0
  328. package/scripts/verify-release-identity.mjs +4 -1
  329. package/scripts/verify-translation-pairing.mjs +121 -0
@@ -0,0 +1,214 @@
1
+ #!/usr/bin/env node
2
+ // Archives GitHub repository traffic before GitHub discards it.
3
+ //
4
+ // The traffic API only serves a rolling 14-day window. Anything older is gone
5
+ // for good -- there is no endpoint that returns it and no way to reconstruct
6
+ // it. So the counts are merged into CSV files that keep growing, and a run that
7
+ // happens at least every 14 days loses nothing.
8
+ //
9
+ // Merge rule: a row is keyed by its day and the newest fetch wins. Today's
10
+ // bucket is still filling while the run happens, so it is always partial; the
11
+ // next run overwrites it with the settled value. Once a day leaves the window
12
+ // it stops being returned at all, and the stored row is final.
13
+
14
+ import fs from "node:fs";
15
+ import path from "node:path";
16
+
17
+ const EXIT_USAGE = 2;
18
+ const EXIT_FORBIDDEN = 3;
19
+
20
+ const SERIES = [
21
+ { endpoint: "clones", file: "clones.csv", columns: ["date", "count", "uniques"] },
22
+ { endpoint: "views", file: "views.csv", columns: ["date", "count", "uniques"] }
23
+ ];
24
+ // Referrers and paths are a 14-day rollup, not a daily series: the API gives no
25
+ // per-day breakdown, so a row is only meaningful next to the day it was read.
26
+ const ROLLUPS = [
27
+ { endpoint: "popular/referrers", file: "referrers.csv", key: "referrer", columns: ["snapshot_date", "referrer", "count", "uniques"] },
28
+ { endpoint: "popular/paths", file: "paths.csv", key: "path", columns: ["snapshot_date", "path", "title", "count", "uniques"] }
29
+ ];
30
+
31
+ function fail(message, code = EXIT_USAGE) {
32
+ console.error(`FAIL: ${message}`);
33
+ process.exit(code);
34
+ }
35
+
36
+ export function parseArguments(argv) {
37
+ const options = { repository: "", out: "traffic", dryRun: false, today: "" };
38
+ for (let index = 0; index < argv.length; index += 1) {
39
+ const argument = argv[index];
40
+ switch (argument) {
41
+ case "--repository": case "--repo": {
42
+ options.repository = argv[index += 1] ?? "";
43
+ if (!/^[^/\s]+\/[^/\s]+$/.test(options.repository)) fail("--repository needs owner/name");
44
+ break;
45
+ }
46
+ case "--out": {
47
+ options.out = argv[index += 1] ?? "";
48
+ if (!options.out) fail("--out needs a directory");
49
+ break;
50
+ }
51
+ // The archive is written from a snapshot date, and a test cannot wait a
52
+ // day to prove the merge. Injecting it keeps the assertions exact.
53
+ case "--today": {
54
+ options.today = argv[index += 1] ?? "";
55
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(options.today)) fail("--today needs YYYY-MM-DD");
56
+ break;
57
+ }
58
+ case "--dry-run": options.dryRun = true; break;
59
+ case "-h": case "--help": options.help = true; break;
60
+ default: fail(`unknown argument: ${argument}`);
61
+ }
62
+ }
63
+ return options;
64
+ }
65
+
66
+ export function csvEscape(value) {
67
+ const text = String(value ?? "");
68
+ return /[",\n\r]/.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
69
+ }
70
+
71
+ export function parseCsv(text) {
72
+ const rows = [];
73
+ let row = [], field = "", quoted = false;
74
+ for (let index = 0; index < text.length; index += 1) {
75
+ const character = text[index];
76
+ if (quoted) {
77
+ if (character === '"' && text[index + 1] === '"') { field += '"'; index += 1; }
78
+ else if (character === '"') quoted = false;
79
+ else field += character;
80
+ continue;
81
+ }
82
+ if (character === '"') quoted = true;
83
+ else if (character === ",") { row.push(field); field = ""; }
84
+ else if (character === "\n") { row.push(field); rows.push(row); row = []; field = ""; }
85
+ else if (character !== "\r") field += character;
86
+ }
87
+ if (field.length || row.length) { row.push(field); rows.push(row); }
88
+ return rows.filter((entry) => entry.some((cell) => cell !== ""));
89
+ }
90
+
91
+ function readTable(file, columns) {
92
+ if (!fs.existsSync(file)) return [];
93
+ const rows = parseCsv(fs.readFileSync(file, "utf8"));
94
+ const header = rows.shift();
95
+ if (!header || header.join(",") !== columns.join(",")) {
96
+ fail(`${file} has header [${header?.join(", ") ?? "none"}], expected [${columns.join(", ")}]`);
97
+ }
98
+ return rows.map((row) => Object.fromEntries(columns.map((column, index) => [column, row[index] ?? ""])));
99
+ }
100
+
101
+ function writeTable(file, columns, rows) {
102
+ const lines = [columns.join(",")];
103
+ for (const row of rows) lines.push(columns.map((column) => csvEscape(row[column])).join(","));
104
+ fs.mkdirSync(path.dirname(file), { recursive: true });
105
+ fs.writeFileSync(file, `${lines.join("\n")}\n`);
106
+ }
107
+
108
+ /**
109
+ * Existing rows plus fetched rows, keyed by `key`. The fetched value wins,
110
+ * because it is the newer reading of the same day. Rows outside the API window
111
+ * are untouched -- that is the whole point of the archive.
112
+ */
113
+ export function mergeByKey(existing, fetched, key) {
114
+ const merged = new Map(existing.map((row) => [row[key], row]));
115
+ for (const row of fetched) merged.set(row[key], row);
116
+ return [...merged.values()].sort((a, b) => String(a[key]).localeCompare(String(b[key])));
117
+ }
118
+
119
+ /** Rollup rows for one snapshot date, replacing any earlier run on that date. */
120
+ export function mergeRollup(existing, fetched, snapshotDate) {
121
+ const kept = existing.filter((row) => row.snapshot_date !== snapshotDate);
122
+ return [...kept, ...fetched].sort((a, b) =>
123
+ String(a.snapshot_date).localeCompare(String(b.snapshot_date))
124
+ || Number(b.count) - Number(a.count));
125
+ }
126
+
127
+ async function fetchTraffic(repository, endpoint, token) {
128
+ const url = `https://api.github.com/repos/${repository}/traffic/${endpoint}`;
129
+ const response = await fetch(url, {
130
+ headers: {
131
+ accept: "application/vnd.github+json",
132
+ authorization: `Bearer ${token}`,
133
+ "user-agent": "piagent-traffic-snapshot",
134
+ "x-github-api-version": "2022-11-28"
135
+ }
136
+ });
137
+ if (response.status === 403 || response.status === 404) {
138
+ // The distinction matters: this is the one failure an operator cannot debug
139
+ // from the status code, because the traffic API answers 403 for a token
140
+ // that is valid but lacks push access -- which the default workflow token
141
+ // may or may not have, depending on repository settings.
142
+ fail(`the token cannot read ${endpoint} for ${repository} (HTTP ${response.status}).\n`
143
+ + " Repository traffic needs push access. If this ran in GitHub Actions with the\n"
144
+ + " default GITHUB_TOKEN, create a fine-grained personal access token with the\n"
145
+ + " 'Administration: read' permission on this repository, store it as the\n"
146
+ + " TRAFFIC_TOKEN secret, and re-run. Nothing was written.", EXIT_FORBIDDEN);
147
+ }
148
+ if (!response.ok) fail(`GET ${url} returned HTTP ${response.status}`);
149
+ return response.json();
150
+ }
151
+
152
+ export async function snapshot(options, token, fetcher = fetchTraffic) {
153
+ const today = options.today || new Date().toISOString().slice(0, 10);
154
+ const summary = { repository: options.repository, snapshotDate: today, files: {} };
155
+
156
+ // Read every existing file before fetching anything. A corrupt archive is a
157
+ // reason to stop, and stopping before the network call keeps the failure
158
+ // about the file rather than about whatever the API happened to answer.
159
+ const existing = new Map();
160
+ for (const target of [...SERIES, ...ROLLUPS]) {
161
+ existing.set(target.file, readTable(path.join(options.out, target.file), target.columns));
162
+ }
163
+
164
+ for (const series of SERIES) {
165
+ const payload = await fetcher(options.repository, series.endpoint, token);
166
+ const fetched = (payload[series.endpoint] ?? []).map((entry) => ({
167
+ date: String(entry.timestamp ?? "").slice(0, 10),
168
+ count: String(entry.count ?? 0),
169
+ uniques: String(entry.uniques ?? 0)
170
+ })).filter((row) => row.date);
171
+ const file = path.join(options.out, series.file);
172
+ const merged = mergeByKey(existing.get(series.file), fetched, "date");
173
+ if (!options.dryRun) writeTable(file, series.columns, merged);
174
+ summary.files[series.file] = { fetchedDays: fetched.length, totalDays: merged.length };
175
+ }
176
+
177
+ for (const rollup of ROLLUPS) {
178
+ const payload = await fetcher(options.repository, rollup.endpoint, token);
179
+ const fetched = (Array.isArray(payload) ? payload : []).map((entry) => ({
180
+ snapshot_date: today,
181
+ [rollup.key]: String(entry[rollup.key] ?? entry.referrer ?? entry.path ?? ""),
182
+ title: String(entry.title ?? ""),
183
+ count: String(entry.count ?? 0),
184
+ uniques: String(entry.uniques ?? 0)
185
+ }));
186
+ const file = path.join(options.out, rollup.file);
187
+ const merged = mergeRollup(existing.get(rollup.file), fetched, today);
188
+ if (!options.dryRun) writeTable(file, rollup.columns, merged);
189
+ summary.files[rollup.file] = { fetchedRows: fetched.length, totalRows: merged.length };
190
+ }
191
+
192
+ return summary;
193
+ }
194
+
195
+ const invokedDirectly = process.argv[1]
196
+ && path.resolve(process.argv[1]) === path.resolve(new URL(import.meta.url).pathname);
197
+
198
+ if (invokedDirectly) {
199
+ const options = parseArguments(process.argv.slice(2));
200
+ if (options.help) {
201
+ console.log(`Usage:
202
+ node scripts/traffic-snapshot.mjs --repository <owner/name> [--out <dir>] [--dry-run]
203
+
204
+ Archives GitHub traffic (clones, views, referrers, paths) into growing CSV files.
205
+ The API only keeps 14 days, so run this at least fortnightly or the gap is
206
+ permanent. Reads the token from TRAFFIC_TOKEN, else GITHUB_TOKEN.`);
207
+ process.exit(0);
208
+ }
209
+ if (!options.repository) fail("--repository is required");
210
+ const token = process.env.TRAFFIC_TOKEN || process.env.GITHUB_TOKEN;
211
+ if (!token) fail("set TRAFFIC_TOKEN or GITHUB_TOKEN");
212
+ const summary = await snapshot(options, token);
213
+ console.log(JSON.stringify(summary, null, 2));
214
+ }
@@ -1,12 +1,53 @@
1
1
  import fs from "node:fs/promises";
2
2
  import { stripTypeScriptTypes } from "node:module";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ // Repository TypeScript must remain erasable: the integrity lock hashes the
7
+ // source bytes and `strip` fails closed if a future change needs codegen.
8
+ // pi-mcp-adapter@2.15.0 is the sole exception because its published OAuth
9
+ // implementation contains parameter properties. Keep that transform isolated
10
+ // to the exact installed adapter root and Node release reviewed below. A Node
11
+ // or adapter upgrade must deliberately update these pins before OAuth loads.
12
+ export const PINNED_EXTERNAL_TRANSFORM = Object.freeze({
13
+ nodeVersion: "24.11.1",
14
+ packageName: "pi-mcp-adapter",
15
+ packageVersion: "2.15.0"
16
+ });
17
+
18
+ async function pinnedTransformRoot(url) {
19
+ const configured = process.env.PIAGENT_PINNED_TS_TRANSFORM_ROOT;
20
+ if (!configured || process.versions.node !== PINNED_EXTERNAL_TRANSFORM.nodeVersion) return false;
21
+ // This asks one question: is the file being loaded inside the pinned adapter?
22
+ // A configured root that is absent, unreadable or not that adapter answers
23
+ // "no". It used to throw instead, and the throw escaped `load` on the first
24
+ // `.ts` file of any kind -- so a machine without pi-mcp-adapter installed
25
+ // could not start the gateway at all, for a reason that had nothing to do
26
+ // with the file it died on. Answering "no" falls back to `strip`, which is
27
+ // the stricter of the two modes: this can only refuse a transform, never
28
+ // grant one.
29
+ let root;
30
+ let metadata;
31
+ try {
32
+ root = await fs.realpath(configured);
33
+ metadata = JSON.parse(await fs.readFile(path.join(root, "package.json"), "utf8"));
34
+ } catch {
35
+ return false;
36
+ }
37
+ if (metadata?.name !== PINNED_EXTERNAL_TRANSFORM.packageName
38
+ || metadata?.version !== PINNED_EXTERNAL_TRANSFORM.packageVersion) return false;
39
+ const target = await fs.realpath(fileURLToPath(url));
40
+ const relative = path.relative(root, target);
41
+ return Boolean(relative) && !relative.startsWith("..") && !path.isAbsolute(relative);
42
+ }
3
43
 
4
44
  export async function load(url, context, nextLoad) {
5
45
  if (!url.endsWith(".ts")) return nextLoad(url, context);
6
46
  const source = await fs.readFile(new URL(url), "utf8");
47
+ const mode = await pinnedTransformRoot(url) ? "transform" : "strip";
7
48
  return {
8
49
  format: "module",
9
50
  shortCircuit: true,
10
- source: stripTypeScriptTypes(source, { mode: "strip", sourceUrl: url })
51
+ source: stripTypeScriptTypes(source, { mode, sourceUrl: url })
11
52
  };
12
53
  }
@@ -80,6 +80,46 @@ run_cmd() {
80
80
  fi
81
81
  }
82
82
 
83
+ # The helper can live under a non-default npm prefix: install falls back to a
84
+ # user-writable root when the configured one is not writable, and --npm-prefix
85
+ # picks one deliberately. A bare `npm uninstall -g` resolves against the
86
+ # configured prefix instead, so it removes nothing and still reports success.
87
+ # Derive the prefix from where this script actually runs, the same way
88
+ # update-global.mjs does, and only add --prefix when it differs.
89
+ installed_helper_prefix() {
90
+ local root="$ROOT"
91
+ [[ "$(basename "$root")" == "platform" ]] || return 0
92
+ local scope_root node_modules_root parent
93
+ scope_root="$(dirname "$root")"
94
+ [[ "$(basename "$scope_root")" == "@piagent" ]] || return 0
95
+ node_modules_root="$(dirname "$scope_root")"
96
+ [[ "$(basename "$node_modules_root")" == "node_modules" ]] || return 0
97
+ parent="$(dirname "$node_modules_root")"
98
+ # An npx run lives in a prunable cache that owns no bin on anyone's PATH;
99
+ # uninstalling from there would claim to remove an install nobody has.
100
+ case "$parent" in
101
+ */_npx/*|*/_npx) return 0 ;;
102
+ esac
103
+ if [[ "$(basename "$parent")" == "lib" ]]; then
104
+ dirname "$parent"
105
+ else
106
+ printf '%s' "$parent"
107
+ fi
108
+ }
109
+
110
+ # The prefix npm has to be pointed at, or empty when the helper already lives
111
+ # under the configured one and the plain command is correct. Returns a single
112
+ # value rather than an argument list: macOS still ships bash 3.2, where
113
+ # expanding an empty array under `set -u` aborts the script.
114
+ npm_prefix_override() {
115
+ local helper_prefix configured
116
+ helper_prefix="$(installed_helper_prefix)"
117
+ [[ -n "$helper_prefix" ]] || return 0
118
+ configured="$(npm prefix -g 2>/dev/null || true)"
119
+ [[ "$helper_prefix" != "$configured" ]] || return 0
120
+ printf '%s' "$helper_prefix"
121
+ }
122
+
83
123
  # Reads the package sources Pi has registered, so removal targets what is
84
124
  # actually installed rather than what this version happens to install today. An
85
125
  # older release registered a different source shape, and it still has to come
@@ -174,7 +214,13 @@ if [[ "$WITH_HOST" == true ]]; then
174
214
  echo
175
215
  if command -v npm >/dev/null 2>&1; then
176
216
  echo "Uninstalling Pi host:"
177
- run_cmd npm uninstall -g "$PI_HOST_PACKAGE"
217
+ HOST_PREFIX="$(npm_prefix_override)"
218
+ if [[ -n "$HOST_PREFIX" ]]; then
219
+ echo " (prefix $HOST_PREFIX, where this helper is installed)"
220
+ run_cmd npm uninstall -g --prefix "$HOST_PREFIX" "$PI_HOST_PACKAGE"
221
+ else
222
+ run_cmd npm uninstall -g "$PI_HOST_PACKAGE"
223
+ fi
178
224
  else
179
225
  echo "WARN: npm is not on PATH; cannot uninstall $PI_HOST_PACKAGE." >&2
180
226
  fi
@@ -231,7 +277,12 @@ echo
231
277
  if [[ "$APPLY" == true ]]; then
232
278
  echo "Uninstall complete."
233
279
  echo "The npm-global helper is separate and stays until you remove it:"
234
- echo " npm uninstall -g $PLATFORM_PACKAGE"
280
+ HELPER_PREFIX="$(npm_prefix_override)"
281
+ if [[ -n "$HELPER_PREFIX" ]]; then
282
+ echo " npm uninstall -g --prefix $HELPER_PREFIX $PLATFORM_PACKAGE"
283
+ else
284
+ echo " npm uninstall -g $PLATFORM_PACKAGE"
285
+ fi
235
286
  else
236
287
  echo "Dry run only. Nothing was removed. Re-run with --apply to perform it."
237
288
  fi
@@ -213,8 +213,21 @@ function binForPrefix(prefix) {
213
213
  return process.platform === "win32" ? prefix : path.join(prefix, "bin");
214
214
  }
215
215
 
216
+ // The npx cache is a `node_modules` tree like any other, so the documented
217
+ // bootstrap -- `npm exec -y --package @piagent/platform@X.Y.Z -- piagent-update`
218
+ // -- ran the helper from `~/.npm/_npx/<hash>/node_modules/@piagent/platform` and
219
+ // this function happily reported that hash directory as the prefix to install
220
+ // into. Host and helper then landed in a cache npm is free to prune, with a `bin`
221
+ // that is on nobody's PATH: the command reported success and the machine had
222
+ // nothing installed. A cache is never an install target, so it is refused here
223
+ // and the caller falls back to a real global prefix.
224
+ function isNpxCacheRoot(root) {
225
+ return root.split(path.sep).some((segment) => segment === "_npx" || segment === "_cacache");
226
+ }
227
+
216
228
  function npmPrefixForInstalledHelper(root) {
217
229
  if (path.basename(root) !== "platform") return undefined;
230
+ if (isNpxCacheRoot(root)) return undefined;
218
231
  const scopeRoot = path.dirname(root);
219
232
  if (path.basename(scopeRoot) !== "@piagent") return undefined;
220
233
  const nodeModulesRoot = path.dirname(scopeRoot);
@@ -444,10 +457,29 @@ function main() {
444
457
  console.log(` npm: using explicit global prefix ${npmTarget.prefix}`);
445
458
  }
446
459
 
460
+ // The host version above was read before this prepend, so it described whatever
461
+ // `pi` the caller's PATH happened to resolve. Once the prefix moves -- a default
462
+ // global root that is not writable, an explicit `--npm-prefix`, or a helper
463
+ // already installed elsewhere -- every step below uses a different `pi`, and
464
+ // "(already current)" could be describing a binary this run never touches. The
465
+ // decision belongs to the `pi` that will actually be used, so it is taken again
466
+ // here rather than trusted from before the move.
467
+ let effectiveHost = currentHost;
468
+ let effectiveHostNeedsChange = hostNeedsChange;
469
+ if (npmTarget.bin) {
470
+ const activeHost = installedHostVersion();
471
+ if (activeHost !== currentHost) {
472
+ effectiveHost = activeHost;
473
+ effectiveHostNeedsChange = options.host && (options.force || activeHost !== targetHost);
474
+ console.log(` host: the active prefix resolves pi ${activeHost ?? "not installed"}, not ${currentHost ?? "not installed"};`
475
+ + ` using ${effectiveHost ?? "not installed"} -> ${targetHost}${effectiveHostNeedsChange ? "" : " (already current)"}`);
476
+ }
477
+ }
478
+
447
479
  // Host first: piagent-install refuses to run against a host that does not match
448
480
  // the version its package.json pins, so a helper installed ahead of the host
449
481
  // would fail on its very next step.
450
- if (hostNeedsChange) {
482
+ if (effectiveHostNeedsChange) {
451
483
  const args = npmInstallArgs(`${HOST_PACKAGE}@${targetHost}`, npmTarget);
452
484
  describeStep(options.dryRun, "npm", args);
453
485
  if (!options.dryRun && !run("npm", args).ok) fail(`could not install ${HOST_PACKAGE}@${targetHost}`);