eve 0.13.4 → 0.13.6
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.
- package/CHANGELOG.md +25 -0
- package/dist/src/channel/schedule-auth.d.ts +7 -0
- package/dist/src/channel/schedule-auth.js +1 -0
- package/dist/src/channel/schedule.d.ts +2 -6
- package/dist/src/channel/schedule.js +1 -1
- package/dist/src/channel/send.d.ts +3 -1
- package/dist/src/channel/send.js +1 -1
- package/dist/src/channel/types.d.ts +6 -0
- package/dist/src/chunks/{use-eve-agent-C8UVUMA4.js → use-eve-agent-8X2UMr8q.js} +31 -20
- package/dist/src/chunks/{use-eve-agent-BLv-Mj5g.js → use-eve-agent-9ZNiSFMb.js} +31 -20
- package/dist/src/cli/dev/tui/blocks.d.ts +1 -1
- package/dist/src/cli/dev/tui/blocks.js +1 -1
- package/dist/src/cli/dev/tui/prompt-command-handler.d.ts +5 -1
- package/dist/src/cli/dev/tui/prompt-command-handler.js +1 -1
- package/dist/src/cli/dev/tui/prompt-commands.d.ts +7 -7
- package/dist/src/cli/dev/tui/prompt-commands.js +2 -2
- package/dist/src/cli/dev/tui/remote-auth-command.d.ts +11 -0
- package/dist/src/cli/dev/tui/remote-auth-command.js +3 -0
- package/dist/src/cli/dev/tui/remote-auth-result.d.ts +5 -0
- package/dist/src/cli/dev/tui/remote-auth-result.js +2 -1
- package/dist/src/cli/dev/tui/remote-auth.d.ts +30 -0
- package/dist/src/cli/dev/tui/remote-auth.js +1 -0
- package/dist/src/cli/dev/tui/remote-connection-probe.d.ts +3 -1
- package/dist/src/cli/dev/tui/remote-connection-probe.js +1 -1
- package/dist/src/cli/dev/tui/remote-connection-types.d.ts +2 -1
- package/dist/src/cli/dev/tui/remote-connection.js +1 -1
- package/dist/src/cli/dev/tui/runner.d.ts +18 -1
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.d.ts +4 -4
- package/dist/src/cli/dev/tui/setup-commands.js +2 -2
- package/dist/src/cli/dev/tui/setup-issues.d.ts +1 -1
- package/dist/src/cli/dev/tui/setup-issues.js +1 -1
- package/dist/src/cli/dev/tui/status-line.d.ts +6 -14
- package/dist/src/cli/dev/tui/status-line.js +1 -1
- package/dist/src/cli/dev/tui/terminal-renderer.d.ts +8 -1
- package/dist/src/cli/dev/tui/terminal-renderer.js +9 -9
- package/dist/src/cli/dev/tui/test/index.d.ts +1 -0
- package/dist/src/cli/dev/tui/test/index.js +1 -1
- package/dist/src/cli/dev/tui/tui.d.ts +1 -1
- package/dist/src/cli/dev/tui/tui.js +1 -1
- package/dist/src/cli/dev/tui/vercel-trusted-sources.js +1 -1
- package/dist/src/cli/run.js +1 -1
- package/dist/src/client/agent-info-error.d.ts +17 -0
- package/dist/src/client/agent-info-error.js +1 -0
- package/dist/src/client/client.d.ts +4 -0
- package/dist/src/client/client.js +1 -1
- package/dist/src/client/index.d.ts +1 -0
- package/dist/src/client/index.js +1 -1
- package/dist/src/client/message-reducer.js +1 -1
- package/dist/src/client/ndjson.js +3 -3
- package/dist/src/context/keys.d.ts +1 -0
- package/dist/src/context/keys.js +1 -1
- package/dist/src/evals/cli/eval-client.js +1 -1
- package/dist/src/execution/delegated-parent-notification.js +1 -1
- package/dist/src/execution/durable-session-store.js +1 -1
- package/dist/src/execution/eve-workflow-attributes.d.ts +8 -0
- package/dist/src/execution/eve-workflow-attributes.js +1 -1
- package/dist/src/execution/hook-ownership.d.ts +7 -0
- package/dist/src/execution/hook-ownership.js +1 -0
- package/dist/src/execution/ndjson-stream.d.ts +19 -0
- package/dist/src/execution/ndjson-stream.js +3 -0
- package/dist/src/execution/runtime-context.js +1 -1
- package/dist/src/execution/subagent-adapter.js +1 -1
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-runtime.d.ts +1 -1
- package/dist/src/execution/workflow-runtime.js +1 -3
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/action-result-helpers.d.ts +2 -3
- package/dist/src/harness/action-result-helpers.js +1 -1
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/messages.js +1 -1
- package/dist/src/harness/provider-tools.d.ts +4 -27
- package/dist/src/harness/provider-tools.js +1 -1
- package/dist/src/harness/step-hooks.d.ts +0 -13
- package/dist/src/harness/step-hooks.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/tool-output-serialization.d.ts +17 -0
- package/dist/src/harness/tool-output-serialization.js +1 -0
- package/dist/src/harness/tools.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/host/configure-nitro-routes.js +1 -1
- package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
- package/dist/src/internal/workflow/configure-world.js +1 -1
- package/dist/src/internal/workflow/queue-namespace.d.ts +0 -1
- package/dist/src/internal/workflow/queue-namespace.js +1 -1
- package/dist/src/internal/workflow/runtime.d.ts +4 -0
- package/dist/src/internal/workflow/runtime.js +1 -0
- package/dist/src/internal/workflow-bundle/builder-support.js +6 -6
- package/dist/src/internal/workflow-bundle/builder.js +2 -2
- package/dist/src/internal/workflow-bundle/vercel-workflow-output.js +1 -1
- package/dist/src/internal/workflow-bundle/workflow-core-shim.d.ts +10 -8
- package/dist/src/public/channels/github/dispatch.d.ts +22 -1
- package/dist/src/public/channels/github/dispatch.js +1 -1
- package/dist/src/public/channels/github/githubChannel.d.ts +21 -3
- package/dist/src/public/channels/github/githubChannel.js +1 -1
- package/dist/src/public/channels/github/inbound.d.ts +46 -1
- package/dist/src/public/channels/github/inbound.js +2 -2
- package/dist/src/public/channels/github/index.d.ts +1 -1
- package/dist/src/public/channels/github/state.d.ts +3 -1
- package/dist/src/public/channels/github/state.js +1 -1
- package/dist/src/public/channels/slack/defaults.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/runtime/connections/callback-route.js +1 -1
- package/dist/src/runtime/framework-tools/web-search.d.ts +2 -2
- package/dist/src/runtime/framework-tools/web-search.js +1 -1
- package/dist/src/runtime/session-callback-route.js +1 -1
- package/dist/src/services/dev-client/request-headers.d.ts +2 -0
- package/dist/src/services/dev-client/request-headers.js +1 -1
- package/dist/src/services/dev-client/vercel-auth-error.d.ts +12 -14
- package/dist/src/services/dev-client/vercel-auth-error.js +9 -2
- package/dist/src/setup/flows/install-vercel-cli.d.ts +1 -1
- package/dist/src/setup/flows/login.d.ts +3 -1
- package/dist/src/setup/flows/login.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/vercel-deployment.d.ts +12 -5
- package/dist/src/setup/vercel-deployment.js +1 -1
- package/dist/src/setup/vercel-project-api.d.ts +13 -2
- package/dist/src/setup/vercel-project-api.js +1 -1
- package/dist/src/setup/vercel-project.d.ts +5 -1
- package/dist/src/setup/vercel-project.js +0 -0
- package/dist/src/setup/verified-remote-client.js +1 -1
- package/dist/src/shared/empty-delivery.d.ts +3 -0
- package/dist/src/shared/empty-delivery.js +1 -0
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/channels/custom.mdx +1 -1
- package/docs/channels/eve.mdx +1 -1
- package/docs/channels/github.mdx +13 -1
- package/docs/channels/slack.mdx +1 -1
- package/docs/concepts/execution-model-and-durability.md +2 -0
- package/docs/guides/client/continuations.mdx +4 -0
- package/docs/guides/client/streaming.mdx +6 -0
- package/docs/guides/dev-tui.md +22 -12
- package/docs/guides/frontend/overview.mdx +28 -8
- package/docs/schedules.mdx +5 -3
- package/docs/tools/overview.mdx +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# eve
|
|
2
2
|
|
|
3
|
+
## 0.13.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7f66a06: Add opt-in GitHub channel hooks for check suite, check run, and workflow run webhooks, with normalized CI metadata and pull request dispatch.
|
|
8
|
+
- a63dfa2: Project search now resolves exact names directly and ranks one fallback result page, avoiding unbounded substring-match pagination for short queries.
|
|
9
|
+
- a63dfa2: Fixed remote `/vc:login` rejecting a freshly resolved Vercel project with "The local Vercel OIDC token does not match the resolved deployment: owner_id." The verified deployment now takes its owner id from Vercel's response instead of the team slug used to scope the lookup, so it matches the OIDC token's `owner_id` claim.
|
|
10
|
+
- a63dfa2: In remote sessions, `/vc:login` resolves the target Vercel project and owning team from the deployment URL. When the target requires authentication and Vercel cannot resolve its host in the active scope, the flow asks you to select another team, then reruns the lookup in that scope. When access is denied, for example because a team SSO session expired, it re-authenticates and retries.
|
|
11
|
+
- a63dfa2: Remote `eve dev --url` now treats `/eve/v1/info` as best-effort inspection rather than a connection gate. Once authentication succeeds and the deployment is reachable, the session connects even when the agent info route is absent (confirmed via the public health route) or returns an unrecognized shape (e.g. a deployment built from an older eve). Inspection-only data is simply omitted from the header in that case, and the underlying parse failure now names the offending fields instead of an opaque message.
|
|
12
|
+
- a63dfa2: Remote `eve dev --url` sessions now show deployment and authentication state, try refreshed project-scoped OIDC credentials at startup, and open a cancellable `/vc:login` recovery flow when access is rejected. The flow can update the target project's Trusted Sources after confirmation.
|
|
13
|
+
- c5071e6: Ensure every eve Workflow runtime entrypoint installs the eve queue namespace through a single guarded boundary.
|
|
14
|
+
- c9e895b: Fix `eve dev` streaming throughput and time-to-first-token degrading as parked (`ask_question` / HITL) sessions accumulate. The dev runtime's NDJSON event-stream reader now forwards cancellation to the underlying run stream, so disconnecting from a parked session no longer leaks a filesystem polling loop for the life of the dev server.
|
|
15
|
+
- c6b2da8: Add `$eve.channel_request_id` workflow attributes from Vercel's `x-vercel-id` header so session and turn workflow runs can be joined back to the inbound request that started or resumed them.
|
|
16
|
+
- ab3e6e8: Give each threadless proactive Slack session a unique temporary continuation token so overlapping scheduled runs targeting the same channel do not conflict before they anchor to a Slack thread.
|
|
17
|
+
- a63dfa2: The dev TUI's `/vc` and `/login` commands are now `/vc:install` and `/vc:login`. `/vc:login` is the single Vercel authentication command: it logs in locally and, in remote (`eve dev --url`) sessions, recovers access with Vercel OIDC.
|
|
18
|
+
|
|
19
|
+
## 0.13.5
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- c927ecd: Confirm continuation-token ownership before an agent turn starts or a session re-keys. Competing sessions now fail before processing input, and successful delivery reports the hook owner atomically.
|
|
24
|
+
- 5f0f69f: Use Parallel through AI Gateway for the built-in `web_search` tool with every string model. Gateway requests no longer select native provider search tools or pin routing to a model provider.
|
|
25
|
+
- 430ed8c: Teach agents that conditionally delivered work can finish successfully without sending a message. Polling schedules can now intentionally skip delivery without treating an accidental blank model response as success.
|
|
26
|
+
- 25b1b14: fix(eve): catch unserializable tool output values instead of sending them to the model
|
|
27
|
+
|
|
3
28
|
## 0.13.4
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SessionAuthContext } from "#channel/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Framework-owned principal used when a schedule runs on behalf of the agent.
|
|
4
|
+
*/
|
|
5
|
+
export declare const SCHEDULE_APP_AUTH: SessionAuthContext;
|
|
6
|
+
/** Returns whether the current request is authenticated as eve's schedule principal. */
|
|
7
|
+
export declare function isScheduleAppAuth(auth: SessionAuthContext | null | undefined): auth is SessionAuthContext;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const SCHEDULE_APP_AUTH={attributes:{},authenticator:`app`,principalId:`eve:app`,principalType:`runtime`};function isScheduleAppAuth(e){return e?.authenticator===SCHEDULE_APP_AUTH.authenticator&&e.principalId===SCHEDULE_APP_AUTH.principalId&&e.principalType===SCHEDULE_APP_AUTH.principalType}export{SCHEDULE_APP_AUTH,isScheduleAppAuth};
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import type { ChannelAdapter } from "#channel/adapter.js";
|
|
2
2
|
import { type Session } from "#channel/session.js";
|
|
3
|
-
import type { Runtime
|
|
3
|
+
import type { Runtime } from "#channel/types.js";
|
|
4
4
|
import type { ScheduleRunHandler } from "#public/definitions/schedule.js";
|
|
5
5
|
import type { ResolvedChannelDefinition } from "#runtime/types.js";
|
|
6
|
-
|
|
7
|
-
* Pre-built application auth context handed to schedules. Schedules
|
|
8
|
-
* run on behalf of the agent itself, not a downstream user.
|
|
9
|
-
*/
|
|
10
|
-
export declare const SCHEDULE_APP_AUTH: SessionAuthContext;
|
|
6
|
+
export { SCHEDULE_APP_AUTH } from "#channel/schedule-auth.js";
|
|
11
7
|
/**
|
|
12
8
|
* Durable adapter kind used when a schedule fires without targeting a
|
|
13
9
|
* channel — the markdown form, and the synthesized run the dispatcher
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createSession}from"#channel/session.js";import{createCrossChannelReceiveFn,toCrossChannelTargets}from"#channel/cross-channel-receive.js";import{expectFunction}from"#internal/authored-module.js";const
|
|
1
|
+
import{createSession}from"#channel/session.js";import{SCHEDULE_APP_AUTH,SCHEDULE_APP_AUTH as SCHEDULE_APP_AUTH$1}from"#channel/schedule-auth.js";import{createCrossChannelReceiveFn,toCrossChannelTargets}from"#channel/cross-channel-receive.js";import{expectFunction}from"#internal/authored-module.js";const SCHEDULE_ADAPTER_KIND=`schedule`,SCHEDULE_ADAPTER={kind:SCHEDULE_ADAPTER_KIND};var ScheduleDispatcher=class{runtime;channels;constructor(e){this.runtime=e.runtime,this.channels=e.channels}async trigger(e){let t=[],i=[],a=createCrossChannelReceiveFn(this.runtime,toCrossChannelTargets(this.channels)),o={appAuth:SCHEDULE_APP_AUTH$1,receive:async(e,n)=>{let r=await a(e,n);return t.push(r),r},waitUntil(e){i.push(e)}};if(e.run)await e.run(o);else if(e.markdown!==void 0){let n=await this.runMarkdown(e.markdown);t.push(n)}else throw Error(`Schedule "${e.scheduleId}" has neither "run" nor "markdown" — at least one must be set.`);return{sessions:t,waitUntilTasks:i}}async runMarkdown(t){let r=await this.runtime.run({adapter:SCHEDULE_ADAPTER,auth:SCHEDULE_APP_AUTH$1,input:{message:t},mode:`task`});return createSession(r.sessionId,r.continuationToken,this.runtime)}};function expectScheduleRun(e,t,n){let r=e;if(typeof r!=`object`||!r)throw Error(`Schedule export "${n??`default`}" from "${t}" must be an object.`);return expectFunction(r.run,`Expected the schedule export "${n??`default`}" from "${t}" to export a \`run\` handler function.`)}export{SCHEDULE_ADAPTER,SCHEDULE_ADAPTER_KIND,SCHEDULE_APP_AUTH,ScheduleDispatcher,expectScheduleRun};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ChannelAdapter } from "#channel/adapter.js";
|
|
2
2
|
import type { Runtime } from "#channel/types.js";
|
|
3
3
|
import type { SendFn } from "#channel/routes.js";
|
|
4
|
-
export declare function createSendFn<TState = undefined>(runtime: Runtime, adapter: ChannelAdapter<any>, channelName: string
|
|
4
|
+
export declare function createSendFn<TState = undefined>(runtime: Runtime, adapter: ChannelAdapter<any>, channelName: string, metadata?: {
|
|
5
|
+
readonly requestId?: string;
|
|
6
|
+
}): SendFn<TState>;
|
package/dist/src/channel/send.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createSession}from"#channel/session.js";import{createLogger}from"#internal/logging.js";import{isRuntimeNoActiveSessionError}from"#execution/runtime-errors.js";import{serializeUrlFilePart}from"#internal/attachments/url-refs.js";const log=createLogger(`channel.send`);function createSendFn(t,r,i){return async(
|
|
1
|
+
import{createSession}from"#channel/session.js";import{createLogger}from"#internal/logging.js";import{isRuntimeNoActiveSessionError}from"#execution/runtime-errors.js";import{serializeUrlFilePart}from"#internal/attachments/url-refs.js";const log=createLogger(`channel.send`);function createSendFn(t,r,i,a={}){return async(o,s)=>{let c=s.auth,l=s.callback,u=s.mode??`conversation`,d=s.state,f=s.continuationToken,p=`${i}:${f}`,{message:m,inputResponses:h,context:g,outputSchema:_}=normalizeSendInput(o),v=serializeUrlFilePartsInMessage(m);try{let n={auth:c,continuationToken:p,requestId:a.requestId,payload:{inputResponses:h,message:v,context:g,outputSchema:_}},{sessionId:r}=await t.deliver(n);return createSession(r,f,t)}catch(e){isRuntimeNoActiveSessionError(e)||log.warn(`deliver failed, falling back to starting a new session`,{continuationToken:p})}if(h&&h.length>0)throw Error(`Cannot deliver inputResponses — the target session was not found via continuation token.`);let y={adapter:d?{...r,state:{...r.state,...d}}:r,auth:c,capabilities:u===`conversation`?{requestInput:!0}:void 0,channelName:i,callback:l,continuationToken:p,input:{message:v??``,context:g,outputSchema:_},mode:u,requestId:a.requestId};return createSession((await t.run(y)).sessionId,f,t)}}function serializeUrlFilePartsInMessage(e){if(e===void 0||typeof e==`string`)return e;let t=!1,n=e.map(e=>e.type===`file`&&e.data instanceof URL&&e.data.protocol!==`data:`?(t=!0,{...e,data:serializeUrlFilePart(e.data)}):e);return t?n:e}function normalizeSendInput(e){return typeof e==`string`||Array.isArray(e)?{message:e}:e}export{createSendFn};
|
|
@@ -87,6 +87,8 @@ export interface DeliverPayload {
|
|
|
87
87
|
*/
|
|
88
88
|
export interface DeliverHookPayload {
|
|
89
89
|
readonly auth?: SessionAuthContext | null;
|
|
90
|
+
/** Inbound channel request id used only for workflow attributes. */
|
|
91
|
+
readonly requestId?: string;
|
|
90
92
|
readonly kind: "deliver";
|
|
91
93
|
readonly payloads: readonly DeliverPayload[];
|
|
92
94
|
}
|
|
@@ -193,6 +195,8 @@ export interface RunInput {
|
|
|
193
195
|
* leave this undefined.
|
|
194
196
|
*/
|
|
195
197
|
readonly capabilities?: SessionCapabilities;
|
|
198
|
+
/** Inbound channel request id used to correlate workflow attributes. */
|
|
199
|
+
readonly requestId?: string;
|
|
196
200
|
/**
|
|
197
201
|
* Optional terminal callback. When present, the runtime posts a single
|
|
198
202
|
* callback when the session completes or fails.
|
|
@@ -229,6 +233,8 @@ export interface DeliverInput {
|
|
|
229
233
|
* this field before calling the adapter's hooks.
|
|
230
234
|
*/
|
|
231
235
|
readonly auth?: SessionAuthContext | null;
|
|
236
|
+
/** Inbound channel request id used to correlate workflow attributes. */
|
|
237
|
+
readonly requestId?: string;
|
|
232
238
|
readonly continuationToken: string;
|
|
233
239
|
readonly payload: DeliverPayload;
|
|
234
240
|
}
|
|
@@ -20,6 +20,18 @@ function createEveContinueSessionRoutePath(sessionId) {
|
|
|
20
20
|
return `${EVE_ROUTE_PREFIX}/session/${encodeURIComponent(sessionId)}`;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/client/agent-info-error.ts
|
|
25
|
+
var AgentInfoResponseError = class extends Error {
|
|
26
|
+
issues;
|
|
27
|
+
constructor(issues = []) {
|
|
28
|
+
const detail = issues.length === 0 ? "" : ` (${issues.join("; ")})`;
|
|
29
|
+
super(`The server returned an unrecognized response from the eve agent info route.${detail}`);
|
|
30
|
+
this.name = "AgentInfoResponseError";
|
|
31
|
+
this.issues = issues;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
23
35
|
//#endregion
|
|
24
36
|
//#region src/client/agent-info-schema.ts
|
|
25
37
|
const source = z.object({
|
|
@@ -397,10 +409,12 @@ async function* readNdjsonStream(body) {
|
|
|
397
409
|
const reader = body.getReader();
|
|
398
410
|
const decoder = new TextDecoder();
|
|
399
411
|
let buffer = "";
|
|
412
|
+
let reachedEof = false;
|
|
400
413
|
try {
|
|
401
414
|
while (true) {
|
|
402
415
|
const result = await reader.read();
|
|
403
416
|
if (result.done) {
|
|
417
|
+
reachedEof = true;
|
|
404
418
|
buffer += decoder.decode();
|
|
405
419
|
break;
|
|
406
420
|
}
|
|
@@ -416,6 +430,7 @@ async function* readNdjsonStream(body) {
|
|
|
416
430
|
const trailing = buffer.trim();
|
|
417
431
|
if (trailing.length > 0) yield JSON.parse(trailing);
|
|
418
432
|
} finally {
|
|
433
|
+
if (!reachedEof) await reader.cancel().catch(() => {});
|
|
419
434
|
reader.releaseLock();
|
|
420
435
|
}
|
|
421
436
|
}
|
|
@@ -720,8 +735,17 @@ var Client = class {
|
|
|
720
735
|
const body = await response.text();
|
|
721
736
|
throw new ClientError(response.status, body);
|
|
722
737
|
}
|
|
723
|
-
|
|
724
|
-
|
|
738
|
+
let payload;
|
|
739
|
+
try {
|
|
740
|
+
payload = await response.json();
|
|
741
|
+
} catch {
|
|
742
|
+
throw new AgentInfoResponseError();
|
|
743
|
+
}
|
|
744
|
+
const result = AgentInfoResultSchema.safeParse(payload);
|
|
745
|
+
if (!result.success) throw new AgentInfoResponseError(result.error.issues.slice(0, 5).map((issue) => {
|
|
746
|
+
const path = issue.path.join(".");
|
|
747
|
+
return path.length === 0 ? issue.message : `${path}: ${issue.message}`;
|
|
748
|
+
}));
|
|
725
749
|
return result.data;
|
|
726
750
|
}
|
|
727
751
|
async fetch(path, init = {}) {
|
|
@@ -1236,7 +1260,7 @@ function reduceMessageData(data, event) {
|
|
|
1236
1260
|
type: "text"
|
|
1237
1261
|
}));
|
|
1238
1262
|
case "message.completed": return updateAssistantMessage(data, event.data.turnId, (message) => {
|
|
1239
|
-
if (event.data.message === null) return
|
|
1263
|
+
if (event.data.message === null) return removeTextPart(message, event.data.stepIndex);
|
|
1240
1264
|
return upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
|
|
1241
1265
|
state: "done",
|
|
1242
1266
|
stepIndex: event.data.stepIndex,
|
|
@@ -1319,25 +1343,16 @@ function upsertPart(message, next) {
|
|
|
1319
1343
|
parts
|
|
1320
1344
|
};
|
|
1321
1345
|
}
|
|
1322
|
-
function
|
|
1323
|
-
const
|
|
1324
|
-
if (
|
|
1325
|
-
const existing = message.parts[index];
|
|
1326
|
-
if (existing?.type !== "text") return message;
|
|
1346
|
+
function removeTextPart(message, stepIndex) {
|
|
1347
|
+
const parts = message.parts.filter((part) => part.type !== "text" || part.stepIndex !== stepIndex);
|
|
1348
|
+
if (parts.length === message.parts.length) return message;
|
|
1327
1349
|
return {
|
|
1328
1350
|
...message,
|
|
1329
1351
|
metadata: {
|
|
1330
1352
|
...message.metadata,
|
|
1331
1353
|
status: "complete"
|
|
1332
1354
|
},
|
|
1333
|
-
parts
|
|
1334
|
-
...message.parts.slice(0, index),
|
|
1335
|
-
{
|
|
1336
|
-
...existing,
|
|
1337
|
-
state: "done"
|
|
1338
|
-
},
|
|
1339
|
-
...message.parts.slice(index + 1)
|
|
1340
|
-
]
|
|
1355
|
+
parts
|
|
1341
1356
|
};
|
|
1342
1357
|
}
|
|
1343
1358
|
function updateToolPart(data, toolCallId, next) {
|
|
@@ -1459,10 +1474,6 @@ function stringifyUnknown(value) {
|
|
|
1459
1474
|
return "Action failed.";
|
|
1460
1475
|
}
|
|
1461
1476
|
}
|
|
1462
|
-
function findLastIndex(items, predicate) {
|
|
1463
|
-
for (let index = items.length - 1; index >= 0; index -= 1) if (predicate(items[index])) return index;
|
|
1464
|
-
return -1;
|
|
1465
|
-
}
|
|
1466
1477
|
|
|
1467
1478
|
//#endregion
|
|
1468
1479
|
//#region src/svelte/use-eve-agent.ts
|
|
@@ -20,6 +20,18 @@ function createEveContinueSessionRoutePath(sessionId) {
|
|
|
20
20
|
return `${EVE_ROUTE_PREFIX}/session/${encodeURIComponent(sessionId)}`;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/client/agent-info-error.ts
|
|
25
|
+
var AgentInfoResponseError = class extends Error {
|
|
26
|
+
issues;
|
|
27
|
+
constructor(issues = []) {
|
|
28
|
+
const detail = issues.length === 0 ? "" : ` (${issues.join("; ")})`;
|
|
29
|
+
super(`The server returned an unrecognized response from the eve agent info route.${detail}`);
|
|
30
|
+
this.name = "AgentInfoResponseError";
|
|
31
|
+
this.issues = issues;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
23
35
|
//#endregion
|
|
24
36
|
//#region src/client/agent-info-schema.ts
|
|
25
37
|
const source = z.object({
|
|
@@ -397,10 +409,12 @@ async function* readNdjsonStream(body) {
|
|
|
397
409
|
const reader = body.getReader();
|
|
398
410
|
const decoder = new TextDecoder();
|
|
399
411
|
let buffer = "";
|
|
412
|
+
let reachedEof = false;
|
|
400
413
|
try {
|
|
401
414
|
while (true) {
|
|
402
415
|
const result = await reader.read();
|
|
403
416
|
if (result.done) {
|
|
417
|
+
reachedEof = true;
|
|
404
418
|
buffer += decoder.decode();
|
|
405
419
|
break;
|
|
406
420
|
}
|
|
@@ -416,6 +430,7 @@ async function* readNdjsonStream(body) {
|
|
|
416
430
|
const trailing = buffer.trim();
|
|
417
431
|
if (trailing.length > 0) yield JSON.parse(trailing);
|
|
418
432
|
} finally {
|
|
433
|
+
if (!reachedEof) await reader.cancel().catch(() => {});
|
|
419
434
|
reader.releaseLock();
|
|
420
435
|
}
|
|
421
436
|
}
|
|
@@ -720,8 +735,17 @@ var Client = class {
|
|
|
720
735
|
const body = await response.text();
|
|
721
736
|
throw new ClientError(response.status, body);
|
|
722
737
|
}
|
|
723
|
-
|
|
724
|
-
|
|
738
|
+
let payload;
|
|
739
|
+
try {
|
|
740
|
+
payload = await response.json();
|
|
741
|
+
} catch {
|
|
742
|
+
throw new AgentInfoResponseError();
|
|
743
|
+
}
|
|
744
|
+
const result = AgentInfoResultSchema.safeParse(payload);
|
|
745
|
+
if (!result.success) throw new AgentInfoResponseError(result.error.issues.slice(0, 5).map((issue) => {
|
|
746
|
+
const path = issue.path.join(".");
|
|
747
|
+
return path.length === 0 ? issue.message : `${path}: ${issue.message}`;
|
|
748
|
+
}));
|
|
725
749
|
return result.data;
|
|
726
750
|
}
|
|
727
751
|
async fetch(path, init = {}) {
|
|
@@ -1236,7 +1260,7 @@ function reduceMessageData(data, event) {
|
|
|
1236
1260
|
type: "text"
|
|
1237
1261
|
}));
|
|
1238
1262
|
case "message.completed": return updateAssistantMessage(data, event.data.turnId, (message) => {
|
|
1239
|
-
if (event.data.message === null) return
|
|
1263
|
+
if (event.data.message === null) return removeTextPart(message, event.data.stepIndex);
|
|
1240
1264
|
return upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
|
|
1241
1265
|
state: "done",
|
|
1242
1266
|
stepIndex: event.data.stepIndex,
|
|
@@ -1319,25 +1343,16 @@ function upsertPart(message, next) {
|
|
|
1319
1343
|
parts
|
|
1320
1344
|
};
|
|
1321
1345
|
}
|
|
1322
|
-
function
|
|
1323
|
-
const
|
|
1324
|
-
if (
|
|
1325
|
-
const existing = message.parts[index];
|
|
1326
|
-
if (existing?.type !== "text") return message;
|
|
1346
|
+
function removeTextPart(message, stepIndex) {
|
|
1347
|
+
const parts = message.parts.filter((part) => part.type !== "text" || part.stepIndex !== stepIndex);
|
|
1348
|
+
if (parts.length === message.parts.length) return message;
|
|
1327
1349
|
return {
|
|
1328
1350
|
...message,
|
|
1329
1351
|
metadata: {
|
|
1330
1352
|
...message.metadata,
|
|
1331
1353
|
status: "complete"
|
|
1332
1354
|
},
|
|
1333
|
-
parts
|
|
1334
|
-
...message.parts.slice(0, index),
|
|
1335
|
-
{
|
|
1336
|
-
...existing,
|
|
1337
|
-
state: "done"
|
|
1338
|
-
},
|
|
1339
|
-
...message.parts.slice(index + 1)
|
|
1340
|
-
]
|
|
1355
|
+
parts
|
|
1341
1356
|
};
|
|
1342
1357
|
}
|
|
1343
1358
|
function updateToolPart(data, toolCallId, next) {
|
|
@@ -1459,10 +1474,6 @@ function stringifyUnknown(value) {
|
|
|
1459
1474
|
return "Action failed.";
|
|
1460
1475
|
}
|
|
1461
1476
|
}
|
|
1462
|
-
function findLastIndex(items, predicate) {
|
|
1463
|
-
for (let index = items.length - 1; index >= 0; index -= 1) if (predicate(items[index])) return index;
|
|
1464
|
-
return -1;
|
|
1465
|
-
}
|
|
1466
1477
|
|
|
1467
1478
|
//#endregion
|
|
1468
1479
|
//#region src/vue/use-eve-agent.ts
|
|
@@ -39,7 +39,7 @@ export interface Block {
|
|
|
39
39
|
* rendered dim beneath the headline, capped to a handful of lines.
|
|
40
40
|
*/
|
|
41
41
|
detail?: string;
|
|
42
|
-
/** Tool
|
|
42
|
+
/** Tool, connection, or synthetic command lifecycle status. */
|
|
43
43
|
status?: ToolStatus;
|
|
44
44
|
/** When true, treat `body` as pre-styled and only wrap + indent it. */
|
|
45
45
|
preformatted?: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import{sliceVisible,visibleLength,wrapVisibleLine}from"./terminal-text.js";import{formatValuePretty,truncate}from"./tool-format.js";import{renderMarkdown}from"./markdown.js";import{isPromptControlCommand}from"./prompt-commands.js";function renderBlockLines(e,n,r,i){let a=nestingPrefix(e.depth??0,r);return renderBody(e,Math.max(8,n-visibleLength(a)),r,i).map(e=>`${a}${e}`)}function nestingPrefix(e,t){return e<=0?``:`${t.colors.orange(t.glyph.rule)} `.repeat(e)}function renderBody(e,t,n,r){switch(e.kind){case`user`:return renderUser(e,t,n);case`assistant`:case`subagent-step`:return renderProse(e,t,n);case`reasoning`:return renderReasoning(e,t,n);case`tool`:case`subagent-tool`:return renderTool(e,t,n,r);case`error`:return renderError(e,t,n);case`notice`:return renderNotice(e,t,n);case`warning`:return renderWarning(e,t,n);case`result`:return renderResult(e,t,n);case`flow`:return renderFlow(e,t,n);case`command`:return renderCommand(e,n);case`question`:case`connection-auth`:return renderPreformatted(e,t,n);case`sandbox`:return renderSandbox(e,t,n,r);case`log`:return renderLog(e,t,n,r);case`subagent`:return renderSubagentHeader(e,t,n);case`agent-header`:return(e.body??``).split(`
|
|
2
2
|
`)}}function renderUser(e,t,n){let r=n.colors.cyan(n.glyph.user);return wrap(e.body??``,t-2).map(e=>`${r} ${e}`)}function renderProse(e,t,r){let i=[],o=e.kind===`subagent-step`,s=o?``:`${r.colors.bold(r.colors.white(r.glyph.brand))} `,c=o?``:` `;e.reasoning&&e.reasoning.trim().length>0&&i.push(...renderReasoningLines(e.reasoning,t,r));let l=(e.body??``).trim();return l.length===0&&i.length===0?[`${s}${r.colors.dim(`thinking${r.glyph.ellipsis}`)}`]:(l.length>0&&renderMarkdown(l).split(`
|
|
3
3
|
`).flatMap(e=>wrapVisibleLine(e,t-c.length)).forEach((e,t)=>{t===0&&!o&&i.length===0?i.push(`${s}${e}`):i.push(`${c}${e}`)}),i.length>0?i:[`${s}`])}function renderReasoning(e,t,n){return e.collapsed?[`${n.colors.gray(n.glyph.reasoning)} ${n.colors.dim(`thinking`)}`]:renderReasoningLines(e.body??``,t,n,n.glyph.reasoning)}function renderReasoningLines(e,t,n,r){let i=r?2:0,a=wrap(e.trim(),t-i);return a.length===0?[]:a.map((e,t)=>`${r?t===0?`${n.colors.gray(r)} `:` `:``}${n.colors.dim(n.colors.italic(e))}`)}function renderTool(e,t,n,r){let{icon:a,accent:o}=toolGlyph(e.status??`running`,n,r),s=e.title??`tool`,c=t-2,l=truncatePlain(s,c),u=`${a} ${n.colors.bold(l)}`,d=c-l.length-2,f=e.subtitle??``;f.length>0&&d>=6&&(u+=` ${n.colors.gray(truncate(f,d))}`);let p=[u];return e.expanded?p.push(...renderToolExpanded(e,t,n)):e.status===`done`&&e.result&&e.result.length>0?p.push(resultLine(n.glyph.arrow,e.result,t,n,o)):e.status===`error`&&e.result?p.push(resultLine(n.glyph.arrow,e.result,t,n,n.colors.red)):e.status===`denied`&&p.push(resultLine(n.glyph.arrow,`denied`,t,n,n.colors.yellow)),p}function renderToolExpanded(e,t,n){let i=[],push=(e,a,o)=>{if(a!==void 0){i.push(` ${n.colors.dim(e)}`);for(let e of wrap(formatValuePretty(a),t-4))i.push(` ${o(e)}`)}};return push(`input`,e.toolInput,n.colors.gray),e.status===`error`&&e.result?push(`error`,e.result,n.colors.red):push(`output`,e.toolOutput,n.colors.gray),i}function resultLine(e,t,n,r,a){let o=n-4;return` ${r.colors.dim(e)} ${a(truncate(t,o))}`}function toolGlyph(e,t,n){switch(e){case`done`:return{icon:t.colors.green(t.glyph.success),accent:t.colors.gray};case`error`:return{icon:t.colors.red(t.glyph.error),accent:t.colors.red};case`denied`:return{icon:t.colors.yellow(t.glyph.warning),accent:t.colors.yellow};case`approval`:return{icon:t.colors.yellow(t.glyph.question),accent:t.colors.yellow};default:return{icon:t.colors.yellow(n.spinner),accent:t.colors.gray}}}function renderError(e,t,n){let r=n.colors.red(n.colors.bold(n.glyph.error)),i=e.title??`Error`,a=[`${r} ${n.colors.red(n.colors.bold(i))}`];for(let r of wrap(e.body??``,t-2))a.push(` ${colorizeError(r,n)}`);return a.push(...renderErrorDetail(e.detail,t,n)),a}function renderErrorDetail(e,t,n){if(e===void 0||e.trim().length===0)return[];let r=e.split(`
|
|
4
|
-
`),i=r.slice(0,12),a=i.map(e=>` ${n.colors.dim(truncatePlain(e,Math.max(1,t-2)))}`),o=r.length-i.length;return o>0&&a.push(` ${n.colors.dim(`${n.glyph.ellipsis} +${o} more line${o===1?``:`s`}`)}`),a}const URL_PATTERN=/(https?:\/\/\S+)/u;function colorizeError(e,t){return URL_PATTERN.test(e)?e.split(URL_PATTERN).map((e,n)=>n%2==1?t.colors.cyan(e):t.colors.red(e)).join(``):t.colors.red(e)}function renderNotice(e,t,n){let r=n.colors.dim(n.glyph.dot),i=wrap(e.body??``,t-2);return i.length===0?[r]:i.map(e=>`${r} ${n.colors.dim(e)}`)}function renderAttentionRows(e,t,n){let r=n.colors.yellow(n.glyph.warning);return wrap(e,t-2).map((e,t)=>`${t===0?r:` `} ${paintCommands(e,n)}`)}function renderWarning(e,t,n){return renderAttentionRows(e.body??``,t,n)}function paintCommands(e,t){return e.replace(/\/[a-z
|
|
4
|
+
`),i=r.slice(0,12),a=i.map(e=>` ${n.colors.dim(truncatePlain(e,Math.max(1,t-2)))}`),o=r.length-i.length;return o>0&&a.push(` ${n.colors.dim(`${n.glyph.ellipsis} +${o} more line${o===1?``:`s`}`)}`),a}const URL_PATTERN=/(https?:\/\/\S+)/u;function colorizeError(e,t){return URL_PATTERN.test(e)?e.split(URL_PATTERN).map((e,n)=>n%2==1?t.colors.cyan(e):t.colors.red(e)).join(``):t.colors.red(e)}function renderNotice(e,t,n){let r=n.colors.dim(n.glyph.dot),i=wrap(e.body??``,t-2);return i.length===0?[r]:i.map(e=>`${r} ${n.colors.dim(e)}`)}function renderAttentionRows(e,t,n){let r=n.colors.yellow(n.glyph.warning);return wrap(e,t-2).map((e,t)=>`${t===0?r:` `} ${paintCommands(e,n)}`)}function renderWarning(e,t,n){return renderAttentionRows(e.body??``,t,n)}function paintCommands(e,t){return e.replace(/\/[a-z:-]+/g,e=>isPromptControlCommand(e)?t.colors.blue(e):e)}function renderCommand(e,t){let n=t.colors,r=e.status===`error`?`${n.red(t.glyph.error)} `:``;return[`${n.cyan(t.glyph.user)} ${r}${n.blue(e.body??``)}`]}function renderFlow(e,t,n){let r=n.colors,i=e.title??`info`,a=i===`success`?r.green(n.glyph.success):i===`warning`?r.yellow(n.glyph.warning):i===`error`?r.red(n.glyph.error):r.dim(n.glyph.dot),o=wrap(e.body??``,t-2),paint=e=>i===`info`?r.dim(e):e;return o.map((e,t)=>`${t===0?a:` `} ${paint(e)}`)}function renderResult(e,t,n){let r=n.colors.dim(n.glyph.elbow),i=wrap(e.body??``,t-7);if(i.length===0)return[` ${r}`];let dim=e=>n.colors.dim(e.replaceAll(`\x1B[22m`,`\x1B[22m\x1B[2m`));return i.map((e,t)=>t===0?` ${r} ${dim(e)}`:` ${dim(e)}`)}function renderPreformatted(e,t,r){let i=e.kind===`connection-auth`?r.colors.yellow(r.glyph.connection):r.colors.yellow(r.colors.bold(r.glyph.question)),a=wrap(e.title??``,t-2),o=a.length===0?[`${i} `]:a.map((e,t)=>t===0?`${i} ${r.colors.bold(e)}`:` ${r.colors.bold(e)}`);for(let r of(e.body??``).split(`
|
|
5
5
|
`))for(let e of wrapVisibleLine(r,t-2))o.push(` ${e}`);return o}function renderSandbox(e,r,i,a){let o=i.colors.cyan(i.glyph.rule),s=i.colors.dim(`sandbox ${i.glyph.dot} `),c=visibleLength(s),l=` `.repeat(c),u=a.previous?.kind===`sandbox`,d=(e.body??``).split(`
|
|
6
6
|
`),f=[];for(let e of d){let t=wrapVisibleLine(e,Math.max(1,r-2-c));for(let e of t){let t=f.length===0&&!u?s:l;f.push(`${o} ${t}${i.colors.gray(e)}`)}}return f.length>0?f:[`${o}`]}function renderLog(e,r,i,a){let o=e.title===`stderr`,s=o?i.colors.red:i.colors.gray,c=i.colors.dim(i.glyph.rule),l=o?`stderr`:`stdout`,u=i.colors.dim(`${l} ${i.glyph.dot} `),d=visibleLength(u),f=` `.repeat(d),p=a.previous?.kind===`log`&&a.previous.title===e.title,m=(e.body??``).split(`
|
|
7
7
|
`),h=[];for(let e of m){let t=wrapVisibleLine(e,Math.max(1,r-2-d));for(let e of t){let t=h.length===0&&!p?u:f;h.push(`${c} ${t}${i.colors.dim(s(e))}`)}}return h.length>0?h:[`${c}`]}function renderSubagentHeader(e,t,n){let r=truncatePlain(e.title??`subagent`,Math.max(8,t-14));return[`${n.colors.orange(n.glyph.subagent)} ${n.colors.bold(r)} ${n.colors.dim(`subagent`)}`]}function wrap(e,t){return e.trim().length===0?[]:e.split(`
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { ApplyModelOutcome } from "#setup/flows/model.js";
|
|
2
2
|
import type { PromptCommandHandler } from "./runner.js";
|
|
3
|
+
import type { RemoteAuthFlow } from "./remote-auth.js";
|
|
3
4
|
import type { TuiSetupFlows } from "./setup-commands.js";
|
|
5
|
+
import type { DevelopmentTuiTarget } from "./target.js";
|
|
4
6
|
export interface PromptCommandHandlerOptions {
|
|
5
|
-
readonly
|
|
7
|
+
readonly target: DevelopmentTuiTarget;
|
|
6
8
|
/** Test seam; defaults to the model flow's shared source-change apply. */
|
|
7
9
|
readonly applyModel?: (input: {
|
|
8
10
|
appRoot: string;
|
|
@@ -12,5 +14,7 @@ export interface PromptCommandHandlerOptions {
|
|
|
12
14
|
readonly modelChangeRefusal?: (appRoot: string) => Promise<string | null>;
|
|
13
15
|
/** Test seam; forwarded to runTuiSetupCommand's injectable flows. */
|
|
14
16
|
readonly flows?: Partial<TuiSetupFlows>;
|
|
17
|
+
/** Test seam for remote authentication. */
|
|
18
|
+
readonly remoteAuthFlow?: RemoteAuthFlow;
|
|
15
19
|
}
|
|
16
20
|
export declare function createPromptCommandHandler(options: PromptCommandHandlerOptions): PromptCommandHandler;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{toErrorMessage}from"#shared/errors.js";function createPromptCommandHandler(
|
|
1
|
+
import{isPromptCommandAvailableFor}from"./prompt-commands.js";import{toErrorMessage}from"#shared/errors.js";function createPromptCommandHandler(n){return{async handle(r,i){let{target:a}=n;if(a.kind===`remote`&&!isPromptCommandAvailableFor(r.name,`remote`))return{message:`/${r.name} needs eve dev running the local server (it is not available with --url).`};if(r.name===`model`&&r.argument.length>0){if(a.kind!==`local`)return{message:`/model needs eve dev running the local server (it is not available with --url).`};let e=a.workspaceRoot;try{let{changeAgentModel:t,formatApplyModelOutcome:i,modelChangeRefusalForUneditableModel:a}=await import(`#setup/flows/model.js`),o=await(n.modelChangeRefusal??a)(e);return o===null?{message:i(await(n.applyModel??t)({appRoot:e,slug:r.argument}))}:{message:o}}catch(e){return{message:`Couldn't change the model: ${toErrorMessage(e)}`}}}let o=i.renderer.setupFlow;if(o===void 0)return{message:`/${r.name} is not supported by this renderer.`};if(r.name===`vc:login`&&a.kind===`remote`){if(i.remoteConnection===void 0)return{message:`/vc:login is not available in this session.`};let e;try{({runRemoteAuthCommand:e}=await import(`./remote-auth-command.js`))}catch(e){return{message:`/vc:login failed: ${toErrorMessage(e)}`}}return{message:await e({connection:i.remoteConnection,flow:n.remoteAuthFlow,renderer:o})}}let s;try{s=await import(`./setup-commands.js`)}catch(e){return{message:`/${r.name} failed: ${toErrorMessage(e)}`}}let{runTuiSetupCommand:c,SETUP_FLOW_CONFIG:l}=s,u=l[r.name];o.begin(u.title,u.indicator);let d=!0;try{let e={command:r.name,appRoot:a.workspaceRoot,renderer:o};i.initialModelStep!==void 0&&(e.initialModelStep=i.initialModelStep),n.flows!==void 0&&(e.flows=n.flows);let t=await c(e);d=t.preserveFlowDiagnostics;let s={message:t.message};return t.effect!==void 0&&(s.effect=t.effect),s}finally{o.end({preserveDiagnostics:d})}}}}export{createPromptCommandHandler};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export type PromptCommandExtensionName = "model" | "channels" | "deploy" | "
|
|
1
|
+
export type PromptCommandExtensionName = "model" | "channels" | "deploy" | "vc:install" | "vc:login";
|
|
2
|
+
type PromptCommandTarget = "local" | "remote";
|
|
2
3
|
/** The slash commands the prompt accepts. */
|
|
3
4
|
export type PromptCommand = {
|
|
4
5
|
type: "new";
|
|
@@ -32,12 +33,10 @@ export interface PromptCommandSpec {
|
|
|
32
33
|
/** Maps a recognized invocation to its parsed command. */
|
|
33
34
|
readonly build: (argument: string) => PromptCommand;
|
|
34
35
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Every slash command the prompt accepts, in typeahead display order. One
|
|
37
|
-
* module owns the command list so the runner's dispatch, the renderer's
|
|
38
|
-
* transcript-echo suppression, and command discovery cannot drift apart.
|
|
39
|
-
*/
|
|
40
36
|
export declare const PROMPT_COMMANDS: readonly PromptCommandSpec[];
|
|
37
|
+
export declare function promptCommandsFor(target: PromptCommandTarget): readonly PromptCommandSpec[];
|
|
38
|
+
/** Whether a command runs against this target — the one authority dispatch shares with discovery. */
|
|
39
|
+
export declare function isPromptCommandAvailableFor(name: PromptCommandExtensionName, target: PromptCommandTarget): boolean;
|
|
41
40
|
/**
|
|
42
41
|
* Recognizes the slash commands the prompt accepts. `/new` clears the
|
|
43
42
|
* session and transcript; `/exit` (and `/quit`) terminate the TUI like
|
|
@@ -51,4 +50,5 @@ export declare function isPromptControlCommand(prompt: string): boolean;
|
|
|
51
50
|
* The table `/help` prints: one line per command — slash name, argument
|
|
52
51
|
* hint, and aliases padded into a column, description after.
|
|
53
52
|
*/
|
|
54
|
-
export declare function formatPromptCommandHelp(): string;
|
|
53
|
+
export declare function formatPromptCommandHelp(commands?: readonly PromptCommandSpec[]): string;
|
|
54
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const
|
|
2
|
-
`)}export{PROMPT_COMMANDS,formatPromptCommandHelp,isPromptControlCommand,parsePromptCommand};
|
|
1
|
+
const PROMPT_COMMAND_DEFINITIONS=[{name:`help`,aliases:[],description:`Show available commands`,takesArgument:!1,build:()=>({type:`help`}),targets:[`local`,`remote`]},{name:`new`,aliases:[],description:`Start a fresh session`,takesArgument:!1,build:()=>({type:`new`}),targets:[`local`,`remote`]},{name:`vc:install`,aliases:[],description:`Install the Vercel CLI`,takesArgument:!1,build:()=>({type:`extension`,name:`vc:install`,argument:``}),targets:[`local`,`remote`]},{name:`vc:login`,aliases:[],description:`Authenticate with Vercel`,takesArgument:!1,build:()=>({type:`extension`,name:`vc:login`,argument:``}),targets:[`local`,`remote`]},{name:`model`,aliases:[],description:`Configure the agent's model and provider`,argumentHint:`[provider/model]`,takesArgument:!0,build:e=>({type:`extension`,name:`model`,argument:e}),targets:[`local`]},{name:`loglevel`,aliases:[],description:`Show or hide captured stdout/stderr/sandbox logs`,argumentHint:`[all|stderr|sandbox|none]`,takesArgument:!0,build:e=>({type:`loglevel`,argument:e}),targets:[`local`,`remote`]},{name:`channels`,aliases:[],description:`Add chat channels to the agent`,takesArgument:!1,build:()=>({type:`extension`,name:`channels`,argument:``}),targets:[`local`]},{name:`deploy`,aliases:[],description:`Deploy the agent to Vercel`,takesArgument:!1,build:()=>({type:`extension`,name:`deploy`,argument:``}),targets:[`local`]},{name:`exit`,aliases:[`quit`],description:`Quit the TUI`,takesArgument:!1,build:()=>({type:`exit`}),targets:[`local`,`remote`]}],PROMPT_COMMANDS=PROMPT_COMMAND_DEFINITIONS;function promptCommandsFor(t){return PROMPT_COMMAND_DEFINITIONS.filter(e=>e.targets.some(e=>e===t))}function isPromptCommandAvailableFor(t,n){return(PROMPT_COMMAND_DEFINITIONS.find(e=>e.name===t)?.targets)?.includes(n)??!1}function parsePromptCommand(e){let n=e.trim();if(!n.startsWith(`/`))return null;for(let e of PROMPT_COMMANDS)for(let t of[e.name,...e.aliases]){let r=`/${t}`;if(n===r)return e.build(``);if(e.takesArgument&&n.startsWith(`${r} `))return e.build(n.slice(r.length).trim())}return null}function isPromptControlCommand(e){return parsePromptCommand(e)!==null}function formatPromptCommandHelp(e=PROMPT_COMMANDS){let n=e.map(e=>{let t=e.argumentHint===void 0?``:` ${e.argumentHint}`,n=e.aliases.map(e=>` (/${e})`).join(``);return{invocation:`/${e.name}${t}${n}`,description:e.description}}),r=Math.max(...n.map(e=>e.invocation.length))+2;return n.map(e=>e.invocation.padEnd(r)+e.description).join(`
|
|
2
|
+
`)}export{PROMPT_COMMANDS,formatPromptCommandHelp,isPromptCommandAvailableFor,isPromptControlCommand,parsePromptCommand,promptCommandsFor};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type RemoteAuthFlow } from "./remote-auth.js";
|
|
2
|
+
import type { RemoteConnectionController } from "./remote-connection.js";
|
|
3
|
+
import type { SetupFlowRenderer } from "./setup-flow.js";
|
|
4
|
+
interface RemoteAuthCommandInput {
|
|
5
|
+
readonly connection: RemoteConnectionController;
|
|
6
|
+
readonly flow?: RemoteAuthFlow;
|
|
7
|
+
readonly renderer: SetupFlowRenderer;
|
|
8
|
+
}
|
|
9
|
+
/** Runs remote `/vc:login` through one TUI panel, connection operation, and auth flow. */
|
|
10
|
+
export declare function runRemoteAuthCommand(input: RemoteAuthCommandInput): Promise<string>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{createTuiPrompter}from"./tui-prompter.js";import{describeRemoteAuthCompletedMutations}from"./remote-auth-result.js";import{runRemoteAuthFlow}from"./remote-auth.js";import{remoteHost}from"./target.js";import{WizardCancelledError}from"#setup/step.js";function shouldConfigureTrustedSources(e){switch(e.state){case`auth-required`:case`auth-failed`:return e.challenge.kind===`vercel-deployment-protection`;case`unavailable`:return e.failure.code===`TRUSTED_SOURCES_ENVIRONMENT_MISMATCH`;case`checking`:case`authenticating`:case`ready`:return!1}}function unavailableAfterAuthentication(e,t){let[n=t,...r]=t.split(/\n\s*\n/u);return[`Authentication was refreshed, but ${e} is unavailable: ${/[.!?]$/u.test(n.trim())?n.trim():`${n.trim()}.`}`,...r.map(e=>e.trim()).filter(e=>e.length>0)].join(`
|
|
2
|
+
|
|
3
|
+
`)}function mutedRenderer(e,t){return{readSelect:n=>t()?Promise.resolve(void 0):e.readSelect(n),readEditableSelect:n=>t()?Promise.resolve(void 0):e.readEditableSelect(n),readText:n=>t()?Promise.resolve(void 0):e.readText(n),readAcknowledge:n=>t()?Promise.resolve():e.readAcknowledge(n),readChoice:n=>t()?{choice:Promise.resolve(void 0),close:()=>{}}:e.readChoice(n),setStatus:n=>{t()||e.setStatus(n)},renderLine:(n,r)=>{(!t()||r===`warning`||r===`error`)&&e.renderLine(n,r)},renderOutput:n=>{t()||e.renderOutput(n)}}}async function runRemoteAuthCommand(i){i.renderer.begin(`Authenticate via Vercel OIDC`,`pulse`);let a=!0,o=!1,s=new AbortController,c=i.renderer.waitForInterrupt(),l=i.connection.current().target;try{let u=i.flow??runRemoteAuthFlow,d=shouldConfigureTrustedSources(i.connection.current().connection),f=createTuiPrompter(mutedRenderer(i.renderer,()=>o)),p=i.connection.authenticate(async e=>{let t=await u({workspaceRoot:l.workspaceRoot,serverUrl:l.serverUrl,configureTrustedSources:d,prompter:f,signal:e});return a=t.kind===`failed`,t},s.signal),m=await Promise.race([p.then(e=>({kind:`completed`,outcome:e})),c.promise.then(()=>({kind:`interrupted`}))]);m.kind===`interrupted`&&(o=!0,a=!0,s.abort(new WizardCancelledError));let h=m.kind===`completed`?m.outcome:await p;switch(h.kind){case`authenticated`:return`Authenticated ${remoteHost(l)} via Vercel OIDC.`;case`cancelled`:if(o){let e=describeRemoteAuthCompletedMutations(h.completedMutations);return e.length===0?`/vc:login interrupted.`:`/vc:login interrupted. Completed before interruption: ${e.join(`, `)}.`}return h.completedMutations.some(e=>e.kind===`vercel-login`)?`/vc:login cancelled after logging in to Vercel.`:`/vc:login cancelled.`;case`failed`:return h.message;case`unavailable`:return unavailableAfterAuthentication(remoteHost(l),h.failure.message)}}finally{c.dispose(),i.renderer.setStatus(void 0),i.renderer.end({preserveDiagnostics:a})}}export{runRemoteAuthCommand};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { VerifiedVercelTarget } from "#setup/vercel-deployment.js";
|
|
2
2
|
export type RemoteAuthCompletedMutation = {
|
|
3
3
|
readonly kind: "vercel-login";
|
|
4
|
+
} | {
|
|
5
|
+
readonly kind: "trusted-sources-updated";
|
|
6
|
+
readonly targetProjectName: string;
|
|
4
7
|
};
|
|
5
8
|
export type RemoteAuthPreparation = {
|
|
6
9
|
readonly kind: "prepared";
|
|
@@ -19,3 +22,5 @@ export type RemoteAuthPreparation = {
|
|
|
19
22
|
export declare function describeRemoteAuthCompletedMutations(completedMutations: readonly RemoteAuthCompletedMutation[]): string[];
|
|
20
23
|
/** Adds the mutations that cannot be rolled back to an authentication failure. */
|
|
21
24
|
export declare function appendRemoteAuthMutationSummary(message: string, completedMutations: readonly RemoteAuthCompletedMutation[]): string;
|
|
25
|
+
/** Formats a Vercel Deployment Protection challenge for the remote TUI. */
|
|
26
|
+
export declare function formatRemoteAuthChallengeMessage(serverUrl: string): string;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
function describeRemoteAuthCompletedMutations(e){return e.map(e=>{switch(e.kind){case`vercel-login`:return`logged in to Vercel`}})}function appendRemoteAuthMutationSummary(e,t){let n=describeRemoteAuthCompletedMutations(t);return n.length===0?e:`${e} Completed before the failure: ${n.join(`, `)}.`}
|
|
1
|
+
function describeRemoteAuthCompletedMutations(e){return e.map(e=>{switch(e.kind){case`vercel-login`:return`logged in to Vercel`;case`trusted-sources-updated`:return`updated Trusted Sources for ${e.targetProjectName}`}})}function appendRemoteAuthMutationSummary(e,t){let n=describeRemoteAuthCompletedMutations(t);return n.length===0?e:`${e} Completed before the failure: ${n.join(`, `)}.`}function formatRemoteAuthChallengeMessage(e){return[`Vercel Deployment Protection blocked the request to ${e}.`,``,"To access the deployment from `eve dev`, do one of:"," • Run `/vc:login` to authenticate this remote via Vercel OIDC.",` • Set VERCEL_AUTOMATION_BYPASS_SECRET to a Protection Bypass for`,` Automation token (Project Settings → Deployment Protection).`,` • Disable Deployment Protection on the target deployment.`,``,`Docs: https://vercel.com/docs/deployment-protection`].join(`
|
|
2
|
+
`)}export{appendRemoteAuthMutationSummary,describeRemoteAuthCompletedMutations,formatRemoteAuthChallengeMessage};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { resolveDevelopmentOidcToken } from "#services/dev-client/request-headers.js";
|
|
2
|
+
import { runLoginFlow } from "#setup/flows/login.js";
|
|
3
|
+
import type { Prompter } from "#setup/prompter.js";
|
|
4
|
+
import { pickTeam } from "#setup/vercel-project.js";
|
|
5
|
+
import { resolveVercelDeployment } from "#setup/vercel-deployment.js";
|
|
6
|
+
import { applyVercelTrustedSourceAccess, prepareVercelTrustedSourceAccess } from "./vercel-trusted-sources.js";
|
|
7
|
+
import { type RemoteAuthPreparation } from "./remote-auth-result.js";
|
|
8
|
+
/** Injectable entry point for the remote authentication flow. */
|
|
9
|
+
export type RemoteAuthFlow = typeof runRemoteAuthFlow;
|
|
10
|
+
export interface RemoteAuthFlowDeps {
|
|
11
|
+
readonly runLoginFlow: typeof runLoginFlow;
|
|
12
|
+
readonly pickTeam: typeof pickTeam;
|
|
13
|
+
readonly resolveVercelDeployment: typeof resolveVercelDeployment;
|
|
14
|
+
readonly resolveOidcToken: typeof resolveDevelopmentOidcToken;
|
|
15
|
+
readonly prepareVercelTrustedSourceAccess: typeof prepareVercelTrustedSourceAccess;
|
|
16
|
+
readonly applyVercelTrustedSourceAccess: typeof applyVercelTrustedSourceAccess;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Authenticates a remote by resolving its deployment URL to the owning Vercel
|
|
20
|
+
* project, updating Trusted Sources when needed and keeping the resolved
|
|
21
|
+
* credential in this TUI session.
|
|
22
|
+
*/
|
|
23
|
+
export declare function runRemoteAuthFlow(input: {
|
|
24
|
+
readonly workspaceRoot: string;
|
|
25
|
+
readonly serverUrl: string;
|
|
26
|
+
readonly configureTrustedSources?: boolean;
|
|
27
|
+
readonly prompter: Prompter;
|
|
28
|
+
readonly signal?: AbortSignal;
|
|
29
|
+
readonly deps?: Partial<RemoteAuthFlowDeps>;
|
|
30
|
+
}): Promise<RemoteAuthPreparation>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{__toESM}from"../../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{applyVercelTrustedSourceAccess,prepareVercelTrustedSourceAccess}from"./vercel-trusted-sources.js";import{appendRemoteAuthMutationSummary}from"./remote-auth-result.js";import{WizardCancelledError}from"#setup/step.js";import{toErrorMessage}from"#shared/errors.js";import{resolveDevelopmentOidcToken}from"#services/dev-client/request-headers.js";import{formatDevelopmentOidcTokenFailure}from"#services/dev-client/vercel-auth-error.js";import{runLoginFlow}from"#setup/flows/login.js";import{pickTeam}from"#setup/vercel-project.js";import{resolveVercelDeployment}from"#setup/vercel-deployment.js";var import_picocolors=__toESM(require_picocolors(),1);const defaultDeps={runLoginFlow,pickTeam,resolveVercelDeployment,resolveOidcToken:resolveDevelopmentOidcToken,prepareVercelTrustedSourceAccess,applyVercelTrustedSourceAccess};function failed(e,t=[]){return{kind:`failed`,message:appendRemoteAuthMutationSummary(e,t),completedMutations:[...t]}}function cancelled(e=[]){return{kind:`cancelled`,completedMutations:[...e]}}function loginFailure(e){switch(e.kind){case`already`:case`logged-in`:return;case`cancelled`:return cancelled();case`cli-missing`:return failed("The Vercel CLI is not installed. Install it with `npm i -g vercel@latest`, then retry /vc:login.");case`failed`:return failed(`Vercel login did not complete. Retry /vc:login.`);case`unavailable`:return failed(`Vercel could not verify your account. Check your connection, then retry /vc:login.`)}}function deploymentFailureMessage(e){return e.cause===`vercel`?e.failure.message:e.message}async function selectVercelDeploymentScope(e,t,n,r,i){return await e.pickTeam(r,t,void 0,{signal:i,selectMessage:e=>`${import_picocolors.default.blue(n)} is not accessible via current team (${import_picocolors.default.bold(e)})\nYou can try selecting another team:`})}async function runRemoteAuthFlow(e){let{workspaceRoot:t,serverUrl:n,prompter:r,signal:i}=e,a=new URL(n).host,o={...defaultDeps,...e.deps},s=[],c=!1;try{let n=await o.runLoginFlow({appRoot:t,prompter:r,signal:i}),l=loginFailure(n);if(l!==void 0)return l;n.kind===`logged-in`&&s.push({kind:`vercel-login`});let u=await o.resolveVercelDeployment({workspaceRoot:t,host:a,signal:i});if(u.kind===`forbidden`){let e=await o.runLoginFlow({appRoot:t,force:!0,prompter:r,signal:i}),n=loginFailure(e);if(n!==void 0)return n;e.kind===`logged-in`&&s.push({kind:`vercel-login`}),i?.throwIfAborted(),u=await o.resolveVercelDeployment({workspaceRoot:t,host:a,signal:i})}if(u.kind===`not-found`)try{let e=await selectVercelDeploymentScope(o,t,a,r,i);i?.throwIfAborted(),u=await o.resolveVercelDeployment({workspaceRoot:t,host:a,scope:e,signal:i})}catch(e){return e instanceof WizardCancelledError?cancelled(s):(i?.throwIfAborted(),failed(`Could not select a Vercel team: ${toErrorMessage(e)}`,s))}let d;switch(u.kind){case`resolved`:d=u.target;break;case`cancelled`:return cancelled(s);case`forbidden`:return failed(`Could not access ${a}. Re-authenticate (for example to complete a team's SSO), then retry /vc:login.`,s);case`not-found`:return failed(`Vercel did not resolve ${a} for the selected Vercel team.`,s);case`project-mismatch`:return failed(`Could not verify ${a}: Vercel resolved project ${u.actualProjectId}, not ${u.expectedProjectId}.`,s);case`failed`:return failed(`Could not verify ${a} through Vercel: ${deploymentFailureMessage(u.failure)}`,s)}let f;if(e.configureTrustedSources===!0){let e=await o.prepareVercelTrustedSourceAccess({workspaceRoot:t,target:d,prompter:r,signal:i});if(i?.throwIfAborted(),e.kind===`cancelled`)return cancelled(s);if(e.kind===`failed`)return failed(e.message,s);e.kind===`approved`&&(f=e.grant)}if(i?.throwIfAborted(),f!==void 0){c=!0;let e=await o.applyVercelTrustedSourceAccess({workspaceRoot:t,grant:f,signal:i});if(e.kind===`failed`)return failed(e.message,s);e.kind===`updated`&&s.push({kind:`trusted-sources-updated`,targetProjectName:e.targetProjectName})}let p=await o.resolveOidcToken({ownerId:d.deployment.ownerId,projectId:d.deployment.projectId,forceRefresh:!0});if(i?.throwIfAborted(),p.kind!==`resolved`)return failed(formatDevelopmentOidcTokenFailure(p),s);let m=p.token.trim();return{kind:`prepared`,target:d,resolveToken:async()=>{let e=await o.resolveOidcToken(d.deployment);return e.kind===`resolved`&&(m=e.token.trim()),m},completedMutations:[...s]}}catch(e){return!c&&(e instanceof WizardCancelledError||i?.aborted===!0)?cancelled(s):failed(`Could not authenticate ${a}: ${toErrorMessage(e)}`,s)}}export{runRemoteAuthFlow};
|
|
@@ -3,7 +3,9 @@ import type { RemoteConnectionState } from "./remote-connection-types.js";
|
|
|
3
3
|
export type RemoteProbeResult = Extract<RemoteConnectionState, {
|
|
4
4
|
state: "ready" | "auth-required" | "unavailable";
|
|
5
5
|
}>;
|
|
6
|
-
export
|
|
6
|
+
export type RemoteProbePhase = "connection-check" | "authentication-verification";
|
|
7
|
+
export declare function classifyRemoteError(error: unknown, phase: RemoteProbePhase): RemoteProbeResult;
|
|
7
8
|
export declare function probeRemoteInfo(input: {
|
|
8
9
|
readonly client: Client;
|
|
10
|
+
readonly phase: RemoteProbePhase;
|
|
9
11
|
}): Promise<RemoteProbeResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isObject}from"#shared/guards.js";import{toErrorMessage}from"#shared/errors.js";import{
|
|
1
|
+
import{isObject}from"#shared/guards.js";import{toErrorMessage}from"#shared/errors.js";import{formatVercelTrustedSourcesFailure,isVercelAuthChallenge,vercelTrustedSourcesErrorCode}from"#services/dev-client/vercel-auth-error.js";import{AgentInfoResponseError,ClientError}from"#client/index.js";function isEveOidcChallenge(t){if(!(t instanceof ClientError)||t.status!==401)return!1;try{let n=JSON.parse(t.body);return isObject(n)&&n.ok===!1&&n.code===`unauthorized`&&n.error===`Authorization is required for this route.`}catch{return!1}}function classifyRemoteError(e,i){if(isVercelAuthChallenge(e))return{state:`auth-required`,challenge:{kind:`vercel-deployment-protection`}};if(isEveOidcChallenge(e))return{state:`auth-required`,challenge:{kind:`eve-oidc`}};if(e instanceof ClientError){let t=vercelTrustedSourcesErrorCode(e.message);if(i===`connection-check`&&e.status===403&&t===`TRUSTED_SOURCES_ENVIRONMENT_MISMATCH`)return{state:`auth-required`,challenge:{kind:`vercel-deployment-protection`}};let r={message:formatVercelTrustedSourcesFailure(e.message)};return{state:`unavailable`,failure:t===void 0?r:{...r,code:t}}}return{state:`unavailable`,failure:{message:toErrorMessage(e)}}}async function probeDeploymentHealth(t){try{let n=await t.health();return isObject(n)&&n.ok===!0}catch{return!1}}async function probeRemoteInfo(e){try{return{state:`ready`,info:await e.client.info()}}catch(t){return(t instanceof AgentInfoResponseError||t instanceof ClientError&&t.status===404)&&await probeDeploymentHealth(e.client)?{state:`ready`}:classifyRemoteError(t,e.phase)}}export{classifyRemoteError,probeRemoteInfo};
|
|
@@ -10,13 +10,14 @@ export type RemoteAuthChallenge = {
|
|
|
10
10
|
readonly kind: "vercel-deployment-protection";
|
|
11
11
|
};
|
|
12
12
|
interface RemoteRequestFailure {
|
|
13
|
+
readonly code?: string;
|
|
13
14
|
readonly message: string;
|
|
14
15
|
}
|
|
15
16
|
export type RemoteConnectionState = {
|
|
16
17
|
readonly state: "checking";
|
|
17
18
|
} | {
|
|
18
19
|
readonly state: "ready";
|
|
19
|
-
readonly info
|
|
20
|
+
readonly info?: AgentInfoResult;
|
|
20
21
|
} | {
|
|
21
22
|
readonly state: "auth-required";
|
|
22
23
|
readonly challenge: RemoteAuthChallenge;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{appendRemoteAuthMutationSummary}from"./remote-auth-result.js";import{
|
|
1
|
+
import{appendRemoteAuthMutationSummary}from"./remote-auth-result.js";import{remoteHost}from"./target.js";import{classifyRemoteError,probeRemoteInfo}from"./remote-connection-probe.js";import{toErrorMessage}from"#shared/errors.js";function challengeFor(e){switch(e.state){case`auth-required`:case`authenticating`:case`auth-failed`:return e.challenge;case`checking`:case`ready`:return{kind:`eve-oidc`};case`unavailable`:return e.failure.code===`TRUSTED_SOURCES_ENVIRONMENT_MISMATCH`?{kind:`vercel-deployment-protection`}:{kind:`eve-oidc`}}}function createRemoteConnectionController(i){let a={state:`checking`},o,s,restoreActiveCredentials,c=0,l=!1,snapshot=()=>o===void 0?{target:i.target,connection:a}:{target:i.target,connection:a,deployment:o},update=e=>(a=e,l||i.onChange(snapshot()),e),beginOperation=e=>{s?.abort();let t=new AbortController;s=t;let n=e===void 0?t.signal:AbortSignal.any([t.signal,e]);return{generation:++c,signal:n}},isCurrent=e=>!l&&e===c,publishTarget=e=>{o=e.deployment,l||i.onChange(snapshot())},authorizeResolvedTarget=async(e,t)=>{let n=i.resolveDeployment;if(n!==void 0)try{let r=await n(e);return!isCurrent(t)||e.aborted||r.kind!==`resolved`?void 0:(publishTarget(r.target),i.credentials.authorize({target:r.target,resolveToken:async()=>await i.resolveOidcToken?.(r.target.deployment)??``}))}catch{}};return i.onChange(snapshot()),{current:snapshot,async check(){let e=beginOperation();restoreActiveCredentials?.(),restoreActiveCredentials=void 0,o=void 0,update({state:`checking`});let t=await authorizeResolvedTarget(e.signal,e.generation);if(!isCurrent(e.generation))return t?.(),a;restoreActiveCredentials=t;let n=await probeRemoteInfo({client:i.client,phase:`connection-check`});return isCurrent(e.generation)?update(n):a},async authenticate(n,o){let s=beginOperation(o),c=a,l=challengeFor(a);update({state:`authenticating`,challenge:l});let u;try{u=await n(s.signal)}catch(e){u={kind:`failed`,message:toErrorMessage(e),completedMutations:[]}}if(!isCurrent(s.generation))return{kind:`cancelled`,completedMutations:u.completedMutations};if(u.kind===`cancelled`)return update(c),{kind:`cancelled`,completedMutations:u.completedMutations};if(u.kind===`failed`)return update(c.state===`ready`?c:{state:`auth-failed`,challenge:l}),{kind:`failed`,message:u.message};if(s.signal.aborted)return update(c),{kind:`cancelled`,completedMutations:u.completedMutations};let d=restoreActiveCredentials,f;try{f=i.credentials.authorize({target:u.target,resolveToken:u.resolveToken})}catch(t){let n=appendRemoteAuthMutationSummary(toErrorMessage(t),u.completedMutations);return update({state:`auth-failed`,challenge:l}),{kind:`failed`,message:n}}let p=await probeRemoteInfo({client:i.client,phase:`authentication-verification`});if(!isCurrent(s.generation))return f(),{kind:`cancelled`,completedMutations:u.completedMutations};if(s.signal.aborted)return f(),update(c),{kind:`cancelled`,completedMutations:u.completedMutations};if(p.state===`ready`)return publishTarget(u.target),restoreActiveCredentials=()=>{f(),d?.()},update(p),{kind:`authenticated`};if(f(),p.state===`auth-required`){let n=appendRemoteAuthMutationSummary(`The selected Vercel project did not authorize ${remoteHost(i.target)}.`,u.completedMutations);return update({state:`auth-failed`,challenge:p.challenge}),{kind:`failed`,message:n}}let m={...p.failure,message:appendRemoteAuthMutationSummary(p.failure.message,u.completedMutations)};return update({state:`unavailable`,failure:m}),{kind:`unavailable`,failure:m}},reportFailure(e){return s?.abort(),c+=1,update(classifyRemoteError(e,`connection-check`))},dispose(){l=!0,c+=1,s?.abort(),s=void 0,restoreActiveCredentials?.(),restoreActiveCredentials=void 0}}}export{createRemoteConnectionController};
|