@pikku/core 0.12.139 → 0.12.142

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 (253) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/errors/errors.d.ts +1 -1
  3. package/dist/errors/errors.js +1 -1
  4. package/dist/function/function-meta.types.d.ts +6 -6
  5. package/dist/function/functions.types.d.ts +2 -2
  6. package/dist/lifecycle.d.ts +6 -0
  7. package/dist/lifecycle.js +58 -0
  8. package/dist/services/audit-service.d.ts +4 -4
  9. package/dist/services/feature-flag-service.d.ts +3 -3
  10. package/dist/services/{http-personas.d.ts → http-virtual-users.d.ts} +25 -47
  11. package/dist/services/{http-personas.js → http-virtual-users.js} +29 -53
  12. package/dist/services/index.d.ts +2 -2
  13. package/dist/services/index.js +1 -1
  14. package/dist/services/meta-service.d.ts +6 -6
  15. package/dist/services/meta-service.js +8 -8
  16. package/dist/{wirings/workflow → services}/scenario-cookie-jar.d.ts +2 -0
  17. package/dist/{wirings/workflow → services}/scenario-cookie-jar.js +18 -14
  18. package/dist/services/scoped-secret-service.d.ts +1 -0
  19. package/dist/services/scoped-secret-service.js +3 -0
  20. package/dist/services/secret-service.d.ts +6 -0
  21. package/dist/services/system-role-guard.d.ts +1 -1
  22. package/dist/services/typed-secret-service.d.ts +1 -0
  23. package/dist/services/typed-secret-service.js +7 -0
  24. package/dist/services/virtual-user-sign-in.d.ts +52 -0
  25. package/dist/services/virtual-user-sign-in.js +80 -0
  26. package/dist/services/virtual-user-statement.d.ts +31 -0
  27. package/dist/services/virtual-user-statement.js +24 -0
  28. package/dist/services/{personas-service.d.ts → virtual-users-service.d.ts} +25 -23
  29. package/dist/services/{personas-service.js → virtual-users-service.js} +3 -3
  30. package/dist/testing/service-tests/secret-service-tests.js +9 -0
  31. package/dist/types/core.types.d.ts +11 -11
  32. package/dist/utils.d.ts +2 -5
  33. package/dist/utils.js +1 -38
  34. package/dist/wirings/cli/cli-runner.js +24 -9
  35. package/dist/wirings/http/http-runner.js +4 -0
  36. package/dist/wirings/http/http.types.d.ts +1 -0
  37. package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
  38. package/dist/wirings/http/pikku-fetch-http-response.js +12 -0
  39. package/dist/wirings/http/web-request.js +7 -0
  40. package/dist/wirings/role/define-system-role.d.ts +1 -1
  41. package/dist/wirings/role/define-system-role.js +1 -1
  42. package/dist/wirings/{actor-flow/actor-flow.types.d.ts → virtual-user/conversation/conversation.types.d.ts} +5 -5
  43. package/dist/wirings/virtual-user/conversation/index.d.ts +2 -0
  44. package/dist/wirings/virtual-user/conversation/run-conversation.d.ts +36 -0
  45. package/dist/wirings/{actor-flow → virtual-user/conversation}/run-conversation.js +30 -30
  46. package/dist/wirings/virtual-user/define-virtual-users.d.ts +32 -0
  47. package/dist/wirings/{persona/define-personas.js → virtual-user/define-virtual-users.js} +9 -9
  48. package/dist/wirings/virtual-user/index.d.ts +30 -7
  49. package/dist/wirings/virtual-user/index.js +23 -4
  50. package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +8 -8
  51. package/dist/wirings/virtual-user/prepare-virtual-user-run.js +9 -9
  52. package/dist/wirings/virtual-user/run-virtual-user.d.ts +6 -6
  53. package/dist/wirings/virtual-user/run-virtual-user.js +10 -10
  54. package/dist/wirings/{persona/validate-personas.d.ts → virtual-user/validate-virtual-users.d.ts} +11 -11
  55. package/dist/wirings/{persona/validate-personas.js → virtual-user/validate-virtual-users.js} +24 -24
  56. package/dist/wirings/virtual-user/virtual-user-agents.d.ts +7 -7
  57. package/dist/wirings/virtual-user/virtual-user-agents.js +2 -2
  58. package/dist/wirings/{persona/persona-app-scopes.d.ts → virtual-user/virtual-user-app-scopes.d.ts} +10 -10
  59. package/dist/wirings/{persona/persona-app-scopes.js → virtual-user/virtual-user-app-scopes.js} +12 -12
  60. package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +3 -3
  61. package/dist/wirings/virtual-user/virtual-user-catalogue.js +2 -2
  62. package/dist/wirings/{persona/persona.types.d.ts → virtual-user/virtual-user-declaration.types.d.ts} +24 -24
  63. package/dist/wirings/virtual-user/virtual-user-derive.js +13 -7
  64. package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +1 -1
  65. package/dist/wirings/{persona/persona-email.d.ts → virtual-user/virtual-user-email.d.ts} +11 -11
  66. package/dist/wirings/{persona/persona-email.js → virtual-user/virtual-user-email.js} +19 -19
  67. package/dist/wirings/{persona/persona-environments.d.ts → virtual-user/virtual-user-environments.d.ts} +10 -10
  68. package/dist/wirings/{persona/persona-environments.js → virtual-user/virtual-user-environments.js} +21 -21
  69. package/dist/wirings/virtual-user/virtual-user-intents.d.ts +3 -3
  70. package/dist/wirings/virtual-user/virtual-user-intents.js +3 -3
  71. package/dist/wirings/{persona/persona-mailbox.d.ts → virtual-user/virtual-user-mailbox.d.ts} +4 -4
  72. package/dist/wirings/virtual-user/virtual-user-run-store.d.ts +4 -4
  73. package/dist/wirings/virtual-user/virtual-user-scaffold.d.ts +42 -61
  74. package/dist/wirings/virtual-user/virtual-user-scaffold.js +69 -117
  75. package/dist/wirings/virtual-user/virtual-user-schedule-store.d.ts +15 -15
  76. package/dist/wirings/virtual-user/virtual-user-schedule.d.ts +6 -6
  77. package/dist/wirings/virtual-user/virtual-user-schedule.js +11 -11
  78. package/dist/wirings/virtual-user/virtual-user-target.d.ts +6 -6
  79. package/dist/wirings/virtual-user/virtual-user-target.js +5 -5
  80. package/dist/wirings/virtual-user/virtual-user.types.d.ts +11 -11
  81. package/dist/wirings/virtual-user/virtual-user.types.js +1 -1
  82. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +9 -9
  83. package/dist/wirings/workflow/pikku-scenario-service.d.ts +28 -28
  84. package/dist/wirings/workflow/pikku-scenario-service.js +77 -77
  85. package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -2
  86. package/dist/wirings/workflow/pikku-workflow-service.js +4 -4
  87. package/dist/wirings/workflow/scenario-prose.d.ts +8 -8
  88. package/dist/wirings/workflow/scenario-prose.js +12 -8
  89. package/dist/wirings/workflow/scenario-run.types.d.ts +13 -13
  90. package/dist/wirings/workflow/scenario-step.types.d.ts +23 -23
  91. package/dist/wirings/workflow/workflow.types.d.ts +2 -2
  92. package/knowledge/decisions/index.md +0 -2
  93. package/knowledge/decisions/internals/a-credential-name-declared-twice-must-agree-on-schema-and-type.md +29 -0
  94. package/knowledge/decisions/internals/a-grant-can-name-a-scope-declared-without-its-addon.md +29 -0
  95. package/knowledge/decisions/internals/a-scheduled-task-writes-its-caller-session-before-it-runs.md +22 -0
  96. package/knowledge/decisions/internals/a-secret-set-in-memory-shadows-the-variable-of-the-same-name.md +28 -0
  97. package/knowledge/decisions/internals/a-virtual-user-acts-through-invokeraw-so-a-refusal-is-data.md +32 -0
  98. package/knowledge/decisions/internals/a-virtual-user-cadence-is-a-row-not-a-timer.md +12 -12
  99. package/knowledge/decisions/internals/a-virtual-user-converse-signs-in-before-its-first-turn.md +24 -0
  100. package/knowledge/decisions/internals/a-virtual-user-email-is-computed-with-the-run-id-as-a-sub-address.md +34 -0
  101. package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-but-it-needs-a-trigger.md +2 -2
  102. package/knowledge/decisions/internals/an-agent-is-offered-under-its-registry-key-and-only-within-the-virtual-users-scopes.md +27 -0
  103. package/knowledge/decisions/internals/an-oauth2-credential-implies-an-optional-app-secret.md +26 -0
  104. package/knowledge/decisions/internals/analytics-identity-resolvers-run-in-declared-order.md +22 -0
  105. package/knowledge/decisions/internals/feature-flag-declarations-refuse-an-empty-anyof-and-conflicting-scopes.md +22 -0
  106. package/knowledge/decisions/internals/feature-flags-fail-open-and-never-enforce-access.md +28 -0
  107. package/knowledge/decisions/internals/flag-sync-rewrites-only-the-declared-text.md +24 -0
  108. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +3 -3
  109. package/knowledge/decisions/internals/index.md +46 -31
  110. package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +10 -10
  111. package/knowledge/decisions/internals/role-names-cannot-contain-the-scope-separator.md +30 -0
  112. package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +23 -19
  113. package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +2 -2
  114. package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +12 -12
  115. package/knowledge/decisions/internals/the-core-scope-validator-refuses-separator-wildcard-and-empty-segments.md +22 -0
  116. package/knowledge/decisions/internals/the-pikku-user-id-resolves-in-a-fixed-order.md +24 -0
  117. package/knowledge/decisions/internals/{the-actor-prompt-says-json-because-of-json-object-mode.md → the-virtual-user-prompt-says-json-because-of-json-object-mode.md} +4 -4
  118. package/knowledge/decisions/internals/{the-persona-runtime-is-exported-from-the-persona-entry-point.md → the-virtual-user-runtime-is-exported-from-the-virtual-user-entry-point.md} +8 -8
  119. package/knowledge/decisions/internals/validate-checks-virtual-users-through-a-shared-module.md +43 -0
  120. package/knowledge/decisions/internals/{actor-flow-drives-the-target-through-a-transport-seam.md → virtual-user-conversation-drives-the-target-through-a-transport-seam.md} +6 -6
  121. package/knowledge/decisions/internals/virtual-user-conversation-verdicts-are-llm-self-evaluations.md +25 -0
  122. package/knowledge/decisions/internals/virtual-user-conversations-seed-a-hidden-kickoff-message.md +23 -0
  123. package/knowledge/decisions/internals/virtual-users-are-declared-in-one-definevirtualusers-call-per-codebase.md +30 -0
  124. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +5 -5
  125. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +2 -2
  126. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +4 -4
  127. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +1 -1
  128. package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +2 -2
  129. package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +1 -1
  130. package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +1 -1
  131. package/knowledge/decisions/security/a-bearer-token-checked-against-a-secret-reads-it-per-request.md +26 -0
  132. package/knowledge/decisions/security/a-call-without-a-session-raises-missing-session-not-forbidden.md +20 -0
  133. package/knowledge/decisions/security/a-caller-cookie-wins-over-the-jar-for-the-same-name.md +23 -0
  134. package/knowledge/decisions/security/a-channel-lifecycle-acts-as-the-socket-upgrade-session.md +16 -0
  135. package/knowledge/decisions/security/a-channel-requires-a-session-unless-it-says-auth-false.md +26 -0
  136. package/knowledge/decisions/security/a-credential-read-path-follows-its-declared-type-not-absence.md +32 -0
  137. package/knowledge/decisions/security/a-credential-type-is-a-literal-the-inspector-checks-at-declaration.md +27 -0
  138. package/knowledge/decisions/security/a-first-party-cookie-is-written-only-after-its-purposes-consent.md +33 -0
  139. package/knowledge/decisions/security/a-readonly-session-reaches-only-readonly-functions.md +25 -0
  140. package/knowledge/decisions/security/a-scaffold-flag-says-a-surface-exists-not-who-may-call-it.md +10 -5
  141. package/knowledge/decisions/security/a-scheduled-virtual-user-run-needs-no-admin-at-run-time.md +27 -0
  142. package/knowledge/decisions/security/a-scoped-credential-view-is-limited-to-declared-names.md +26 -0
  143. package/knowledge/decisions/security/a-scoped-secret-view-reads-only-declared-keys-and-never-writes.md +25 -0
  144. package/knowledge/decisions/security/a-secret-is-sent-only-to-the-hosts-it-declares.md +29 -0
  145. package/knowledge/decisions/security/a-step-can-name-an-identity-no-virtual-user-holds-through-per-call-headers.md +25 -0
  146. package/knowledge/decisions/security/a-stopped-run-by-id-skips-the-ownership-check.md +24 -0
  147. package/knowledge/decisions/security/a-vault-secret-redacts-on-serialization-and-throws-on-coercion.md +29 -0
  148. package/knowledge/decisions/security/a-virtual-user-catalogue-entry-is-filtered-by-scope-and-approval-is-denied-by-default.md +30 -0
  149. package/knowledge/decisions/security/a-virtual-user-environment-fails-closed.md +38 -0
  150. package/knowledge/decisions/security/a-virtual-user-never-runs-against-production.md +23 -0
  151. package/knowledge/decisions/security/a-virtual-user-reads-its-roles-from-the-apps-own-rpc-before-better-auth.md +27 -0
  152. package/knowledge/decisions/security/a-virtual-user-run-treats-an-unresolved-environment-as-production.md +41 -0
  153. package/knowledge/decisions/security/a-virtual-user-scopes-are-expanded-from-its-roles-once-at-run-preparation.md +25 -0
  154. package/knowledge/decisions/security/a-virtual-user-whose-roles-drift-from-the-declaration-refuses-to-run.md +32 -0
  155. package/knowledge/decisions/security/addon-screen-scopes-hide-and-do-not-enforce.md +20 -0
  156. package/knowledge/decisions/security/an-addon-header-can-only-narrow-the-session.md +26 -0
  157. package/knowledge/decisions/security/an-addon-instance-reads-only-the-secrets-and-credentials-it-is-named.md +33 -0
  158. package/knowledge/decisions/security/an-addon-may-reach-only-itself-and-the-addons-it-uses.md +16 -0
  159. package/knowledge/decisions/security/an-api-key-is-jwt-decoded-into-the-session.md +26 -0
  160. package/knowledge/decisions/security/an-external-virtual-user-caller-presents-one-signed-statement.md +38 -0
  161. package/knowledge/decisions/security/an-inbound-webhook-source-dispatches-only-verified-requests.md +31 -0
  162. package/knowledge/decisions/security/an-mcp-call-with-no-http-request-stays-anonymous.md +18 -0
  163. package/knowledge/decisions/security/an-omitted-user-id-addresses-the-platform-credential.md +32 -0
  164. package/knowledge/decisions/security/analytics-identity-is-stamped-from-the-session-not-the-event.md +24 -0
  165. package/knowledge/decisions/security/app-access-is-a-scope-tree-synthesised-from-virtual-users.md +26 -0
  166. package/knowledge/decisions/security/approval-policy-decides-who-answers-a-tool-call.md +27 -0
  167. package/knowledge/decisions/security/auth-false-on-a-session-function-warns-and-still-requires-one.md +25 -0
  168. package/knowledge/decisions/security/bearer-token-hashes-are-unpeppered-sha256.md +18 -0
  169. package/knowledge/decisions/security/consent-is-read-from-a-cookie-and-a-recognised-denial-counts-as-refusal.md +29 -0
  170. package/knowledge/decisions/security/cors-defaults-to-any-origin-and-refuses-the-wildcard-with-credentials.md +22 -0
  171. package/knowledge/decisions/security/credential-backends-share-one-conformance-suite-for-per-user-isolation.md +29 -0
  172. package/knowledge/decisions/security/each-stage-has-one-virtual-user-key-pair.md +27 -0
  173. package/knowledge/decisions/security/hmac-verification-fails-closed-on-empty-inputs.md +25 -0
  174. package/knowledge/decisions/security/index.md +88 -24
  175. package/knowledge/decisions/security/local-content-refuses-private-buckets-under-the-public-segment.md +21 -0
  176. package/knowledge/decisions/security/mail-is-allowlisted-before-a-virtual-user-run-sees-it.md +38 -0
  177. package/knowledge/decisions/security/mcp-resources-tools-and-prompts-take-sessionless-functions.md +18 -0
  178. package/knowledge/decisions/security/origin-locked-routes-match-the-origin-exactly.md +22 -0
  179. package/knowledge/decisions/security/oss-auth-works-without-pikku-studio-cloud.md +26 -0
  180. package/knowledge/decisions/security/outbound-webhooks-use-an-allowlist-when-configured.md +24 -0
  181. package/knowledge/decisions/security/pikku-carries-virtual-user-scopes-as-data-and-the-app-grants-them.md +35 -0
  182. package/knowledge/decisions/security/scoped-content-access-is-a-root-folder-with-longest-prefix-grants.md +31 -0
  183. package/knowledge/decisions/security/services-without-secrets-get-a-throwing-secrets-accessor.md +22 -0
  184. package/knowledge/decisions/security/shared-guards-refuse-to-mutate-or-shadow-a-system-role.md +34 -0
  185. package/knowledge/decisions/security/signed-uploads-are-verified-by-the-same-check-as-signed-reads.md +26 -0
  186. package/knowledge/decisions/security/system-role-scopes-must-be-declared-with-define-scope.md +24 -0
  187. package/knowledge/decisions/security/system-roles-are-additive-and-immutable.md +16 -0
  188. package/knowledge/decisions/security/the-channel-rpc-does-not-send-the-callers-session.md +21 -0
  189. package/knowledge/decisions/security/the-remote-jobs-inbox-fails-closed-without-a-secret.md +24 -0
  190. package/knowledge/decisions/security/the-remote-rpc-gate-fails-closed-and-binds-the-token-to-its-function.md +34 -0
  191. package/knowledge/decisions/security/the-workflow-status-stream-rechecks-ownership-on-every-poll.md +16 -0
  192. package/knowledge/decisions/security/two-credentials-on-one-key-must-share-a-read-mode.md +29 -0
  193. package/knowledge/decisions/security/verified-bearer-claims-are-pass-through-data-that-core-never-fills.md +23 -0
  194. package/knowledge/decisions/security/virtual-user-catalogue-excludes-the-machinery-that-runs-virtual-users.md +25 -0
  195. package/knowledge/decisions/security/{actor-flow-missing-approval-decisions-default-to-denied.md → virtual-user-conversation-missing-approval-decisions-default-to-denied.md} +7 -7
  196. package/knowledge/decisions/security/virtual-user-run-records-are-gated-behind-a-read-scope.md +18 -0
  197. package/knowledge/decisions/security/virtual-user-sign-in-does-not-exist-in-production.md +25 -0
  198. package/knowledge/decisions/security/virtual-user-sign-in-has-one-door.md +42 -0
  199. package/knowledge/decisions/security/{actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md → virtual-user-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md} +10 -8
  200. package/knowledge/decisions/security/virtual-user-sign-in-only-works-for-virtual-user-flagged-users.md +29 -0
  201. package/knowledge/decisions/security/workflow-helper-functions-are-sessionless-by-declaration.md +18 -0
  202. package/knowledge/decisions/security/{workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md → workflow-scenario-sessions-are-isolated-per-virtual-user-and-per-scenario.md} +6 -6
  203. package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +5 -5
  204. package/knowledge/decisions/security/{workflow-actor-steps-always-use-the-real-transport.md → workflow-virtual-user-steps-always-use-the-real-transport.md} +11 -11
  205. package/knowledge/decisions/security/writing-a-virtual-user-schedule-is-gated-by-its-own-scope.md +18 -0
  206. package/knowledge/index.md +0 -2
  207. package/knowledge/questions/a-bearer-jwt-with-no-identity-becomes-a-session.md +24 -0
  208. package/knowledge/questions/dev-quick-login-as-impersonation.md +25 -0
  209. package/knowledge/questions/does-a-delayed-rpc-run-as-the-session-it-was-scheduled-with.md +26 -0
  210. package/knowledge/questions/does-a-user-id-with-a-colon-read-another-users-credentials.md +27 -0
  211. package/knowledge/questions/does-a-wirecli-command-need-a-session-by-default.md +26 -0
  212. package/knowledge/questions/does-an-adversarial-in-scope-success-count-as-a-finding.md +26 -0
  213. package/knowledge/questions/does-approve-step-need-the-run-owners-session-or-the-gates-approvers.md +34 -0
  214. package/knowledge/questions/does-cors-origin-true-reflect-any-origin-with-credentials.md +20 -0
  215. package/knowledge/questions/does-skip-user-session-do-anything-on-a-channel.md +24 -0
  216. package/knowledge/questions/does-the-store-session-match-the-other-two.md +19 -0
  217. package/knowledge/questions/index.md +25 -2
  218. package/knowledge/questions/is-the-agent-score-worker-reachable-without-a-session.md +21 -0
  219. package/knowledge/questions/live-scheduled-tests-may-write.md +19 -0
  220. package/knowledge/questions/provision-virtual-users-has-no-caller-in-this-repo.md +23 -0
  221. package/knowledge/questions/remote-secret-refuses-requests-without-a-remote-token-on-every-path.md +32 -0
  222. package/knowledge/questions/should-a-middleware-set-session-persist-to-the-store.md +25 -0
  223. package/knowledge/questions/should-a-scoped-secret-view-throw-from-has-secret-for-a-disallowed-key.md +23 -0
  224. package/knowledge/questions/should-a-wrong-bearer-token-be-anonymous-or-refused.md +35 -0
  225. package/knowledge/questions/should-an-empty-webhook-signing-secret-send-unsigned.md +23 -0
  226. package/knowledge/questions/should-http-virtual-user-sessions-reset-between-scenarios-in-one-run.md +27 -0
  227. package/knowledge/questions/should-the-cookie-jar-scope-cookies-to-the-api-origin.md +26 -0
  228. package/knowledge/questions/should-voice-input-fetch-audio-urls-without-a-host-allowlist.md +20 -0
  229. package/knowledge/questions/staging-impersonation-rules.md +27 -0
  230. package/knowledge/questions/virtual-user-keys-on-cloud-stages-are-pikku-studios-to-build.md +34 -0
  231. package/knowledge/questions/virtual-user-statement-replay-is-per-process.md +20 -0
  232. package/knowledge/questions/what-an-impersonated-session-carries.md +22 -0
  233. package/package.json +3 -3
  234. package/src/public-surface.json +43 -47
  235. package/dist/services/persona-actor-secret.d.ts +0 -38
  236. package/dist/services/persona-actor-secret.js +0 -39
  237. package/dist/services/persona-sign-in.d.ts +0 -117
  238. package/dist/services/persona-sign-in.js +0 -154
  239. package/dist/wirings/actor-flow/index.d.ts +0 -2
  240. package/dist/wirings/actor-flow/run-conversation.d.ts +0 -36
  241. package/dist/wirings/persona/define-personas.d.ts +0 -32
  242. package/dist/wirings/persona/index.d.ts +0 -23
  243. package/dist/wirings/persona/index.js +0 -19
  244. package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +0 -23
  245. package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +0 -25
  246. package/knowledge/decisions/internals/validate-checks-personas-through-a-shared-module.md +0 -43
  247. package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +0 -31
  248. package/knowledge/decisions/security/an-actor-credential-is-derived-per-persona.md +0 -42
  249. package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +0 -26
  250. /package/dist/wirings/{actor-flow/actor-flow.types.js → virtual-user/conversation/conversation.types.js} +0 -0
  251. /package/dist/wirings/{actor-flow → virtual-user/conversation}/index.js +0 -0
  252. /package/dist/wirings/{persona/persona.types.js → virtual-user/virtual-user-declaration.types.js} +0 -0
  253. /package/dist/wirings/{persona/persona-mailbox.js → virtual-user/virtual-user-mailbox.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,50 @@
1
+ ## 0.12.142
2
+
3
+ ### Patch Changes
4
+
5
+ - fdcc821: Fabric is gone from the open toolchain. The previous names are removed with no aliases.
6
+
7
+ The CLI group is `pikku cloud …` and the export is `@pikku/cli/cloud`. The project link is the `cloud` key of `pikku.config.json` (`cloud.projectId`), the CLI keeps its local state in `~/.pikkustudio` (run `pikku cloud login` again), and the project config file is `pikkustudio.config.json`.
8
+
9
+ Every environment variable drops the `FABRIC_` prefix for `PIKKUSTUDIO_` with the same suffix: `PIKKUSTUDIO_API_URL`, `PIKKUSTUDIO_PROJECT_ID`, `PIKKUSTUDIO_TOKEN`, `PIKKUSTUDIO_OPERATOR_TOKEN`, `PIKKUSTUDIO_AUTH_PUBLIC_KEY`, `PIKKUSTUDIO_STAGE_ID` and the rest. Rename them wherever you set them.
10
+
11
+ Wire ids: the operator sign-in route is `/sign-in/cloud`, the plugin and mode literal is `'cloud'`, the Better Auth plugin is `pikkuCloud`, its session field is `pikkustudioadmin`, and the signature header is `x-cloud-sig`. The cloud API calls are `getCloudLogs`, `getCloudLogsByStageKind`, `cloudCliProjects`, `cloudCliDeployments`, `providedByCloud` and `recordCloudAnalyticsEvents`. Addon packages are `@pikkustudio/*`, scaffolded files live under `scaffold/cloud` and `__cloud_*__`, and the API hosts are the `pikkustudio.app` and `pikkustudio.dev` domains.
12
+
13
+ `pikku skills install --fabric` is `--cloud`, the install group is `cloud`, and the skills are `pikku-cloud`, `pikku-cloud-debug`, `pikku-admin-to-cloud` and `pikku-blueprint-to-cloud`.
14
+
15
+ The stale analytics forwarder copies are removed from the online-shop example and the starter template.
16
+
17
+ The sealed-box salt stays `pikkufabric/sealed-box/v1`: it is a cryptographic constant that already-sealed secrets depend on.
18
+
19
+ - 33b102d: Virtual users now have one name everywhere. The id column of `virtual_user_run` and `virtual_user_schedule` is `virtual_user_id` (a migration renames it in place), the CLI group is `pikku virtual-user …`, and the declarations and imports live under `@pikku/core/virtual-user`. The previous names are removed with no aliases.
20
+
21
+ The default virtual user email domain is now `virtualuser.invalid`: apps that rely on the default domain get new accounts at the next provisioning (`pikku virtual-user sync`, deploy, or `pikku dev` start), and the old rows stay unused.
22
+
23
+ The sign-in surface carries the same name. The route is `/sign-in/virtual-user`, the environment variables are `PIKKU_ALLOW_VIRTUAL_USER_SIGN_IN` and the `PIKKU_DEV_VIRTUAL_USER_SIGN_IN` / `VITE_*` equivalents, the Better Auth plugin is `pikkuVirtualUser`, the scenario step option and wire member are `virtualUser` and `virtualUsers`, and the Better Auth user flag column is `virtual_user`. Rename the environment variables wherever you set them, and add a migration that renames the flag column on the `user` table. Nothing is aliased.
24
+
25
+ The conversation runner is now `@pikku/core/virtual-user/conversation`, replacing the old `-flow` subpath. Update the import; the old subpath is gone.
26
+
27
+ - 6a25c70: Virtual users no longer run against production. Starting a run, and enabling a schedule, is refused with a 403 in a production environment for every disposition, including `accountable`, which was the one disposition production used to accept. Turning a schedule off or editing a disabled one is still allowed, so a leftover schedule can be stopped.
28
+ - a084c3b: Virtual users sign themselves in. A scheduled run signs in from inside the app through a server-only Better Auth endpoint, then drives the app over HTTP with the cookie. Outside callers (`pikku dev`, `pikku scenario run`, `pikku virtual-user run` and `rpc`, `pikku pages screenshot --as`, the Playwright provider) present one signed, short-lived, single-use EdDSA statement, which the app checks against `VIRTUAL_USER_VERIFY_KEY`; `pikku dev` generates the key pair, and a deployed stage's deployer holds `VIRTUAL_USER_SIGNING_KEY`. `@pikku/jose` gains `JoseVirtualUserStatementVerifier` and `@pikku/better-auth` takes `verifyKey`. Removed with no aliases: the operator token and `OperatorSignIn`, derived per-virtual-user secrets, `SCENARIO_VIRTUAL_USER_SECRET`, `PIKKU_VIRTUAL_USER_SECRETS`, `pikku virtual-user secret`, and `wireVirtualUserSignIn`. In production neither sign-in endpoint is registered.
29
+
30
+ The scenario cookie jar moved to `services` and `createCookieJar` is exported from `@pikku/core/virtual-user`, which removes the wire-to-wire import cycles; `VirtualUserSignIn.headers` is now optional.
31
+
32
+ Migration for apps: pass `verifyKey: await variables.get('VIRTUAL_USER_VERIFY_KEY')` to `pikkuVirtualUser` instead of `secret`, declare that variable as optional, delete any `SCENARIO_VIRTUAL_USER_SECRET` secret and any `wireVirtualUserSignIn` call, and stop passing `secret` or `operator` to `createHttpVirtualUsers`. A stage that must run scenarios still opts in with `PIKKU_ALLOW_VIRTUAL_USER_SIGN_IN`.
33
+
34
+ ## 0.12.141
35
+
36
+ ### Patch Changes
37
+
38
+ - b04e444: Fix CLI commands that come from an addon package. Auth and permissions set on such a command are now merged into the addon's own function instead of replacing it, and the command's input is shaped by the addon's own schema (for example a comma list becomes an array). The inspector now also resolves `...refCLI('addon:contract')`, spreads and `defineCLICommands` identifiers inside a command's `subcommands`.
39
+ - d3d8a98: Graceful shutdown ignores repeat signals. A second SIGTERM or SIGINT arriving while `beforeStop` and the service teardown are still running no longer falls through to the default handler and kills the process mid-cleanup. `@pikku/core/lifecycle` is a new entry point holding `onShutdownSignals`, `stopSingletonServices` and `pikkuServerLifecycle` (the latter two stay re-exported from `utils`), which the server runtimes now share.
40
+ - 658da50: `SecretService` gains an optional `setEncryptedSecret(key, sealed)` for stores that hold a sealing key, so a browser can seal a secret and the caller's process never sees the plaintext.
41
+
42
+ ## 0.12.140
43
+
44
+ ### Patch Changes
45
+
46
+ - f396538: Event-stream responses pass through `applyWebResponse` without being read, so an SSE route can proxy another stream. HTTP responses gain `onClose`, which `executeRoute` uses to tell an SSE route's event hub when the client leaves. `pikku all` wires the console's `/meta/stream` route to `console:streamMetaChanges`.
47
+
1
48
  ## 0.12.139
2
49
 
3
50
  ### Patch Changes
@@ -118,7 +118,7 @@ export declare class AIProviderAuthError extends PikkuError {
118
118
  *
119
119
  * System roles ship with the product: the console may show and grant them, but
120
120
  * renaming, re-scoping or deleting one would let a UI action silently change
121
- * what a declared persona means, and what every scenario written against that
121
+ * what a declared virtual user means, and what every scenario written against that
122
122
  * role is actually testing.
123
123
  * @group Error
124
124
  */
@@ -314,7 +314,7 @@ addError(AIProviderAuthError, {
314
314
  *
315
315
  * System roles ship with the product: the console may show and grant them, but
316
316
  * renaming, re-scoping or deleting one would let a UI action silently change
317
- * what a declared persona means, and what every scenario written against that
317
+ * what a declared virtual user means, and what every scenario written against that
318
318
  * role is actually testing.
319
319
  * @group Error
320
320
  */
@@ -80,17 +80,17 @@ export type FunctionRuntimeMeta = {
80
80
  */
81
81
  scenarioStepSurfaces?: ScenarioSurface[];
82
82
  /**
83
- * Scenario steps only: this step runs as a persona, so every call site must
84
- * pass one and the runner injects it as `wire.actor`.
83
+ * Scenario steps only: this step runs as a virtual user, so every call site must
84
+ * pass one and the runner injects it as `wire.virtualUser`.
85
85
  *
86
- * Declared by `actor: true`, or implied by a `browser` binding — a window is
86
+ * Declared by `virtualUser: true`, or implied by a `browser` binding — a window is
87
87
  * opened as somebody. Absent on a step with nobody to be: an assertion over
88
88
  * what an earlier step returned, or one posting credentials precisely because
89
- * it must not reuse an actor's session.
89
+ * it must not reuse a virtual user's session.
90
90
  */
91
- scenarioStepRequiresActor?: boolean;
91
+ scenarioStepRequiresVirtualUser?: boolean;
92
92
  /**
93
- * Scenario steps only: who acts. Absent means `persona` — the ordinary step,
93
+ * Scenario steps only: who acts. Absent means `virtualUser` — the ordinary step,
94
94
  * and the only kind that existed before the other two.
95
95
  *
96
96
  * A `platform` or `addon` step is the app or a third-party system acting, and
@@ -111,8 +111,8 @@ export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any,
111
111
  * and report how much of the flow each surface actually covers.
112
112
  */
113
113
  surfaces?: ScenarioSurface[];
114
- /** Scenario steps only, and set by the definer rather than by hand: this step needs a persona, so the runner injects `wire.actor`. */
115
- requiresActor?: boolean;
114
+ /** Scenario steps only, and set by the definer rather than by hand: this step needs a virtual user, so the runner injects `wire.virtualUser`. */
115
+ requiresVirtualUser?: boolean;
116
116
  /**
117
117
  * Records every call in the audit log. `transactional` durability writes the
118
118
  * entry in the same transaction as the work, so the two cannot disagree;
@@ -0,0 +1,6 @@
1
+ import type { CoreSingletonServices, ServerLifecycle } from './types/core.types.js';
2
+ /** Stops addon package services first, then the parent singleton services. */
3
+ export declare const stopSingletonServices: () => Promise<void>;
4
+ /** Wrap server lifecycle hooks so the inspector can discover them. */
5
+ export declare const pikkuServerLifecycle: <SS extends CoreSingletonServices = CoreSingletonServices>(lifecycle: ServerLifecycle<SS>) => ServerLifecycle<SS>;
6
+ export declare const onShutdownSignals: (run: (signal: NodeJS.Signals) => void | Promise<void>, signals?: NodeJS.Signals[]) => (() => void);
@@ -0,0 +1,58 @@
1
+ import { getSingletonServices, getAllPackageStates } from './pikku-state.js';
2
+ const stopService = async (logger, name, service) => {
3
+ const stop = service?.stop;
4
+ if (stop) {
5
+ logger.info(`Stopping singleton service: ${name}`);
6
+ try {
7
+ await stop.call(service);
8
+ }
9
+ catch (e) {
10
+ logger.error(`Error stopping service ${name}:`, e);
11
+ }
12
+ }
13
+ };
14
+ /** Stops addon package services first, then the parent singleton services. */
15
+ export const stopSingletonServices = async () => {
16
+ const singletonServices = getSingletonServices();
17
+ const logger = singletonServices.logger;
18
+ const stateMap = getAllPackageStates();
19
+ if (stateMap.size > 0) {
20
+ for (const [packageName, packageState] of stateMap) {
21
+ if (packageName === '__main__')
22
+ continue;
23
+ const packageServices = packageState.package?.singletonServices;
24
+ if (packageServices) {
25
+ logger.info(`Stopping singleton services for package: ${packageName}`);
26
+ for (const [name, service] of Object.entries(packageServices)) {
27
+ await stopService(logger, `${packageName}/${name}`, service);
28
+ }
29
+ packageState.package.singletonServices = null;
30
+ }
31
+ }
32
+ }
33
+ for (const [name, service] of Object.entries(singletonServices)) {
34
+ await stopService(logger, name, service);
35
+ }
36
+ };
37
+ /** Wrap server lifecycle hooks so the inspector can discover them. */
38
+ export const pikkuServerLifecycle = (lifecycle) => lifecycle;
39
+ export const onShutdownSignals = (run, signals = ['SIGINT', 'SIGTERM']) => {
40
+ const proc = typeof process !== 'undefined' ? process : undefined;
41
+ if (!proc?.on)
42
+ return () => { };
43
+ let stopping = false;
44
+ const handlers = signals.map((signal) => {
45
+ const handler = () => {
46
+ if (stopping)
47
+ return;
48
+ stopping = true;
49
+ void run(signal);
50
+ };
51
+ proc.on(signal, handler);
52
+ return [signal, handler];
53
+ });
54
+ return () => {
55
+ for (const [signal, handler] of handlers)
56
+ proc.off(signal, handler);
57
+ };
58
+ };
@@ -13,10 +13,10 @@ export type ResolvedAuditConfig = {
13
13
  /**
14
14
  * Who an event happened under.
15
15
  *
16
- * A user, not an "actor": in pikku an actor is a synthetic person a scenario
17
- * drives, flagged `actor` on the user row, and the overwhelming majority of
18
- * audited events are caused by ordinary customers. Naming this `actor` made the
19
- * synthetic case unsayable — `actor.actor === true` — and implied every
16
+ * A user, not an "virtualUser": in pikku a virtual user is a synthetic person a scenario
17
+ * drives, flagged `virtualUser` on the user row, and the overwhelming majority of
18
+ * audited events are caused by ordinary customers. Naming this `virtualUser` made the
19
+ * synthetic case unsayable — `virtualUser.virtualUser === true` — and implied every
20
20
  * recorded action was a test.
21
21
  *
22
22
  * `pikkuUserId` is the identity pikku resolves for every wire, so it is the one
@@ -88,10 +88,10 @@ export interface FeatureFlagStore extends FeatureFlagSource {
88
88
  * every flag to render a board would grow with the wrong number.
89
89
  */
90
90
  listOverrides(key: string): Promise<FlagOverrideRow[]>;
91
- setEnabled(key: string, enabled: boolean, actor?: string, note?: string): Promise<void>;
91
+ setEnabled(key: string, enabled: boolean, virtualUser?: string, note?: string): Promise<void>;
92
92
  /** `percent` is 0–100, or null to remove the rollout constraint. */
93
- setRollout(key: string, percent: number | null, actor?: string): Promise<void>;
94
- setOverride(key: string, subject: FlagSubject, enabled: boolean, actor?: string): Promise<void>;
93
+ setRollout(key: string, percent: number | null, virtualUser?: string): Promise<void>;
94
+ setOverride(key: string, subject: FlagSubject, enabled: boolean, virtualUser?: string): Promise<void>;
95
95
  clearOverride(key: string, subject: FlagSubject): Promise<void>;
96
96
  /** Flags in the store with no declaration left in code; powers `pikku flags audit`. */
97
97
  findStaleFlags(): Promise<string[]>;
@@ -1,7 +1,7 @@
1
- import type { ScenarioPersona, ResolvedPersona, ScenarioPersonas, ScenarioInvokeOptions, ScenarioHttpResponse } from './personas-service.js';
2
- import type { ConverseOptions, ActorFlowVerdict } from '../wirings/actor-flow/actor-flow.types.js';
3
- import { type ActorSecretResolver, type OperatorSignInOptions } from './persona-sign-in.js';
4
- export interface HttpPersonasConfig {
1
+ import type { ScenarioVirtualUser, ResolvedVirtualUser, ScenarioVirtualUsers, ScenarioInvokeOptions, ScenarioHttpResponse } from './virtual-users-service.js';
2
+ import type { ConverseOptions, ConversationVerdict } from '../wirings/virtual-user/conversation/conversation.types.js';
3
+ import { type VirtualUserSignIn } from './virtual-user-sign-in.js';
4
+ export interface HttpVirtualUsersConfig {
5
5
  /**
6
6
  * Base API URL of the target app, INCLUDING the HTTP prefix — e.g.
7
7
  * `https://app.example.com/api` or `http://localhost:4000/api`. Sign-in is
@@ -10,39 +10,21 @@ export interface HttpPersonasConfig {
10
10
  */
11
11
  apiUrl: string;
12
12
  /**
13
- * The ROOT actor secret, from which each persona's own credential is derived
14
- * and bound to their address. Sign-in only ever works for user rows flagged
15
- * `actor: true`, and a derived credential only ever works for the one address
16
- * it was derived for.
17
- *
18
- * Pass an {@link ActorSecretResolver} instead to drive personas whose
19
- * credentials were minted elsewhere — a caller entitled to one persona then
20
- * never holds the root.
21
- *
22
- * The local-development credential. A deployed stage has none, and passes
23
- * {@link HttpPersonasConfig.operator} instead.
24
- */
25
- secret?: string | ActorSecretResolver;
26
- /**
27
- * Fabric operator credentials, for signing personas into a DEPLOYED stage.
28
- *
29
- * Mutually exclusive with {@link HttpPersonasConfig.secret}: the operator
30
- * path acts as the persona through an admin session rather than logging in as
31
- * them, so no test credential has to exist on the target at all.
13
+ * How each virtual user obtains a session: {@link inProcessSignIn} from inside
14
+ * the app, {@link statementSignIn} from outside it.
32
15
  */
33
- operator?: OperatorSignInOptions;
34
- /** Persona id → the declaration with its address filled in. */
35
- personas: Record<string, ResolvedPersona>;
16
+ signIn: VirtualUserSignIn;
17
+ /** Virtual user id → the declaration with its address filled in. */
18
+ virtualUsers: Record<string, ResolvedVirtualUser>;
36
19
  /**
37
- * Sign-in path under apiUrl, for whichever of the two paths is in use — an
38
- * app that mounts auth under `/api` moves both. Default: the actor plugin's
39
- * `/auth/sign-in/actor`, or `/auth/sign-in/fabric` for an operator.
40
- * {@link OperatorSignInOptions.signInPath} overrides it.
20
+ * The sign-in path, when the app mounts auth somewhere other than `/auth`.
21
+ * Only the mount is used here, to find `get-session`; signing in itself is
22
+ * the job of {@link HttpVirtualUsersConfig.signIn}.
41
23
  */
42
24
  signInPath?: string;
43
25
  /**
44
26
  * Where the session (and its roles) is read back. Defaults to `get-session`
45
- * under the same auth mount as {@link HttpPersonasConfig.signInPath}, so an
27
+ * under the same auth mount as {@link HttpVirtualUsersConfig.signInPath}, so an
46
28
  * app that moved auth under `/api` moves this with it and does not have to
47
29
  * say so twice.
48
30
  */
@@ -57,28 +39,24 @@ export interface HttpPersonasConfig {
57
39
  * on scopes that column is a projection rather than the model — it exists so
58
40
  * better-auth's own admin endpoints have something to read, is written by
59
41
  * whatever keeps it in step, and is absent entirely from an app that declares
60
- * no such field. A persona verified against it is verified against a copy.
42
+ * no such field. A virtual user verified against it is verified against a copy.
61
43
  */
62
44
  rolesRpc?: string | false;
63
45
  /**
64
- * Default model a persona thinks with when `converse(...)` is called without
46
+ * Default model a virtual user thinks with when `converse(...)` is called without
65
47
  * an explicit `model`. Its own turns/approvals/evaluation run in-process via
66
48
  * the configured `agentRunner`.
67
49
  */
68
50
  model?: string;
69
51
  }
70
52
  /**
71
- * Default HTTP-backed persona. Signs in lazily on first invoke, holds the
53
+ * Default HTTP-backed virtual user. Signs in lazily on first invoke, holds the
72
54
  * session cookies for its lifetime, and re-logs-in once on a 401 mid-run (long
73
55
  * health-check runs can outlive a session).
74
- *
75
- * How it signs in depends on the target, and the two ways are not
76
- * interchangeable — see {@link ActorSignIn} for local development and
77
- * {@link OperatorSignIn} for a deployed stage.
78
56
  */
79
- export declare class HttpPersona implements ScenarioPersona {
57
+ export declare class HttpVirtualUser implements ScenarioVirtualUser {
80
58
  readonly name: string;
81
- private persona;
59
+ private virtualUser;
82
60
  private config;
83
61
  private jar;
84
62
  /**
@@ -89,15 +67,15 @@ export declare class HttpPersona implements ScenarioPersona {
89
67
  */
90
68
  private signedIn;
91
69
  private signIn;
92
- constructor(name: string, persona: ResolvedPersona, config: HttpPersonasConfig);
70
+ constructor(name: string, virtualUser: ResolvedVirtualUser, config: HttpVirtualUsersConfig);
93
71
  get email(): string;
94
72
  invoke(rpcName: string, data: unknown): Promise<unknown>;
95
73
  invokeRaw(rpcName: string, data: unknown, options?: ScenarioInvokeOptions): Promise<ScenarioHttpResponse>;
96
- converse(options: ConverseOptions): Promise<ActorFlowVerdict>;
74
+ converse(options: ConverseOptions): Promise<ConversationVerdict>;
97
75
  /**
98
76
  * The roles the stage says this session holds.
99
77
  *
100
- * {@link HttpPersonasConfig.rolesRpc} first, then better-auth's
78
+ * {@link HttpVirtualUsersConfig.rolesRpc} first, then better-auth's
101
79
  * `get-session` — where its admin plugin puts `role` on the user, as a
102
80
  * comma-separated list. A target that answers neither returns `null` rather
103
81
  * than an empty list, because "this stage does not report roles" and "this
@@ -112,7 +90,7 @@ export declare class HttpPersona implements ScenarioPersona {
112
90
  private rolesFromRpc;
113
91
  private rolesFromSession;
114
92
  /**
115
- * Start/continue the target agent's run over HTTP as this persona.
93
+ * Start/continue the target agent's run over HTTP as this virtual user.
116
94
  *
117
95
  * The SSE route, not the plain one. `POST /rpc/agent/:name` buffers the whole
118
96
  * run before it sends a single byte, so a run longer than the client's
@@ -134,7 +112,7 @@ export declare class HttpPersona implements ScenarioPersona {
134
112
  private login;
135
113
  }
136
114
  /**
137
- * Build the injected `personas` service from the declared personas: id → lazy
138
- * HTTP persona. Wire the result as the `personas` singleton service.
115
+ * Build the injected `virtualUsers` service from the declared virtual users: id → lazy
116
+ * HTTP virtual user. Wire the result as the `virtualUsers` singleton service.
139
117
  */
140
- export declare function createHttpPersonas(config: HttpPersonasConfig): ScenarioPersonas;
118
+ export declare function createHttpVirtualUsers(config: HttpVirtualUsersConfig): ScenarioVirtualUsers;
@@ -1,21 +1,17 @@
1
- import { readScenarioHttpResponse } from './personas-service.js';
2
- import { runConversation } from '../wirings/actor-flow/run-conversation.js';
3
- import { createCookieJar, } from '../wirings/workflow/scenario-cookie-jar.js';
4
- import { ActorSignIn, OperatorSignIn, authMount, } from './persona-sign-in.js';
1
+ import { readScenarioHttpResponse } from './virtual-users-service.js';
2
+ import { runConversation } from '../wirings/virtual-user/conversation/run-conversation.js';
3
+ import { createCookieJar, } from './scenario-cookie-jar.js';
4
+ import { authMount } from './virtual-user-sign-in.js';
5
5
  import { getSingletonServices } from '../pikku-state.js';
6
6
  import { AIProviderNotConfiguredError } from '../errors/errors.js';
7
7
  /**
8
- * Default HTTP-backed persona. Signs in lazily on first invoke, holds the
8
+ * Default HTTP-backed virtual user. Signs in lazily on first invoke, holds the
9
9
  * session cookies for its lifetime, and re-logs-in once on a 401 mid-run (long
10
10
  * health-check runs can outlive a session).
11
- *
12
- * How it signs in depends on the target, and the two ways are not
13
- * interchangeable — see {@link ActorSignIn} for local development and
14
- * {@link OperatorSignIn} for a deployed stage.
15
11
  */
16
- export class HttpPersona {
12
+ export class HttpVirtualUser {
17
13
  name;
18
- persona;
14
+ virtualUser;
19
15
  config;
20
16
  jar;
21
17
  /**
@@ -26,29 +22,15 @@ export class HttpPersona {
26
22
  */
27
23
  signedIn = false;
28
24
  signIn;
29
- constructor(name, persona, config) {
25
+ constructor(name, virtualUser, config) {
30
26
  this.name = name;
31
- this.persona = persona;
27
+ this.virtualUser = virtualUser;
32
28
  this.config = config;
33
29
  this.jar = createCookieJar(config.apiUrl);
34
- if (config.operator) {
35
- this.signIn = new OperatorSignIn(config.apiUrl, {
36
- ...config.operator,
37
- signInPath: config.operator.signInPath ??
38
- (authMount(config.signInPath)
39
- ? `${authMount(config.signInPath)}/sign-in/fabric`
40
- : undefined),
41
- });
42
- }
43
- else if (config.secret) {
44
- this.signIn = new ActorSignIn(config.apiUrl, config.secret, config.signInPath ?? '/auth/sign-in/actor');
45
- }
46
- else {
47
- throw new Error(`[scenario] persona '${name}' has no way to sign in — set 'secret' for a dev target or 'operator' for a deployed one`);
48
- }
30
+ this.signIn = config.signIn;
49
31
  }
50
32
  get email() {
51
- return this.persona.email;
33
+ return this.virtualUser.email;
52
34
  }
53
35
  async invoke(rpcName, data) {
54
36
  const res = await this.invokeRaw(rpcName, data);
@@ -78,20 +60,20 @@ export class HttpPersona {
78
60
  // Signed in here rather than left to postAgent's 401 retry, which a public
79
61
  // agent route never triggers. An unowned thread is minted under a fresh
80
62
  // anonymous id per request, so turn one succeeds and turn two is refused as
81
- // somebody else's — and a persona is a real account with real credentials,
63
+ // somebody else's — and a virtual user is a real account with real credentials,
82
64
  // so there is no case where conversing as nobody is the intent.
83
65
  if (!this.signedIn) {
84
66
  await this.login();
85
67
  }
86
68
  const model = options.model ?? this.config.model;
87
69
  if (!model) {
88
- throw new Error(`[scenario] persona '${this.name}' converse needs a model — pass options.model or set 'model' on the personas service`);
70
+ throw new Error(`[scenario] virtual user '${this.name}' converse needs a model — pass options.model or set 'model' on the virtual users service`);
89
71
  }
90
72
  const threadId = globalThis.crypto.randomUUID();
91
- const resourceId = `persona:${this.name}`;
73
+ const resourceId = `virtualUser:${this.name}`;
92
74
  return runConversation({
93
- persona: this.persona,
94
- personaId: this.name,
75
+ virtualUser: this.virtualUser,
76
+ virtualUserId: this.name,
95
77
  agentName: options.agent,
96
78
  task: options.task,
97
79
  evaluate: options.evaluate,
@@ -108,7 +90,7 @@ export class HttpPersona {
108
90
  /**
109
91
  * The roles the stage says this session holds.
110
92
  *
111
- * {@link HttpPersonasConfig.rolesRpc} first, then better-auth's
93
+ * {@link HttpVirtualUsersConfig.rolesRpc} first, then better-auth's
112
94
  * `get-session` — where its admin plugin puts `role` on the user, as a
113
95
  * comma-separated list. A target that answers neither returns `null` rather
114
96
  * than an empty list, because "this stage does not report roles" and "this
@@ -148,11 +130,9 @@ export class HttpPersona {
148
130
  return roles.filter((name) => typeof name === 'string');
149
131
  }
150
132
  async rolesFromSession() {
151
- const mount = authMount(this.config.operator?.signInPath ?? this.config.signInPath);
133
+ const mount = authMount(this.config.signInPath);
152
134
  const sessionPath = this.config.sessionPath ?? `${mount ?? '/auth'}/get-session`;
153
- const res = await this.jar.fetch(`${this.config.apiUrl}${sessionPath}`, {
154
- headers: this.signIn.headers(),
155
- });
135
+ const res = await this.jar.fetch(`${this.config.apiUrl}${sessionPath}`);
156
136
  if (!res.ok) {
157
137
  return null;
158
138
  }
@@ -183,7 +163,7 @@ export class HttpPersona {
183
163
  return user ? [] : null;
184
164
  }
185
165
  /**
186
- * Start/continue the target agent's run over HTTP as this persona.
166
+ * Start/continue the target agent's run over HTTP as this virtual user.
187
167
  *
188
168
  * The SSE route, not the plain one. `POST /rpc/agent/:name` buffers the whole
189
169
  * run before it sends a single byte, so a run longer than the client's
@@ -216,10 +196,7 @@ export class HttpPersona {
216
196
  const url = `${this.config.apiUrl}${rpcPath}/${subPath}`;
217
197
  const send = () => this.jar.fetch(url, {
218
198
  method: 'POST',
219
- headers: {
220
- 'content-type': 'application/json',
221
- ...this.signIn.headers(),
222
- },
199
+ headers: { 'content-type': 'application/json' },
223
200
  body: JSON.stringify(body),
224
201
  });
225
202
  let res = await send();
@@ -247,7 +224,6 @@ export class HttpPersona {
247
224
  method: 'POST',
248
225
  headers: {
249
226
  'content-type': 'application/json',
250
- ...this.signIn.headers(),
251
227
  ...extraHeaders,
252
228
  },
253
229
  body: JSON.stringify({ data }),
@@ -259,7 +235,7 @@ export class HttpPersona {
259
235
  this.signedIn = false;
260
236
  }
261
237
  async login() {
262
- await this.signIn.login(this.jar, this.persona);
238
+ await this.signIn.login(this.jar, this.virtualUser);
263
239
  this.signedIn = true;
264
240
  }
265
241
  }
@@ -358,13 +334,13 @@ function normalizeAgentReply(raw) {
358
334
  };
359
335
  }
360
336
  /**
361
- * Build the injected `personas` service from the declared personas: id → lazy
362
- * HTTP persona. Wire the result as the `personas` singleton service.
337
+ * Build the injected `virtualUsers` service from the declared virtual users: id → lazy
338
+ * HTTP virtual user. Wire the result as the `virtualUsers` singleton service.
363
339
  */
364
- export function createHttpPersonas(config) {
365
- const personas = {};
366
- for (const [id, persona] of Object.entries(config.personas)) {
367
- personas[id] = new HttpPersona(id, persona, config);
340
+ export function createHttpVirtualUsers(config) {
341
+ const virtualUsers = {};
342
+ for (const [id, virtualUser] of Object.entries(config.virtualUsers)) {
343
+ virtualUsers[id] = new HttpVirtualUser(id, virtualUser, config);
368
344
  }
369
- return personas;
345
+ return virtualUsers;
370
346
  }
@@ -23,12 +23,12 @@ export { InMemoryLeaseService } from './in-memory-lease-service.js';
23
23
  export { InMemoryAgentRunStateService } from './in-memory-agent-run-state-service.js';
24
24
  export { LocalGatewayService } from './local-gateway-service.js';
25
25
  export type { ContentService, ContentVisibility, GetDownloadURLArgs, SignContentKeyArgs, SignURLArgs, GetUploadURLArgs, UploadURLResult, BucketKeyArgs, WriteFileArgs, CopyFileArgs, } from './content-service.js';
26
- export type { ScenarioPersona, ResolvedPersona, ScenarioPersonas, } from './personas-service.js';
26
+ export type { ScenarioVirtualUser, ResolvedVirtualUser, ScenarioVirtualUsers, } from './virtual-users-service.js';
27
27
  export type { JWTService } from './jwt-service.js';
28
28
  export type { EmailAttachment, EmailService, SendEmailInput, SendEmailResult, SendHTMLEmailInput, SendTemplateEmailInput, SendTextEmailInput, } from './email-service.js';
29
29
  export { renderEmail, type EmailAssets, type EmailTemplateAssets, type EmailTemplateHashes, type RenderEmailRequest, type RenderedEmailResult, } from './email-template.js';
30
30
  export { DEFAULT_WEBHOOK_RETRIES, PIKKU_OUTGOING_WEBHOOK_QUEUE_NAME, WebhookService, type SendWebhookInput, type SendWebhookResult, type WebhookAttemptResult, type WebhookDeliveryRecord, type WebhookDeliveryWithAttempts, type WebhookJobData, type WebhookServiceConfig, } from './webhook-service.js';
31
- export { ACTOR_ROOT_SECRET_MIN_LENGTH, ACTOR_SECRET_INFO, ACTOR_SECRET_NAME, actorSecretSubject, deriveActorSecret, verifyActorSecret, } from './persona-actor-secret.js';
31
+ export { VIRTUAL_USER_IN_PROCESS_ENDPOINT, VIRTUAL_USER_STATEMENT_ALGORITHM, VIRTUAL_USER_STATEMENT_MAX_TTL_SECONDS, VIRTUAL_USER_STATEMENT_TTL_SECONDS, VIRTUAL_USER_SIGNING_KEY_VARIABLE, VIRTUAL_USER_VERIFY_KEY_VARIABLE, VirtualUserStatementError, type VirtualUserStatementVerifier, } from './virtual-user-statement.js';
32
32
  export type { Logger } from './logger.js';
33
33
  export type { SecretService, SecretValues } from './secret-service.js';
34
34
  export type { VariablesService } from './variables-service.js';
@@ -24,7 +24,7 @@ export { InMemoryAgentRunStateService } from './in-memory-agent-run-state-servic
24
24
  export { LocalGatewayService } from './local-gateway-service.js';
25
25
  export { renderEmail, } from './email-template.js';
26
26
  export { DEFAULT_WEBHOOK_RETRIES, PIKKU_OUTGOING_WEBHOOK_QUEUE_NAME, WebhookService, } from './webhook-service.js';
27
- export { ACTOR_ROOT_SECRET_MIN_LENGTH, ACTOR_SECRET_INFO, ACTOR_SECRET_NAME, actorSecretSubject, deriveActorSecret, verifyActorSecret, } from './persona-actor-secret.js';
27
+ export { VIRTUAL_USER_IN_PROCESS_ENDPOINT, VIRTUAL_USER_STATEMENT_ALGORITHM, VIRTUAL_USER_STATEMENT_MAX_TTL_SECONDS, VIRTUAL_USER_STATEMENT_TTL_SECONDS, VIRTUAL_USER_SIGNING_KEY_VARIABLE, VIRTUAL_USER_VERIFY_KEY_VARIABLE, VirtualUserStatementError, } from './virtual-user-statement.js';
28
28
  export { SchedulerService } from './scheduler-service.js';
29
29
  export { TypedCredentialService } from './typed-credential-service.js';
30
30
  export { NoopAuditService, createInvocationAudit } from './audit-service.js';
@@ -7,7 +7,7 @@ import type { CLIMeta } from '../wirings/cli/cli.types.js';
7
7
  import type { MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from '../wirings/mcp/mcp.types.js';
8
8
  import type { WorkflowsMeta } from '../wirings/workflow/workflow.types.js';
9
9
  import type { FeaturesMeta } from '../wirings/workflow/scenario.types.js';
10
- import type { ResolvedPersona } from './personas-service.js';
10
+ import type { ResolvedVirtualUser } from './virtual-users-service.js';
11
11
  import type { SystemRoleDefinitionsMeta } from '../wirings/role/role.types.js';
12
12
  import type { FeatureFlagDefinitionsMeta } from '../wirings/flag/flag.types.js';
13
13
  import type { ScopeDefinitionsMeta } from '../wirings/scope/scope.types.js';
@@ -147,12 +147,12 @@ export interface MetaService {
147
147
  getGatewayMeta(): Promise<GatewaysMeta>;
148
148
  getRpcMeta(): Promise<RPCMetaRecord>;
149
149
  getWorkflowMeta(): Promise<WorkflowsMeta>;
150
- getPersonasMeta(): Promise<Record<string, ResolvedPersona>>;
150
+ getVirtualUsersMeta(): Promise<Record<string, ResolvedVirtualUser>>;
151
151
  /**
152
152
  * The roles declared with `defineSystemRole`, keyed by name.
153
153
  *
154
- * A persona declares roles; a function checks scopes. Anything showing what a
155
- * persona can reach — the console's persona page, a run's catalogue — needs
154
+ * A virtual user declares roles; a function checks scopes. Anything showing what a
155
+ * virtual user can reach — the console's virtual user page, a run's catalogue — needs
156
156
  * this to get from one to the other, and needs it to be the same expansion the
157
157
  * seed granted from rather than a second one.
158
158
  */
@@ -206,7 +206,7 @@ export declare class LocalMetaService implements MetaService {
206
206
  private gatewayMetaCache;
207
207
  private rpcMetaCache;
208
208
  private workflowMetaCache;
209
- private personasMetaCache;
209
+ private virtualUsersMetaCache;
210
210
  private systemRolesMetaCache;
211
211
  private scopesMetaCache;
212
212
  private featureFlagsMetaCache;
@@ -244,7 +244,7 @@ export declare class LocalMetaService implements MetaService {
244
244
  getRpcMeta(): Promise<RPCMetaRecord>;
245
245
  private readWorkflowMetaDir;
246
246
  getWorkflowMeta(): Promise<WorkflowsMeta>;
247
- getPersonasMeta(): Promise<Record<string, ResolvedPersona>>;
247
+ getVirtualUsersMeta(): Promise<Record<string, ResolvedVirtualUser>>;
248
248
  getSystemRolesMeta(): Promise<SystemRoleDefinitionsMeta>;
249
249
  getScopesMeta(): Promise<ScopeDefinitionsMeta>;
250
250
  getFeatureFlagsMeta(): Promise<FeatureFlagDefinitionsMeta>;
@@ -14,7 +14,7 @@ export class LocalMetaService {
14
14
  gatewayMetaCache = null;
15
15
  rpcMetaCache = null;
16
16
  workflowMetaCache = null;
17
- personasMetaCache = null;
17
+ virtualUsersMetaCache = null;
18
18
  systemRolesMetaCache = null;
19
19
  scopesMetaCache = null;
20
20
  featureFlagsMetaCache = null;
@@ -114,7 +114,7 @@ export class LocalMetaService {
114
114
  this.gatewayMetaCache = null;
115
115
  this.rpcMetaCache = null;
116
116
  this.workflowMetaCache = null;
117
- this.personasMetaCache = null;
117
+ this.virtualUsersMetaCache = null;
118
118
  this.systemRolesMetaCache = null;
119
119
  this.scopesMetaCache = null;
120
120
  this.featureFlagsMetaCache = null;
@@ -265,12 +265,12 @@ export class LocalMetaService {
265
265
  return this.workflowMetaCache;
266
266
  }
267
267
  }
268
- async getPersonasMeta() {
269
- if (this.personasMetaCache)
270
- return this.personasMetaCache;
271
- const content = await this.readFile('workflow/personas.gen.json');
272
- this.personasMetaCache = content ? JSON.parse(content) : {};
273
- return this.personasMetaCache;
268
+ async getVirtualUsersMeta() {
269
+ if (this.virtualUsersMetaCache)
270
+ return this.virtualUsersMetaCache;
271
+ const content = await this.readFile('workflow/virtual-users.gen.json');
272
+ this.virtualUsersMetaCache = content ? JSON.parse(content) : {};
273
+ return this.virtualUsersMetaCache;
274
274
  }
275
275
  async getSystemRolesMeta() {
276
276
  if (this.systemRolesMetaCache)
@@ -1,6 +1,8 @@
1
1
  export interface ScenarioCookieJar {
2
2
  fetch: typeof fetch;
3
3
  clear(): void;
4
+ /** Take in raw `Set-Cookie` values from a response this jar did not fetch. */
5
+ absorb(setCookies: readonly string[]): void;
4
6
  readonly empty: boolean;
5
7
  }
6
8
  /**