eve 0.27.12 → 0.28.0

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 (157) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/src/channel/adapter.d.ts +5 -5
  3. package/dist/src/channel/session.d.ts +2 -2
  4. package/dist/src/channel/types.d.ts +10 -6
  5. package/dist/src/chunks/{use-eve-agent-CsSQOKnp.js → use-eve-agent-CZkX_ZTT.js} +90 -1
  6. package/dist/src/chunks/{use-eve-agent-CWYe-vqE.js → use-eve-agent-hdPX68_i.js} +90 -1
  7. package/dist/src/cli/commands/channels.js +1 -1
  8. package/dist/src/cli/commands/integration-setup.js +1 -1
  9. package/dist/src/cli/commands/register-registry-commands.js +1 -1
  10. package/dist/src/cli/commands/registry-setup-command.d.ts +5 -3
  11. package/dist/src/cli/commands/registry-setup-command.js +1 -1
  12. package/dist/src/cli/commands/registry.d.ts +9 -3
  13. package/dist/src/cli/commands/registry.js +1 -1
  14. package/dist/src/cli/dev/tui/runner.js +1 -1
  15. package/dist/src/cli/dev/tui/subagent-pump.d.ts +8 -2
  16. package/dist/src/cli/dev/tui/subagent-pump.js +1 -1
  17. package/dist/src/cli/invoke/result.d.ts +15 -0
  18. package/dist/src/cli/invoke/result.js +1 -1
  19. package/dist/src/client/eve-agent-store.d.ts +7 -4
  20. package/dist/src/client/eve-agent-store.js +1 -1
  21. package/dist/src/client/index.d.ts +3 -3
  22. package/dist/src/client/index.js +1 -1
  23. package/dist/src/client/message-action-parts.js +1 -1
  24. package/dist/src/client/message-reducer-types.d.ts +5 -3
  25. package/dist/src/client/message-response.d.ts +4 -4
  26. package/dist/src/client/ndjson.d.ts +3 -3
  27. package/dist/src/client/open-stream.d.ts +2 -2
  28. package/dist/src/client/output-schema.d.ts +2 -2
  29. package/dist/src/client/reducer.d.ts +2 -2
  30. package/dist/src/client/session-utils.d.ts +5 -5
  31. package/dist/src/client/session.d.ts +2 -2
  32. package/dist/src/client/types.d.ts +2 -2
  33. package/dist/src/compiler/compile-from-memory.d.ts +1 -0
  34. package/dist/src/compiler/extension-compatibility.d.ts +8 -8
  35. package/dist/src/compiler/extension-compatibility.js +1 -1
  36. package/dist/src/compiler/manifest.d.ts +2 -2
  37. package/dist/src/compiler/manifest.js +1 -1
  38. package/dist/src/compiler/normalize-agent-config.js +1 -1
  39. package/dist/src/context/dynamic-instruction-lifecycle.d.ts +2 -2
  40. package/dist/src/context/dynamic-model-lifecycle.d.ts +2 -2
  41. package/dist/src/context/dynamic-skill-lifecycle.d.ts +2 -2
  42. package/dist/src/context/dynamic-tool-lifecycle.d.ts +2 -2
  43. package/dist/src/context/hook-lifecycle.d.ts +2 -2
  44. package/dist/src/evals/assertions/run.d.ts +3 -3
  45. package/dist/src/evals/match.d.ts +4 -4
  46. package/dist/src/evals/runner/derive-run-facts.d.ts +2 -2
  47. package/dist/src/evals/session.d.ts +3 -3
  48. package/dist/src/evals/types.d.ts +12 -12
  49. package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
  50. package/dist/src/execution/route-child-delivery.d.ts +4 -3
  51. package/dist/src/execution/route-child-delivery.js +1 -1
  52. package/dist/src/execution/session-delivery-hook.d.ts +1 -0
  53. package/dist/src/execution/session-delivery-hook.js +1 -1
  54. package/dist/src/execution/session-timeout-control.d.ts +9 -0
  55. package/dist/src/execution/session-timeout-control.js +1 -0
  56. package/dist/src/execution/session-timeout-steps.d.ts +13 -0
  57. package/dist/src/execution/session-timeout-steps.js +1 -0
  58. package/dist/src/execution/session-timeout-workflow.d.ts +6 -0
  59. package/dist/src/execution/session-timeout-workflow.js +1 -0
  60. package/dist/src/execution/session-timeout.d.ts +2 -0
  61. package/dist/src/execution/session-timeout.js +1 -0
  62. package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
  63. package/dist/src/execution/subagent-event-proxy-step.js +1 -1
  64. package/dist/src/execution/subagent-hitl-proxy.d.ts +5 -1
  65. package/dist/src/execution/subagent-hitl-proxy.js +1 -1
  66. package/dist/src/execution/terminal-session-completion-step.d.ts +5 -0
  67. package/dist/src/execution/terminal-session-completion-step.js +1 -0
  68. package/dist/src/execution/terminal-session-failure-step.js +1 -1
  69. package/dist/src/execution/turn-workflow.js +1 -1
  70. package/dist/src/execution/workflow-entry.d.ts +1 -0
  71. package/dist/src/execution/workflow-entry.js +1 -1
  72. package/dist/src/execution/workflow-runtime.d.ts +4 -0
  73. package/dist/src/execution/workflow-runtime.js +1 -1
  74. package/dist/src/execution/workflow-steps.d.ts +5 -2
  75. package/dist/src/execution/workflow-steps.js +1 -1
  76. package/dist/src/harness/agent-otel-provider.js +1 -1
  77. package/dist/src/harness/ai-sdk-hook-bridge.js +1 -1
  78. package/dist/src/harness/input-extraction.js +1 -1
  79. package/dist/src/harness/input-request-class.d.ts +23 -0
  80. package/dist/src/harness/input-request-class.js +1 -0
  81. package/dist/src/harness/input-requests.d.ts +20 -9
  82. package/dist/src/harness/input-requests.js +1 -1
  83. package/dist/src/harness/instrumentation-lifecycle.d.ts +12 -1
  84. package/dist/src/harness/proxy-input-requests.d.ts +10 -4
  85. package/dist/src/harness/proxy-input-requests.js +1 -1
  86. package/dist/src/harness/session-limit-continuation.d.ts +0 -11
  87. package/dist/src/harness/session-limit-continuation.js +1 -1
  88. package/dist/src/harness/session-limit-enforcement.d.ts +3 -2
  89. package/dist/src/harness/session-limit-enforcement.js +1 -1
  90. package/dist/src/harness/session-token-limits.d.ts +41 -0
  91. package/dist/src/harness/session-token-limits.js +1 -0
  92. package/dist/src/harness/stale-input-responses.js +1 -1
  93. package/dist/src/harness/subagent-token-budget.d.ts +6 -4
  94. package/dist/src/harness/subagent-token-budget.js +1 -1
  95. package/dist/src/harness/tool-loop.js +1 -1
  96. package/dist/src/harness/turn-tag-state.d.ts +26 -17
  97. package/dist/src/harness/turn-tag-state.js +1 -1
  98. package/dist/src/harness/types.d.ts +4 -4
  99. package/dist/src/harness/workflow-lifecycle.d.ts +2 -2
  100. package/dist/src/internal/application/package.js +1 -1
  101. package/dist/src/internal/authored-definition/core.js +1 -1
  102. package/dist/src/internal/node-esm-compat-banner.js +1 -1
  103. package/dist/src/internal/workflow-bundle/workflow-core-shim.d.ts +1 -1
  104. package/dist/src/internal/workflow-bundle/workflow-core-shim.js +1 -1
  105. package/dist/src/protocol/event-dedupe.d.ts +25 -0
  106. package/dist/src/protocol/event-dedupe.js +1 -0
  107. package/dist/src/protocol/event-id.d.ts +16 -0
  108. package/dist/src/protocol/event-id.js +1 -0
  109. package/dist/src/protocol/message.d.ts +39 -23
  110. package/dist/src/protocol/message.js +2 -2
  111. package/dist/src/public/channels/discord/discordChannel.d.ts +3 -3
  112. package/dist/src/public/channels/github/githubChannel.d.ts +3 -3
  113. package/dist/src/public/channels/linear/defaults.js +4 -2
  114. package/dist/src/public/channels/linear/linearChannel.d.ts +3 -3
  115. package/dist/src/public/channels/slack/hitl.js +1 -1
  116. package/dist/src/public/channels/slack/slackChannel.d.ts +3 -3
  117. package/dist/src/public/channels/teams/hitl.js +1 -1
  118. package/dist/src/public/channels/teams/teamsChannel.d.ts +3 -3
  119. package/dist/src/public/channels/telegram/telegramChannel.d.ts +3 -3
  120. package/dist/src/public/channels/twilio/twilioChannel.d.ts +3 -3
  121. package/dist/src/public/definitions/channel.d.ts +4 -4
  122. package/dist/src/public/definitions/hook.d.ts +2 -2
  123. package/dist/src/react/use-eve-agent.d.ts +3 -2
  124. package/dist/src/runtime/framework-tools/ask-question.js +1 -1
  125. package/dist/src/runtime/hooks/registry.d.ts +2 -2
  126. package/dist/src/runtime/input/types.d.ts +19 -4
  127. package/dist/src/runtime/input/types.js +1 -1
  128. package/dist/src/runtime/resolve-agent.js +1 -1
  129. package/dist/src/runtime/types.d.ts +2 -2
  130. package/dist/src/setup/scaffold/create/project.js +1 -1
  131. package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
  132. package/dist/src/setup/scaffold/create/web-template.js +2 -2
  133. package/dist/src/shared/agent-definition.d.ts +12 -0
  134. package/dist/src/shared/dynamic-tool-definition.d.ts +2 -2
  135. package/dist/src/shared/ulid.d.ts +39 -0
  136. package/dist/src/shared/ulid.js +1 -0
  137. package/dist/src/svelte/index.js +1 -1
  138. package/dist/src/svelte/use-eve-agent.d.ts +4 -4
  139. package/dist/src/svelte/use-eve-agent.js +1 -1
  140. package/dist/src/vue/index.js +1 -1
  141. package/dist/src/vue/use-eve-agent.d.ts +4 -4
  142. package/dist/src/vue/use-eve-agent.js +1 -1
  143. package/docs/agent-config.md +28 -16
  144. package/docs/channels/linear.mdx +4 -0
  145. package/docs/concepts/execution-model-and-durability.mdx +1 -1
  146. package/docs/concepts/sessions-runs-and-streaming.md +61 -0
  147. package/docs/extensions.md +3 -1
  148. package/docs/guides/client/streaming.mdx +9 -3
  149. package/docs/guides/frontend/overview.mdx +4 -2
  150. package/docs/guides/frontend/use-eve-agent-svelte.mdx +1 -1
  151. package/docs/guides/frontend/use-eve-agent-vue.mdx +10 -10
  152. package/docs/guides/hooks.md +40 -2
  153. package/docs/guides/instrumentation.md +4 -0
  154. package/docs/install-integrations.mdx +76 -1
  155. package/docs/reference/cli.md +3 -0
  156. package/docs/tools/human-in-the-loop.md +5 -0
  157. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # eve
