@piagent/platform 1.37.0 → 1.38.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 (292) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +5 -3
  3. package/README.vi.md +2 -2
  4. package/catalog/capabilities.json +2 -2
  5. package/docs/command-reference-vietnamese.md +4 -3
  6. package/docs/distribution-standard.md +6 -6
  7. package/docs/en/maintainer-guide.md +8 -0
  8. package/docs/en/workspace-editor.md +222 -0
  9. package/docs/languages.json +13 -4
  10. package/docs/operator-manual-vietnamese.md +7 -7
  11. package/docs/publishing-for-teams.md +3 -0
  12. package/docs/release-install-policy.md +2 -2
  13. package/docs/research/ide-m0-spike.md +101 -0
  14. package/docs/team-onboarding.md +2 -2
  15. package/docs/vi/maintainer-guide.md +8 -0
  16. package/docs/vi/workspace-editor.md +217 -0
  17. package/docs-site/architecture.html +1 -1
  18. package/docs-site/benchmark.html +1 -1
  19. package/docs-site/commands.html +1 -1
  20. package/docs-site/content/en/index.html +4 -4
  21. package/docs-site/content/en/whats-new.html +23 -0
  22. package/docs-site/content/index.html +4 -4
  23. package/docs-site/content/whats-new.html +23 -0
  24. package/docs-site/context-engine.html +1 -1
  25. package/docs-site/ecosystem.html +1 -1
  26. package/docs-site/en/architecture.html +1 -1
  27. package/docs-site/en/benchmark.html +1 -1
  28. package/docs-site/en/commands.html +1 -1
  29. package/docs-site/en/context-engine.html +1 -1
  30. package/docs-site/en/ecosystem.html +1 -1
  31. package/docs-site/en/index.html +5 -5
  32. package/docs-site/en/mcp-approval.html +1 -1
  33. package/docs-site/en/mcp-auth.html +1 -1
  34. package/docs-site/en/mcp-servers.html +1 -1
  35. package/docs-site/en/mcp.html +1 -1
  36. package/docs-site/en/permissions.html +1 -1
  37. package/docs-site/en/profiles.html +1 -1
  38. package/docs-site/en/quickstart.html +1 -1
  39. package/docs-site/en/runtime.html +1 -1
  40. package/docs-site/en/scope.html +1 -1
  41. package/docs-site/en/security.html +1 -1
  42. package/docs-site/en/team.html +1 -1
  43. package/docs-site/en/whats-new.html +24 -1
  44. package/docs-site/en/windows.html +1 -1
  45. package/docs-site/en/workflows.html +1 -1
  46. package/docs-site/index.html +5 -5
  47. package/docs-site/mcp-approval.html +1 -1
  48. package/docs-site/mcp-auth.html +1 -1
  49. package/docs-site/mcp-servers.html +1 -1
  50. package/docs-site/mcp.html +1 -1
  51. package/docs-site/permissions.html +1 -1
  52. package/docs-site/profiles.html +1 -1
  53. package/docs-site/quickstart.html +1 -1
  54. package/docs-site/runtime.html +1 -1
  55. package/docs-site/scope.html +1 -1
  56. package/docs-site/security.html +1 -1
  57. package/docs-site/team.html +1 -1
  58. package/docs-site/whats-new.html +24 -1
  59. package/docs-site/windows.html +1 -1
  60. package/docs-site/workflows.html +1 -1
  61. package/evals/fixtures/piagent-webui/checkpoint-v1.invalid.json +21 -0
  62. package/evals/fixtures/piagent-webui/checkpoint-v1.valid.json +20 -0
  63. package/evals/fixtures/piagent-webui/terminal-v1.invalid.json +17 -0
  64. package/evals/fixtures/piagent-webui/terminal-v1.valid.json +16 -0
  65. package/evals/fixtures/piagent-webui/workspace-file-v1.invalid.json +24 -0
  66. package/evals/fixtures/piagent-webui/workspace-file-v1.valid.json +23 -0
  67. package/evals/fixtures/piagent-webui/workspace-paths-v1.invalid.json +24 -0
  68. package/evals/fixtures/piagent-webui/workspace-paths-v1.valid.json +24 -0
  69. package/evals/fixtures/piagent-webui/workspace-search-v1.invalid.json +26 -0
  70. package/evals/fixtures/piagent-webui/workspace-search-v1.valid.json +26 -0
  71. package/evals/fixtures/piagent-webui/workspace-tree-v1.invalid.json +28 -0
  72. package/evals/fixtures/piagent-webui/workspace-tree-v1.valid.json +27 -0
  73. package/evals/fixtures/piagent-webui/workspace-write-v1.invalid.json +19 -0
  74. package/evals/fixtures/piagent-webui/workspace-write-v1.valid.json +19 -0
  75. package/evals/long-task-soak-v1/README.md +17 -0
  76. package/evals/long-task-soak-v1/lib/session-loop.mjs +19 -3
  77. package/evals/long-task-soak-v1/scenarios/ide-editor-terminal.json +19 -0
  78. package/evals/long-task-soak-v1/surfaces/webui-gateway.mjs +17 -2
  79. package/evals/long-task-soak-v1/surfaces/workspace-actions.mjs +95 -0
  80. package/evals/private-holdout-v1/public-exposure.v2.json +2 -2
  81. package/package.json +7 -3
  82. package/packages/piagent-core/extensions/fallback-base-policy.ts +1 -1
  83. package/packages/piagent-core/extensions/guard-types.ts +3 -1
  84. package/packages/piagent-core/extensions/path-suggestions.ts +137 -0
  85. package/packages/piagent-core/extensions/piagent-guard.ts +85 -7
  86. package/packages/piagent-core/extensions/workspace-inspection.ts +145 -0
  87. package/packages/piagent-core/extensions/workspace-policy.d.ts +7 -0
  88. package/packages/piagent-core/extensions/workspace-policy.js +3 -0
  89. package/packages/piagent-core/extensions/workspace-search-index.mjs +8 -0
  90. package/packages/piagent-core/extensions/workspace-search.ts +74 -0
  91. package/packages/piagent-core/extensions/workspace-write.ts +116 -0
  92. package/packages/piagent-core/managed/background-process.mjs +9 -4
  93. package/packages/piagent-core/managed/boundary-package-proxy.mjs +21 -0
  94. package/packages/piagent-core/managed/boundary-queue.mjs +24 -0
  95. package/packages/piagent-core/managed/checkpoint-git.mjs +16 -0
  96. package/packages/piagent-core/managed/checkpoints.mjs +17 -64
  97. package/packages/piagent-core/managed/command-tools.mjs +6 -6
  98. package/packages/piagent-core/managed/continuation.mjs +3 -0
  99. package/packages/piagent-core/managed/dist/workspace/assets/adapters/backend-api/profile.json +88 -0
  100. package/packages/piagent-core/managed/dist/workspace/assets/adapters/be-readonly-fe/profile.json +130 -0
  101. package/packages/piagent-core/managed/dist/workspace/assets/adapters/data/profile.json +88 -0
  102. package/packages/piagent-core/managed/dist/workspace/assets/adapters/devops/profile.json +90 -0
  103. package/packages/piagent-core/managed/dist/workspace/assets/adapters/docs/profile.json +74 -0
  104. package/packages/piagent-core/managed/dist/workspace/assets/adapters/fullstack/profile.json +92 -0
  105. package/packages/piagent-core/managed/dist/workspace/assets/adapters/generic/profile.json +95 -0
  106. package/packages/piagent-core/managed/dist/workspace/assets/adapters/mobile/profile.json +86 -0
  107. package/packages/piagent-core/managed/dist/workspace/assets/adapters/node-typescript/profile.json +74 -0
  108. package/packages/piagent-core/managed/dist/workspace/assets/adapters/python/profile.json +75 -0
  109. package/packages/piagent-core/managed/dist/workspace/assets/adapters/web-frontend/profile.json +99 -0
  110. package/packages/piagent-core/managed/dist/workspace/assets/local-state-path-BrmghxEZ.js +284 -0
  111. package/packages/piagent-core/managed/dist/workspace/assets/packages/piagent-core/policies/base-policy.json +351 -0
  112. package/packages/piagent-core/managed/dist/workspace/manifest.json +65 -0
  113. package/packages/piagent-core/managed/dist/workspace/worker.mjs +7374 -0
  114. package/packages/piagent-core/managed/dist/workspace/workspace-search-index.mjs +1007 -0
  115. package/packages/piagent-core/managed/helper-run.mjs +11 -1
  116. package/packages/piagent-core/managed/helper-settlement.mjs +17 -6
  117. package/packages/piagent-core/managed/ip-policy.mjs +50 -0
  118. package/packages/piagent-core/managed/memory-lessons.mjs +4 -1
  119. package/packages/piagent-core/managed/memory.mjs +1 -1
  120. package/packages/piagent-core/managed/package-proxy.mjs +12 -14
  121. package/packages/piagent-core/managed/patch-snapshot.mjs +6 -8
  122. package/packages/piagent-core/managed/permission.mjs +29 -6
  123. package/packages/piagent-core/managed/repository-operation.mjs +2 -1
  124. package/packages/piagent-core/managed/review-snapshot-request.mjs +21 -0
  125. package/packages/piagent-core/managed/sandbox-diagnostic.mjs +2 -0
  126. package/packages/piagent-core/managed/session-mutation-observations.mjs +37 -0
  127. package/packages/piagent-core/managed/session.mjs +6 -7
  128. package/packages/piagent-core/managed/skill-feedback.mjs +9 -1
  129. package/packages/piagent-core/managed/source-revert-requests.mjs +21 -0
  130. package/packages/piagent-core/managed/studio-link.mjs +16 -0
  131. package/packages/piagent-core/managed/terminal-boundary.mjs +88 -0
  132. package/packages/piagent-core/managed/terminal-channel.mjs +66 -0
  133. package/packages/piagent-core/managed/terminal-runtime.mjs +64 -0
  134. package/packages/piagent-core/managed/terminal-seatbelt.mjs +48 -0
  135. package/packages/piagent-core/managed/terminal-worker.mjs +70 -0
  136. package/packages/piagent-core/managed/tool-boundary.mjs +45 -35
  137. package/packages/piagent-core/managed/tool-freshness.mjs +47 -0
  138. package/packages/piagent-core/managed/tool-worker.mjs +18 -3
  139. package/packages/piagent-core/managed/web-fetch.mjs +3 -14
  140. package/packages/piagent-core/managed/workspace-worker-pins.mjs +26 -0
  141. package/packages/piagent-core/package.json +1 -1
  142. package/packages/piagent-core/policies/base-policy.json +2 -1
  143. package/packages/piagent-core/runtime/checkpoints/checkpoint-authority.ts +43 -0
  144. package/packages/piagent-core/runtime/checkpoints/checkpoint-refs.mjs +51 -0
  145. package/packages/piagent-core/runtime/checkpoints/checkpoint-store.mjs +179 -0
  146. package/packages/piagent-core/runtime/checkpoints/checkpoint-worker.ts +28 -0
  147. package/packages/piagent-core/runtime/checkpoints/git-adapter.mjs +36 -0
  148. package/packages/piagent-core/runtime/checkpoints/persistent-history.mjs +96 -0
  149. package/packages/piagent-core/runtime/checkpoints/personal-git.ts +272 -0
  150. package/packages/piagent-core/runtime/checkpoints/personal-runtime.ts +158 -0
  151. package/packages/piagent-core/runtime/checkpoints/prune.mjs +29 -0
  152. package/packages/piagent-core/runtime/checkpoints/restore-preview.mjs +46 -0
  153. package/packages/piagent-core/runtime/checkpoints/turn-checkpoints.mjs +167 -0
  154. package/packages/piagent-core/runtime/hooks/session-hooks.ts +19 -16
  155. package/packages/piagent-core/runtime/hooks/session-start-hook.ts +3 -0
  156. package/packages/piagent-core/runtime/hooks/tool-call-hook.ts +2 -2
  157. package/packages/piagent-core/runtime/inspection/diff-projection.ts +2 -1
  158. package/packages/piagent-core/runtime/inspection/managed-source-revert.ts +90 -0
  159. package/packages/piagent-core/runtime/inspection/review-state-projection.ts +19 -8
  160. package/packages/piagent-core/runtime/inspection/session-diff-projection.ts +47 -0
  161. package/packages/piagent-core/runtime/inspection/session-hunk-provenance.ts +56 -0
  162. package/packages/piagent-core/runtime/inspection/session-mutation-observer.ts +125 -0
  163. package/packages/piagent-core/runtime/inspection/source-action-contract.ts +123 -0
  164. package/packages/piagent-core/runtime/inspection/source-change-projection.ts +3 -9
  165. package/packages/piagent-core/runtime/inspection/source-mutation-projection.ts +3 -41
  166. package/packages/piagent-core/runtime/inspection/source-mutation-store.ts +6 -36
  167. package/packages/piagent-core/runtime/inspection/source-revert-projection.ts +36 -30
  168. package/packages/piagent-core/runtime/inspection/text-diff.ts +5 -4
  169. package/packages/piagent-core/runtime/inspection/workspace-worker.ts +79 -0
  170. package/packages/piagent-core/runtime/policy/source-index-transaction.ts +3 -10
  171. package/packages/piagent-core/runtime/policy/source-mutation-guard-binding.ts +27 -2
  172. package/packages/piagent-core/runtime/policy/source-mutation-guard.ts +42 -12
  173. package/packages/piagent-core/runtime/policy/source-worktree-transaction.ts +10 -5
  174. package/packages/piagent-core/runtime/policy/workspace-write-authority.ts +51 -0
  175. package/packages/piagent-core/runtime/process-owner.mjs +20 -0
  176. package/packages/piagent-core/runtime/process-tree-watch.mjs +46 -0
  177. package/packages/piagent-core/runtime/quality/model-mutation-proof.ts +8 -5
  178. package/packages/piagent-core/runtime/registration/permission-commands.ts +10 -2
  179. package/packages/piagent-core/runtime/registration/task-evidence-tools.ts +1 -1
  180. package/packages/piagent-core/runtime/session/workspace-member-edits.d.mts +7 -0
  181. package/packages/piagent-core/runtime/session/workspace-member-edits.mjs +41 -0
  182. package/packages/piagent-core/security/workspace-file-reader.ts +2 -1
  183. package/packages/piagent-webui/dist/client/assets/Alert-DXF8-XqE.js +1 -0
  184. package/packages/piagent-webui/dist/client/assets/Button-DZJosXQi.js +1 -0
  185. package/packages/piagent-webui/dist/client/assets/DialogTitle-CL-fzCnT.js +3 -0
  186. package/packages/piagent-webui/dist/client/assets/MarkdownMessage-k4tq1y8s.js +29 -0
  187. package/packages/piagent-webui/dist/client/assets/TerminalPanel-DvOPgrGI.js +2 -0
  188. package/packages/piagent-webui/dist/client/assets/TerminalView-B_a16moC.js +9 -0
  189. package/packages/piagent-webui/dist/client/assets/TerminalView-kHJ-D0s7.css +1 -0
  190. package/packages/piagent-webui/dist/client/assets/Typography-DMZL1kLS.js +1 -0
  191. package/packages/piagent-webui/dist/client/assets/WorkspaceCodeEditor-BCiYM9NA.js +2 -0
  192. package/packages/piagent-webui/dist/client/assets/WorkspaceExplorer-DttpQtpf.js +5 -0
  193. package/packages/piagent-webui/dist/client/assets/WorkspaceQuickOpen-fgXwQ46B.js +1 -0
  194. package/packages/piagent-webui/dist/client/assets/bootstrap-CedkNtRG.js +1 -0
  195. package/packages/piagent-webui/dist/client/assets/dist-B1M7IjfA.js +10 -0
  196. package/packages/piagent-webui/dist/client/assets/dist-BUYtGaUP.js +1 -0
  197. package/packages/piagent-webui/dist/client/assets/dist-C82AtDDT.js +6 -0
  198. package/packages/piagent-webui/dist/client/assets/dist-D9b8j6pJ.js +1 -0
  199. package/packages/piagent-webui/dist/client/assets/dist-DLfpWwLs.js +23 -0
  200. package/packages/piagent-webui/dist/client/assets/dist-DcEu_WYV.js +1 -0
  201. package/packages/piagent-webui/dist/client/assets/dist-_JsfplOG.js +9 -0
  202. package/packages/piagent-webui/dist/client/assets/dist-idN8f9Fc.js +1 -0
  203. package/packages/piagent-webui/dist/client/assets/dist-nvgpa2Us.js +1 -0
  204. package/packages/piagent-webui/dist/client/assets/index-BW8-BUMx.js +102 -0
  205. package/packages/piagent-webui/dist/client/assets/index-Brs_HjIo.css +1 -0
  206. package/packages/piagent-webui/dist/client/assets/rolldown-runtime-hePW80VL.js +1 -0
  207. package/packages/piagent-webui/dist/client/assets/tab-close-HE0XxoJf.js +1 -0
  208. package/packages/piagent-webui/dist/client/assets/ui-preferences-DiddStu0.js +124 -0
  209. package/packages/piagent-webui/dist/client/assets/useTheme-_ESOj7MI.js +10 -0
  210. package/packages/piagent-webui/dist/client/assets/workspace-api-O7auv_td.js +1 -0
  211. package/packages/piagent-webui/dist/client/index.html +10 -2
  212. package/packages/piagent-webui/extension/same-session-bridge.ts +2 -3
  213. package/packages/piagent-webui/extension/source-revert-controller.ts +14 -208
  214. package/packages/piagent-webui/gateway/checkpoint-sessions.ts +99 -0
  215. package/packages/piagent-webui/gateway/checkpoint-store.ts +6 -0
  216. package/packages/piagent-webui/gateway/company-relay.ts +5 -0
  217. package/packages/piagent-webui/gateway/company-terminal-cache.ts +54 -0
  218. package/packages/piagent-webui/gateway/company-terminal-channel.ts +117 -0
  219. package/packages/piagent-webui/gateway/company-terminal-relay.ts +75 -0
  220. package/packages/piagent-webui/gateway/gateway-protocol-service.ts +12 -0
  221. package/packages/piagent-webui/gateway/gateway-service.ts +48 -4
  222. package/packages/piagent-webui/gateway/managed-gateway.mjs +30 -3
  223. package/packages/piagent-webui/gateway/managed-projection.ts +5 -3
  224. package/packages/piagent-webui/gateway/managed-source-revert-controller.ts +45 -0
  225. package/packages/piagent-webui/gateway/managed-source-revert-sessions.ts +74 -0
  226. package/packages/piagent-webui/gateway/managed-terminal-binding.ts +30 -0
  227. package/packages/piagent-webui/gateway/managed-terminal-processes.ts +74 -0
  228. package/packages/piagent-webui/gateway/managed-terminal-sessions.ts +9 -0
  229. package/packages/piagent-webui/gateway/path-suggestions.ts +1 -124
  230. package/packages/piagent-webui/gateway/personal-terminal-binding.ts +36 -0
  231. package/packages/piagent-webui/gateway/personal-terminal-diagnostic.mjs +16 -0
  232. package/packages/piagent-webui/gateway/personal-terminal-processes.ts +119 -0
  233. package/packages/piagent-webui/gateway/personal-terminal-sessions.ts +22 -0
  234. package/packages/piagent-webui/gateway/runtime-session-controls.ts +2 -1
  235. package/packages/piagent-webui/gateway/session-catalog.ts +3 -2
  236. package/packages/piagent-webui/gateway/session-command-controller.ts +4 -4
  237. package/packages/piagent-webui/gateway/session-inspection-registry.ts +29 -5
  238. package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +8 -8
  239. package/packages/piagent-webui/gateway/signed-session-journal.ts +77 -0
  240. package/packages/piagent-webui/gateway/source-revert-sessions.ts +74 -0
  241. package/packages/piagent-webui/gateway/source-revert-store.ts +47 -0
  242. package/packages/piagent-webui/gateway/terminal-command-ledger.ts +33 -0
  243. package/packages/piagent-webui/gateway/terminal-mentions.ts +29 -0
  244. package/packages/piagent-webui/gateway/terminal-output-buffer.ts +58 -0
  245. package/packages/piagent-webui/gateway/terminal-router.ts +12 -0
  246. package/packages/piagent-webui/gateway/terminal-sessions.ts +247 -0
  247. package/packages/piagent-webui/gateway/workspace-write-sessions.ts +69 -0
  248. package/packages/piagent-webui/gateway/workspace-write-store.ts +6 -0
  249. package/packages/piagent-webui/package.json +14 -2
  250. package/packages/piagent-webui/server/checkpoint-command.ts +30 -0
  251. package/packages/piagent-webui/server/checkpoint-controller.ts +87 -0
  252. package/packages/piagent-webui/server/checkpoint-routes.ts +38 -0
  253. package/packages/piagent-webui/server/control-command-digest.ts +5 -0
  254. package/packages/piagent-webui/server/core-inspection-provider.ts +16 -22
  255. package/packages/piagent-webui/server/gateway-websocket.ts +36 -8
  256. package/packages/piagent-webui/server/loopback-server.ts +9 -0
  257. package/packages/piagent-webui/server/read-model-provider.ts +3 -0
  258. package/packages/piagent-webui/server/read-only-router.ts +3 -0
  259. package/packages/piagent-webui/server/session-auth.ts +4 -1
  260. package/packages/piagent-webui/server/session-source-revert-routes.ts +54 -0
  261. package/packages/piagent-webui/server/source-projection-binding.ts +18 -0
  262. package/packages/piagent-webui/server/source-revert-controller.ts +225 -0
  263. package/packages/piagent-webui/server/terminal-command.ts +35 -0
  264. package/packages/piagent-webui/server/terminal-websocket-stream.ts +56 -0
  265. package/packages/piagent-webui/server/transcript-projection.ts +2 -1
  266. package/packages/piagent-webui/server/workspace-read-routes.ts +32 -0
  267. package/packages/piagent-webui/server/workspace-reader.ts +23 -0
  268. package/packages/piagent-webui/server/workspace-write-controller.ts +118 -0
  269. package/packages/piagent-webui/server/workspace-write-routes.ts +38 -0
  270. package/packages/piagent-webui/shared/terminal-message.ts +23 -0
  271. package/schemas/piagent-webui/catalog-v1.json +63 -0
  272. package/schemas/piagent-webui/checkpoint-v1.schema.json +466 -0
  273. package/schemas/piagent-webui/control-command-v1.schema.json +68 -3
  274. package/schemas/piagent-webui/diff-v1.schema.json +4 -0
  275. package/schemas/piagent-webui/gateway-protocol-v1.schema.json +123 -3
  276. package/schemas/piagent-webui/session-catalog-v1.schema.json +1 -1
  277. package/schemas/piagent-webui/session-command-v1.schema.json +1 -1
  278. package/schemas/piagent-webui/snapshot-v1.schema.json +2 -1
  279. package/schemas/piagent-webui/source-revert-v1.schema.json +22 -3
  280. package/schemas/piagent-webui/terminal-v1.schema.json +495 -0
  281. package/schemas/piagent-webui/workspace-file-v1.schema.json +79 -0
  282. package/schemas/piagent-webui/workspace-paths-v1.schema.json +71 -0
  283. package/schemas/piagent-webui/workspace-search-v1.schema.json +80 -0
  284. package/schemas/piagent-webui/workspace-tree-v1.schema.json +87 -0
  285. package/schemas/piagent-webui/workspace-write-v1.schema.json +276 -0
  286. package/schemas/project-profile.schema.json +8 -3
  287. package/scripts/company-terminal.mjs +16 -11
  288. package/scripts/pi-auto.sh +5 -1
  289. package/scripts/team-doctor.sh +8 -0
  290. package/packages/piagent-webui/dist/client/assets/MarkdownMessage-CfgyQQbW.js +0 -29
  291. package/packages/piagent-webui/dist/client/assets/index-HyzWKvDu.js +0 -234
  292. package/packages/piagent-webui/dist/client/assets/index-_0nGP2n3.css +0 -1
