eve 0.76.0 → 0.76.2

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 (171) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/src/channel/channel-address.d.ts +3 -1
  3. package/dist/src/channel/channel-address.js +1 -1
  4. package/dist/src/channel/session-stranded-error.d.ts +25 -0
  5. package/dist/src/channel/session-stranded-error.js +1 -0
  6. package/dist/src/channel/session.d.ts +13 -6
  7. package/dist/src/channel/types.d.ts +29 -1
  8. package/dist/src/chunks/{use-eve-agent-QmriPA-w.js → use-eve-agent-BtKWTEpm.js} +31 -14
  9. package/dist/src/chunks/{use-eve-agent-D2V9UhLt.js → use-eve-agent-jI6EsYAu.js} +31 -14
  10. package/dist/src/cli/commands/registry-project.d.ts +10 -3
  11. package/dist/src/cli/commands/registry-project.js +2 -2
  12. package/dist/src/cli/commands/registry.js +1 -1
  13. package/dist/src/cli/dev/tui/runner.js +3 -3
  14. package/dist/src/cli/dev/tui/stranded-session.d.ts +9 -0
  15. package/dist/src/cli/dev/tui/stranded-session.js +1 -0
  16. package/dist/src/client/client-error.d.ts +16 -0
  17. package/dist/src/client/client-error.js +1 -1
  18. package/dist/src/client/client.js +1 -1
  19. package/dist/src/client/index.d.ts +3 -2
  20. package/dist/src/client/index.js +1 -1
  21. package/dist/src/client/open-stream.d.ts +5 -3
  22. package/dist/src/client/open-stream.js +1 -1
  23. package/dist/src/client/session-controls.js +1 -1
  24. package/dist/src/client/session.js +1 -1
  25. package/dist/src/client/transcript-reducer.d.ts +46 -0
  26. package/dist/src/client/transcript-reducer.js +2 -0
  27. package/dist/src/compiled/.vendor-stamp.json +1 -1
  28. package/dist/src/compiler/extension-compatibility.d.ts +20 -20
  29. package/dist/src/compiler/extension-compatibility.js +1 -1
  30. package/dist/src/compiler/manifest.js +1 -1
  31. package/dist/src/compiler/normalize-agent-config.js +1 -1
  32. package/dist/src/context/accessors.d.ts +1 -1
  33. package/dist/src/context/build-callback-context.js +1 -1
  34. package/dist/src/context/dynamic-resolve-context.js +1 -1
  35. package/dist/src/context/keys.d.ts +5 -0
  36. package/dist/src/context/keys.js +1 -1
  37. package/dist/src/context/providers/session.d.ts +1 -0
  38. package/dist/src/context/providers/session.js +1 -1
  39. package/dist/src/context/session-context.d.ts +8 -2
  40. package/dist/src/dynamic/definition.d.ts +7 -1
  41. package/dist/src/evals/types.d.ts +2 -1
  42. package/dist/src/eve-channel/index.js +1 -1
  43. package/dist/src/eve-channel/request.js +2 -2
  44. package/dist/src/eve-channel/support.d.ts +2 -0
  45. package/dist/src/eve-channel/support.js +1 -1
  46. package/dist/src/execution/agent-sessions/steps.js +1 -1
  47. package/dist/src/execution/dynamic-workflow/tool.js +1 -1
  48. package/dist/src/execution/eve-workflow-attributes.d.ts +15 -0
  49. package/dist/src/execution/eve-workflow-attributes.js +1 -1
  50. package/dist/src/execution/install-workflow-world.d.ts +7 -0
  51. package/dist/src/execution/install-workflow-world.js +1 -0
  52. package/dist/src/execution/legacy-session/authorization.js +1 -1
  53. package/dist/src/execution/legacy-session/inbox.js +1 -1
  54. package/dist/src/execution/legacy-session/turn-workflow.js +1 -1
  55. package/dist/src/execution/session/entry.js +1 -1
  56. package/dist/src/execution/session/handoff-steps.d.ts +11 -0
  57. package/dist/src/execution/session/handoff-steps.js +1 -1
  58. package/dist/src/execution/session/program.js +1 -1
  59. package/dist/src/execution/session/timeout-steps.js +1 -1
  60. package/dist/src/execution/session-event-stream.d.ts +6 -0
  61. package/dist/src/execution/session-event-stream.js +1 -1
  62. package/dist/src/execution/session-inbox/address.d.ts +4 -0
  63. package/dist/src/execution/session-inbox/address.js +1 -1
  64. package/dist/src/execution/session-inbox/end-stranded-session.d.ts +22 -0
  65. package/dist/src/execution/session-inbox/end-stranded-session.js +1 -0
  66. package/dist/src/execution/session-inbox/hook-release.d.ts +4 -0
  67. package/dist/src/execution/session-inbox/hook-release.js +1 -0
  68. package/dist/src/execution/session-inbox/owner.d.ts +48 -0
  69. package/dist/src/execution/session-inbox/owner.js +1 -0
  70. package/dist/src/execution/session-inbox/resume.d.ts +12 -0
  71. package/dist/src/execution/session-inbox/resume.js +1 -1
  72. package/dist/src/execution/session-inbox/runnable-owner.d.ts +13 -0
  73. package/dist/src/execution/session-inbox/runnable-owner.js +1 -0
  74. package/dist/src/execution/session-inbox/stranded-replay-guard.d.ts +16 -0
  75. package/dist/src/execution/session-inbox/stranded-replay-guard.js +1 -0
  76. package/dist/src/execution/tools/agent-router-workflow.js +1 -1
  77. package/dist/src/execution/workflow-runtime.d.ts +5 -1
  78. package/dist/src/execution/workflow-runtime.js +1 -1
  79. package/dist/src/harness/compaction/step.js +1 -1
  80. package/dist/src/harness/input-request-resolution.js +1 -1
  81. package/dist/src/harness/model-call/call.d.ts +1 -1
  82. package/dist/src/harness/model-call/call.js +1 -1
  83. package/dist/src/harness/model-call/errors.d.ts +5 -6
  84. package/dist/src/harness/model-call/errors.js +1 -1
  85. package/dist/src/harness/model-call/recovery.d.ts +4 -3
  86. package/dist/src/harness/model-call/request.d.ts +2 -1
  87. package/dist/src/harness/model-call/request.js +1 -1
  88. package/dist/src/harness/model-call/tools.js +1 -1
  89. package/dist/src/harness/model-profile.d.ts +10 -3
  90. package/dist/src/harness/model-profile.js +1 -1
  91. package/dist/src/harness/prompt-cache.d.ts +6 -3
  92. package/dist/src/harness/prompt-cache.js +1 -1
  93. package/dist/src/harness/provider-safety.d.ts +2 -1
  94. package/dist/src/harness/provider-safety.js +1 -1
  95. package/dist/src/harness/provider-tools.d.ts +1 -1
  96. package/dist/src/harness/provider-tools.js +1 -1
  97. package/dist/src/harness/session-machine/transitions.d.ts +3 -1
  98. package/dist/src/harness/session-machine/transitions.js +1 -1
  99. package/dist/src/harness/step/context.js +1 -1
  100. package/dist/src/harness/step-hooks.js +1 -1
  101. package/dist/src/internal/application/compiled-artifacts.js +4 -4
  102. package/dist/src/internal/application/package.d.ts +1 -1
  103. package/dist/src/internal/application/package.js +1 -1
  104. package/dist/src/internal/application/stamped-package-version.d.ts +5 -0
  105. package/dist/src/internal/application/stamped-package-version.js +1 -0
  106. package/dist/src/internal/authored-definition/core.d.ts +3 -0
  107. package/dist/src/internal/authored-definition/core.js +1 -1
  108. package/dist/src/internal/model-auth/available-models.js +1 -1
  109. package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
  110. package/dist/src/internal/workflow/development-run-unavailable-error.d.ts +15 -0
  111. package/dist/src/internal/workflow/development-run-unavailable-error.js +1 -0
  112. package/dist/src/internal/workflow/development-world-server.js +1 -1
  113. package/dist/src/internal/workflow-bundle/workflow-builders.js +1 -1
  114. package/dist/src/protocol/message.d.ts +14 -0
  115. package/dist/src/protocol/message.js +1 -1
  116. package/dist/src/public/channels/index.d.ts +1 -1
  117. package/dist/src/public/channels/index.js +1 -1
  118. package/dist/src/public/context/index.d.ts +1 -1
  119. package/dist/src/public/definitions/callback-context.d.ts +1 -1
  120. package/dist/src/public/definitions/channel.d.ts +1 -0
  121. package/dist/src/public/definitions/channel.js +1 -1
  122. package/dist/src/public/models/openai/chatgpt/model.js +1 -1
  123. package/dist/src/public/models/openai/chatgpt/transport.js +1 -1
  124. package/dist/src/public/tanstack/index.d.ts +40 -0
  125. package/dist/src/public/tanstack/index.js +1 -0
  126. package/dist/src/runtime/agent/resolve-model.js +1 -1
  127. package/dist/src/runtime/resolve-agent.js +1 -1
  128. package/dist/src/setup/flows/model-login.js +1 -1
  129. package/dist/src/setup/integrations/web/framework.d.ts +8 -0
  130. package/dist/src/setup/integrations/web/framework.js +1 -0
  131. package/dist/src/setup/integrations/web/hosting.d.ts +43 -0
  132. package/dist/src/setup/integrations/web/hosting.js +15 -0
  133. package/dist/src/setup/integrations/web/setup.d.ts +6 -10
  134. package/dist/src/setup/integrations/web/setup.js +23 -17
  135. package/dist/src/setup/scaffold/create/project.js +1 -1
  136. package/dist/src/setup/scaffold/create/web-template.d.ts +6 -2
  137. package/dist/src/setup/scaffold/create/web-template.js +39 -2
  138. package/dist/src/setup/scaffold/update/channels.js +1 -1
  139. package/dist/src/setup/vercel-project-framework.js +1 -1
  140. package/dist/src/shared/agent-definition.d.ts +25 -0
  141. package/dist/src/shared/agent-definition.js +1 -1
  142. package/dist/src/shared/chatgpt-model.d.ts +8 -0
  143. package/dist/src/shared/chatgpt-model.js +1 -1
  144. package/dist/src/subagents/callback-route.js +1 -1
  145. package/dist/src/svelte/index.js +1 -1
  146. package/dist/src/svelte/use-eve-agent.js +1 -1
  147. package/dist/src/tools/provided/ask-question-workflow.js +1 -1
  148. package/dist/src/tools/provided/sleep-workflow.js +1 -1
  149. package/dist/src/vue/index.js +1 -1
  150. package/dist/src/vue/use-eve-agent.js +1 -1
  151. package/docs/agent-config.md +32 -1
  152. package/docs/channels/custom.mdx +26 -0
  153. package/docs/channels/eve.mdx +8 -5
  154. package/docs/concepts/built-in-tools.md +17 -0
  155. package/docs/concepts/execution-model-and-durability.mdx +100 -0
  156. package/docs/concepts/project-structure.mdx +2 -2
  157. package/docs/concepts/sessions-runs-and-streaming.md +36 -34
  158. package/docs/guides/client/messages.mdx +10 -1
  159. package/docs/guides/deployment/overview.md +2 -2
  160. package/docs/guides/dev-tui.md +2 -0
  161. package/docs/guides/frontend/meta.json +9 -1
  162. package/docs/guides/frontend/nextjs.mdx +1 -1
  163. package/docs/guides/frontend/overview.mdx +9 -8
  164. package/docs/guides/frontend/tanstack.mdx +201 -0
  165. package/docs/guides/session-context.md +1 -0
  166. package/docs/install-integrations.mdx +1 -1
  167. package/docs/instructions.mdx +1 -1
  168. package/docs/reference/typescript-api.md +1 -1
  169. package/docs/tools/human-in-the-loop.md +2 -0
  170. package/docs/tutorial/ship-it.mdx +1 -1
  171. package/package.json +7 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # eve