2
2
 
3
+ ## 0.28.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 98d17c7: Input requests now include a required `kind` discriminator so clients can route tool approvals, questions, and session-limit decisions without inferring behavior from tool names or request IDs. Descendant session-limit Stop responses now let the parent own turn cancellation, avoiding a parent-child wait cycle.
8
+ - 7ff4f77: Every session stream event now carries a stable, `evt_`-prefixed ULID in `meta.id`, and stream consumers use it to drop re-delivery without collapsing distinct events. Retried steps re-emit under new ids, while reconnects, rewinds, and saved-log overlap preserve the original id.
9
+
10
+ **Breaking:** `MessageStreamEvent` is now the canonical public type for events read from a stream, with `meta.id` and `meta.at` required. `HandleMessageStreamEvent` remains as a deprecated alias, so existing imports continue to compile; code that constructs unstamped events under that type must add the envelope. Client, channel, hook, frontend, and eval APIs carry `MessageStreamEvent` end to end, so consumers can read `meta.id` without guards. Events persisted by an earlier version carry `meta.at` but no `meta.id`, so rewinding into a session that started before this release yields events whose id is absent despite the type. eve passes those through rather than dropping them, and they cannot be deduplicated; the exposure ends when those sessions do.
11
+
12
+ ### Patch Changes
13
+
14
+ - 28417c4: Declining a session token-limit prompt no longer leaves a stale copy of the prompt in the parked session. Previously the cancelled turn settled with a snapshot that resurrected the already-answered prompt, so every follow-up message was queued behind it and never re-raised the prompt; follow-ups now reach the budget gate, which re-raises a fresh prompt while the session is over budget.
15
+ - 33ea372: Records Vercel AI Gateway cost on local trace spans: `agent.step` spans now carry `gen_ai.usage.cost`, `gen_ai.usage.gateway_cost`, `gen_ai.usage.input_cost`/`output_cost`, and `gen_ai.generation.id` when the gateway reports them. The attributes only exist for gateway-served calls — other providers emit nothing.
16
+ - 28417c4: Session token limits are now tracked as a runtime limit — an absolute lifetime-usage ceiling that each approved continuation re-anchors to `usage + configured limit` — replacing the window-baseline bookkeeping. Behavior is unchanged except the continuation prompt's `usedTokens` now reports the absolute session total instead of the window-relative amount.
17
+ - feac858: Complete durable sessions after 30 days by default, and add `limits.sessionTimeoutMs` to configure or disable the lifetime for each agent. Once an expired session settles, the next qualifying channel message for its continuation starts a fresh session.
18
+ - 28417c4: Keep one session token-limit prompt pending while concurrent input queues behind it. Approving restores the configured budget window, delegated sessions inherit from the fresh window, and zero-quota child tasks no longer raise continuation prompts that cannot grant tokens.
19
+ - dbc8eae: Splits token usage on local trace spans: model and step spans now record `gen_ai.usage.cache_read.input_tokens` and `gen_ai.usage.cache_creation.input_tokens` (OTel GenAI semantic-convention names) alongside the input/output totals when the provider reports detailed usage — cached tokens price differently, so the split makes cost attribution exact. Providers without detailed usage emit only the totals.
20
+ - 46c6ce3: The dev TUI now renders the session token-limit continuation prompt as a proper question — prompt copy and labeled Approve/Stop options in the question pane — instead of a generic y/n tool-approval line, and answers every confirmation prompt with the request's own option ids instead of hardcoded `approve`/`deny`. Previously, approving the continuation prompt in the TUI submitted an option the server did not recognize, so the same prompt was re-raised indefinitely.
21
+
22
+ ## 0.27.13
23
+
24
+ ### Patch Changes
25
+
26
+ - c1bf6d4: Fix `eve dev` startup for bundled extensions whose output declares `__filename` without `__dirname`.
27
+ - 5d25b16: Render user-scoped connection authorization in Linear Agent Sessions. Linear users now receive the native account-linking affordance, and the channel posts the authorization outcome before a parked turn resumes.
28
+ - d257866: `eve add` now asks before running an official registry item's setup and prints a resumable command when setup is skipped or cancelled. Run `eve add <item> --skip-install` to launch setup later without reinstalling the item.
29
+
3
30
  ## 0.27.12
4
31
 
5
32
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  import type { ContextAccessor } from "#context/key.js";
2
2
  import type { StepInput } from "#harness/types.js";
3
- import type { HandleMessageStreamEvent } from "#protocol/message.js";
3
+ import type { UnstampedMessageStreamEvent } from "#protocol/message.js";
4
4
  import type { SessionHandle } from "#channel/session.js";
5
5
  import type { DeliverPayload } from "#channel/types.js";
6
6
  import type { FetchFileResult, FetchFileFunction } from "#shared/channel-definition.js";