@@ -0,0 +1,1007 @@
1
+ import { i as contextIndexExcludeDigest, n as resolveLocalStatePath, r as matchesProtectedPath, s as normalizeContextIndexExcludePatterns, t as ensurePrivateStateDirectory } from "./assets/local-state-path-BrmghxEZ.js";
2
+ import path from "node:path";
3
+ import "node:crypto";
4
+ import fs from "node:fs";
5
+ import { execFileSync } from "node:child_process";
6
+ import { parentPort, workerData } from "node:worker_threads";
7
+ //#region ../piagent-core/extensions/workflow-catalog.ts
8
+ var WORKFLOW_IDS = [
9
+ "task",
10
+ "scout",
11
+ "be-to-fe",
12
+ "discuss",
13
+ "plan",
14
+ "review",
15
+ "commit",
16
+ "pr",
17
+ "onboard",
18
+ "platform-improve"
19
+ ];
20
+ var WORKFLOW_ALIASES = Object.freeze(Object.fromEntries([
21
+ {
22
+ id: "task",
23
+ aliases: ["task", "implement"],
24
+ label: "Task",
25
+ description: "Implement a bounded task",
26
+ argumentHint: "<request>",
27
+ requestRequired: true,
28
+ contextWorkflow: "task",
29
+ changeMode: "source-change",
30
+ modelUse: "required",
31
+ recommendedFreshSession: true
32
+ },
33
+ {
34
+ id: "scout",
35
+ aliases: ["scout", "audit"],
36
+ label: "Scout",
37
+ description: "Read-only audit or research",
38
+ argumentHint: "<area/spec/risk>",
39
+ requestRequired: true,
40
+ contextWorkflow: "scout",
41
+ changeMode: "read-only",
42
+ modelUse: "required",
43
+ recommendedFreshSession: true
44
+ },
45
+ {
46
+ id: "be-to-fe",
47
+ aliases: ["be-to-fe", "befe"],
48
+ label: "BE → FE",
49
+ description: "Implement frontend from a backend contract",
50
+ argumentHint: "<BE spec/change + FE outcome>",
51
+ requestRequired: true,
52
+ contextWorkflow: "task",
53
+ changeMode: "source-change",
54
+ modelUse: "required",
55
+ recommendedFreshSession: true
56
+ },
57
+ {
58
+ id: "discuss",
59
+ aliases: ["discuss", "clarify"],
60
+ label: "Discuss",
61
+ description: "Clarify before planning or editing",
62
+ argumentHint: "<rough idea>",
63
+ requestRequired: true,
64
+ contextWorkflow: "discuss",
65
+ changeMode: "clarification",
66
+ modelUse: "required",
67
+ recommendedFreshSession: false
68
+ },
69
+ {
70
+ id: "plan",
71
+ aliases: ["plan"],
72
+ label: "Plan",
73
+ description: "Create an implementation plan",
74
+ argumentHint: "<goal>",
75
+ requestRequired: true,
76
+ contextWorkflow: "plan",
77
+ changeMode: "plan-only",
78
+ modelUse: "required",
79
+ recommendedFreshSession: false
80
+ },
81
+ {
82
+ id: "review",
83
+ aliases: ["review"],
84
+ label: "Review",
85
+ description: "Review a diff or source read-only",
86
+ argumentHint: "<target or diff>",
87
+ requestRequired: true,
88
+ contextWorkflow: "review",
89
+ changeMode: "read-only",
90
+ modelUse: "required",
91
+ recommendedFreshSession: false
92
+ },
93
+ {
94
+ id: "commit",
95
+ aliases: ["commit"],
96
+ label: "Commit",
97
+ description: "Run the guarded local commit workflow",
98
+ argumentHint: "[message]",
99
+ requestRequired: false,
100
+ contextWorkflow: "release",
101
+ changeMode: "git",
102
+ modelUse: "required",
103
+ recommendedFreshSession: false
104
+ },
105
+ {
106
+ id: "pr",
107
+ aliases: ["pr"],
108
+ label: "PR",
109
+ description: "Prepare a guarded pull request",
110
+ argumentHint: "[title]",
111
+ requestRequired: false,
112
+ contextWorkflow: "release",
113
+ changeMode: "git",
114
+ modelUse: "required",
115
+ recommendedFreshSession: false
116
+ },
117
+ {
118
+ id: "onboard",
119
+ aliases: ["onboard", "onboard-project"],
120
+ label: "Onboard",
121
+ description: "Run first-read project onboarding",
122
+ argumentHint: "[focus]",
123
+ requestRequired: false,
124
+ contextWorkflow: "onboard",
125
+ changeMode: "onboarding",
126
+ modelUse: "required",
127
+ recommendedFreshSession: true
128
+ },
129
+ {
130
+ id: "platform-improve",
131
+ aliases: ["platform-improve", "platform"],
132
+ label: "Platform improve",
133
+ description: "Improve Pi Agent Platform itself",
134
+ argumentHint: "<goal + affected area>",
135
+ requestRequired: true,
136
+ contextWorkflow: "task",
137
+ changeMode: "platform",
138
+ modelUse: "required",
139
+ recommendedFreshSession: true
140
+ }
141
+ ].flatMap((option) => option.aliases.map((alias) => [alias, option.id]))));
142
+ function workflowCommandNames(options = {}) {
143
+ return options.aliases === false ? [...WORKFLOW_IDS] : Object.keys(WORKFLOW_ALIASES);
144
+ }
145
+ function escapedPattern(value) {
146
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
147
+ }
148
+ /** A regex fragment derived from the catalog, for command/projection boundaries. */
149
+ function workflowCommandPattern(options = {}) {
150
+ return workflowCommandNames(options).sort((left, right) => right.length - left.length).map(escapedPattern).join("|");
151
+ }
152
+ new RegExp(`^/(?:piagent-workflow|workflow)\\s+(${workflowCommandPattern()})(?=\\s|$)\\s*`, "i");
153
+ new RegExp(`^/(${workflowCommandPattern({ aliases: false })})(?=\\s|$)\\s*`, "i");
154
+ new Int32Array(new SharedArrayBuffer(4));
155
+ function readTailText(filePath, maxBytes) {
156
+ try {
157
+ const descriptor = fs.openSync(filePath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
158
+ try {
159
+ const stat = fs.fstatSync(descriptor);
160
+ const start = Math.max(0, stat.size - maxBytes);
161
+ const length = stat.size - start;
162
+ const buffer = Buffer.allocUnsafe(length);
163
+ fs.readSync(descriptor, buffer, 0, length, start);
164
+ let text = buffer.toString("utf8");
165
+ if (start > 0) text = text.slice(Math.max(0, text.indexOf("\n") + 1));
166
+ return text;
167
+ } finally {
168
+ fs.closeSync(descriptor);
169
+ }
170
+ } catch (error) {
171
+ if (error?.code === "ENOENT") return "";
172
+ throw error;
173
+ }
174
+ }
175
+ function readJsonlTail(filePath, options = {}) {
176
+ const limit = Math.max(1, Number.isInteger(options.limit) ? options.limit : 100);
177
+ const maxBytes = Math.max(65536, Number.isInteger(options.maxBytes) ? options.maxBytes : 8388608);
178
+ const safeFilePath = options.projectRoot ? resolveLocalStatePath(options.projectRoot, filePath, { label: "Local JSONL state" }) : filePath;
179
+ const lines = (options.projectRoot ? [resolveLocalStatePath(options.projectRoot, `${filePath}.1`, { label: "Rotated local JSONL state" }), safeFilePath] : [`${safeFilePath}.1`, safeFilePath]).flatMap((source) => readTailText(source, maxBytes).split(/\r?\n/).filter(Boolean));
180
+ const records = [];
181
+ for (const line of lines.slice(-limit)) try {
182
+ records.push(JSON.parse(line));
183
+ } catch {}
184
+ return records;
185
+ }
186
+ //#endregion
187
+ //#region ../piagent-core/extensions/context-efficiency-metrics.js
188
+ function contextMetricPartition(event, taskByTurn = /* @__PURE__ */ new Map()) {
189
+ const sessionId = typeof event.sessionId === "string" ? event.sessionId : "";
190
+ const turnId = typeof event.turnId === "string" ? event.turnId : "";
191
+ const taskRunId = typeof event.taskRunId === "string" ? event.taskRunId : taskByTurn.get(`${sessionId}\0${turnId}`) ?? "";
192
+ if (!sessionId || !taskRunId) return "";
193
+ return [
194
+ sessionId,
195
+ taskRunId,
196
+ event.model ?? "unknown",
197
+ event.thinkingLevel ?? "unknown"
198
+ ].join("\0");
199
+ }
200
+ var BOUND_IMPORT_STRING = `pi_import_string_(\\d+)`;
201
+ new RegExp(String.raw`(?<![.$\w])(?:import|export)\s+(?:type\s+)?[\w$*{},\s]+?\s+from\s+(${BOUND_IMPORT_STRING})`, "gu"), new RegExp(String.raw`(?<![.$\w])import\s+(${BOUND_IMPORT_STRING})`, "gu"), new RegExp(String.raw`(?<![.$\w])require\s*\(\s*(${BOUND_IMPORT_STRING})\s*\)`, "gu"), new RegExp(String.raw`(?<![.$\w])import\s*\(\s*(${BOUND_IMPORT_STRING})\s*\)`, "gu");
202
+ function directExplicitImportLinks(importRows, explicitRows) {
203
+ const explicitPaths = new Set(explicitRows.map((row) => row.path));
204
+ const byPath = /* @__PURE__ */ new Map();
205
+ const rankingRows = [];
206
+ const add = (candidatePath, kind, explicitPath) => {
207
+ const links = byPath.get(candidatePath) ?? [];
208
+ if (!links.some((link) => link.kind === kind && link.path === explicitPath)) {
209
+ links.push({
210
+ kind,
211
+ path: explicitPath
212
+ });
213
+ rankingRows.push({ path: candidatePath });
214
+ }
215
+ byPath.set(candidatePath, links);
216
+ };
217
+ for (const row of importRows) {
218
+ if (typeof row.specifier !== "string" || !/^\.{1,2}\//.test(row.specifier)) continue;
219
+ if (explicitPaths.has(row.file_path)) add(row.target_path, "explicit-imports-candidate", row.file_path);
220
+ if (explicitPaths.has(row.target_path)) add(row.file_path, "candidate-imports-explicit", row.target_path);
221
+ }
222
+ return {
223
+ byPath,
224
+ rankingRows
225
+ };
226
+ }
227
+ //#endregion
228
+ //#region ../piagent-core/extensions/context-query-paths.js
229
+ function normalizeRelative$1(value) {
230
+ return String(value ?? "").replaceAll("\\", "/").replace(/^\.\/+/, "").replace(/\/+/g, "/");
231
+ }
232
+ function safeProjectRelativeQueryPath(raw) {
233
+ const candidate = normalizeRelative$1(raw);
234
+ if (!candidate || candidate.length > 512 || path.posix.isAbsolute(candidate)) return void 0;
235
+ if (candidate.split("/").some((segment) => !segment || segment === "." || segment === "..")) return void 0;
236
+ return candidate;
237
+ }
238
+ function safeGlobSegment(segment) {
239
+ let bracketDepth = 0;
240
+ let braceDepth = 0;
241
+ for (const character of segment) if (character === "[") {
242
+ if (++bracketDepth > 1) return false;
243
+ } else if (character === "]") {
244
+ if (--bracketDepth < 0) return false;
245
+ } else if (character === "{") {
246
+ if (++braceDepth > 1) return false;
247
+ } else if (character === "}") {
248
+ if (--braceDepth < 0) return false;
249
+ } else if (character === "," && braceDepth === 0 || character === "!" && bracketDepth === 0) return false;
250
+ return bracketDepth === 0 && braceDepth === 0;
251
+ }
252
+ function safeProjectRelativeGlob(raw) {
253
+ const candidate = safeProjectRelativeQueryPath(String(raw ?? "").replace(/[.,]+$/u, ""));
254
+ if (!candidate || !candidate.includes("/") || !/[*?\[\]{}]/u.test(candidate)) return void 0;
255
+ if (!/^[\p{L}\p{N}_.@*?{}\[\]!,-]+(?:\/[\p{L}\p{N}_.@*?{}\[\]!,-]+)+$/u.test(candidate)) return void 0;
256
+ return candidate.split("/").every(safeGlobSegment) ? candidate : void 0;
257
+ }
258
+ function queryPathCandidates(query) {
259
+ const pattern = /(?:^|[\s"'`(])((?:\.{0,2}\/)?[\p{L}\p{N}_.@-]+(?:\/[\p{L}\p{N}_.@-]+)+|[\p{L}\p{N}_.@-]+\.[\p{L}\p{N}]{1,8}|\.[\p{L}\p{N}_@-]{1,32})(?=$|[\s"'`),:])/gu;
260
+ const globPattern = /(?:^|[\s"'(\x60=,:])((?:\.\/)?[\p{L}\p{N}_.@*?{}\[\]!,-]+(?:\/[\p{L}\p{N}_.@*?{}\[\]!,-]+)+)(?=$|[\s"'\x60),:;])/gu;
261
+ const explicitRoots = /^(?:\.github|app|apps|backend|bin|config|docs|examples|frontend|lib|logs|packages|pages|public|scripts|services|spec|src|test|tests|vendor|__tests__)\//i;
262
+ const text = String(query ?? "");
263
+ const candidates = [...text.matchAll(pattern)].flatMap((match) => {
264
+ const raw = match[1], candidate = safeProjectRelativeQueryPath(raw);
265
+ return candidate && (raw.startsWith("./") || explicitRoots.test(candidate) || candidate.split("/").length >= 3 || /(?:^|\/)(?:\.[^/]+|[^/]+\.[\p{L}\p{N}]{1,8})$/u.test(candidate)) ? [{
266
+ candidate,
267
+ index: match.index ?? 0
268
+ }] : [];
269
+ });
270
+ for (const match of text.matchAll(globPattern)) {
271
+ const candidate = safeProjectRelativeGlob(match[1]);
272
+ if (candidate) candidates.push({
273
+ candidate,
274
+ index: match.index ?? 0
275
+ });
276
+ }
277
+ candidates.sort((left, right) => left.index - right.index);
278
+ return [...new Set(candidates.map((entry) => entry.candidate))];
279
+ }
280
+ //#endregion
281
+ //#region ../piagent-core/extensions/context-engine.js
282
+ var INDEX_SCHEMA_VERSION = 2;
283
+ var RRF_K = 60;
284
+ var MAX_TELEMETRY_EVENTS = 5e4;
285
+ var MAX_TELEMETRY_READ_BYTES = 33554432;
286
+ var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
287
+ ".c",
288
+ ".cc",
289
+ ".cpp",
290
+ ".cs",
291
+ ".css",
292
+ ".dart",
293
+ ".ex",
294
+ ".exs",
295
+ ".go",
296
+ ".h",
297
+ ".hpp",
298
+ ".html",
299
+ ".java",
300
+ ".js",
301
+ ".jsx",
302
+ ".kt",
303
+ ".kts",
304
+ ".lua",
305
+ ".m",
306
+ ".md",
307
+ ".mdx",
308
+ ".php",
309
+ ".proto",
310
+ ".py",
311
+ ".rb",
312
+ ".rs",
313
+ ".scala",
314
+ ".scss",
315
+ ".sh",
316
+ ".sql",
317
+ ".svelte",
318
+ ".swift",
319
+ ".toml",
320
+ ".ts",
321
+ ".tsx",
322
+ ".vue",
323
+ ".xml",
324
+ ".yaml",
325
+ ".yml"
326
+ ]);
327
+ var SOURCE_NAMES = /* @__PURE__ */ new Set([
328
+ "AGENTS.md",
329
+ "Dockerfile",
330
+ "Makefile",
331
+ "Procfile",
332
+ "README",
333
+ "README.md",
334
+ "go.mod",
335
+ "package.json",
336
+ "pyproject.toml",
337
+ "requirements.txt",
338
+ "tsconfig.json"
339
+ ]);
340
+ var IGNORED_SEGMENTS = /* @__PURE__ */ new Set([
341
+ ".git",
342
+ ".next",
343
+ ".nuxt",
344
+ ".output",
345
+ ".turbo",
346
+ ".venv",
347
+ "build",
348
+ "coverage",
349
+ "dist",
350
+ "node_modules",
351
+ "out",
352
+ "target",
353
+ "vendor"
354
+ ]);
355
+ var SECRET_FILE_PATTERNS = [
356
+ /(^|\/)\.env(?:\.|$)/i,
357
+ /(^|\/)auth\.json$/i,
358
+ /(^|\/)(?:credentials?|secrets?|tokens?)\.json$/i,
359
+ /(^|\/)\.pi\/settings\.json$/i,
360
+ /(^|\/)\.pi\/piagent-profile(?:\.lock)?\.json$/i,
361
+ /(^|\/)\.pi\/piagent-state(?:\/|$)/i
362
+ ];
363
+ var STOP_TERMS = /* @__PURE__ */ new Set([
364
+ "about",
365
+ "after",
366
+ "agent",
367
+ "before",
368
+ "build",
369
+ "change",
370
+ "check",
371
+ "code",
372
+ "could",
373
+ "file",
374
+ "from",
375
+ "have",
376
+ "into",
377
+ "just",
378
+ "make",
379
+ "need",
380
+ "please",
381
+ "project",
382
+ "should",
383
+ "task",
384
+ "that",
385
+ "them",
386
+ "then",
387
+ "there",
388
+ "these",
389
+ "this",
390
+ "through",
391
+ "update",
392
+ "using",
393
+ "want",
394
+ "what",
395
+ "when",
396
+ "where",
397
+ "which",
398
+ "with",
399
+ "would",
400
+ "anh",
401
+ "cho",
402
+ "cua",
403
+ "em",
404
+ "giup",
405
+ "lam",
406
+ "minh",
407
+ "muon",
408
+ "nay",
409
+ "trong",
410
+ "voi"
411
+ ]);
412
+ var sqliteModulePromise;
413
+ var retrievalFeedbackCache = /* @__PURE__ */ new Map();
414
+ function normalizeRelative(value) {
415
+ return String(value ?? "").replaceAll("\\", "/").replace(/^\.\/+/, "").replace(/\/+/g, "/");
416
+ }
417
+ function clampInteger(value, fallback, min, max) {
418
+ const number = Number(value);
419
+ if (!Number.isFinite(number)) return fallback;
420
+ return Math.max(min, Math.min(max, Math.trunc(number)));
421
+ }
422
+ function ratio(numerator, denominator) {
423
+ return denominator > 0 ? numerator / denominator : 0;
424
+ }
425
+ function requireExplicitExcludePatterns(options, operation) {
426
+ if (!Array.isArray(options?.excludePatterns)) throw new TypeError(`${operation} requires an explicit excludePatterns array`);
427
+ return normalizeContextIndexExcludePatterns(options.excludePatterns);
428
+ }
429
+ function contextEnginePaths(cwd) {
430
+ const root = path.join(cwd, ".pi", "piagent-state", "context-engine");
431
+ return {
432
+ root,
433
+ database: path.join(root, "context-v2.sqlite"),
434
+ telemetry: path.join(root, "events.jsonl"),
435
+ report: path.join(root, "efficiency-report.json")
436
+ };
437
+ }
438
+ function hardenContextDatabaseArtifacts(cwd) {
439
+ const database = resolveLocalStatePath(cwd, contextEnginePaths(cwd).database, { label: "Context index database" });
440
+ for (const artifact of [
441
+ database,
442
+ `${database}-wal`,
443
+ `${database}-shm`
444
+ ]) try {
445
+ if (!fs.lstatSync(artifact).isFile()) throw new Error(`Context index storage path must be a regular file: ${artifact}`);
446
+ fs.chmodSync(artifact, 384);
447
+ } catch (error) {
448
+ if (error?.code !== "ENOENT") throw error;
449
+ }
450
+ }
451
+ async function loadSqlite() {
452
+ if (!sqliteModulePromise) sqliteModulePromise = (async () => {
453
+ const emitWarning = process.emitWarning;
454
+ process.emitWarning = function filteredWarning(warning, ...args) {
455
+ if ((warning instanceof Error ? warning.message : String(warning)).includes("SQLite is an experimental feature")) return;
456
+ return emitWarning.call(process, warning, ...args);
457
+ };
458
+ try {
459
+ return await import("node:sqlite");
460
+ } finally {
461
+ process.emitWarning = emitWarning;
462
+ }
463
+ })();
464
+ return sqliteModulePromise;
465
+ }
466
+ async function openDatabase(cwd, { create = true } = {}) {
467
+ const paths = contextEnginePaths(cwd);
468
+ const database = resolveLocalStatePath(cwd, paths.database, { label: "Context index database" });
469
+ if (!create && !fs.existsSync(database)) return void 0;
470
+ if (create) ensurePrivateStateDirectory(cwd, paths.root, "Context index storage root");
471
+ else {
472
+ const existingRoot = resolveLocalStatePath(cwd, paths.root, {
473
+ label: "Context index storage root",
474
+ kind: "directory"
475
+ });
476
+ try {
477
+ fs.chmodSync(existingRoot, 448);
478
+ } catch {}
479
+ }
480
+ hardenContextDatabaseArtifacts(cwd);
481
+ const descriptor = fs.openSync(database, fs.constants.O_RDWR | (create ? fs.constants.O_CREAT : 0) | (fs.constants.O_NOFOLLOW ?? 0), 384);
482
+ try {
483
+ fs.fchmodSync(descriptor, 384);
484
+ } finally {
485
+ fs.closeSync(descriptor);
486
+ }
487
+ const { DatabaseSync } = await loadSqlite();
488
+ const db = new DatabaseSync(database);
489
+ try {
490
+ db.exec(`
491
+ PRAGMA journal_mode = WAL;
492
+ PRAGMA synchronous = NORMAL;
493
+ PRAGMA foreign_keys = ON;
494
+ PRAGMA secure_delete = ON;
495
+ CREATE TABLE IF NOT EXISTS metadata (
496
+ key TEXT PRIMARY KEY,
497
+ value TEXT NOT NULL
498
+ );
499
+ CREATE TABLE IF NOT EXISTS files (
500
+ path TEXT PRIMARY KEY,
501
+ hash TEXT NOT NULL,
502
+ bytes INTEGER NOT NULL,
503
+ mtime_ms REAL NOT NULL,
504
+ language TEXT NOT NULL,
505
+ indexed_at TEXT NOT NULL
506
+ );
507
+ CREATE TABLE IF NOT EXISTS symbols (
508
+ id INTEGER PRIMARY KEY,
509
+ file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE,
510
+ name TEXT NOT NULL,
511
+ kind TEXT NOT NULL,
512
+ line INTEGER NOT NULL,
513
+ end_line INTEGER NOT NULL,
514
+ signature TEXT NOT NULL
515
+ );
516
+ CREATE INDEX IF NOT EXISTS symbols_name_idx ON symbols(name);
517
+ CREATE INDEX IF NOT EXISTS symbols_file_idx ON symbols(file_path);
518
+ CREATE TABLE IF NOT EXISTS imports (
519
+ id INTEGER PRIMARY KEY,
520
+ file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE,
521
+ specifier TEXT NOT NULL,
522
+ target_path TEXT,
523
+ line INTEGER NOT NULL
524
+ );
525
+ CREATE INDEX IF NOT EXISTS imports_file_idx ON imports(file_path);
526
+ CREATE INDEX IF NOT EXISTS imports_target_idx ON imports(target_path);
527
+ CREATE VIRTUAL TABLE IF NOT EXISTS file_fts USING fts5(
528
+ path UNINDEXED,
529
+ body,
530
+ symbol_names,
531
+ tokenize = 'unicode61 remove_diacritics 2'
532
+ );
533
+ `);
534
+ const ftsSecureDelete = db.prepare(`
535
+ SELECT v
536
+ FROM file_fts_config
537
+ WHERE k = 'secure-delete'
538
+ `).get();
539
+ if (Number(ftsSecureDelete?.v) !== 1) db.exec("INSERT INTO file_fts(file_fts, rank) VALUES('secure-delete', 1)");
540
+ hardenContextDatabaseArtifacts(cwd);
541
+ return db;
542
+ } catch (error) {
543
+ db.close();
544
+ throw error;
545
+ }
546
+ }
547
+ function metadataMap(db) {
548
+ const result = {};
549
+ for (const row of db.prepare("SELECT key, value FROM metadata").all()) result[row.key] = row.value;
550
+ return result;
551
+ }
552
+ function shouldIndexPath(relativePath, options = {}) {
553
+ const rel = normalizeRelative(relativePath);
554
+ if (!rel || path.isAbsolute(rel) || rel.startsWith("../")) return false;
555
+ if (rel.split("/").some((segment) => IGNORED_SEGMENTS.has(segment))) return false;
556
+ if (SECRET_FILE_PATTERNS.some((pattern) => pattern.test(rel))) return false;
557
+ if (matchesProtectedPath(rel, options.excludePatterns ?? [])) return false;
558
+ const name = path.posix.basename(rel);
559
+ return SOURCE_NAMES.has(name) || SOURCE_EXTENSIONS.has(path.posix.extname(name).toLowerCase());
560
+ }
561
+ function projectFileInfo(cwd, relativePath, root = fs.realpathSync.native(cwd), directoryCache = /* @__PURE__ */ new Map()) {
562
+ const expected = path.resolve(root, relativePath);
563
+ if (expected !== root && !expected.startsWith(`${root}${path.sep}`)) return void 0;
564
+ try {
565
+ const directPath = path.resolve(cwd, relativePath);
566
+ const directParent = path.dirname(directPath);
567
+ let canonicalParent = directoryCache.get(directParent);
568
+ if (canonicalParent === void 0) {
569
+ canonicalParent = fs.realpathSync.native(directParent);
570
+ directoryCache.set(directParent, canonicalParent);
571
+ }
572
+ if (canonicalParent !== path.dirname(expected)) return void 0;
573
+ const direct = fs.lstatSync(directPath);
574
+ if (direct.isSymbolicLink() || !direct.isFile()) return void 0;
575
+ return {
576
+ absolute: expected,
577
+ stat: direct
578
+ };
579
+ } catch {
580
+ return;
581
+ }
582
+ }
583
+ function gitFileList(cwd) {
584
+ try {
585
+ return execFileSync("git", [
586
+ "-C",
587
+ cwd,
588
+ "ls-files",
589
+ "--cached",
590
+ "--others",
591
+ "--exclude-standard",
592
+ "-z"
593
+ ], {
594
+ encoding: "utf8",
595
+ maxBuffer: 33554432,
596
+ stdio: [
597
+ "ignore",
598
+ "pipe",
599
+ "ignore"
600
+ ]
601
+ }).split("\0").filter(Boolean).map(normalizeRelative);
602
+ } catch {
603
+ return;
604
+ }
605
+ }
606
+ function foldSearchSignal(value) {
607
+ return String(value ?? "").normalize("NFKD").replace(/\p{M}/gu, "").replace(/[đĐ]/g, (character) => character === "Đ" ? "D" : "d").toLowerCase();
608
+ }
609
+ function tokenizeQuery(query) {
610
+ const terms = String(query ?? "").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replaceAll("_", " ").replaceAll("-", " ").match(/[\p{L}][\p{L}\p{N}]{1,63}/gu) ?? [];
611
+ return [...new Set(terms.map((term) => term.toLowerCase()).filter((term) => !STOP_TERMS.has(foldSearchSignal(term))))].slice(0, 16);
612
+ }
613
+ function ftsQuery(terms) {
614
+ return terms.map((term) => `"${term.replaceAll("\"", "\"\"")}"`).join(" OR ");
615
+ }
616
+ function gitChangedFiles(cwd) {
617
+ try {
618
+ return execFileSync("git", [
619
+ "-C",
620
+ cwd,
621
+ "diff",
622
+ "--name-only",
623
+ "--diff-filter=ACMR",
624
+ "HEAD"
625
+ ], {
626
+ encoding: "utf8",
627
+ stdio: [
628
+ "ignore",
629
+ "pipe",
630
+ "ignore"
631
+ ]
632
+ }).split(/\r?\n/).map(normalizeRelative).filter(Boolean);
633
+ } catch {
634
+ return [];
635
+ }
636
+ }
637
+ async function contextIndexV2Status(cwd, options = {}) {
638
+ const expectedExcludePatterns = requireExplicitExcludePatterns(options, "contextIndexV2Status");
639
+ const expectedExcludeDigest = contextIndexExcludeDigest(expectedExcludePatterns);
640
+ const paths = contextEnginePaths(cwd);
641
+ const projectRoot = fs.realpathSync.native(cwd);
642
+ const directoryCache = /* @__PURE__ */ new Map();
643
+ const database = resolveLocalStatePath(cwd, paths.database, { label: "Context index database" });
644
+ if (!fs.existsSync(database)) return {
645
+ schemaVersion: INDEX_SCHEMA_VERSION,
646
+ exists: false,
647
+ path: normalizeRelative(path.relative(cwd, paths.database)),
648
+ stale: false,
649
+ policyStale: false,
650
+ expectedExcludeDigest,
651
+ purgePending: false,
652
+ warnings: ["index-v2 missing"]
653
+ };
654
+ const db = await openDatabase(cwd, { create: false });
655
+ try {
656
+ const metadata = metadataMap(db);
657
+ const fileRows = db.prepare("SELECT path, bytes, mtime_ms FROM files").all();
658
+ const files = fileRows.length;
659
+ const symbols = Number(db.prepare("SELECT COUNT(*) count FROM symbols").get().count);
660
+ const imports = Number(db.prepare("SELECT COUNT(*) count FROM imports").get().count);
661
+ const indexedPaths = new Set(fileRows.map((row) => row.path));
662
+ const storedExcludeDigest = metadata.excludeDigest;
663
+ const purgePending = metadata.purgePending === "1";
664
+ const excludeDigestStale = typeof storedExcludeDigest !== "string" || storedExcludeDigest !== expectedExcludeDigest;
665
+ const policyStale = purgePending || excludeDigestStale;
666
+ const statChanged = [];
667
+ for (const row of fileRows) {
668
+ if (!shouldIndexPath(row.path, { excludePatterns: expectedExcludePatterns })) continue;
669
+ const file = projectFileInfo(cwd, row.path, projectRoot, directoryCache);
670
+ if (!file || file.stat.size !== Number(row.bytes) || Math.abs(file.stat.mtimeMs - Number(row.mtime_ms)) >= .5) statChanged.push(row.path);
671
+ }
672
+ let skippedPaths = /* @__PURE__ */ new Set();
673
+ try {
674
+ const parsed = JSON.parse(metadata.skippedPaths ?? "[]");
675
+ if (Array.isArray(parsed)) skippedPaths = new Set(parsed.filter((value) => typeof value === "string"));
676
+ } catch {
677
+ skippedPaths = /* @__PURE__ */ new Set();
678
+ }
679
+ const listed = gitFileList(cwd);
680
+ const newlyVisible = listed ? listed.filter((file) => !indexedPaths.has(file) && !skippedPaths.has(file) && shouldIndexPath(file, { excludePatterns: expectedExcludePatterns })) : [];
681
+ const stalePaths = [.../* @__PURE__ */ new Set([...statChanged, ...newlyVisible])];
682
+ const warnings = [];
683
+ if (purgePending) warnings.push("context index storage purge pending");
684
+ if (excludeDigestStale) warnings.push("context index exclusion policy changed");
685
+ if (stalePaths.length > 0) warnings.push(`${stalePaths.length} changed file(s) since the last index build`);
686
+ return {
687
+ schemaVersion: Number(metadata.schemaVersion ?? INDEX_SCHEMA_VERSION),
688
+ exists: true,
689
+ path: normalizeRelative(path.relative(cwd, paths.database)),
690
+ builtAt: metadata.builtAt,
691
+ files,
692
+ symbols,
693
+ imports,
694
+ stale: policyStale || stalePaths.length > 0,
695
+ policyStale,
696
+ purgePending,
697
+ excludePolicyVersion: metadata.excludePolicyVersion,
698
+ excludeDigest: storedExcludeDigest,
699
+ expectedExcludeDigest,
700
+ stalePaths: stalePaths.slice(0, 20),
701
+ warnings
702
+ };
703
+ } finally {
704
+ db.close();
705
+ }
706
+ }
707
+ function addRankedList(scores, rows, source, weight = 1) {
708
+ rows.forEach((row, index) => {
709
+ const filePath = row.path ?? row.file_path;
710
+ if (!filePath) return;
711
+ const current = scores.get(filePath) ?? {
712
+ path: filePath,
713
+ score: 0,
714
+ sources: /* @__PURE__ */ new Set(),
715
+ rows: []
716
+ };
717
+ current.score += weight / (RRF_K + index + 1);
718
+ current.sources.add(source);
719
+ current.rows.push({
720
+ source,
721
+ ...row
722
+ });
723
+ scores.set(filePath, current);
724
+ });
725
+ }
726
+ function personalizedPageRank(importRows, seeds, iterations = 8) {
727
+ const nodes = /* @__PURE__ */ new Set();
728
+ const outgoing = /* @__PURE__ */ new Map();
729
+ for (const row of importRows) {
730
+ if (!row.target_path) continue;
731
+ nodes.add(row.file_path);
732
+ nodes.add(row.target_path);
733
+ const targets = outgoing.get(row.file_path) ?? /* @__PURE__ */ new Set();
734
+ targets.add(row.target_path);
735
+ outgoing.set(row.file_path, targets);
736
+ }
737
+ for (const seed of seeds.keys()) nodes.add(seed);
738
+ if (nodes.size === 0) return [];
739
+ const seedTotal = [...seeds.values()].reduce((sum, value) => sum + Math.max(value, 0), 0) || 1;
740
+ const teleport = new Map([...nodes].map((node) => [node, (seeds.get(node) ?? 0) / seedTotal]));
741
+ let rank = new Map(teleport);
742
+ const alpha = .85;
743
+ for (let iteration = 0; iteration < iterations; iteration += 1) {
744
+ const next = new Map([...nodes].map((node) => [node, .15000000000000002 * (teleport.get(node) ?? 0)]));
745
+ let dangling = 0;
746
+ for (const node of nodes) {
747
+ const targets = outgoing.get(node);
748
+ if (!targets?.size) {
749
+ dangling += rank.get(node) ?? 0;
750
+ continue;
751
+ }
752
+ const share = alpha * (rank.get(node) ?? 0) / targets.size;
753
+ for (const target of targets) next.set(target, (next.get(target) ?? 0) + share);
754
+ }
755
+ for (const node of nodes) next.set(node, (next.get(node) ?? 0) + alpha * dangling * (teleport.get(node) ?? 1 / nodes.size));
756
+ rank = next;
757
+ }
758
+ return [...rank.entries()].sort((left, right) => right[1] - left[1]).map(([filePath, score]) => ({
759
+ path: filePath,
760
+ graphScore: score
761
+ }));
762
+ }
763
+ function retrievalFeedback(cwd) {
764
+ let signature = "missing";
765
+ try {
766
+ const target = resolveLocalStatePath(cwd, contextEnginePaths(cwd).telemetry, { label: "Context telemetry" });
767
+ const stat = fs.statSync(target);
768
+ signature = `${stat.size}:${stat.mtimeMs}`;
769
+ } catch {
770
+ return {
771
+ rows: [],
772
+ observedSelected: 0,
773
+ selected: 0,
774
+ used: 0,
775
+ unused: 0,
776
+ utilizationRate: 0,
777
+ fallbackRereads: 0,
778
+ fallbackRereadRate: 0
779
+ };
780
+ }
781
+ const cached = retrievalFeedbackCache.get(cwd);
782
+ if (cached?.signature === signature) return cached.value;
783
+ const events = readContextTelemetry(cwd, {
784
+ limit: 12e3,
785
+ maxBytes: 12582912
786
+ });
787
+ const selectedCounts = /* @__PURE__ */ new Map();
788
+ const usedCounts = /* @__PURE__ */ new Map();
789
+ const fallbackReadCounts = /* @__PURE__ */ new Map();
790
+ const latestPackByPartition = /* @__PURE__ */ new Map();
791
+ const taskByTurn = new Map(events.filter((event) => event.event === "turn_task_bound" && typeof event.sessionId === "string" && typeof event.turnId === "string" && typeof event.taskRunId === "string").map((event) => [`${event.sessionId}\0${event.turnId}`, event.taskRunId]));
792
+ let observedSelected = 0, selected = 0, used = 0, fallbackRereads = 0;
793
+ const eventPaths = (event) => [...new Set([...Array.isArray(event.selectedPaths) ? event.selectedPaths : [], ...Array.isArray(event.selectedItems) ? event.selectedItems.map((item) => item?.path) : []].map(normalizeRelative).filter((filePath) => shouldIndexPath(filePath, {})))];
794
+ const successfulMutationPaths = (event) => {
795
+ if (event.event !== "tool_result" || event.isError === true) return [];
796
+ const explicit = [
797
+ event.changedPaths,
798
+ event.mutationPaths,
799
+ event.targetPaths
800
+ ].find((value) => Array.isArray(value));
801
+ if (explicit) return [...new Set(explicit.map(normalizeRelative).filter(Boolean))];
802
+ const toolName = String(event.toolName ?? "").toLowerCase();
803
+ if (![
804
+ "write",
805
+ "edit",
806
+ "apply_patch",
807
+ "patch"
808
+ ].includes(toolName)) return [];
809
+ const targetPath = normalizeRelative(event.targetPath);
810
+ return targetPath ? [targetPath] : [];
811
+ };
812
+ for (const event of events) {
813
+ const partition = contextMetricPartition(event, taskByTurn);
814
+ if (event.event === "context_pack_injected") {
815
+ const selectedPaths = eventPaths(event);
816
+ observedSelected += selectedPaths.length;
817
+ if (!partition) continue;
818
+ const pack = {
819
+ selectedPaths: new Set(selectedPaths),
820
+ usedPaths: /* @__PURE__ */ new Set(),
821
+ fallbackReadPaths: /* @__PURE__ */ new Set()
822
+ };
823
+ latestPackByPartition.set(partition, pack);
824
+ for (const filePath of selectedPaths) {
825
+ selectedCounts.set(filePath, (selectedCounts.get(filePath) ?? 0) + 1);
826
+ selected += 1;
827
+ }
828
+ continue;
829
+ }
830
+ if (!partition) continue;
831
+ const pack = latestPackByPartition.get(partition);
832
+ if (!pack) continue;
833
+ const targetPath = normalizeRelative(event.targetPath);
834
+ if (event.event === "tool_call" && [
835
+ "read",
836
+ "grep",
837
+ "find",
838
+ "ls"
839
+ ].includes(event.toolName) && targetPath && pack.selectedPaths.has(targetPath) && !pack.fallbackReadPaths.has(targetPath)) {
840
+ pack.fallbackReadPaths.add(targetPath);
841
+ fallbackReadCounts.set(targetPath, (fallbackReadCounts.get(targetPath) ?? 0) + 1);
842
+ fallbackRereads += 1;
843
+ continue;
844
+ }
845
+ for (const mutationPath of successfulMutationPaths(event)) {
846
+ if (!pack.selectedPaths.has(mutationPath) || pack.usedPaths.has(mutationPath)) continue;
847
+ pack.usedPaths.add(mutationPath);
848
+ usedCounts.set(mutationPath, (usedCounts.get(mutationPath) ?? 0) + 1);
849
+ used += 1;
850
+ }
851
+ }
852
+ const value = {
853
+ rows: [...usedCounts.entries()].map(([filePath, usedCount]) => {
854
+ const selectedCount = selectedCounts.get(filePath) ?? usedCount;
855
+ const utilization = ratio(usedCount, selectedCount);
856
+ const evidence = Math.min(1, selectedCount / 3);
857
+ return {
858
+ path: filePath,
859
+ selectedCount,
860
+ usedCount,
861
+ fallbackRereadCount: fallbackReadCounts.get(filePath) ?? 0,
862
+ feedbackScore: utilization * evidence
863
+ };
864
+ }).sort((left, right) => right.feedbackScore - left.feedbackScore || right.usedCount - left.usedCount || left.path.localeCompare(right.path)),
865
+ observedSelected,
866
+ selected,
867
+ used,
868
+ unused: Math.max(0, selected - used),
869
+ utilizationRate: ratio(used, selected),
870
+ fallbackRereads,
871
+ fallbackRereadRate: ratio(fallbackRereads, selected)
872
+ };
873
+ retrievalFeedbackCache.set(cwd, {
874
+ signature,
875
+ value
876
+ });
877
+ return value;
878
+ }
879
+ async function searchContextIndexV2(cwd, query, options = {}) {
880
+ const excludePatterns = requireExplicitExcludePatterns(options, "searchContextIndexV2");
881
+ const limit = clampInteger(options.limit, 12, 1, 50);
882
+ const projectRoot = fs.realpathSync.native(cwd);
883
+ const directoryCache = /* @__PURE__ */ new Map();
884
+ const status = await contextIndexV2Status(cwd, { excludePatterns });
885
+ if (!status.exists) return {
886
+ query,
887
+ terms: [],
888
+ confidence: "none",
889
+ results: [],
890
+ status
891
+ };
892
+ const terms = tokenizeQuery(query);
893
+ const explicitPaths = queryPathCandidates(query);
894
+ if (terms.length === 0 && explicitPaths.length === 0) return {
895
+ query,
896
+ terms,
897
+ confidence: "none",
898
+ results: [],
899
+ status
900
+ };
901
+ const db = await openDatabase(cwd, { create: false });
902
+ try {
903
+ const scores = /* @__PURE__ */ new Map();
904
+ const pathAllowed = (filePath) => shouldIndexPath(filePath, { excludePatterns });
905
+ const allFiles = db.prepare("SELECT path, mtime_ms FROM files").all().filter((file) => pathAllowed(file.path));
906
+ const explicitRows = [];
907
+ for (const file of allFiles) {
908
+ const normalizedFile = file.path.toLowerCase();
909
+ const basename = path.posix.basename(file.path).toLowerCase();
910
+ if (explicitPaths.some((candidate) => {
911
+ const normalized = candidate.toLowerCase();
912
+ return normalizedFile === normalized || !normalized.includes("/") && basename === normalized;
913
+ })) explicitRows.push({
914
+ path: file.path,
915
+ exact: true
916
+ });
917
+ }
918
+ addRankedList(scores, explicitRows, "explicit", 3);
919
+ let lexicalRows = [];
920
+ if (terms.length > 0) {
921
+ lexicalRows = db.prepare(`
922
+ SELECT path, bm25(file_fts, 0.0, 1.0, 2.2) lexical_score
923
+ FROM file_fts WHERE file_fts MATCH ? ORDER BY lexical_score LIMIT ?
924
+ `).all(ftsQuery(terms), Math.max(limit * 4, 30)).filter((row) => pathAllowed(row.path));
925
+ addRankedList(scores, lexicalRows, "lexical", 1.5);
926
+ }
927
+ const symbolRows = [];
928
+ const symbolStatement = db.prepare(`
929
+ SELECT file_path, name, kind, line, end_line, signature
930
+ FROM symbols WHERE lower(name) = ? OR lower(name) LIKE ?
931
+ ORDER BY CASE WHEN lower(name) = ? THEN 0 ELSE 1 END, length(name) LIMIT ?
932
+ `);
933
+ for (const term of terms.slice(0, 8)) symbolRows.push(...symbolStatement.all(term, `%${term}%`, term, Math.max(limit * 2, 20)).filter((row) => pathAllowed(row.file_path)));
934
+ addRankedList(scores, [...new Map(symbolRows.map((row) => [`${row.file_path}:${row.line}`, row])).values()], "symbol", 2.2);
935
+ addRankedList(scores, gitChangedFiles(cwd).map((filePath) => ({ path: filePath })).filter((row) => scores.has(row.path)), "git-change", .8);
936
+ addRankedList(scores, allFiles.filter((file) => /(^|\/)(?:test|tests|__tests__)(\/|$)|(?:\.test|\.spec|_test)\./i.test(file.path)).filter((file) => terms.some((term) => file.path.toLowerCase().includes(term))).map((file) => ({ path: file.path })), "test", 1.1);
937
+ addRankedList(scores, retrievalFeedback(cwd).rows.filter((row) => scores.has(row.path)), "feedback", .45);
938
+ const graphSeeds = new Map([...scores.entries()].map(([filePath, value]) => [filePath, value.score]));
939
+ const importRows = db.prepare("SELECT file_path, specifier, target_path FROM imports WHERE target_path IS NOT NULL").all().filter((row) => pathAllowed(row.file_path) && pathAllowed(row.target_path));
940
+ const directLinks = directExplicitImportLinks(importRows, explicitRows);
941
+ addRankedList(scores, directLinks.rankingRows, "import", 1.8);
942
+ addRankedList(scores, personalizedPageRank(importRows, graphSeeds).slice(0, Math.max(limit * 3, 30)), "graph", 1);
943
+ const ranked = [...scores.values()].filter((candidate) => shouldIndexPath(candidate.path, { excludePatterns }) && projectFileInfo(cwd, candidate.path, projectRoot, directoryCache)).sort((left, right) => right.score - left.score).slice(0, limit);
944
+ const symbolLookup = db.prepare("SELECT name, kind, line, end_line, signature FROM symbols WHERE file_path = ? ORDER BY line LIMIT 12");
945
+ const results = ranked.map((candidate) => {
946
+ const matchingSymbols = candidate.rows.filter((row) => row.source === "symbol").map((row) => ({
947
+ name: row.name,
948
+ kind: row.kind,
949
+ line: row.line,
950
+ endLine: row.end_line,
951
+ signature: row.signature
952
+ }));
953
+ const symbols = matchingSymbols.length > 0 ? matchingSymbols : symbolLookup.all(candidate.path).slice(0, 6).map((row) => ({
954
+ name: row.name,
955
+ kind: row.kind,
956
+ line: row.line,
957
+ endLine: row.end_line,
958
+ signature: row.signature
959
+ }));
960
+ return {
961
+ path: candidate.path,
962
+ score: Number(candidate.score.toFixed(6)),
963
+ sources: [...candidate.sources],
964
+ links: directLinks.byPath.get(candidate.path) ?? [],
965
+ symbols
966
+ };
967
+ });
968
+ const top = results[0];
969
+ const exact = Boolean(top?.sources.includes("explicit")) || Boolean(top?.sources.includes("symbol") && top.sources.length >= 2);
970
+ return {
971
+ query,
972
+ terms,
973
+ confidence: !top ? "none" : exact ? "high" : top.sources.length >= 2 ? "medium" : "low",
974
+ results,
975
+ status
976
+ };
977
+ } finally {
978
+ db.close();
979
+ }
980
+ }
981
+ function readContextTelemetry(cwd, options = {}) {
982
+ const target = contextEnginePaths(cwd).telemetry;
983
+ return readJsonlTail(target, {
984
+ limit: clampInteger(options.limit, MAX_TELEMETRY_EVENTS, 1, MAX_TELEMETRY_EVENTS),
985
+ maxBytes: clampInteger(options.maxBytes, MAX_TELEMETRY_READ_BYTES, 65536, 268435456),
986
+ projectRoot: cwd
987
+ });
988
+ }
989
+ //#endregion
990
+ //#region ../piagent-core/extensions/workspace-search-index.mjs
991
+ try {
992
+ const result = await searchContextIndexV2(workerData.root, workerData.query, {
993
+ excludePatterns: workerData.excludePatterns,
994
+ limit: 50
995
+ });
996
+ parentPort.postMessage({
997
+ paths: result.results.map((row) => row.path),
998
+ available: result.status.exists
999
+ });
1000
+ } catch {
1001
+ parentPort.postMessage({
1002
+ paths: [],
1003
+ available: false
1004
+ });
1005
+ }
1006
+ //#endregion
1007
+ export {};