2
2
 
3
+ ## 0.76.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 91f4b68: Add `modelOptions.promptCache` for models eve calls directly. `promptCache: { anthropic: { ttl: "1h" } }` switches eve's Anthropic cache breakpoints to a 1-hour lifetime. `promptCache: { anthropic: {} }` turns breakpoints on for an Anthropic model eve can't recognize from its id, such as a Bedrock application inference profile.
8
+ - c160b22: A session that replaces a retired stranded session names the session it replaced in `ctx.session.predecessor` (also on dynamic resolver contexts) and `session.started` `data.predecessor` (`{ sessionId }`). The new `transcriptReducer()` in `eve/client` folds a session's stream into its user and completed assistant text since the last clear; combine it with `sessions.attach(predecessor.sessionId).stream()` from `eve/server` in a `session.started` user-role dynamic instruction to give the replacement the earlier conversation.
9
+ - 89bd625: Add `eve/tanstack`, a Vite plugin that runs an eve agent inside a TanStack Start app: Nitro proxies `/eve/v1/**` to a local eve server in development, and Vercel builds deploy eve as a sibling service. Set `devServerTimeoutMs` to wait longer for a slow eve dev server to start. `eve build` and `eve dev` now always use Nitro's Rolldown builder, so an agent that shares its root with a TanStack Start app no longer fails to start.
10
+ - b664838: `eve add channel/web` now asks which framework Web Chat uses and can install a TanStack Start app under `apps/web/`, hosted as a separate Vercel service or inside the app through `eve/tanstack`; non-interactive installs keep Next.js unless you pass `--answer 'web-framework="tanstack"'`. Web Chat setup also checks for authored configuration before writing, removes the `vercel.ts` and scripts it wrote when you switch hosting modes, and renders text in the loaded Geist fonts.
11
+
12
+ ## 0.76.1
13
+
14
+ ### Patch Changes
15
+
16
+ - fcbd479: A denied tool approval that carries `text` now passes that note to the model in the denial reason instead of dropping it.
17
+ - 9626748: Use build-stamped package metadata in bundled runtimes so serverless functions can start without resolving `eve/package.json` at runtime.
18
+ - 25b3f35: `/login chatgpt` now lists current subscription models such as `gpt-6-luna`, and the default `chatgpt()` model (`gpt-6-luna-fast`) works: eve sends it to Codex as `gpt-6-luna` on the priority service tier, since Codex rejects `-fast` model IDs.
19
+ - 416e63e: Direct OpenAI and `chatgpt()` model calls now send a per-session `promptCacheKey`, which helps OpenAI route a session's calls to the cache holding its prompt prefix. `chatgpt()` calls also send it as the `session-id` header the Codex backend routes on. An authored `providerOptions.openai.promptCacheKey` still takes precedence.
20
+ - b04acbb: On worlds without per-deployment routing, incompatible subagent sessions and workflow tool runs (including tasks) are now cancelled when their queue deliveries arrive, instead of attempting replay on the new eve version. Top-level sessions remain available for replacement or reset, and session timeout workflows continue to run.
21
+ - b04acbb: Sessions whose workflow run cannot execute after an eve upgrade (a stranded session) are no longer accepted and left unanswered, and the local World and Postgres stop replaying and failing them with `CORRUPTED_EVENT_LOG`. eve treats every World other than Vercel as running one eve version at a time, so the next message through a channel address (Slack, `from(address).send()`) ends a stranded session and starts a fresh one. Sends by session ID throw `SessionStrandedError` (`ClientSessionStrandedError` in `eve/client`), and the eve HTTP channel returns `409 session_stranded`; `reset()` ends a stranded session while `clear()` refuses one, and recorded history stays readable with `stream({ follow: false })` or `follow=false` on the stream route. On Worlds other than Vercel, a retired session's own session timeout now ends it at its deadline, so a retired session no longer stays active forever when no message arrives.
22
+ - cf72486: Agents whose OpenAI model is served by an endpoint without OpenAI web search, such as Amazon Bedrock through `createOpenAI({ baseURL })` or AI Gateway, now retry the step without `web_search` instead of failing every turn.
23
+
3
24
  ## 0.76.0
4
25
 
5
26
  ### Minor Changes
@@ -17,7 +17,9 @@ export type ChannelAddressDeliveryOptions<TState = undefined> = [TState] extends
17
17
  };
18
18
  /**
19
19
  * Dynamic handle for whichever durable session currently owns one channel-local address.
20
- * Only {@link send} may create a session when the address is unowned.
20
+ * Only {@link send} may create a session: when the address is unowned, or in
21
+ * place of a stranded session that another eve version built. Sends to a session whose
22
+ * owner is only unavailable throw `SessionStrandedError` and deliver nothing.
21
23
  */