@@ -44,7 +44,7 @@ type StateOf<TCtx> = TCtx extends ChannelAdapterContext<infer S> ? S : Record<st
44
44
  * Extracts the `data` field type from a stream event by its `type` discriminant.
45
45
  * Events that carry no `data` field (e.g. `session.completed`) resolve to `undefined`.
46
46
  */
47
- type EventData<T extends HandleMessageStreamEvent["type"]> = Extract<HandleMessageStreamEvent, {
47
+ type EventData<T extends UnstampedMessageStreamEvent["type"]> = Extract<UnstampedMessageStreamEvent, {
48
48
  type: T;
49
49
  }> extends {
50
50
  data: infer D;
@@ -53,14 +53,14 @@ type EventData<T extends HandleMessageStreamEvent["type"]> = Extract<HandleMessa
53
53
  * A single outbound event handler. Receives the event's `data` (not the full
54
54
  * envelope) and the adapter context. Void return — side effects only.
55
55
  */
56
- type EventHandler<T extends HandleMessageStreamEvent["type"], TCtx extends ChannelAdapterContext<any> = ChannelAdapterContext> = (data: EventData<T>, ctx: TCtx) => void | Promise<void>;
56
+ type EventHandler<T extends UnstampedMessageStreamEvent["type"], TCtx extends ChannelAdapterContext<any> = ChannelAdapterContext> = (data: EventData<T>, ctx: TCtx) => void | Promise<void>;
57
57
  /**
58
58
  * Map of outbound event handlers keyed by event type. The adapter declares
59
59
  * handlers for the event types it cares about. For undeclared types, the
60
60
  * framework's default handlers run.
61
61
  */
62
62
  export type ChannelEventHandlers<TCtx extends ChannelAdapterContext<any> = ChannelAdapterContext> = {
63
- [K in HandleMessageStreamEvent["type"]]?: EventHandler<K, TCtx>;
63
+ [K in UnstampedMessageStreamEvent["type"]]?: EventHandler<K, TCtx>;
64
64
  };
65
65
  /**
66
66
  * Enriched return shape from a channel's {@link ChannelAdapter.fetchFile}
@@ -155,4 +155,4 @@ export declare function getAdapterKind(adapter: ChannelAdapter): string;
155
155
  * Throwing handlers are logged and swallowed so a downstream delivery
156
156
  * failure does not corrupt the event stream write path.
157
157
  */
158
- export declare function callAdapterEventHandler(adapter: ChannelAdapter, event: HandleMessageStreamEvent, ctx: ChannelAdapterContext): Promise<HandleMessageStreamEvent>;
158
+ export declare function callAdapterEventHandler(adapter: ChannelAdapter, event: UnstampedMessageStreamEvent, ctx: ChannelAdapterContext): Promise<UnstampedMessageStreamEvent>;
@@ -1,5 +1,5 @@
1
1
  import type { ContextAccessor } from "#context/key.js";
2
- import type { HandleMessageStreamEvent } from "#protocol/message.js";
2
+ import type { MessageStreamEvent } from "#protocol/message.js";
3
3
  import type { CancelTurnResult, Runtime } from "#channel/types.js";
4
4
  import type { SessionAuth } from "#context/keys.js";
5
5
  /**
@@ -29,7 +29,7 @@ export interface Session {
29
29
  */
30
30
  getEventStream(options?: {
31
31
  startIndex?: number;
32
- }): Promise<ReadableStream<HandleMessageStreamEvent>>;
32
+ }): Promise<ReadableStream<MessageStreamEvent>>;
33
33
  /**
34
34
  * Resolves the durable tail of the event stream: the zero-based index of
35
35
  * the last recorded event, or `-1` before the first.
@@ -1,5 +1,5 @@
1
1
  import type { UserContent } from "ai";
2
- import type { HandleMessageStreamEvent } from "#protocol/message.js";
2
+ import type { UnstampedMessageStreamEvent, MessageStreamEvent } from "#protocol/message.js";
3
3
  import type { CancelTurnStatus } from "#protocol/cancel-turn.js";
4
4
  import type { RunMode } from "#shared/run-mode.js";
5
5
  import type { RuntimeActionResult } from "#runtime/actions/types.js";
@@ -83,7 +83,7 @@ export interface SessionAuthContext {
83
83
  * Backed by `getWritable()` in the workflow runtime. Not part of the adapter
84
84
  * interface: the runtime always writes events itself.
85
85
  */
86
- export type EventEmitFn = (event: HandleMessageStreamEvent) => Promise<void>;
86
+ export type EventEmitFn = (event: UnstampedMessageStreamEvent) => Promise<void>;
87
87
  /**
88
88
  * Base deliver payload crossing the runtime boundary.
89
89
  *
@@ -117,6 +117,10 @@ export interface DeliverHookPayload {
117
117
  readonly kind: "deliver";
118
118
  readonly payloads: readonly DeliverPayload[];
119
119
  }
120
+ /** Internal deadline signal sent through the session's delivery hook. */
121
+ export interface SessionTimeoutHookPayload {
122
+ readonly kind: "session-timeout";
123
+ }
120
124
  /**
121
125
  * Runtime-action results resumed back into a parked parent workflow.
122
126
  */
@@ -153,7 +157,7 @@ export interface SubagentInputRequestHookPayload {
153
157
  readonly subagentName: string;
154
158
  }
155
159
  /** Authorization lifecycle event forwarded from a delegated child. */