22
24
  interface ChannelAddress<TState = undefined> {
23
25
  readonly continuationToken: string;
@@ -1 +1 @@
1
- import{createSession,sessionCallbackToTurnCaller}from"#channel/session.js";import{createChannelDeliveryMetadata}from"#channel/delivery-metadata.js";import{normalizeSendInput,serializeUrlFilePartsInMessage}from"#channel/send-input.js";import{DEFAULT_TURN_POLICY}from"#channel/types.js";import{isReservedSessionCommandToken}from"#execution/session-inbox/address.js";function createChannelAddress(e){let t=e.metadata??{},n=`${e.channelName}:${e.continuationToken}`;if(isReservedSessionCommandToken(n))throw Error(`Channel address "${n}" uses eve's reserved session namespace.`);return{continuationToken:e.continuationToken,async deliver(r,i){let a=t.channelKind!==void 0&&t.channelName!==void 0?createChannelDeliveryMetadata(t):void 0,o=normalizeSendInput(r),s=sessionCallbackToTurnCaller(i.callback),c={auth:i.auth,delivery:a,kind:`send`,payload:{...o,message:serializeUrlFilePartsInMessage(o.message)},requestId:t.requestId,turnPolicy:o.message===void 0?void 0:i.turnPolicy??e.turnPolicy??DEFAULT_TURN_POLICY},l=s===void 0?c:{...c,caller:s},u=await(async()=>{let r=await e.runtime.dispatchContinuation({command:l,continuationToken:n});return r.status===`accepted`?createSession(r.sessionId,e.runtime,{...t,turnPolicy:e.turnPolicy}):void 0})();if(u!==void 0)return u;if(o.inputResponses&&o.inputResponses.length>0)throw Error(`Cannot deliver inputResponses — the target session was not found via continuation token.`);let d=i.state,f={adapter:d===void 0?e.adapter:{...e.adapter,state:{...e.adapter.state,...d}},auth:i.auth,capabilities:{requestInput:!0},callback:i.callback,channelName:e.channelName,continuationConflictCommand:l,continuationToken:n,delivery:a,initiatorAuth:i.initiatorAuth,input:{context:o.context,message:serializeUrlFilePartsInMessage(o.message)??``,outputSchema:o.outputSchema,state:o.state},requestId:t.requestId,title:i.title},p=await e.runtime.createSession(f);return createSession(p.sessionId,e.runtime,{...t,turnPolicy:e.turnPolicy})},async send(e,t){return await this.deliver({message:e},t)},async respond(e,t){if(e===void 0||e.length===0)throw Error(`respond() requires at least one input response.`);return await this.deliver({inputResponses:e},t)},async cancel(t){return await e.runtime.dispatchContinuation({command:{kind:`cancel`,turnId:t?.turnId},continuationToken:n})},async compact(){return await e.runtime.dispatchContinuation({command:{kind:`compact`},continuationToken:n})},async clear(){return await e.runtime.dispatchContinuation({command:{kind:`clear`},continuationToken:n})},async reset(t){return await e.runtime.dispatchContinuation({command:{kind:`reset`,reason:t?.reason},continuationToken:n})},async resolveSession(){let r=await e.runtime.resolveContinuation(n);return r===void 0?void 0:createSession(r.sessionId,e.runtime,{...t,turnPolicy:e.turnPolicy})}}}function createChannelAddressFn(e){return t=>createChannelAddress({...e,continuationToken:t})}export{createChannelAddress,createChannelAddressFn};
1
+ import{createSession,sessionCallbackToTurnCaller}from"#channel/session.js";import{createChannelDeliveryMetadata}from"#channel/delivery-metadata.js";import{normalizeSendInput,serializeUrlFilePartsInMessage}from"#channel/send-input.js";import{DEFAULT_TURN_POLICY}from"#channel/types.js";import{isReservedSessionCommandToken}from"#execution/session-inbox/address.js";function createChannelAddress(e){let t=e.metadata??{},n=`${e.channelName}:${e.continuationToken}`;if(isReservedSessionCommandToken(n))throw Error(`Channel address "${n}" uses eve's reserved session namespace.`);return{continuationToken:e.continuationToken,async deliver(r,i){let a=t.channelKind!==void 0&&t.channelName!==void 0?createChannelDeliveryMetadata(t):void 0,o=normalizeSendInput(r),s=sessionCallbackToTurnCaller(i.callback),c={auth:i.auth,delivery:a,kind:`send`,payload:{...o,message:serializeUrlFilePartsInMessage(o.message)},requestId:t.requestId,turnPolicy:o.message===void 0?void 0:i.turnPolicy??e.turnPolicy??DEFAULT_TURN_POLICY},l=s===void 0?c:{...c,caller:s},u=i.state,d={adapter:u===void 0?e.adapter:{...e.adapter,state:{...e.adapter.state,...u}},auth:i.auth,capabilities:{requestInput:!0},callback:i.callback,channelName:e.channelName,continuationConflictCommand:l,continuationToken:n,delivery:a,initiatorAuth:i.initiatorAuth,input:{context:o.context,message:serializeUrlFilePartsInMessage(o.message)??``,outputSchema:o.outputSchema,state:o.state},requestId:t.requestId,title:i.title},toSession=n=>createSession(n,e.runtime,{...t,turnPolicy:e.turnPolicy}),f=await e.runtime.dispatchContinuation({command:l,continuationToken:n,successor:d});if(f.status===`accepted`)return toSession(f.sessionId);if(o.inputResponses&&o.inputResponses.length>0)throw Error(`Cannot deliver inputResponses — the target session was not found via continuation token.`);return toSession((await e.runtime.createSession(d)).sessionId)},async send(e,t){return await this.deliver({message:e},t)},async respond(e,t){if(e===void 0||e.length===0)throw Error(`respond() requires at least one input response.`);return await this.deliver({inputResponses:e},t)},async cancel(t){return await e.runtime.dispatchContinuation({command:{kind:`cancel`,turnId:t?.turnId},continuationToken:n})},async compact(){return await e.runtime.dispatchContinuation({command:{kind:`compact`},continuationToken:n})},async clear(){return await e.runtime.dispatchContinuation({command:{kind:`clear`},continuationToken:n})},async reset(t){return await e.runtime.dispatchContinuation({command:{kind:`reset`,reason:t?.reason},continuationToken:n})},async resolveSession(){let r=await e.runtime.resolveContinuation(n);return r===void 0?void 0:createSession(r.sessionId,e.runtime,{...t,turnPolicy:e.turnPolicy})}}}function createChannelAddressFn(e){return t=>createChannelAddress({...e,continuationToken:t})}export{createChannelAddress,createChannelAddressFn};
@@ -0,0 +1,25 @@
1
+ /** The owner of a stranded session, as far as it recorded itself. */
2
+ interface StrandedSessionOwner {
3
+ /** eve version that built the owner, when it recorded one. */
4
+ readonly eveVersion?: string;
5
+ }
6
+ /**
7
+ * Thrown when sending, responding, clearing, or following the live stream of
8
+ * a session whose owner another eve version built, on a World that only runs
9
+ * this build, so the owner can never execute again. Nothing is delivered and
10
+ * nothing is mutated. Historical reads with `follow: false` still succeed.
11
+ * Call `reset()` to end the session, then start a new one. Narrow with
12
+ * {@link SessionStrandedError.is}.
13
+ */
14
+ export declare class SessionStrandedError extends Error {
15
+ readonly owner: StrandedSessionOwner;
16
+ constructor(owner: StrandedSessionOwner, message?: string);
17
+ /** Narrows stranded-session errors across bundle boundaries, where `instanceof` can miss. */
18
+ static is(error: unknown): error is SessionStrandedError;
19
+ }
20
+ /**
21
+ * One actionable sentence pair that names the cause, the version, and the
22
+ * next step. `nextStep` replaces the default recovery instruction.
23
+ */
24
+ export declare function describeStrandedSession(owner: StrandedSessionOwner, nextStep?: string): string;
25
+ export {};
@@ -0,0 +1 @@
1
+ var SessionStrandedError=class SessionStrandedError extends Error{owner;constructor(e,t){super(t??describeStrandedSession(e)),this.name=`SessionStrandedError`,this.owner=e}static is(e){return e instanceof SessionStrandedError||typeof e==`object`&&!!e&&Reflect.get(e,`name`)===`SessionStrandedError`&&typeof Reflect.get(e,`owner`)==`object`}};function describeStrandedSession(e,t){return`This session is stranded: ${e.eveVersion===void 0?`it was created by an earlier eve release`:`it was created by eve ${e.eveVersion}`} on a deployment that is no longer available, so it cannot process messages. ${t??`Reset the session to start fresh.`}`}export{SessionStrandedError,describeStrandedSession};
@@ -2,16 +2,20 @@ import type { ContextAccessor } from "#context/key.js";
2
2
  import { type ChannelDeliverySource } from "#channel/delivery-metadata.js";
3
3
  import type { MessageStreamEvent } from "#protocol/message.js";
4
4
  import type { UserContent } from "ai";
5
- import type { CancelTurnResult, ClearSessionResult, CompactSessionResult, ResetSessionResult, Runtime, SessionAuthContext, SessionCallback, SessionSendCommandResult, TurnPolicy, TurnCaller } from "#channel/types.js";
5
+ import type { CancelTurnResult, ClearSessionResult, CompactSessionResult, GetEventStreamOptions, ResetSessionResult, Runtime, SessionAuthContext, SessionCallback, SessionSendCommandResult, TurnPolicy, TurnCaller } from "#channel/types.js";
6
6
  import type { SessionAuth } from "#context/keys.js";
7
7
  import { type InputResponse, type StrictInputResponses } from "#shared/input.js";
8
8
  import type { JsonObject } from "#shared/json.js";
9
9
  /** Immutable-ID handle for one exact durable session. */
10
10
  export interface Session {
11
11
  readonly id: string;
12
- /** Sends a message to this exact session ID without creating or following a replacement. */
12
+ /**
13
+ * Sends a message to this exact session ID without creating or following a
14
+ * replacement. Throws `SessionStrandedError` when the session's owner cannot
15
+ * execute here; nothing is delivered. Call {@link reset} to end it.
16
+ */
13
17
  send(message: string | UserContent, options: SessionSendOptions): Promise<SessionSendCommandResult>;
14
- /** Answers pending input requests on this exact session ID. */
18
+ /** Answers pending input requests on this exact session ID. Throws `SessionStrandedError` like {@link send}. */
15
19
  respond<const TResponses extends readonly InputResponse[]>(inputResponses: StrictInputResponses<TResponses>, options: SessionRespondOptions): Promise<SessionSendCommandResult>;
16
20
  /** Requests cancellation of this exact session's active turn. */
17
21
  cancel(options?: {
@@ -25,9 +29,12 @@ export interface Session {
25
29
  reset(options?: {
26
30
  reason?: string;
27
31
  }): Promise<ResetSessionResult>;
28
- getEventStream(options?: {
29
- startIndex?: number;
30
- }): Promise<ReadableStream<MessageStreamEvent>>;
32
+ /**
33
+ * Opens the recorded stream. Following it throws `SessionStrandedError`
34
+ * while its owner is stranded; `follow: false` reads recorded history up to
35
+ * the current tail without inspecting or changing the session.
36
+ */
37
+ getEventStream(options?: GetEventStreamOptions): Promise<ReadableStream<MessageStreamEvent>>;
31
38
  getStreamTailIndex(): Promise<number>;
32
39
  }
33
40
  interface SessionDeliveryOptions {
@@ -31,7 +31,10 @@ export type CompactSessionResult = {
31
31
  } | {
32
32
  readonly status: "no_active_session";
33
33
  };
34
- /** Result of queueing a manual context clear for a session. */
34
+ /**
35
+ * Result of queueing a manual context clear for a session. A stranded session
36
+ * cannot run the clear, so it throws `SessionStrandedError` instead.
37
+ */
35
38
  export type ClearSessionResult = {
36
39
  readonly status: "accepted";
37
40
  readonly sessionId: string;
@@ -210,6 +213,11 @@ export type SessionCommandResult<TCommand extends SessionCommand = SessionComman
210
213
  export interface DispatchContinuationInput<TCommand extends SessionCommand = SessionCommand> {
211
214
  readonly command: TCommand;
212
215
  readonly continuationToken: string;
216
+ /**
217
+ * Fresh creation inputs for a send. Used only when the address's owner is
218
+ * stranded: the runtime ends it and starts this successor in its place.
219
+ */
220
+ readonly successor?: RunInput;
213
221
  }
214
222
  export interface DispatchSessionInput<TCommand extends SessionCommand = SessionCommand> {
215
223
  readonly command: TCommand;
@@ -528,7 +536,17 @@ export interface Runtime {
528
536
  * completion.
529
537
  */
530
538
  createSession(input: RunInput): Promise<RunHandle>;
539
+ /**
540
+ * Sends a command to whichever session owns a continuation address. When
541
+ * that owner is stranded, a send with a `successor` ends it and is accepted
542
+ * by the successor; a send without one, or a `clear`, throws
543
+ * `SessionStrandedError`, and a `reset` ends it.
544
+ */
531
545
  dispatchContinuation<TCommand extends SessionCommand>(input: DispatchContinuationInput<TCommand>): Promise<SessionCommandResult<TCommand>>;
546
+ /**
547
+ * Sends a command to one exact session. A send or `clear` to a stranded
548
+ * session throws `SessionStrandedError`; a `reset` ends it.
549
+ */
532
550
  dispatchSession<TCommand extends SessionCommand>(input: DispatchSessionInput<TCommand>): Promise<SessionCommandResult<TCommand>>;
533
551
  /**
534
552
  * Resolves the session that currently owns a continuation token without
@@ -549,6 +567,10 @@ export interface Runtime {
549
567
  * first event to yield. Negative values read relative to the current tail.
550
568
  * The framework HTTP session-stream route forwards the `startIndex` query
551
569
  * parameter unchanged.
570
+ *
571
+ * A following read throws `SessionStrandedError` when the session's owner
572
+ * cannot execute here. A historical read (`follow: false`) never inspects
573
+ * or changes the session's lifecycle.
552
574
  */
553
575
  getEventStream(sessionId: string, options?: GetEventStreamOptions): Promise<ReadableStream<MessageStreamEvent>>;
554
576
  /**
@@ -569,4 +591,10 @@ export interface GetEventStreamOptions {
569
591
  * (replay the entire stream).
570
592
  */
571
593
  readonly startIndex?: number;
594
+ /**
595
+ * Whether to keep following events recorded after the read opens. When
596
+ * `false`, the stream ends at the durable tail observed when it opens, and
597
+ * it stays readable while the session is stranded. Defaults to `true`.
598
+ */
599
+ readonly follow?: boolean;
572
600
  }
@@ -550,25 +550,39 @@ var ClientError = class extends Error {
550
550
  constructor(status, body, headers) {
551
551
  const normalizedHeaders = Object.freeze(Object.fromEntries(new Headers(headers).entries()));
552
552
  const contentType = normalizedHeaders["content-type"]?.toLowerCase();
553
+ const parsed = parseJsonObject$1(body);
553
554
  let message = body || `Server returned ${status}.`;
554
- let code;
555
- try {
556
- const parsed = JSON.parse(body);
557
- if (isObject(parsed)) {
558
- if (typeof parsed.error === "string") message = parsed.error;
559
- if (typeof parsed.code === "string") code = parsed.code;
560
- }
561
- } catch {
562
- if (contentType?.includes("text/html")) message = `Server returned ${status} with an HTML response. Check the eve route and development server configuration.`;
563
- }
555
+ if (typeof parsed?.error === "string") message = parsed.error;
556
+ else if (parsed === void 0 && contentType?.includes("text/html")) message = `Server returned ${status} with an HTML response. Check the eve route and development server configuration.`;
564
557
  super(message);
565
558
  this.name = "ClientError";
566
- this.code = code;
559
+ this.code = typeof parsed?.code === "string" ? parsed.code : void 0;
567
560
  this.status = status;
568
561
  this.body = body;
569
562
  this.headers = normalizedHeaders;
570
563
  }
571
564
  };
565
+ var ClientSessionStrandedError = class extends ClientError {
566
+ eveVersion;
567
+ constructor(status, body, headers, details) {
568
+ super(status, body, headers);
569
+ this.name = "ClientSessionStrandedError";
570
+ this.eveVersion = details.eveVersion;
571
+ }
572
+ };
573
+ function createClientError(status, body, headers) {
574
+ const parsed = status === 409 ? parseJsonObject$1(body) : void 0;
575
+ if (parsed?.code !== "session_stranded") return new ClientError(status, body, headers);
576
+ return new ClientSessionStrandedError(status, body, headers, { eveVersion: typeof parsed.eveVersion === "string" ? parsed.eveVersion : void 0 });
577
+ }
578
+ function parseJsonObject$1(body) {
579
+ try {
580
+ const parsed = JSON.parse(body);
581
+ return isObject(parsed) ? parsed : void 0;
582
+ } catch {
583
+ return;
584
+ }
585
+ }
572
586
 
573
587
  //#endregion
574
588
  //#region src/shared/errors.ts
@@ -1583,6 +1597,7 @@ async function* followStreamIterable(input) {
1583
1597
  caughtUp = true;
1584
1598
  input.onCaughtUp?.();
1585
1599
  }
1600
+ if (event.type === "session.failed" || event.type === "session.completed") return;
1586
1601
  if (input.follow === false && tailIndex !== void 0 && startIndex > tailIndex) return;
1587
1602
  }
1588
1603
  } catch (error) {
@@ -1612,6 +1627,7 @@ async function openStreamBody(input) {
1612
1627
  if (controlVersion !== void 0) searchParams[EVE_STREAM_CONTROL_VERSION_QUERY] = controlVersion;
1613
1628
  if (input.startIndex !== 0) searchParams.startIndex = String(input.startIndex);
1614
1629
  if (input.requestTailIndex === true) searchParams.includeTailIndex = "1";
1630
+ if (input.follow === false) searchParams.follow = "false";
1615
1631
  for (let attempt = 0; attempt < openRetryPolicy.maxAttempts; attempt += 1) {
1616
1632
  input.signal?.throwIfAborted();
1617
1633
  const url = createClientUrl(input.host, input.path, Object.keys(searchParams).length > 0 ? searchParams : void 0);
@@ -1652,7 +1668,8 @@ async function openStreamBody(input) {
1652
1668
  lastStatus = response.status;
1653
1669
  lastBody = await response.text();
1654
1670
  lastHeaders = response.headers;
1655
- if (!retryPolicy.retryableErrorStatuses.has(response.status)) throw new ClientError(response.status, lastBody, response.headers);
1671
+ const error = createClientError(response.status, lastBody, response.headers);
1672
+ if (error instanceof ClientSessionStrandedError || !retryPolicy.retryableErrorStatuses.has(response.status)) throw error;
1656
1673
  if (attempt < openRetryPolicy.maxAttempts - 1) {
1657
1674
  await sleep(retryDelayMs, input.signal);
1658
1675
  retryDelayMs = Math.min(retryDelayMs * 2, openRetryPolicy.maxDelayMs);
@@ -1909,7 +1926,7 @@ async function postJson(input) {
1909
1926
  signal: input.signal
1910
1927
  }, input.context.redirect));
1911
1928
  const text = await response.text();
1912
- if (!response.ok) throw new ClientError(response.status, text, response.headers);
1929
+ if (!response.ok) throw createClientError(response.status, text, response.headers);
1913
1930
  try {
1914
1931
  return {
1915
1932
  payload: JSON.parse(text),
@@ -2503,7 +2520,7 @@ async function postTurn(context, path, input, requireMessage, stubs) {
2503
2520
  });
2504
2521
  if (!response.ok) {
2505
2522
  const responseBody = await response.text();
2506
- throw new ClientError(response.status, responseBody, response.headers);
2523
+ throw createClientError(response.status, responseBody, response.headers);
2507
2524
  }
2508
2525
  return response;
2509
2526
  }
@@ -551,25 +551,39 @@ var ClientError = class extends Error {
551
551
  constructor(status, body, headers) {
552
552
  const normalizedHeaders = Object.freeze(Object.fromEntries(new Headers(headers).entries()));
553
553
  const contentType = normalizedHeaders["content-type"]?.toLowerCase();
554
+ const parsed = parseJsonObject$1(body);
554
555
  let message = body || `Server returned ${status}.`;
555
- let code;
556
- try {
557
- const parsed = JSON.parse(body);
558
- if (isObject(parsed)) {
559
- if (typeof parsed.error === "string") message = parsed.error;
560
- if (typeof parsed.code === "string") code = parsed.code;
561
- }
562
- } catch {
563
- if (contentType?.includes("text/html")) message = `Server returned ${status} with an HTML response. Check the eve route and development server configuration.`;
564
- }
556
+ if (typeof parsed?.error === "string") message = parsed.error;
557
+ else if (parsed === void 0 && contentType?.includes("text/html")) message = `Server returned ${status} with an HTML response. Check the eve route and development server configuration.`;
565
558
  super(message);
566
559
  this.name = "ClientError";
567
- this.code = code;
560
+ this.code = typeof parsed?.code === "string" ? parsed.code : void 0;
568
561
  this.status = status;
569
562
  this.body = body;
570
563
  this.headers = normalizedHeaders;
571
564
  }
572
565
  };
566
+ var ClientSessionStrandedError = class extends ClientError {
567
+ eveVersion;
568
+ constructor(status, body, headers, details) {
569
+ super(status, body, headers);
570
+ this.name = "ClientSessionStrandedError";
571
+ this.eveVersion = details.eveVersion;
572
+ }
573
+ };
574
+ function createClientError(status, body, headers) {
575
+ const parsed = status === 409 ? parseJsonObject$1(body) : void 0;
576
+ if (parsed?.code !== "session_stranded") return new ClientError(status, body, headers);
577
+ return new ClientSessionStrandedError(status, body, headers, { eveVersion: typeof parsed.eveVersion === "string" ? parsed.eveVersion : void 0 });
578
+ }
579
+ function parseJsonObject$1(body) {
580
+ try {
581
+ const parsed = JSON.parse(body);
582
+ return isObject(parsed) ? parsed : void 0;
583
+ } catch {
584
+ return;
585
+ }
586
+ }
573
587
 
574
588
  //#endregion
575
589
  //#region src/shared/errors.ts
@@ -1584,6 +1598,7 @@ async function* followStreamIterable(input) {
1584
1598
  caughtUp = true;
1585
1599
  input.onCaughtUp?.();
1586
1600
  }
1601
+ if (event.type === "session.failed" || event.type === "session.completed") return;
1587
1602
  if (input.follow === false && tailIndex !== void 0 && startIndex > tailIndex) return;
1588
1603
  }
1589
1604
  } catch (error) {
@@ -1613,6 +1628,7 @@ async function openStreamBody(input) {
1613
1628
  if (controlVersion !== void 0) searchParams[EVE_STREAM_CONTROL_VERSION_QUERY] = controlVersion;
1614
1629
  if (input.startIndex !== 0) searchParams.startIndex = String(input.startIndex);
1615
1630
  if (input.requestTailIndex === true) searchParams.includeTailIndex = "1";
1631
+ if (input.follow === false) searchParams.follow = "false";
1616
1632
  for (let attempt = 0; attempt < openRetryPolicy.maxAttempts; attempt += 1) {
1617
1633
  input.signal?.throwIfAborted();
1618
1634
  const url = createClientUrl(input.host, input.path, Object.keys(searchParams).length > 0 ? searchParams : void 0);
@@ -1653,7 +1669,8 @@ async function openStreamBody(input) {
1653
1669
  lastStatus = response.status;
1654
1670
  lastBody = await response.text();
1655
1671
  lastHeaders = response.headers;
1656
- if (!retryPolicy.retryableErrorStatuses.has(response.status)) throw new ClientError(response.status, lastBody, response.headers);
1672
+ const error = createClientError(response.status, lastBody, response.headers);
1673
+ if (error instanceof ClientSessionStrandedError || !retryPolicy.retryableErrorStatuses.has(response.status)) throw error;
1657
1674
  if (attempt < openRetryPolicy.maxAttempts - 1) {
1658
1675
  await sleep(retryDelayMs, input.signal);
1659
1676
  retryDelayMs = Math.min(retryDelayMs * 2, openRetryPolicy.maxDelayMs);
@@ -1910,7 +1927,7 @@ async function postJson(input) {
1910
1927
  signal: input.signal
1911
1928
  }, input.context.redirect));
1912
1929
  const text = await response.text();
1913
- if (!response.ok) throw new ClientError(response.status, text, response.headers);
1930
+ if (!response.ok) throw createClientError(response.status, text, response.headers);
1914
1931
  try {
1915
1932
  return {
1916
1933
  payload: JSON.parse(text),
@@ -2504,7 +2521,7 @@ async function postTurn(context, path, input, requireMessage, stubs) {
2504
2521
  });
2505
2522
  if (!response.ok) {
2506
2523
  const responseBody = await response.text();
2507
- throw new ClientError(response.status, responseBody, response.headers);
2524
+ throw createClientError(response.status, responseBody, response.headers);
2508
2525
  }
2509
2526
  return response;
2510
2527
  }
@@ -1,16 +1,23 @@
1
1
  import type { RegistryConfig } from "#compiled/shadcn-registry/index.js";
2
+ import type { Asker } from "#setup/ask.js";
3
+ import { type WebChatFramework } from "#setup/integrations/web/framework.js";
2
4
  interface AddRegistryMappingsResult {
3
5
  added: string[];
4
6
  skippedBuiltIn: string[];
5
7
  skippedExisting: string[];
6
8
  }
9
+ /**
10
+ * Picks the framework `eve add channel/web` installs, before it writes any file.
11
+ * An app already in `apps/web` decides; an explicit answer that conflicts fails.
12
+ */
13
+ export declare function resolveWebChatFramework(appRoot: string, asker: Asker, answers?: Readonly<Record<string, unknown>>): Promise<WebChatFramework>;
7
14
  /** Resolves and prepares the root package that owns Web Chat. */
8
- export declare function prepareWebChatProjectRoot(appRoot: string): Promise<string>;
15
+ export declare function prepareWebChatProjectRoot(appRoot: string, framework?: WebChatFramework): Promise<string>;
9
16
  /** Reads registry namespace mappings from package.json. */
10
17
  export declare function readRegistryConfig(appRoot: string): Promise<RegistryConfig>;
11
- export declare function addWebRegistryTsconfig(source: string, path: string): string;
18
+ export declare function addWebRegistryTsconfig(source: string, path: string, framework?: WebChatFramework): string;
12
19
  /** Prepares the TypeScript host configuration shadcn registry items expect. */
13
- export declare function prepareWebRegistryProject(appRoot: string): Promise<void>;
20
+ export declare function prepareWebRegistryProject(appRoot: string, framework?: WebChatFramework): Promise<void>;
14
21
  /** Adds explicit registry namespace mappings to package.json. */
15
22
  export declare function addRegistryMappings(appRoot: string, arguments_: readonly string[]): Promise<AddRegistryMappingsResult>;
16
23
  export {};
@@ -1,2 +1,2 @@
1
- import{readFile,writeFile}from"node:fs/promises";import{join}from"node:path";import{resolveEveProjectContext}from"#internal/project-context.js";import{applyEdits,modify,parse}from"#compiled/jsonc-parser/index.js";import{WEB_APP_TEMPLATE_FILES}from"#setup/scaffold/create/web-template.js";function errorMessage(e){return e instanceof Error?e.message:String(e)}function isRegistrySource(e){return typeof e==`string`?!0:typeof e!=`object`||!e||!(`url`in e)?!1:typeof e.url==`string`}function parseRegistries(e,t){if(t===void 0)return{};if(typeof t!=`object`||!t||Array.isArray(t))throw Error(`${e} has an invalid registries field.`);let n={};for(let[r,i]of Object.entries(t)){if(!r.startsWith(`@`)||!isRegistrySource(i))throw Error(`${e} has an invalid registry entry for ${r}.`);n[r]=i}return n}async function readRegistryPackage(e){let t=await resolveEveProjectContext(e),n=join(t.environmentRoot,`package.json`),r;try{r=JSON.parse(await readFile(n,`utf8`))}catch(e){throw Error(`Could not read ${n}: ${errorMessage(e)}`)}if(typeof r!=`object`||!r||Array.isArray(r))throw Error(`${n} must contain a JSON object.`);let i=r;return{path:n,document:i,config:{registries:parseRegistries(n,i.registries)}}}function parseRegistryMapping(e){let t=e.indexOf(`=`),n=t===-1?e:e.slice(0,t),r=t===-1?``:e.slice(t+1);if(!n.startsWith(`@`))throw Error(`Registry namespaces must start with @: ${n}`);if(!r.includes(`{name}`))throw Error(`Pass a registry URL containing {name}, for example ${n}=https://example.com/r/{name}.json.`);return{namespace:n,url:r}}async function prepareWebChatProjectRoot(e){let t=await resolveEveProjectContext(e);if(t.kind===`workspace`)throw Error(`Web Chat setup requires a selected workspace agent.`);let n=t.environmentRoot,r=join(n,`package.json`),i=await readFile(r,`utf8`),a=JSON.parse(i),o={...a.scripts};return o[`dev:web`]??=`next dev apps/web`,o[`build:web`]??=`next build apps/web`,await writeFile(r,`${JSON.stringify({...a,scripts:o},null,2)}\n`,`utf8`),n}async function readRegistryConfig(e){return(await readRegistryPackage(e)).config}const JSONC_FORMATTING={insertSpaces:!0,tabSize:2,eol:`
2
- `};function setJsoncValue(e,t,n){return applyEdits(e,modify(e,t,n,{formattingOptions:JSONC_FORMATTING}))}function addWebRegistryTsconfig(e,t){let n=[],r=parse(e,n,{allowTrailingComma:!0});if(n.length>0||typeof r!=`object`||!r||Array.isArray(r))throw Error(`Could not add Web Chat because ${t} is not a valid JSON object.`);let i=r,a=JSON.parse(WEB_APP_TEMPLATE_FILES[`tsconfig.json`]),o=i.compilerOptions?.paths?.[`@/*`];if(o!==void 0&&(!Array.isArray(o)||!o.includes(`./*`)))throw Error(`Could not add Web Chat because ${t} already defines @/* without mapping it to ./*.`);let s=e;for(let[e,t]of Object.entries(a.compilerOptions))e!==`paths`&&e!==`plugins`&&i.compilerOptions?.[e]===void 0&&(s=setJsoncValue(s,[`compilerOptions`,e],t));o===void 0&&(s=setJsoncValue(s,[`compilerOptions`,`paths`,`@/*`],[`./*`]));let c=i.compilerOptions?.plugins??[];return c.some(e=>typeof e==`object`&&!!e&&`name`in e&&e.name===`next`)||(s=setJsoncValue(s,[`compilerOptions`,`plugins`],[...c,{name:`next`}])),s=setJsoncValue(s,[`include`],[...new Set([...i.include??[],...a.include])]),s=setJsoncValue(s,[`exclude`],[...new Set([...i.exclude??[],...a.exclude])]),s}async function prepareWebRegistryProject(e){let t=join(e,`apps`,`web`,`tsconfig.json`),n;try{n=await readFile(t,`utf8`)}catch(e){if(e.code===`ENOENT`)return;throw Error(`Could not add Web Chat because ${t} could not be read: ${errorMessage(e)}`)}let r=addWebRegistryTsconfig(n,t);r!==n&&await writeFile(t,r,`utf8`)}async function addRegistryMappings(e,t){if(t.length===0)throw Error(`Pass at least one registry to add.`);let n=await readRegistryPackage(e),r=t.map(parseRegistryMapping),i={...n.config.registries},a={added:[],skippedBuiltIn:[],skippedExisting:[]};for(let e of r)e.namespace===`@shadcn`||e.namespace===`@skills`?a.skippedBuiltIn.push(e.namespace):i[e.namespace]===void 0?(i[e.namespace]=e.url,a.added.push(e.namespace)):a.skippedExisting.push(e.namespace);return a.added.length>0&&await writeFile(n.path,`${JSON.stringify({...n.document,registries:i},null,2)}\n`,`utf8`),a}export{addRegistryMappings,addWebRegistryTsconfig,prepareWebChatProjectRoot,prepareWebRegistryProject,readRegistryConfig};
1
+ import{readFile,writeFile}from"node:fs/promises";import{join}from"node:path";import{resolveEveProjectContext}from"#internal/project-context.js";import{applyEdits,modify,parse}from"#compiled/jsonc-parser/index.js";import{WEB_CHAT_FRAMEWORK_LABELS,WEB_FRAMEWORK_QUESTION,detectWebChatFramework}from"#setup/integrations/web/framework.js";import{WEB_APP_TANSTACK_TEMPLATE_FILES,WEB_APP_TEMPLATE_FILES}from"#setup/scaffold/create/web-template.js";function errorMessage(e){return e instanceof Error?e.message:String(e)}function isRegistrySource(e){return typeof e==`string`?!0:typeof e!=`object`||!e||!(`url`in e)?!1:typeof e.url==`string`}function parseRegistries(e,t){if(t===void 0)return{};if(typeof t!=`object`||!t||Array.isArray(t))throw Error(`${e} has an invalid registries field.`);let n={};for(let[r,i]of Object.entries(t)){if(!r.startsWith(`@`)||!isRegistrySource(i))throw Error(`${e} has an invalid registry entry for ${r}.`);n[r]=i}return n}async function readRegistryPackage(e){let t=await resolveEveProjectContext(e),n=join(t.environmentRoot,`package.json`),r;try{r=JSON.parse(await readFile(n,`utf8`))}catch(e){throw Error(`Could not read ${n}: ${errorMessage(e)}`)}if(typeof r!=`object`||!r||Array.isArray(r))throw Error(`${n} must contain a JSON object.`);let i=r;return{path:n,document:i,config:{registries:parseRegistries(n,i.registries)}}}function parseRegistryMapping(e){let t=e.indexOf(`=`),n=t===-1?e:e.slice(0,t),r=t===-1?``:e.slice(t+1);if(!n.startsWith(`@`))throw Error(`Registry namespaces must start with @: ${n}`);if(!r.includes(`{name}`))throw Error(`Pass a registry URL containing {name}, for example ${n}=https://example.com/r/{name}.json.`);return{namespace:n,url:r}}const WEB_CHAT_SCRIPTS={next:{"dev:web":`next dev apps/web`,"build:web":`next build apps/web`},tanstack:{"dev:web":`vite dev apps/web`,"build:web":`vite build apps/web`}};function isWebChatScriptDefault(e,t){return Object.values(WEB_CHAT_SCRIPTS).some(n=>n[e]===t)}async function resolveWebChatFramework(e,t,n={}){let r=await resolveEveProjectContext(e);if(r.kind===`workspace`)throw Error(`Web Chat setup requires a selected workspace agent.`);let i=await detectWebChatFramework(join(r.environmentRoot,`apps`,`web`));if(i!==void 0&&!(WEB_FRAMEWORK_QUESTION.key in n))return i;let a=await t.ask(WEB_FRAMEWORK_QUESTION);if(i!==void 0&&a!==i)throw Error(`apps/web already contains a ${WEB_CHAT_FRAMEWORK_LABELS[i]} app. Remove apps/web to switch Web Chat to ${WEB_CHAT_FRAMEWORK_LABELS[a]}, or answer ${WEB_FRAMEWORK_QUESTION.key}="${i}".`);return a}async function prepareWebChatProjectRoot(e,t=`next`){let n=await resolveEveProjectContext(e);if(n.kind===`workspace`)throw Error(`Web Chat setup requires a selected workspace agent.`);let r=n.environmentRoot,i=join(r,`package.json`),a=await readFile(i,`utf8`),o=JSON.parse(a),s={...o.scripts};for(let[e,n]of Object.entries(WEB_CHAT_SCRIPTS[t])){let t=s[e];(t===void 0||isWebChatScriptDefault(e,t))&&(s[e]=n)}return await writeFile(i,`${JSON.stringify({...o,scripts:s},null,2)}\n`,`utf8`),r}async function readRegistryConfig(e){return(await readRegistryPackage(e)).config}const JSONC_FORMATTING={insertSpaces:!0,tabSize:2,eol:`
2
+ `};function setJsoncValue(e,t,n){return applyEdits(e,modify(e,t,n,{formattingOptions:JSONC_FORMATTING}))}const WEB_REGISTRY_TSCONFIG_SOURCES={next:WEB_APP_TEMPLATE_FILES[`tsconfig.json`],tanstack:WEB_APP_TANSTACK_TEMPLATE_FILES[`tsconfig.json`]};function addWebRegistryTsconfig(e,t,n=`next`){let r=[],i=parse(e,r,{allowTrailingComma:!0});if(r.length>0||typeof i!=`object`||!i||Array.isArray(i))throw Error(`Could not add Web Chat because ${t} is not a valid JSON object.`);let a=i,o=JSON.parse(WEB_REGISTRY_TSCONFIG_SOURCES[n]),s=a.compilerOptions?.paths?.[`@/*`];if(s!==void 0&&(!Array.isArray(s)||!s.includes(`./*`)))throw Error(`Could not add Web Chat because ${t} already defines @/* without mapping it to ./*.`);let c=e;for(let[e,t]of Object.entries(o.compilerOptions)){if(e===`paths`||e===`plugins`)continue;let n=a.compilerOptions?.[e];if(n===void 0)c=setJsoncValue(c,[`compilerOptions`,e],t);else if(e===`types`&&Array.isArray(n)&&Array.isArray(t)){let e=[...new Set([...n,...t])];e.length>n.length&&(c=setJsoncValue(c,[`compilerOptions`,`types`],e))}}s===void 0&&(c=setJsoncValue(c,[`compilerOptions`,`paths`,`@/*`],[`./*`]));let l=a.compilerOptions?.plugins??[],u=l.some(e=>typeof e==`object`&&!!e&&`name`in e&&e.name===`next`);return n===`next`&&!u&&(c=setJsoncValue(c,[`compilerOptions`,`plugins`],[...l,{name:`next`}])),c=setJsoncValue(c,[`include`],[...new Set([...a.include??[],...o.include])]),c=setJsoncValue(c,[`exclude`],[...new Set([...a.exclude??[],...o.exclude])]),c}async function prepareWebRegistryProject(e,t=`next`){let n=join(e,`apps`,`web`,`tsconfig.json`),r;try{r=await readFile(n,`utf8`)}catch(e){if(e.code===`ENOENT`)return;throw Error(`Could not add Web Chat because ${n} could not be read: ${errorMessage(e)}`)}let i=addWebRegistryTsconfig(r,n,t);i!==r&&await writeFile(n,i,`utf8`)}async function addRegistryMappings(e,t){if(t.length===0)throw Error(`Pass at least one registry to add.`);let n=await readRegistryPackage(e),r=t.map(parseRegistryMapping),i={...n.config.registries},a={added:[],skippedBuiltIn:[],skippedExisting:[]};for(let e of r)e.namespace===`@shadcn`||e.namespace===`@skills`?a.skippedBuiltIn.push(e.namespace):i[e.namespace]===void 0?(i[e.namespace]=e.url,a.added.push(e.namespace)):a.skippedExisting.push(e.namespace);return a.added.length>0&&await writeFile(n.path,`${JSON.stringify({...n.document,registries:i},null,2)}\n`,`utf8`),a}export{addRegistryMappings,addWebRegistryTsconfig,prepareWebChatProjectRoot,prepareWebRegistryProject,readRegistryConfig,resolveWebChatFramework};
@@ -1 +1 @@
1
- import{hasInteractiveTerminal}from"./preconditions.js";import{serializeHeadlessSetupEvent}from"./setup-headless.js";import{prepareWebChatProjectRoot,prepareWebRegistryProject,readRegistryConfig}from"./registry-project.js";import{errorMessage,reportRegistryCompletion,resolveRegistryItemForAdd,runRegistryAction,setupReminder,setupResumeCommand}from"./registry-recovery.js";import{runRegistryAddCommand}from"./registry-add-command.js";import{RegistrySetupFailedError,runDeclaredSetups}from"./registry-declared-setups.js";import{installRegistryItemTransaction}from"./registry-install-transaction.js";import{eveMetadataFromRegistryItem,parseOfficialRegistrySearchMetadata}from"./registry-metadata.js";import{prepareDeclaredPnpmBuildPolicy}from"./registry-pnpm-build-policy-flow.js";import{printRegistrySearchResults,registryViewText}from"./registry-presentation.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{createPrompter}from"#setup/prompter.js";import{WizardCancelledError}from"#setup/step.js";import{addRegistryItems,getRegistryItems,searchRegistries}from"#compiled/shadcn-registry/index.js";import semver from"#compiled/semver/index.js";const defaultAddCommandDependencies={createPrompter,hasInteractiveTerminal,loadSetupCommandRunner:async()=>(await import(`./registry-setup-command.js`)).runRegistrySetupCommand,prepareWebRegistryProject};function resolveOfficialRegistryUrl(e=process.env.EVE_DEV_OFFICIAL_REGISTRY_URL){if(e===void 0)return`https://eve.dev/r`;let t;try{t=new URL(e)}catch{throw Error(`EVE_DEV_OFFICIAL_REGISTRY_URL must be an HTTP(S) URL.`)}if(t.protocol!==`http:`&&t.protocol!==`https:`)throw Error(`EVE_DEV_OFFICIAL_REGISTRY_URL must be an HTTP(S) URL.`);if(t.username!==``||t.password!==``)throw Error(`EVE_DEV_OFFICIAL_REGISTRY_URL must not include credentials.`);if(t.search!==``||t.hash!==``)throw Error(`EVE_DEV_OFFICIAL_REGISTRY_URL must not include a query or fragment.`);return t.pathname=t.pathname.replace(/\/+$/,``),t.toString().replace(/\/$/,``)}const OFFICIAL_REGISTRY=resolveOfficialRegistryUrl(),OFFICIAL_CATALOG=`${OFFICIAL_REGISTRY}/registry.json`,SKILLS_REGISTRY=`@skills`;function itemAddress(e){return e.startsWith(`@`)||/^https?:\/\//.test(e)?e:`${OFFICIAL_REGISTRY}/${e}.json`}function assertCompatibleEveVersion(e){if(e===void 0)return;let t=resolveInstalledPackageInfo().version;if(semver.validRange(e)===null)throw Error(`Registry item has an invalid eve version requirement: ${e}.`);if(!semver.subset(t,e))throw Error(`This registry item requires eve ${e}, but this project is using eve ${t}. Upgrade eve and run the command again.`)}function isOfficialItemAddress(e){return e.startsWith(`${OFFICIAL_REGISTRY}/`)}function withBuiltInRegistries(e){return{...e,registries:{[SKILLS_REGISTRY]:`https://www.skills.sh/r/{name}?agent=eve`,...e.registries}}}async function readEveRegistryConfig(e){return withBuiltInRegistries(await readRegistryConfig(e))}function configuredRegistrySources(e){return Object.keys(e.registries??{})}function validateRegistrySource(e){if(e!==void 0&&!e.startsWith(`@`)&&!/^https?:\/\//.test(e))throw Error(`Registry sources must be a namespace or URL: ${e}`)}async function loadOfficialSearchMetadata(){let e=await fetch(OFFICIAL_CATALOG);if(!e.ok)throw Error(`Could not read the eve registry (${e.status}).`);return parseOfficialRegistrySearchMetadata(await e.json())}function searchItemAddress(e){return e.registry===OFFICIAL_CATALOG?e.name:e.addCommandArgument}function enrichSearchItem(e,t){let n=searchItemAddress(e);return{item:e,address:n,...t.get(n)}}function registrySourceLabel(e){return e===OFFICIAL_CATALOG?`eve`:e===SKILLS_REGISTRY?`skills.sh`:e}function searchPresentationSections(e,t,n){return e.flatMap(e=>{let r=t.get(e);return r===void 0?[]:[{label:registrySourceLabel(e),items:r.items.map(e=>enrichSearchItem(e,n)),total:r.pagination.total}]})}async function printAddSuggestions(e,t,n){try{let r=n.split(`/`).at(-1)||n,{resultsBySource:i,sources:a,metadataByAddress:o}=await searchRegistryCatalog(t,{limit:5,query:r}),s=searchPresentationSections(a,i,o);if(s.every(e=>e.items.length===0))return;e.log(`Did you mean?`),printRegistrySearchResults(e,{query:r,sections:s})}catch{}}async function searchRegistryCatalog(e,t){validateRegistrySource(t.source);let n=await readEveRegistryConfig(e),r=t.source?[t.source]:[OFFICIAL_CATALOG,...configuredRegistrySources(n).filter(e=>t.query!==void 0||e!==SKILLS_REGISTRY)],i=await Promise.all(r.map(async e=>{try{return{result:await searchRegistries([e],{config:n,limit:t.limit??500,query:t.query}),source:e}}catch(t){return{error:t,source:e}}})),a=[],o=new Map;for(let e of i)if(`error`in e)a.push({message:errorMessage(e.error),registry:e.source});else{let t=e.result.errors??[];if(a.push(...t),t.length===0){let t=e.result.items.filter(t=>t.registry===e.source);o.set(e.source,{...e.result,items:t,pagination:{...e.result.pagination,total:e.result.items.length===t.length?e.result.pagination.total:0}})}}let s=new Map(a.map(e=>[`${e.registry}\0${e.message}`,e])),c=o.has(OFFICIAL_CATALOG)?await loadOfficialSearchMetadata():new Map,l=o.get(OFFICIAL_CATALOG);if(l!==void 0){let e=l.items.filter(e=>c.get(searchItemAddress(e))?.hidden!==!0);l.items=e,l.pagination={...l.pagination,total:e.length},l.items.sort((e,t)=>{let rank=e=>c.get(searchItemAddress(e))?.implementation===`native`?0:1;return rank(e)-rank(t)})}let u=[...o.values()];return{config:n,result:{items:u.flatMap(e=>e.items),pagination:{hasMore:u.some(e=>e.pagination.hasMore),limit:t.limit??500,offset:0,total:u.reduce((e,t)=>e+t.pagination.total,0)},...s.size>0?{errors:[...s.values()]}:{}},resultsBySource:o,sources:r,metadataByAddress:c}}async function browseRegistryCatalog(e,t={}){let{result:n}=await searchRegistryCatalog(e,t);return{items:n.items.map(e=>{let t={address:e.registry===OFFICIAL_CATALOG?e.name:e.addCommandArgument,name:e.name,source:e.registry===OFFICIAL_CATALOG?`Vercel`:e.registry};return e.title!==void 0&&(t.title=e.title),e.type!==void 0&&(t.type=e.type),e.description!==void 0&&(t.description=e.description),t}),total:n.pagination.total,errors:n.errors??[]}}async function browseRegistryItems(e,t,n,r,i={}){let{result:a,resultsBySource:o,sources:s,metadataByAddress:c}=await searchRegistryCatalog(t,{limit:i.limit,query:n,source:r}),l=a.errors??[];if(i.json||o.size>0){let t=a.items.map(e=>({...e,...c.get(searchItemAddress(e))})),r={query:n,sections:searchPresentationSections(s,o,c)};i.json&&(r.json={...a,items:t}),printRegistrySearchResults(e,r)}for(let t of l)e.error(`${t.registry}: ${t.message}`);l.length>0&&(process.exitCode=1)}async function installRegistryItem(e,t,n={},r=defaultAddCommandDependencies){let i,a=[],o={error:e=>{i=e},log:e=>a.push(e)},s=process.exitCode,c;try{c=await runAddCommand(o,e,t,{...n,yes:n.prompter===void 0||n.yes,setupAuthorized:n.prompter!==void 0,throwSetupFailures:!0},r)}catch(e){if(process.exitCode=s,!(e instanceof RegistrySetupFailedError))throw e;let t={resumeCommand:e.resumeCommand,reason:e.reason};return e.prerequisite!==void 0&&(t.prerequisite=e.prerequisite),{output:a,setupIncomplete:t}}if(process.exitCode=s,i!==void 0)throw Error(i);if(c===!1)throw new WizardCancelledError;if(c===`setup-incomplete`)return{output:a,setupIncomplete:{resumeCommand:setupResumeCommand(t)}};let l={output:a};return c!==void 0&&(l.setup=c),l}async function runAddCommand(e,t,n,r,i=defaultAddCommandDependencies){let setupIncomplete=t=>(r.silent!==!0&&e.log(setupReminder(n,t)),`setup-incomplete`);return runRegistryAction(e,t,async()=>{let a=itemAddress(n),o=a===itemAddress(`channel/web`)&&r.skipInstall!==!0?await prepareWebChatProjectRoot(t):t,s=await readEveRegistryConfig(t);if(r.skipInstall===!0){if(r.overwrite===!0)throw Error(`--overwrite cannot be used with --skip-install.`);if(r.skipSetup===!0)throw Error(`--skip-install cannot be used with --skip-setup.`);if(!isOfficialItemAddress(a))throw Error(`Setup flows are currently supported only for official eve registry items.`)}let c=await resolveRegistryItemForAdd(e,async()=>(await getRegistryItems([a],{config:s}))[0],()=>printAddSuggestions(e,t,n));if(!c.found)return;let l=c.item,u=isOfficialItemAddress(a)?eveMetadataFromRegistryItem(l):void 0;if(assertCompatibleEveVersion(u?.requires),r.skipInstall===!0){if(u?.setup===void 0)throw Error(`Registry item "${n}" does not declare a setup flow.`);let a=await runDeclaredSetups({logger:e,appRoot:t,item:n,setups:u.setup,options:r,dependencies:i,resumeCommand:setupResumeCommand(n)});return a===!1&&!r.nonInteractive?setupIncomplete(`cancelled`):reportRegistryCompletion(e,n,a,r)}if(!await prepareDeclaredPnpmBuildPolicy({logger:e,appRoot:o,item:n,policies:u?.install?.pnpm?.buildScripts,options:r}))return!1;if(a===itemAddress(`channel/web`)&&await(i.prepareWebRegistryProject??prepareWebRegistryProject)(o),await installRegistryItemTransaction({appRoot:o,item:n,registryItem:l,nonInteractive:r.nonInteractive,logger:e,install:async()=>{await addRegistryItems([a],{config:s,cwd:o,overwrite:r.overwrite,silent:r.silent})}}),u?.setup===void 0)return reportRegistryCompletion(e,n,{facts:[]},r);let d=i.hasInteractiveTerminal?.()??defaultAddCommandDependencies.hasInteractiveTerminal();if(r.nonInteractive&&e.log(serializeHeadlessSetupEvent({version:1,type:`progress`,message:r.skipInstall?`Setup ${n}`:`Installed ${n}`})),r.skipSetup===!0)return r.nonInteractive?reportRegistryCompletion(e,n,{facts:[]},r):setupIncomplete(`skipped`);if(!r.nonInteractive&&!r.yes&&!d&&r.setupAuthorized!==!0)return setupIncomplete(`skipped`);if(!r.nonInteractive&&!r.yes&&r.setupAuthorized!==!0)try{if(await(r.prompter??i.createPrompter?.()??defaultAddCommandDependencies.createPrompter()).select({message:`Set up ${n} now?`,initialValue:`yes`,options:[{value:`yes`,label:`Yes`},{value:`no`,label:`No`}]})===`no`)return setupIncomplete(`skipped`)}catch(e){if(!(e instanceof WizardCancelledError))throw e;return setupIncomplete(`cancelled`)}let f=await runDeclaredSetups({logger:e,appRoot:t,item:n,setups:u.setup,options:{...r,force:r.overwrite},dependencies:i,resumeCommand:setupResumeCommand(n)});return f===!1&&!r.nonInteractive?setupIncomplete(`cancelled`):reportRegistryCompletion(e,n,f,r)},{rethrow:e=>r.throwSetupFailures===!0&&e instanceof RegistrySetupFailedError})}async function runRegistryListCommand(e,t,n,r={}){await runRegistryAction(e,t,()=>browseRegistryItems(e,t,void 0,n,r))}async function runRegistrySearchCommand(e,t,n,r,i={}){await runRegistryAction(e,t,()=>browseRegistryItems(e,t,n,r,{...i,limit:i.limit??10}))}async function runRegistryViewCommand(e,t,n,r={}){await runRegistryAction(e,t,async()=>{let i=await readEveRegistryConfig(t),a=await getRegistryItems([itemAddress(n)],{config:i}),o=a.length===1?a[0]:a;e.log(r.json?JSON.stringify(o,null,2):registryViewText(n,o))})}export{browseRegistryCatalog,installRegistryItem,resolveOfficialRegistryUrl,runAddCommand,runRegistryAddCommand,runRegistryListCommand,runRegistrySearchCommand,runRegistryViewCommand};
1
+ import{hasInteractiveTerminal}from"./preconditions.js";import{headlessSetupContinuation,serializeHeadlessSetupEvent}from"./setup-headless.js";import{prepareWebChatProjectRoot,prepareWebRegistryProject,readRegistryConfig,resolveWebChatFramework}from"./registry-project.js";import{errorMessage,reportRegistryCompletion,resolveRegistryItemForAdd,runRegistryAction,setupReminder,setupResumeCommand}from"./registry-recovery.js";import{runRegistryAddCommand}from"./registry-add-command.js";import{RegistrySetupFailedError,runDeclaredSetups}from"./registry-declared-setups.js";import{installRegistryItemTransaction}from"./registry-install-transaction.js";import{eveMetadataFromRegistryItem,parseOfficialRegistrySearchMetadata}from"./registry-metadata.js";import{prepareDeclaredPnpmBuildPolicy}from"./registry-pnpm-build-policy-flow.js";import{printRegistrySearchResults,registryViewText}from"./registry-presentation.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{createPrompter}from"#setup/prompter.js";import{WizardCancelledError}from"#setup/step.js";import{InvalidAnswerError,headlessAsker,interactiveAsker,withAnswers,withPolicy}from"#setup/ask.js";import{setupQuestionToWire}from"#setup/setup-question-wire.js";import{addRegistryItems,getRegistryItems,searchRegistries}from"#compiled/shadcn-registry/index.js";import semver from"#compiled/semver/index.js";const defaultAddCommandDependencies={createPrompter,hasInteractiveTerminal,loadSetupCommandRunner:async()=>(await import(`./registry-setup-command.js`)).runRegistrySetupCommand,prepareWebRegistryProject};function resolveOfficialRegistryUrl(e=process.env.EVE_DEV_OFFICIAL_REGISTRY_URL){if(e===void 0)return`https://eve.dev/r`;let t;try{t=new URL(e)}catch{throw Error(`EVE_DEV_OFFICIAL_REGISTRY_URL must be an HTTP(S) URL.`)}if(t.protocol!==`http:`&&t.protocol!==`https:`)throw Error(`EVE_DEV_OFFICIAL_REGISTRY_URL must be an HTTP(S) URL.`);if(t.username!==``||t.password!==``)throw Error(`EVE_DEV_OFFICIAL_REGISTRY_URL must not include credentials.`);if(t.search!==``||t.hash!==``)throw Error(`EVE_DEV_OFFICIAL_REGISTRY_URL must not include a query or fragment.`);return t.pathname=t.pathname.replace(/\/+$/,``),t.toString().replace(/\/$/,``)}const OFFICIAL_REGISTRY=resolveOfficialRegistryUrl(),OFFICIAL_CATALOG=`${OFFICIAL_REGISTRY}/registry.json`,SKILLS_REGISTRY=`@skills`;function itemAddress(e){return e.startsWith(`@`)||/^https?:\/\//.test(e)?e:`${OFFICIAL_REGISTRY}/${e}.json`}const WEB_CHAT_ITEMS={next:`channel/web`,tanstack:`channel/web-tanstack`};async function askWebChatFramework(e,t,n,r,i){let a=r.nonInteractive===!0,o=r.setupAuthorized===!0||(i.hasInteractiveTerminal??defaultAddCommandDependencies.hasInteractiveTerminal)(),s=withAnswers(r.answers??{})(r.yes===!0||a||!o?withPolicy(`assume`)(headlessAsker()):interactiveAsker(r.prompter??i.createPrompter?.()??defaultAddCommandDependencies.createPrompter()));try{return await resolveWebChatFramework(t,s,r.answers)}catch(t){if(t instanceof WizardCancelledError)return!1;if(!a||!(t instanceof InvalidAnswerError))throw t;let i=setupQuestionToWire(t.question);e.error(serializeHeadlessSetupEvent({version:1,type:`blocked`,item:n,installed:!1,completedItems:[],status:`input_required`,question:i,issue:{code:`invalid_answer`,message:t.message},next:headlessSetupContinuation({item:n,installed:!1,answers:r.answers,question:i})})),process.exitCode=2;return}}function assertCompatibleEveVersion(e){if(e===void 0)return;let t=resolveInstalledPackageInfo().version;if(semver.validRange(e)===null)throw Error(`Registry item has an invalid eve version requirement: ${e}.`);if(!semver.subset(t,e))throw Error(`This registry item requires eve ${e}, but this project is using eve ${t}. Upgrade eve and run the command again.`)}function isOfficialItemAddress(e){return e.startsWith(`${OFFICIAL_REGISTRY}/`)}function withBuiltInRegistries(e){return{...e,registries:{[SKILLS_REGISTRY]:`https://www.skills.sh/r/{name}?agent=eve`,...e.registries}}}async function readEveRegistryConfig(e){return withBuiltInRegistries(await readRegistryConfig(e))}function configuredRegistrySources(e){return Object.keys(e.registries??{})}function validateRegistrySource(e){if(e!==void 0&&!e.startsWith(`@`)&&!/^https?:\/\//.test(e))throw Error(`Registry sources must be a namespace or URL: ${e}`)}async function loadOfficialSearchMetadata(){let e=await fetch(OFFICIAL_CATALOG);if(!e.ok)throw Error(`Could not read the eve registry (${e.status}).`);return parseOfficialRegistrySearchMetadata(await e.json())}function searchItemAddress(e){return e.registry===OFFICIAL_CATALOG?e.name:e.addCommandArgument}function enrichSearchItem(e,t){let n=searchItemAddress(e);return{item:e,address:n,...t.get(n)}}function registrySourceLabel(e){return e===OFFICIAL_CATALOG?`eve`:e===SKILLS_REGISTRY?`skills.sh`:e}function searchPresentationSections(e,t,n){return e.flatMap(e=>{let r=t.get(e);return r===void 0?[]:[{label:registrySourceLabel(e),items:r.items.map(e=>enrichSearchItem(e,n)),total:r.pagination.total}]})}async function printAddSuggestions(e,t,n){try{let r=n.split(`/`).at(-1)||n,{resultsBySource:i,sources:a,metadataByAddress:o}=await searchRegistryCatalog(t,{limit:5,query:r}),s=searchPresentationSections(a,i,o);if(s.every(e=>e.items.length===0))return;e.log(`Did you mean?`),printRegistrySearchResults(e,{query:r,sections:s})}catch{}}async function searchRegistryCatalog(e,t){validateRegistrySource(t.source);let n=await readEveRegistryConfig(e),r=t.source?[t.source]:[OFFICIAL_CATALOG,...configuredRegistrySources(n).filter(e=>t.query!==void 0||e!==SKILLS_REGISTRY)],i=await Promise.all(r.map(async e=>{try{return{result:await searchRegistries([e],{config:n,limit:t.limit??500,query:t.query}),source:e}}catch(t){return{error:t,source:e}}})),a=[],o=new Map;for(let e of i)if(`error`in e)a.push({message:errorMessage(e.error),registry:e.source});else{let t=e.result.errors??[];if(a.push(...t),t.length===0){let t=e.result.items.filter(t=>t.registry===e.source);o.set(e.source,{...e.result,items:t,pagination:{...e.result.pagination,total:e.result.items.length===t.length?e.result.pagination.total:0}})}}let s=new Map(a.map(e=>[`${e.registry}\0${e.message}`,e])),c=o.has(OFFICIAL_CATALOG)?await loadOfficialSearchMetadata():new Map,l=o.get(OFFICIAL_CATALOG);if(l!==void 0){let e=l.items.filter(e=>c.get(searchItemAddress(e))?.hidden!==!0);l.items=e,l.pagination={...l.pagination,total:e.length},l.items.sort((e,t)=>{let rank=e=>c.get(searchItemAddress(e))?.implementation===`native`?0:1;return rank(e)-rank(t)})}let u=[...o.values()];return{config:n,result:{items:u.flatMap(e=>e.items),pagination:{hasMore:u.some(e=>e.pagination.hasMore),limit:t.limit??500,offset:0,total:u.reduce((e,t)=>e+t.pagination.total,0)},...s.size>0?{errors:[...s.values()]}:{}},resultsBySource:o,sources:r,metadataByAddress:c}}async function browseRegistryCatalog(e,t={}){let{result:n}=await searchRegistryCatalog(e,t);return{items:n.items.map(e=>{let t={address:e.registry===OFFICIAL_CATALOG?e.name:e.addCommandArgument,name:e.name,source:e.registry===OFFICIAL_CATALOG?`Vercel`:e.registry};return e.title!==void 0&&(t.title=e.title),e.type!==void 0&&(t.type=e.type),e.description!==void 0&&(t.description=e.description),t}),total:n.pagination.total,errors:n.errors??[]}}async function browseRegistryItems(e,t,n,r,i={}){let{result:a,resultsBySource:o,sources:s,metadataByAddress:c}=await searchRegistryCatalog(t,{limit:i.limit,query:n,source:r}),l=a.errors??[];if(i.json||o.size>0){let t=a.items.map(e=>({...e,...c.get(searchItemAddress(e))})),r={query:n,sections:searchPresentationSections(s,o,c)};i.json&&(r.json={...a,items:t}),printRegistrySearchResults(e,r)}for(let t of l)e.error(`${t.registry}: ${t.message}`);l.length>0&&(process.exitCode=1)}async function installRegistryItem(e,t,n={},r=defaultAddCommandDependencies){let i,a=[],o={error:e=>{i=e},log:e=>a.push(e)},s=process.exitCode,c;try{c=await runAddCommand(o,e,t,{...n,yes:n.prompter===void 0||n.yes,setupAuthorized:n.prompter!==void 0,throwSetupFailures:!0},r)}catch(e){if(process.exitCode=s,!(e instanceof RegistrySetupFailedError))throw e;let t={resumeCommand:e.resumeCommand,reason:e.reason};return e.prerequisite!==void 0&&(t.prerequisite=e.prerequisite),{output:a,setupIncomplete:t}}if(process.exitCode=s,i!==void 0)throw Error(i);if(c===!1)throw new WizardCancelledError;if(c===`setup-incomplete`)return{output:a,setupIncomplete:{resumeCommand:setupResumeCommand(t)}};let l={output:a};return c!==void 0&&(l.setup=c),l}async function runAddCommand(e,t,n,r,i=defaultAddCommandDependencies){let setupIncomplete=t=>(r.silent!==!0&&e.log(setupReminder(n,t)),`setup-incomplete`);return runRegistryAction(e,t,async()=>{let a=itemAddress(n),o;if(a===itemAddress(WEB_CHAT_ITEMS.next)&&r.skipInstall!==!0){let a=await askWebChatFramework(e,t,n,r,i);if(a===!1||a===void 0)return a;o=a}let s=o===void 0?a:itemAddress(WEB_CHAT_ITEMS[o]),c=o===void 0?t:await prepareWebChatProjectRoot(t,o),l=await readEveRegistryConfig(t);if(r.skipInstall===!0){if(r.overwrite===!0)throw Error(`--overwrite cannot be used with --skip-install.`);if(r.skipSetup===!0)throw Error(`--skip-install cannot be used with --skip-setup.`);if(!isOfficialItemAddress(a))throw Error(`Setup flows are currently supported only for official eve registry items.`)}let u=await resolveRegistryItemForAdd(e,async()=>(await getRegistryItems([s],{config:l}))[0],()=>printAddSuggestions(e,t,n));if(!u.found)return;let d=u.item,f=isOfficialItemAddress(a)?eveMetadataFromRegistryItem(d):void 0;if(assertCompatibleEveVersion(f?.requires),r.skipInstall===!0){if(f?.setup===void 0)throw Error(`Registry item "${n}" does not declare a setup flow.`);let a=await runDeclaredSetups({logger:e,appRoot:t,item:n,setups:f.setup,options:r,dependencies:i,resumeCommand:setupResumeCommand(n)});return a===!1&&!r.nonInteractive?setupIncomplete(`cancelled`):reportRegistryCompletion(e,n,a,r)}if(!await prepareDeclaredPnpmBuildPolicy({logger:e,appRoot:c,item:n,policies:f?.install?.pnpm?.buildScripts,options:r}))return!1;if(o!==void 0&&await(i.prepareWebRegistryProject??prepareWebRegistryProject)(c,o),await installRegistryItemTransaction({appRoot:c,item:n,registryItem:d,nonInteractive:r.nonInteractive,logger:e,install:async()=>{await addRegistryItems([s],{config:l,cwd:c,overwrite:r.overwrite,silent:r.silent})}}),f?.setup===void 0)return reportRegistryCompletion(e,n,{facts:[]},r);let p=i.hasInteractiveTerminal?.()??defaultAddCommandDependencies.hasInteractiveTerminal();if(r.nonInteractive&&e.log(serializeHeadlessSetupEvent({version:1,type:`progress`,message:r.skipInstall?`Setup ${n}`:`Installed ${n}`})),r.skipSetup===!0)return r.nonInteractive?reportRegistryCompletion(e,n,{facts:[]},r):setupIncomplete(`skipped`);if(!r.nonInteractive&&!r.yes&&!p&&r.setupAuthorized!==!0)return setupIncomplete(`skipped`);if(!r.nonInteractive&&!r.yes&&r.setupAuthorized!==!0)try{if(await(r.prompter??i.createPrompter?.()??defaultAddCommandDependencies.createPrompter()).select({message:`Set up ${n} now?`,initialValue:`yes`,options:[{value:`yes`,label:`Yes`},{value:`no`,label:`No`}]})===`no`)return setupIncomplete(`skipped`)}catch(e){if(!(e instanceof WizardCancelledError))throw e;return setupIncomplete(`cancelled`)}let m=await runDeclaredSetups({logger:e,appRoot:t,item:n,setups:f.setup,options:{...r,force:r.overwrite},dependencies:i,resumeCommand:setupResumeCommand(n)});return m===!1&&!r.nonInteractive?setupIncomplete(`cancelled`):reportRegistryCompletion(e,n,m,r)},{rethrow:e=>r.throwSetupFailures===!0&&e instanceof RegistrySetupFailedError})}async function runRegistryListCommand(e,t,n,r={}){await runRegistryAction(e,t,()=>browseRegistryItems(e,t,void 0,n,r))}async function runRegistrySearchCommand(e,t,n,r,i={}){await runRegistryAction(e,t,()=>browseRegistryItems(e,t,n,r,{...i,limit:i.limit??10}))}async function runRegistryViewCommand(e,t,n,r={}){await runRegistryAction(e,t,async()=>{let i=await readEveRegistryConfig(t),a=await getRegistryItems([itemAddress(n)],{config:i}),o=a.length===1?a[0]:a;e.log(r.json?JSON.stringify(o,null,2):registryViewText(n,o))})}export{browseRegistryCatalog,installRegistryItem,resolveOfficialRegistryUrl,runAddCommand,runRegistryAddCommand,runRegistryListCommand,runRegistrySearchCommand,runRegistryViewCommand};