156
- export type SubagentAuthorizationEvent = Extract<HandleMessageStreamEvent, {
160
+ export type SubagentAuthorizationEvent = Extract<UnstampedMessageStreamEvent, {
157
161
  type: "authorization.required" | "authorization.completed";
158
162
  }>;
159
163
  /**
@@ -172,7 +176,7 @@ export interface SubagentAuthorizationEventHookPayload {
172
176
  /**
173
177
  * Serializable payload sent through the workflow `resumeHook`.
174
178
  */
175
- export type HookPayload = DeliverHookPayload | RuntimeActionResultHookPayload | SubagentAuthorizationEventHookPayload | SubagentInputRequestHookPayload;
179
+ export type HookPayload = DeliverHookPayload | RuntimeActionResultHookPayload | SessionTimeoutHookPayload | SubagentAuthorizationEventHookPayload | SubagentInputRequestHookPayload;
176
180
  /**
177
181
  * Terminal callback metadata attached to a session at creation.
178
182
  *
@@ -318,7 +322,7 @@ export type RunResult = {
318
322
  */
319
323
  export interface RunHandle {
320
324
  readonly continuationToken: string;
321
- readonly events: ReadableStream<HandleMessageStreamEvent>;
325
+ readonly events: ReadableStream<MessageStreamEvent>;
322
326
  /**
323
327
  * Runtime-owned identifier for this session. Stream and inspection APIs
324
328
  * key on it: workflow-backed runs expose the workflow run id.
@@ -367,7 +371,7 @@ export interface Runtime {
367
371
  * The framework HTTP session-stream route forwards the `startIndex` query
368
372
  * parameter unchanged.
369
373
  */
370
- getEventStream(sessionId: string, options?: GetEventStreamOptions): Promise<ReadableStream<HandleMessageStreamEvent>>;
374
+ getEventStream(sessionId: string, options?: GetEventStreamOptions): Promise<ReadableStream<MessageStreamEvent>>;
371
375
  /**
372
376
  * Resolves the durable tail of a session's event stream: the zero-based
373
377
  * index of the last recorded event, or `-1` before the first. Callers use
@@ -296,6 +296,71 @@ function safeJsonStringify(value) {
296
296
  }
297
297
  }
298
298
 
299
+ //#endregion
300
+ //#region src/shared/ulid.ts
301
+ const ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
302
+ const TIME_CHARS = 10;
303
+ const TIME_MAX = 2 ** 48 - 1;
304
+ const RANDOM_BYTES = 10;
305
+ function createUlidFactory() {
306
+ let lastTimeMs = -1;
307
+ const lastRandom = new Uint8Array(RANDOM_BYTES);
308
+ return function createUlidFromFactory() {
309
+ const now = Date.now();
310
+ if (!Number.isInteger(now) || now < 0 || now > TIME_MAX) throw new Error(`Cannot mint a ULID: timestamp must be an integer from 0 to ${TIME_MAX}.`);
311
+ if (now > lastTimeMs) {
312
+ lastTimeMs = now;
313
+ randomFill(lastRandom);
314
+ } else if (!incrementRandom(lastRandom)) {
315
+ if (lastTimeMs === TIME_MAX) throw new Error("Cannot mint a ULID: random component overflowed at the maximum timestamp.");
316
+ lastTimeMs += 1;
317
+ randomFill(lastRandom);
318
+ }
319
+ return `${encodeTime(lastTimeMs)}${encodeRandom(lastRandom)}`;
320
+ };
321
+ }
322
+ const createUlid = createUlidFactory();
323
+ function randomFill(target) {
324
+ const webCrypto = globalThis.crypto;
325
+ if (typeof webCrypto?.getRandomValues !== "function") throw new Error("Cannot mint a ULID: globalThis.crypto.getRandomValues is unavailable.");
326
+ webCrypto.getRandomValues(target);
327
+ }
328
+ function encodeTime(timeMs) {
329
+ let remaining = timeMs;
330
+ let encoded = "";
331
+ for (let index = 0; index < TIME_CHARS; index += 1) {
332
+ encoded = ENCODING[remaining % 32] + encoded;
333
+ remaining = Math.floor(remaining / 32);
334
+ }
335
+ return encoded;
336
+ }
337
+ function encodeRandom(bytes) {
338
+ let buffer = 0;
339
+ let bufferedBits = 0;
340
+ let encoded = "";
341
+ for (const byte of bytes) {
342
+ buffer = buffer << 8 | byte;
343
+ bufferedBits += 8;
344
+ while (bufferedBits >= 5) {
345
+ bufferedBits -= 5;
346
+ encoded += ENCODING[buffer >>> bufferedBits & 31];
347
+ }
348
+ buffer &= (1 << bufferedBits) - 1;
349
+ }
350
+ return encoded;
351
+ }
352
+ function incrementRandom(bytes) {
353
+ for (let index = bytes.length - 1; index >= 0; index -= 1) {
354
+ const byte = bytes[index] ?? 0;
355
+ if (byte < 255) {
356
+ bytes[index] = byte + 1;
357
+ bytes.fill(0, index + 1);
358
+ return true;
359
+ }
360
+ }
361
+ return false;
362
+ }
363
+
299
364
  //#endregion
300
365
  //#region src/protocol/message.ts
301
366
  const EVE_SESSION_ID_HEADER = "x-eve-session-id";
@@ -1081,6 +1146,24 @@ function withRedirectPolicy(init, redirect) {
1081
1146
  };
1082
1147
  }
1083
1148
 
1149
+ //#endregion
1150
+ //#region src/protocol/event-dedupe.ts
1151
+ function createEventDeduper() {
1152
+ const seen = /* @__PURE__ */ new Set();
1153
+ return {
1154
+ admit(event) {
1155
+ const id = event.meta?.id;
1156
+ if (id === void 0) return true;
1157
+ if (seen.has(id)) return false;
1158
+ seen.add(id);
1159
+ return true;
1160
+ },
1161
+ get size() {
1162
+ return seen.size;
1163
+ }
1164
+ };
1165
+ }
1166
+
1084
1167
  //#endregion
1085
1168
  //#region src/client/eve-agent-store.ts
1086
1169
  var EveAgentStore = class {
@@ -1088,6 +1171,7 @@ var EveAgentStore = class {
1088
1171
  #optimistic;
1089
1172
  #reducer;
1090
1173
  #subscribers = /* @__PURE__ */ new Set();
1174
+ #seenEvents = createEventDeduper();
1091
1175
  #abortController;
1092
1176
  #callbacks = {};
1093
1177
  #data;
@@ -1105,7 +1189,9 @@ var EveAgentStore = class {
1105
1189
  headers: init.headers,
1106
1190
  host: init.host ?? ""
1107
1191
  }).session(init.initialSession);
1108
- this.#events = [...init.initialEvents ?? []];
1192
+ const initialEvents = [];
1193
+ for (const event of init.initialEvents ?? []) if (this.#seenEvents.admit(event)) initialEvents.push(event);
1194
+ this.#events = initialEvents;
1109
1195
  this.#projectionEvents = [...this.#events];
1110
1196
  this.#optimistic = init.optimistic ?? true;
1111
1197
  this.#reducer = init.reducer;
@@ -1150,6 +1236,7 @@ var EveAgentStore = class {
1150
1236
  sawEvent = true;
1151
1237
  this.#status = "streaming";
1152
1238
  }
1239
+ if (!this.#seenEvents.admit(event)) continue;
1153
1240
  this.#events = [...this.#events, event];
1154
1241
  this.#applyServerEvent(event);
1155
1242
  this.#callbacks.onEvent?.(event);
@@ -1187,6 +1274,7 @@ var EveAgentStore = class {
1187
1274
  this.#abortController = void 0;
1188
1275
  this.#session = this.#createSession?.() ?? this.#session;
1189
1276
  this.#events = [];
1277
+ this.#seenEvents = createEventDeduper();
1190
1278
  this.#pendingMessageSubmission = void 0;
1191
1279
  this.#projectionEvents = [];
1192
1280
  this.#data = this.#reducer.initial();
@@ -1403,6 +1491,7 @@ function toMessageInputRequest(request) {
1403
1491
  return {
1404
1492
  allowFreeform: request.allowFreeform,
1405
1493
  display: request.display,
1494
+ kind: request.kind,
1406
1495
  options: request.options,
1407
1496
  prompt: request.prompt,
1408
1497
  requestId: request.requestId
@@ -296,6 +296,71 @@ function safeJsonStringify(value) {
296
296
  }
297
297
  }
298
298
 
299
+ //#endregion
300
+ //#region src/shared/ulid.ts
301
+ const ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
302
+ const TIME_CHARS = 10;
303
+ const TIME_MAX = 2 ** 48 - 1;
304
+ const RANDOM_BYTES = 10;
305
+ function createUlidFactory() {
306
+ let lastTimeMs = -1;
307
+ const lastRandom = new Uint8Array(RANDOM_BYTES);
308
+ return function createUlidFromFactory() {
309
+ const now = Date.now();
310
+ if (!Number.isInteger(now) || now < 0 || now > TIME_MAX) throw new Error(`Cannot mint a ULID: timestamp must be an integer from 0 to ${TIME_MAX}.`);
311
+ if (now > lastTimeMs) {
312
+ lastTimeMs = now;
313
+ randomFill(lastRandom);
314
+ } else if (!incrementRandom(lastRandom)) {
315
+ if (lastTimeMs === TIME_MAX) throw new Error("Cannot mint a ULID: random component overflowed at the maximum timestamp.");
316
+ lastTimeMs += 1;
317
+ randomFill(lastRandom);
318
+ }
319
+ return `${encodeTime(lastTimeMs)}${encodeRandom(lastRandom)}`;
320
+ };
321
+ }
322
+ const createUlid = createUlidFactory();
323
+ function randomFill(target) {
324
+ const webCrypto = globalThis.crypto;
325
+ if (typeof webCrypto?.getRandomValues !== "function") throw new Error("Cannot mint a ULID: globalThis.crypto.getRandomValues is unavailable.");
326
+ webCrypto.getRandomValues(target);
327
+ }
328
+ function encodeTime(timeMs) {
329
+ let remaining = timeMs;
330
+ let encoded = "";
331
+ for (let index = 0; index < TIME_CHARS; index += 1) {
332
+ encoded = ENCODING[remaining % 32] + encoded;
333
+ remaining = Math.floor(remaining / 32);
334
+ }
335
+ return encoded;
336
+ }
337
+ function encodeRandom(bytes) {
338
+ let buffer = 0;
339
+ let bufferedBits = 0;
340
+ let encoded = "";
341
+ for (const byte of bytes) {
342
+ buffer = buffer << 8 | byte;
343
+ bufferedBits += 8;
344
+ while (bufferedBits >= 5) {
345
+ bufferedBits -= 5;
346
+ encoded += ENCODING[buffer >>> bufferedBits & 31];
347
+ }
348
+ buffer &= (1 << bufferedBits) - 1;
349
+ }
350
+ return encoded;
351
+ }
352
+ function incrementRandom(bytes) {
353
+ for (let index = bytes.length - 1; index >= 0; index -= 1) {
354
+ const byte = bytes[index] ?? 0;
355
+ if (byte < 255) {
356
+ bytes[index] = byte + 1;
357
+ bytes.fill(0, index + 1);
358
+ return true;
359
+ }
360
+ }
361
+ return false;
362
+ }
363
+
299
364
  //#endregion
300
365
  //#region src/protocol/message.ts
301
366
  const EVE_SESSION_ID_HEADER = "x-eve-session-id";
@@ -1081,6 +1146,24 @@ function withRedirectPolicy(init, redirect) {
1081
1146
  };
1082
1147
  }
1083
1148
 
1149
+ //#endregion
1150
+ //#region src/protocol/event-dedupe.ts
1151
+ function createEventDeduper() {
1152
+ const seen = /* @__PURE__ */ new Set();
1153
+ return {
1154
+ admit(event) {
1155
+ const id = event.meta?.id;
1156
+ if (id === void 0) return true;
1157
+ if (seen.has(id)) return false;
1158
+ seen.add(id);
1159
+ return true;
1160
+ },
1161
+ get size() {
1162
+ return seen.size;
1163
+ }
1164
+ };
1165
+ }
1166
+
1084
1167
  //#endregion
1085
1168
  //#region src/client/eve-agent-store.ts
1086
1169
  var EveAgentStore = class {
@@ -1088,6 +1171,7 @@ var EveAgentStore = class {
1088
1171
  #optimistic;
1089
1172
  #reducer;
1090
1173
  #subscribers = /* @__PURE__ */ new Set();
1174
+ #seenEvents = createEventDeduper();
1091
1175
  #abortController;
1092
1176
  #callbacks = {};
1093
1177
  #data;
@@ -1105,7 +1189,9 @@ var EveAgentStore = class {
1105
1189
  headers: init.headers,
1106
1190
  host: init.host ?? ""
1107
1191
  }).session(init.initialSession);
1108
- this.#events = [...init.initialEvents ?? []];
1192
+ const initialEvents = [];
1193
+ for (const event of init.initialEvents ?? []) if (this.#seenEvents.admit(event)) initialEvents.push(event);
1194
+ this.#events = initialEvents;
1109
1195
  this.#projectionEvents = [...this.#events];
1110
1196
  this.#optimistic = init.optimistic ?? true;
1111
1197
  this.#reducer = init.reducer;
@@ -1150,6 +1236,7 @@ var EveAgentStore = class {
1150
1236
  sawEvent = true;
1151
1237
  this.#status = "streaming";
1152
1238
  }
1239
+ if (!this.#seenEvents.admit(event)) continue;
1153
1240
  this.#events = [...this.#events, event];
1154
1241
  this.#applyServerEvent(event);
1155
1242
  this.#callbacks.onEvent?.(event);
@@ -1187,6 +1274,7 @@ var EveAgentStore = class {
1187
1274
  this.#abortController = void 0;
1188
1275
  this.#session = this.#createSession?.() ?? this.#session;
1189
1276
  this.#events = [];
1277
+ this.#seenEvents = createEventDeduper();
1190
1278
  this.#pendingMessageSubmission = void 0;
1191
1279
  this.#projectionEvents = [];
1192
1280
  this.#data = this.#reducer.initial();
@@ -1403,6 +1491,7 @@ function toMessageInputRequest(request) {
1403
1491
  return {
1404
1492
  allowFreeform: request.allowFreeform,
1405
1493
  display: request.display,
1494
+ kind: request.kind,
1406
1495
  options: request.options,
1407
1496
  prompt: request.prompt,
1408
1497
  requestId: request.requestId
@@ -1 +1 @@
1
- import{NOT_AN_AGENT_MESSAGE}from"./preconditions.js";import{isEveProject,listAuthoredChannels}from"#setup/scaffold/index.js";import{createPrompter}from"#setup/prompter.js";const KNOWN_CHANNEL_KINDS=[`slack`,`web`];function parseChannelKind(e){if(KNOWN_CHANNEL_KINDS.includes(e))return e;throw Error(`Unknown channel kind "${e}". Known: ${KNOWN_CHANNEL_KINDS.join(`, `)}.`)}const defaultChannelsAddDependencies={createPrompter,loadAddCommand:async()=>(await import(`./registry.js`)).runAddCommand,loadChannelsFlow:async()=>(await import(`#setup/flows/channels.js`)).runChannelsFlow};async function runChannelsAddCompatibilityCommand(n,r,o,s=defaultChannelsAddDependencies){if(!await isEveProject(r)){n.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}try{if(o.kind!==void 0){let e=parseChannelKind(o.kind),t=await s.loadAddCommand(),i={};o.options.force===!0&&(i.overwrite=!0),o.options.yes===!0&&(i.setupArgs=[`--yes`]),await t(n,r,`channel/${e}`,i);return}if(o.options.yes||!process.stdin.isTTY||!process.stdout.isTTY)throw Error(`Pass a channel kind: \`eve channels add <${KNOWN_CHANNEL_KINDS.join(`|`)}>\`.`);await(await s.loadChannelsFlow())({appRoot:r,prompter:s.createPrompter()})}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1}}async function runChannelsListCommand(r,i,a){if(!await isEveProject(i)){r.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}let o=await listAuthoredChannels(i);if(a.json){r.log(JSON.stringify({channels:o},null,2));return}if(o.length===0){r.log("No channels defined. Run `eve channels add` to add one.");return}for(let e of o)r.log(e)}export{runChannelsAddCompatibilityCommand,runChannelsListCommand};
1
+ import{NOT_AN_AGENT_MESSAGE}from"./preconditions.js";import{isEveProject,listAuthoredChannels}from"#setup/scaffold/index.js";import{createPrompter}from"#setup/prompter.js";const KNOWN_CHANNEL_KINDS=[`slack`,`web`];function parseChannelKind(e){if(KNOWN_CHANNEL_KINDS.includes(e))return e;throw Error(`Unknown channel kind "${e}". Known: ${KNOWN_CHANNEL_KINDS.join(`, `)}.`)}const defaultChannelsAddDependencies={createPrompter,loadAddCommand:async()=>(await import(`./registry.js`)).runAddCommand,loadChannelsFlow:async()=>(await import(`#setup/flows/channels.js`)).runChannelsFlow};async function runChannelsAddCompatibilityCommand(n,r,o,s=defaultChannelsAddDependencies){if(!await isEveProject(r)){n.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}try{if(o.kind!==void 0){let e=parseChannelKind(o.kind),t=await s.loadAddCommand(),i={};o.options.force===!0&&(i.overwrite=!0),o.options.yes===!0&&(i.yes=!0),await t(n,r,`channel/${e}`,i);return}if(o.options.yes||!process.stdin.isTTY||!process.stdout.isTTY)throw Error(`Pass a channel kind: \`eve channels add <${KNOWN_CHANNEL_KINDS.join(`|`)}>\`.`);await(await s.loadChannelsFlow())({appRoot:r,prompter:s.createPrompter()})}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1}}async function runChannelsListCommand(r,i,a){if(!await isEveProject(i)){r.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}let o=await listAuthoredChannels(i);if(a.json){r.log(JSON.stringify({channels:o},null,2));return}if(o.length===0){r.log("No channels defined. Run `eve channels add` to add one.");return}for(let e of o)r.log(e)}export{runChannelsAddCompatibilityCommand,runChannelsListCommand};
@@ -1 +1 @@
1
- import{NOT_AN_AGENT_MESSAGE}from"./preconditions.js";import{isEveProject}from"#setup/scaffold/index.js";import{createPrompter}from"#setup/prompter.js";import{interactiveAsker}from"#setup/ask.js";import{deployChannelSetup}from"#setup/channel-setup-deployment.js";import{channelSetupEnvironment,describeChannelSetupEnvironment}from"#setup/channel-setup-environment.js";import{channelSetupIntegration,createChannelSetupUi}from"#setup/channel-setup-integrations.js";import{detectDeployment,projectResolutionFromDeployment}from"#setup/project-resolution.js";import{createDefaultSetupState}from"#setup/state.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";const defaultIntegrationSetupDependencies={detectDeployment,getVercelAuthStatus};async function runIntegrationSetupCommand(n,r,a,o={},s=defaultIntegrationSetupDependencies){if(!await isEveProject(r)){n.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}try{if(a!==`slack`&&a!==`web`)throw Error(`Integration setup "${a}" is not available in this version of eve. Upgrade eve and try again.`);let e=a,t=s.createPrompter?.()??createPrompter();t.intro(`Set up ${channelSetupIntegration(e).label}`),t.log.message(`Checking Vercel setup...`);let[n,i]=await Promise.all([s.detectDeployment(r),s.getVercelAuthStatus(r)]),c=projectResolutionFromDeployment(n),l=channelSetupEnvironment(i,c);t.log.info(describeChannelSetupEnvironment(l));let u={...createDefaultSetupState(),project:c,projectPath:{kind:`resolved`,inPlace:!0,path:r},channelSelection:[e]},d=await channelSetupIntegration(e).setup({environment:l,state:u,ui:createChannelSetupUi({asker:interactiveAsker(t),prompter:t}),presetCreateSlackbot:o.yes?!0:void 0,presetPortableCredentials:o.yes?!0:void 0,skipDependencyMutation:!0,deps:s.addChannelsDeps});if(d.kind===`cancelled`)return;let f=d.state;(f.slackbotAttached||l.vercel.kind===`available`&&f.channels.includes(`web`))&&(f=await deployChannelSetup({state:f,ui:createChannelSetupUi({asker:interactiveAsker(t),prompter:t}),presetDeploy:o.yes===!0?!0:!process.stdin.isTTY||!process.stdout.isTTY?!1:void 0,deps:s.deployProjectDeps})),t.outro(f.channels.includes(e)?`Integration set up.`:`No changes made.`)}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1}}export{runIntegrationSetupCommand};
1
+ import{NOT_AN_AGENT_MESSAGE}from"./preconditions.js";import{isEveProject}from"#setup/scaffold/index.js";import{createPrompter}from"#setup/prompter.js";import{interactiveAsker}from"#setup/ask.js";import{deployChannelSetup}from"#setup/channel-setup-deployment.js";import{channelSetupEnvironment,describeChannelSetupEnvironment}from"#setup/channel-setup-environment.js";import{channelSetupIntegration,createChannelSetupUi}from"#setup/channel-setup-integrations.js";import{detectDeployment,projectResolutionFromDeployment}from"#setup/project-resolution.js";import{createDefaultSetupState}from"#setup/state.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";const defaultIntegrationSetupDependencies={detectDeployment,getVercelAuthStatus};async function runIntegrationSetupCommand(n,r,a,o={},s=defaultIntegrationSetupDependencies){if(!await isEveProject(r)){n.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}try{if(a!==`slack`&&a!==`web`)throw Error(`Integration setup "${a}" is not available in this version of eve. Upgrade eve and try again.`);let e=a,t=s.createPrompter?.()??createPrompter();t.intro(`Set up ${channelSetupIntegration(e).label}`),t.log.message(`Checking Vercel setup...`);let[n,i]=await Promise.all([s.detectDeployment(r),s.getVercelAuthStatus(r)]),c=projectResolutionFromDeployment(n),l=channelSetupEnvironment(i,c);t.log.info(describeChannelSetupEnvironment(l));let u={...createDefaultSetupState(),project:c,projectPath:{kind:`resolved`,inPlace:!0,path:r},channelSelection:[e]},d=await channelSetupIntegration(e).setup({environment:l,state:u,ui:createChannelSetupUi({asker:interactiveAsker(t),prompter:t}),presetCreateSlackbot:o.yes?!0:void 0,presetPortableCredentials:o.yes?!0:void 0,skipDependencyMutation:!0,deps:s.addChannelsDeps});if(d.kind===`cancelled`){process.env.EVE_SETUP===`1`&&(process.exitCode=130);return}let f=d.state;(f.slackbotAttached||l.vercel.kind===`available`&&f.channels.includes(`web`))&&(f=await deployChannelSetup({state:f,ui:createChannelSetupUi({asker:interactiveAsker(t),prompter:t}),presetDeploy:o.yes===!0?!0:!process.stdin.isTTY||!process.stdout.isTTY?!1:void 0,deps:s.deployProjectDeps})),t.outro(f.channels.includes(e)?`Integration set up.`:`No changes made.`)}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1}}export{runIntegrationSetupCommand};
@@ -1 +1 @@
1
- function registerRegistryCommands(e){let{appRoot:t,logger:n,program:r}=e;r.command(`add <item>`).description(`Install a registry item; relative paths use the official eve registry.`).option(`-o, --overwrite`,`Overwrite existing files.`).action(async(e,r)=>{let{runAddCommand:i}=await import(`./registry.js`);await i(n,t,e,r)});let i=r.command(`registry`).description(`Configure and browse extension and agent registry catalogs.`);i.command(`add <registries...>`).description(`Add registry namespace mappings to package.json.`).action(async e=>{let{runRegistryAddCommand:r}=await import(`./registry.js`);await r(n,t,e)}),i.command(`list`).description(`List items from all registries or one source.`).option(`-r, --registry <source>`,`List items from one registry.`).action(async e=>{let{runRegistryListCommand:r}=await import(`./registry.js`);await r(n,t,e.registry)}),i.command(`search <query>`).description(`Search all registries or one source.`).option(`-r, --registry <source>`,`Search one registry.`).action(async(e,r)=>{let{runRegistrySearchCommand:i}=await import(`./registry.js`);await i(n,t,e,r.registry)}),i.command(`view <item>`).description(`Print one registry item as JSON.`).action(async e=>{let{runRegistryViewCommand:r}=await import(`./registry.js`);await r(n,t,e)})}export{registerRegistryCommands};
1
+ function registerRegistryCommands(e){let{appRoot:t,logger:n,program:r}=e;r.command(`add <item>`).description(`Install a registry item; relative paths use the official eve registry.`).option(`-o, --overwrite`,`Overwrite existing files.`).option(`--skip-install`,`Run the item's setup flow without installing it.`).option(`--skip-setup`,`Skip the item's setup flow.`).option(`-y, --yes`,`Run setup and accept its recommended defaults.`).action(async(e,r)=>{let{runAddCommand:i}=await import(`./registry.js`);await i(n,t,e,r)});let i=r.command(`registry`).description(`Configure and browse extension and agent registry catalogs.`);i.command(`add <registries...>`).description(`Add registry namespace mappings to package.json.`).action(async e=>{let{runRegistryAddCommand:r}=await import(`./registry.js`);await r(n,t,e)}),i.command(`list`).description(`List items from all registries or one source.`).option(`-r, --registry <source>`,`List items from one registry.`).action(async e=>{let{runRegistryListCommand:r}=await import(`./registry.js`);await r(n,t,e.registry)}),i.command(`search <query>`).description(`Search all registries or one source.`).option(`-r, --registry <source>`,`Search one registry.`).action(async(e,r)=>{let{runRegistrySearchCommand:i}=await import(`./registry.js`);await i(n,t,e,r.registry)}),i.command(`view <item>`).description(`Print one registry item as JSON.`).action(async e=>{let{runRegistryViewCommand:r}=await import(`./registry.js`);await r(n,t,e)})}export{registerRegistryCommands};
@@ -1,6 +1,8 @@
1
1
  export interface RegistrySetupCommand {
2
- command: string;
2
+ package: string;
3
+ bin: string;
3
4
  args: string[];
4
5
  }
5
- /** Executes a trusted registry setup command in the consuming project. */
6
- export declare function runRegistrySetupCommand(appRoot: string, setup: RegistrySetupCommand): Promise<void>;
6
+ export type RegistrySetupCommandResult = "completed" | "cancelled";
7
+ /** Executes a trusted registry setup command from an installed package's declared Node binary. */
8
+ export declare function runRegistrySetupCommand(appRoot: string, setup: RegistrySetupCommand, item: string): Promise<RegistrySetupCommandResult>;
@@ -1 +1 @@
1
- import{spawn}from"node:child_process";function runRegistrySetupCommand(t,n){let r=n.command,i=n.args;return new Promise((n,a)=>{let o=spawn(r,i,{cwd:t,stdio:`inherit`});o.once(`error`,a),o.once(`close`,(e,t)=>{if(e===0){n();return}a(Error(t===null?`Setup command exited with code ${e??`unknown`}.`:`Setup command was terminated by ${t}.`))})})}export{runRegistrySetupCommand};
1
+ import{findPackageJSON}from"node:module";import{z}from"#compiled/zod/index.js";import{dirname,isAbsolute,relative,resolve}from"node:path";import{readFile}from"node:fs/promises";import{spawn}from"node:child_process";import{pathToFileURL}from"node:url";const PackageJsonSchema=z.object({name:z.string().min(1),bin:z.union([z.string(),z.record(z.string(),z.string())]).optional()});function declaredBinPath(e,t){return typeof e.bin==`string`?t===e.name.slice(e.name.lastIndexOf(`/`)+1)?e.bin:void 0:e.bin?.[t]}async function resolveNodePackageBin(e,t){let s=dirname(e),c=PackageJsonSchema.parse(JSON.parse(await readFile(e,`utf8`))),l=declaredBinPath(c,t);if(l===void 0)throw Error(`Package "${c.name}" does not declare a "${t}" binary.`);let u=resolve(s,l),d=relative(s,u);if(d.startsWith(`..`)||isAbsolute(d))throw Error(`Package "${c.name}" declares its "${t}" binary outside the package directory.`);return u}async function runRegistrySetupCommand(t,n,r){let i=findPackageJSON(n.package,pathToFileURL(resolve(t,`package.json`)));if(i===void 0)throw Error(`Setup package "${n.package}" is not installed. Run \`eve add ${r}\` first.`);let o=await resolveNodePackageBin(i,n.bin);return new Promise((e,i)=>{let a=spawn(process.execPath,[o,...n.args],{cwd:t,env:{...process.env,EVE_SETUP:`1`,EVE_SETUP_ITEM:r},stdio:`inherit`});a.once(`error`,i),a.once(`close`,(t,n)=>{if(t===0){e(`completed`);return}if(t===130||n===`SIGINT`){e(`cancelled`);return}i(Error(n===null?`Setup command exited with code ${t??`unknown`}.`:`Setup command was terminated by ${n}.`))})})}export{runRegistrySetupCommand};
@@ -1,16 +1,22 @@
1
+ import { type Prompter } from "#setup/prompter.js";
1
2
  import type { runRegistrySetupCommand } from "./registry-setup-command.js";
2
3
  export interface RegistryCommandLogger {
3
4
  error(message: string): void;
4
5
  log(message: string): void;
5
6
  }
6
7
  export interface AddCommandOptions {
8
+ skipInstall?: boolean;
7
9
  overwrite?: boolean;
8
- /** Arguments forwarded to a trusted setup command after installation. */
9
- setupArgs?: string[];
10
+ skipSetup?: boolean;
11
+ yes?: boolean;
10
12
  }
11
- export interface AddCommandDependencies {
13
+ export interface RegistrySetupDependencies {
12
14
  loadSetupCommandRunner(): Promise<typeof runRegistrySetupCommand>;
13
15
  }
16
+ export interface AddCommandDependencies extends RegistrySetupDependencies {
17
+ createPrompter?: () => Prompter;
18
+ isInteractive?: () => boolean;
19
+ }
14
20
  /** Installs an official registry item without running its declared setup command. */
15
21
  export declare function installOfficialRegistryItem(appRoot: string, item: string, options?: AddCommandOptions): Promise<void>;
16
22
  /** Installs an official, configured, or URL-addressed registry item. */
@@ -1 +1 @@
1
- import{NOT_AN_AGENT_MESSAGE}from"./preconditions.js";import{addRegistryMappings,readRegistryConfig}from"./registry-project.js";import{z}from"#compiled/zod/index.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{isEveProject}from"#setup/scaffold/index.js";import{addRegistryItems,getRegistryItems,searchRegistries}from"#compiled/shadcn-registry/index.js";import semver from"#compiled/semver/index.js";const defaultAddCommandDependencies={loadSetupCommandRunner:async()=>(await import(`./registry-setup-command.js`)).runRegistrySetupCommand},OFFICIAL_REGISTRY=`https://eve.dev/r`,OFFICIAL_CATALOG=`${OFFICIAL_REGISTRY}/registry.json`;function isRegistryAddress(e){return e.startsWith(`@`)||/^https?:\/\//.test(e)}function itemAddress(e){return isRegistryAddress(e)?e:`${OFFICIAL_REGISTRY}/${e}.json`}async function installOfficialRegistryItem(e,t,r={}){let i=await readRegistryConfig(e);await addRegistryItems([itemAddress(t)],{...r,config:i,cwd:e})}const EveRegistryItemMetadataSchema=z.object({meta:z.object({eve:z.object({requires:z.string().optional(),setup:z.object({command:z.literal(`eve`),args:z.tuple([z.literal(`integration`),z.literal(`setup`),z.string().min(1)])}).optional()}).optional()}).optional()});function eveMetadataFromRegistryItem(e){return EveRegistryItemMetadataSchema.parse(e).meta?.eve}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 errorMessage(e){return e instanceof Error?e.message:String(e)}async function runRegistryAction(t,n,r){if(!await isEveProject(n)){t.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}try{await r()}catch(e){t.error(errorMessage(e)),process.exitCode=1}}function configuredRegistrySources(e){return Object.keys(e.registries??{})}function validateRegistrySource(e){if(e!==void 0&&!isRegistryAddress(e))throw Error(`Registry sources must be a namespace or URL: ${e}`)}function printSearchResults(e,t,n){if(t.items.length===0){e.log(`No registry items found.`);return}let r=`${t.pagination.total} item${t.pagination.total===1?``:`s`}`,i=n.query===void 0?``:` matching "${n.query}"`,a=`${n.sources.length} registr${n.sources.length===1?`y`:`ies`}`;e.log(`Found ${r}${i} in ${a}`),e.log(``);for(let r of t.items){let t=r.registry===OFFICIAL_CATALOG?r.name:r.addCommandArgument,i=n.query===void 0&&r.description?` — ${r.description}`:``;e.log(`${t}${i}`)}}async function browseRegistryItems(e,t,r,i){validateRegistrySource(i);let a=await readRegistryConfig(t),o=i?[i]:[OFFICIAL_CATALOG,...configuredRegistrySources(a)],s=await searchRegistries(o,{config:a,continueOnError:o.length>1,query:r}),l=s.errors??[];l.length<o.length&&printSearchResults(e,s,{query:r,sources:o});for(let t of l)e.error(`${t.registry}: ${t.message}`);l.length>0&&(process.exitCode=1)}async function runAddCommand(e,t,r,i,a=defaultAddCommandDependencies){await runRegistryAction(e,t,async()=>{let e=await readRegistryConfig(t),c=itemAddress(r),[l]=await getRegistryItems([c],{config:e}),u=isOfficialItemAddress(c)?eveMetadataFromRegistryItem(l):void 0;assertCompatibleEveVersion(u?.requires);let d={config:e,cwd:t,overwrite:i.overwrite};await addRegistryItems([c],d),u?.setup!==void 0&&await(await a.loadSetupCommandRunner())(t,{...u.setup,args:[...u.setup.args,...i.setupArgs??[]]})})}async function runRegistryAddCommand(e,n,r){await runRegistryAction(e,n,async()=>{let i=await addRegistryMappings(n,r);for(let t of i.skippedBuiltIn)e.log(`Skipped ${t} because it is built in.`);for(let t of i.skippedExisting)e.log(`Skipped ${t} because it is already configured.`);i.added.length>0&&e.log(`Added ${i.added.join(`, `)} to package.json.`)})}async function runRegistryListCommand(e,t,n){await runRegistryAction(e,t,()=>browseRegistryItems(e,t,void 0,n))}async function runRegistrySearchCommand(e,t,n,r){await runRegistryAction(e,t,()=>browseRegistryItems(e,t,n,r))}async function runRegistryViewCommand(e,t,r){await runRegistryAction(e,t,async()=>{let i=await readRegistryConfig(t),a=await getRegistryItems([itemAddress(r)],{config:i});e.log(JSON.stringify(a.length===1?a[0]:a,null,2))})}export{installOfficialRegistryItem,runAddCommand,runRegistryAddCommand,runRegistryListCommand,runRegistrySearchCommand,runRegistryViewCommand};
1
+ import{NOT_AN_AGENT_MESSAGE}from"./preconditions.js";import{addRegistryMappings,readRegistryConfig}from"./registry-project.js";import{z}from"#compiled/zod/index.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{isEveProject}from"#setup/scaffold/index.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,isInteractive:()=>process.stdin.isTTY===!0&&process.stdout.isTTY===!0,loadSetupCommandRunner:async()=>(await import(`./registry-setup-command.js`)).runRegistrySetupCommand},OFFICIAL_REGISTRY=`https://eve.dev/r`,OFFICIAL_CATALOG=`${OFFICIAL_REGISTRY}/registry.json`;function isRegistryAddress(e){return e.startsWith(`@`)||/^https?:\/\//.test(e)}function itemAddress(e){return isRegistryAddress(e)?e:`${OFFICIAL_REGISTRY}/${e}.json`}async function installOfficialRegistryItem(e,t,r={}){let i=await readRegistryConfig(e);await addRegistryItems([itemAddress(t)],{config:i,cwd:e,overwrite:r.overwrite})}const EveRegistryItemMetadataSchema=z.object({meta:z.object({eve:z.object({requires:z.string().optional(),setup:z.object({package:z.string().min(1),bin:z.string().min(1),args:z.array(z.string()).default([])}).optional()}).optional()}).optional()});function eveMetadataFromRegistryItem(e){return EveRegistryItemMetadataSchema.parse(e).meta?.eve}function setupResumeCommand(e){return`eve add ${/^[\w@./:-]+$/.test(e)?e:`'${e.replaceAll(`'`,`'\\''`)}'`} --skip-install`}function setupReminder(e,t){return`${t===`cancelled`?`Setup cancelled.`:`Setup skipped.`} Run \`${setupResumeCommand(e)}\` when you're ready.`}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 errorMessage(e){return e instanceof Error?e.message:String(e)}async function runRegistryAction(t,n,r){if(!await isEveProject(n)){t.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}try{await r()}catch(e){t.error(errorMessage(e)),process.exitCode=1}}function configuredRegistrySources(e){return Object.keys(e.registries??{})}function validateRegistrySource(e){if(e!==void 0&&!isRegistryAddress(e))throw Error(`Registry sources must be a namespace or URL: ${e}`)}function printSearchResults(e,t,n){if(t.items.length===0){e.log(`No registry items found.`);return}let r=`${t.pagination.total} item${t.pagination.total===1?``:`s`}`,i=n.query===void 0?``:` matching "${n.query}"`,a=`${n.sources.length} registr${n.sources.length===1?`y`:`ies`}`;e.log(`Found ${r}${i} in ${a}`),e.log(``);for(let r of t.items){let t=r.registry===OFFICIAL_CATALOG?r.name:r.addCommandArgument,i=n.query===void 0&&r.description?` — ${r.description}`:``;e.log(`${t}${i}`)}}async function browseRegistryItems(e,t,r,i){validateRegistrySource(i);let a=await readRegistryConfig(t),o=i?[i]:[OFFICIAL_CATALOG,...configuredRegistrySources(a)],s=await searchRegistries(o,{config:a,continueOnError:o.length>1,query:r}),c=s.errors??[];c.length<o.length&&printSearchResults(e,s,{query:r,sources:o});for(let t of c)e.error(`${t.registry}: ${t.message}`);c.length>0&&(process.exitCode=1)}async function runDeclaredSetup(e,t,n,r,i,a){if(r===void 0)return;let o=await a.loadSetupCommandRunner();try{await o(t,{...r,args:[...r.args,...i.yes?[`--yes`]:[]]},n)===`cancelled`&&e.log(setupReminder(n,`cancelled`))}catch(e){throw Error(`${errorMessage(e)} Try again with \`${setupResumeCommand(n)}\`.`)}}async function runAddCommand(e,t,r,i,a=defaultAddCommandDependencies){await runRegistryAction(e,t,async()=>{let o=await readRegistryConfig(t),l=itemAddress(r);if(i.skipInstall===!0){if(i.overwrite===!0)throw Error(`--overwrite cannot be used with --skip-install.`);if(i.skipSetup===!0)throw Error(`--skip-install cannot be used with --skip-setup.`);if(!isOfficialItemAddress(l))throw Error(`Setup flows are currently supported only for official eve registry items.`)}let[u]=await getRegistryItems([l],{config:o}),d=isOfficialItemAddress(l)?eveMetadataFromRegistryItem(u):void 0;if(assertCompatibleEveVersion(d?.requires),i.skipInstall===!0){if(d?.setup===void 0)throw Error(`Registry item "${r}" does not declare a setup flow.`);await runDeclaredSetup(e,t,r,d.setup,i,a);return}if(await addRegistryItems([l],{config:o,cwd:t,overwrite:i.overwrite}),d?.setup===void 0)return;let f=a.isInteractive?.()??defaultAddCommandDependencies.isInteractive();if(i.skipSetup===!0||!i.yes&&!f){e.log(setupReminder(r,`skipped`));return}if(!i.yes)try{if(await(a.createPrompter?.()??defaultAddCommandDependencies.createPrompter()).select({message:`Set up ${r} now?`,initialValue:`yes`,options:[{value:`yes`,label:`Yes`},{value:`no`,label:`No`}]})===`no`){e.log(setupReminder(r,`skipped`));return}}catch(t){if(!(t instanceof WizardCancelledError))throw t;e.log(setupReminder(r,`cancelled`));return}await runDeclaredSetup(e,t,r,d.setup,i,a)})}async function runRegistryAddCommand(e,n,r){await runRegistryAction(e,n,async()=>{let i=await addRegistryMappings(n,r);for(let t of i.skippedBuiltIn)e.log(`Skipped ${t} because it is built in.`);for(let t of i.skippedExisting)e.log(`Skipped ${t} because it is already configured.`);i.added.length>0&&e.log(`Added ${i.added.join(`, `)} to package.json.`)})}async function runRegistryListCommand(e,t,n){await runRegistryAction(e,t,()=>browseRegistryItems(e,t,void 0,n))}async function runRegistrySearchCommand(e,t,n,r){await runRegistryAction(e,t,()=>browseRegistryItems(e,t,n,r))}async function runRegistryViewCommand(e,t,r){await runRegistryAction(e,t,async()=>{let i=await readRegistryConfig(t),a=await getRegistryItems([itemAddress(r)],{config:i});e.log(JSON.stringify(a.length===1?a[0]:a,null,2))})}export{installOfficialRegistryItem,runAddCommand,runRegistryAddCommand,runRegistryListCommand,runRegistrySearchCommand,runRegistryViewCommand};