eve 0.6.0-beta.16 → 0.6.0-beta.17
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 +20 -0
- package/dist/docs/public/advanced/dev-tui.md +4 -2
- package/dist/docs/public/reference/cli.md +18 -0
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/cli/commands/deploy.d.ts +21 -0
- package/dist/src/cli/commands/deploy.js +1 -0
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/cli/commands/link.d.ts +21 -0
- package/dist/src/cli/commands/link.js +1 -0
- package/dist/src/cli/commands/preconditions.d.ts +7 -0
- package/dist/src/cli/commands/preconditions.js +1 -0
- package/dist/src/cli/commands/register-project-commands.d.ts +12 -0
- package/dist/src/cli/commands/register-project-commands.js +1 -0
- package/dist/src/cli/dev/tui/agent-header.d.ts +2 -0
- package/dist/src/cli/dev/tui/agent-header.js +1 -1
- package/dist/src/cli/dev/tui/blocks.d.ts +1 -1
- package/dist/src/cli/dev/tui/blocks.js +2 -2
- package/dist/src/cli/dev/tui/command-typeahead.d.ts +47 -0
- package/dist/src/cli/dev/tui/command-typeahead.js +1 -0
- package/dist/src/cli/dev/tui/errors.d.ts +18 -0
- package/dist/src/cli/dev/tui/errors.js +1 -1
- package/dist/src/cli/dev/tui/prompt-command-handler.d.ts +10 -0
- package/dist/src/cli/dev/tui/prompt-command-handler.js +1 -0
- package/dist/src/cli/dev/tui/prompt-commands.d.ts +51 -0
- package/dist/src/cli/dev/tui/prompt-commands.js +2 -0
- package/dist/src/cli/dev/tui/runner.d.ts +22 -36
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.d.ts +47 -0
- package/dist/src/cli/dev/tui/setup-commands.js +1 -0
- package/dist/src/cli/dev/tui/setup-flow.d.ts +32 -0
- package/dist/src/cli/dev/tui/setup-flow.js +1 -0
- package/dist/src/cli/dev/tui/setup-issues.d.ts +40 -0
- package/dist/src/cli/dev/tui/setup-issues.js +1 -0
- package/dist/src/cli/dev/tui/setup-panel.d.ts +95 -0
- package/dist/src/cli/dev/tui/setup-panel.js +1 -0
- package/dist/src/cli/dev/tui/terminal-renderer.d.ts +15 -0
- package/dist/src/cli/dev/tui/terminal-renderer.js +2 -2
- 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/test/mock-terminal.d.ts +1 -0
- package/dist/src/cli/dev/tui/test/mock-terminal.js +1 -1
- package/dist/src/cli/dev/tui/theme.d.ts +4 -0
- package/dist/src/cli/dev/tui/theme.js +1 -1
- package/dist/src/cli/dev/tui/tui-prompter.d.ts +20 -0
- package/dist/src/cli/dev/tui/tui-prompter.js +1 -0
- package/dist/src/cli/dev/tui/tui.js +1 -1
- package/dist/src/cli/run.js +2 -2
- package/dist/src/compiler/normalize-agent-config.js +1 -1
- package/dist/src/compiler/normalize-manifest.js +1 -1
- package/dist/src/harness/model-call-error.d.ts +12 -0
- package/dist/src/harness/model-call-error.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/host/ports.d.ts +8 -0
- package/dist/src/internal/nitro/host/ports.js +1 -0
- package/dist/src/internal/nitro/host/start-development-server.js +1 -1
- package/dist/src/services/dev-client/client-options.d.ts +8 -0
- package/dist/src/services/dev-client/client-options.js +1 -0
- package/dist/src/services/dev-client/runtime-artifacts.d.ts +13 -0
- package/dist/src/services/dev-client/runtime-artifacts.js +1 -0
- package/dist/src/services/dev-client.js +1 -1
- package/dist/src/setup/boxes/add-channels.d.ts +11 -1
- package/dist/src/setup/boxes/add-channels.js +2 -2
- package/dist/src/setup/boxes/apply-ai-gateway-credential.js +1 -1
- package/dist/src/setup/boxes/deploy-project.js +1 -1
- package/dist/src/setup/boxes/detect-ai-gateway.d.ts +8 -1
- package/dist/src/setup/boxes/detect-ai-gateway.js +1 -1
- package/dist/src/setup/boxes/resolve-provisioning.d.ts +8 -0
- package/dist/src/setup/boxes/resolve-provisioning.js +1 -1
- package/dist/src/setup/boxes/select-channels.d.ts +2 -0
- package/dist/src/setup/boxes/select-channels.js +1 -1
- package/dist/src/setup/boxes/select-model.d.ts +2 -0
- package/dist/src/setup/boxes/select-model.js +1 -1
- package/dist/src/setup/channel-add-conflicts.d.ts +28 -0
- package/dist/src/setup/channel-add-conflicts.js +1 -0
- package/dist/src/setup/cli/channel-setup-prompter.d.ts +10 -0
- package/dist/src/setup/cli/index.d.ts +1 -0
- package/dist/src/setup/cli/index.js +1 -1
- package/dist/src/setup/cli/select-component.d.ts +2 -2
- package/dist/src/setup/cli/select-component.js +1 -1
- package/dist/src/setup/cli/select-option-codec.d.ts +12 -0
- package/dist/src/setup/cli/select-option-codec.js +1 -0
- package/dist/src/setup/connection-connector.js +1 -1
- package/dist/src/setup/flows/channels.d.ts +43 -0
- package/dist/src/setup/flows/channels.js +1 -0
- package/dist/src/setup/flows/deploy.d.ts +40 -0
- package/dist/src/setup/flows/deploy.js +1 -0
- package/dist/src/setup/flows/in-project.d.ts +16 -0
- package/dist/src/setup/flows/in-project.js +1 -0
- package/dist/src/setup/flows/link.d.ts +43 -0
- package/dist/src/setup/flows/link.js +1 -0
- package/dist/src/setup/flows/model.d.ts +43 -0
- package/dist/src/setup/flows/model.js +1 -0
- package/dist/src/setup/flows/vercel.d.ts +30 -0
- package/dist/src/setup/flows/vercel.js +2 -0
- package/dist/src/setup/index.js +1 -1
- package/dist/src/setup/project-resolution.d.ts +18 -0
- package/dist/src/setup/project-resolution.js +1 -1
- package/dist/src/setup/prompter.d.ts +13 -0
- package/dist/src/setup/prompter.js +1 -1
- package/dist/src/setup/scaffold/channels-catalog.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +2 -2
- package/dist/src/setup/scaffold/index.d.ts +1 -1
- package/dist/src/setup/scaffold/index.js +1 -1
- package/dist/src/setup/scaffold/update/channels.d.ts +8 -0
- package/dist/src/setup/scaffold/update/channels.js +2 -2
- package/dist/src/setup/scaffold/update/connections.js +2 -2
- package/dist/src/setup/scaffold/version-tokens.d.ts +11 -0
- package/dist/src/setup/scaffold/version-tokens.js +1 -0
- package/dist/src/setup/slackbot.js +1 -1
- package/dist/src/setup/vercel-project.js +1 -1
- package/package.json +1 -1
- package/dist/src/cli/dev/change-agent-model.d.ts +0 -27
- package/dist/src/cli/dev/change-agent-model.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# eve
|
|
2
2
|
|
|
3
|
+
## 0.6.0-beta.17
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 20f0fc8: The dev TUI's `/channels` is now an action list: pick an unregistered channel to run its add flow, return to the repainted list (added channels show locked), and leave with the Done row or Esc. Web Chat (the Next.js app) is now addable in projects that already have the scaffolded `agent/channels/eve.ts` session channel — the row locks only when the project actually depends on `next`, and the REPL channel shows as its own locked row.
|
|
8
|
+
- 20f0fc8: The dev TUI now discovers its slash commands: typing `/` opens a suggestion list above the prompt with each command's argument hint and description — `↑`/`↓` move the highlight, `Tab` completes, `Enter` runs, `Esc` dismisses — and a new `/help` command prints the full table. Unknown `/text` is still sent to the agent as a normal message.
|
|
9
|
+
- 20f0fc8: New `eve link` and `eve deploy` commands, also available inside the `eve dev` TUI as `/vercel`, `/channels`, and `/deploy` when the server runs locally. `eve link` picks the Vercel team and project and pulls AI Gateway credentials into `.env.local`; `eve deploy` links when needed and remains successful when its production URL cannot be verified; AI Gateway authentication failures in the TUI now suggest `/vercel`, and the dev server picks up pulled credentials without a restart.
|
|
10
|
+
- 20f0fc8: The dev TUI's bare `/model` now opens the same searchable AI Gateway catalog picker that `eve init` uses — full catalog with the featured shortlist, pre-selected on the model the runtime is serving — instead of a short hand-curated list. `/model <provider/model-id>` still applies directly.
|
|
11
|
+
- 20f0fc8: The dev TUI's `/vercel` now asks which model provider you want before any linking: pick AI Gateway and connect via a project or by pasting your own `AI_GATEWAY_API_KEY` (saved to `.env.local`), or pick another provider to get wiring instructions instead.
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 20f0fc8: `eve channels add` and the dev TUI `/channels` command now run `pnpm install` after recording channels, so a running `eve dev` can load newly scaffolded channel modules (for example `@vercel/connect` for Slack) immediately instead of failing to resolve them until the next deploy.
|
|
16
|
+
- 20f0fc8: `eve dev` no longer clears the terminal scrollback when the terminal UI starts, and skips the redundant `server listening at` line in TUI mode — the header already shows the URL. Headless and REPL modes still print it.
|
|
17
|
+
- 20f0fc8: Make `eve init` install the newest Eve prerelease through the npm `beta` dist-tag, including when scaffolding Web Chat.
|
|
18
|
+
- 20f0fc8: Replace removed `create-eve` and `eve setup` guidance with the current `eve init` and `eve link` commands.
|
|
19
|
+
- 20f0fc8: Restore the `eve link` and `eve deploy` command registrations after the `eve init` migration.
|
|
20
|
+
- 20f0fc8: Keep superseded Vercel project-name warnings inside the `/vercel` panel when linking ultimately succeeds.
|
|
21
|
+
- 20f0fc8: Scaffolding channels, connections, and new projects from an unstamped dev build (for example under `pnpm dev`'s watch emit) now resolves dependency versions from the live workspace catalog instead of failing with "unstamped version token". Published builds are unchanged: they are stamped at build time, and an unstamped token outside a dev tree still fails loudly.
|
|
22
|
+
|
|
3
23
|
## 0.6.0-beta.16
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
|
@@ -19,10 +19,12 @@ On startup the TUI prints a header for the connected agent — the model, instru
|
|
|
19
19
|
· Subagents researcher
|
|
20
20
|
· Server http://localhost:3000
|
|
21
21
|
|
|
22
|
-
Type to chat · ↑ history · /new reset session · /exit quit · Ctrl+C interrupt
|
|
22
|
+
Type to chat · ↑ history · /new reset session · /model /vercel /channels /deploy · /exit quit · Ctrl+C interrupt
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
From there the conversation streams straight into your terminal's normal scrollback — your prompts, the agent's replies, reasoning, tool calls, nested subagents, connection-authorization prompts, and any captured `stdout`/`stderr` — so you keep native scrolling, copy/paste, and a transcript that persists after you exit. Each turn is rendered without boxes: a colored gutter glyph marks who's speaking, tool calls collapse to a one-line summary (`✓ get_weather city="SF" → 73°F`), and a subagent's work is indented beneath its `◆` header. A sticky line at the bottom shows the input prompt or the live status (spinner, token usage). Press `Enter` to send; `Ctrl+C` interrupts a running turn or quits at the prompt.
|
|
25
|
+
From there the conversation streams straight into your terminal's normal scrollback — your prompts, the agent's replies, reasoning, tool calls, nested subagents, connection-authorization prompts, and any captured `stdout`/`stderr` — so you keep native scrolling, copy/paste, and a transcript that persists after you exit. Each turn is rendered without boxes: a colored gutter glyph marks who's speaking, tool calls collapse to a one-line summary (`✓ get_weather city="SF" → 73°F`), and a subagent's work is indented beneath its `◆` header. A sticky line at the bottom shows the input prompt or the live status (spinner, token usage). Press `Enter` to send; `Ctrl+C` interrupts a running turn or quits at the prompt. Slash commands: `/new` starts a fresh session and `/exit` quits.
|
|
26
|
+
|
|
27
|
+
When `eve dev` runs the server locally, three more slash commands manage the project without leaving the session. `/vercel` opens with two questions — which model provider to use (picking something other than AI Gateway shows wiring instructions for your own provider and stops there) and how to connect to AI Gateway (paste your own `AI_GATEWAY_API_KEY`, saved straight to `.env.local`, or connect via a project) — and the project path then walks the same Vercel team/project pickers as setup (picking again re-links) and pulls the project's environment so an AI Gateway credential lands in `.env.local` — the dev server reloads env files automatically, no restart needed. `/channels` shows the agent's channel list — already-registered channels render as locked rows — and adds the one you pick, including the Slack Connect provisioning, then installs the dependencies the scaffold added so the dev server can load the new channels right away; after each addition the list repaints with the new channel locked, until Done (or Esc) leaves the flow. `/deploy` ships the agent to Vercel production, linking first when the directory is unlinked. Each command echoes as an invocation line, asks through a bordered panel that takes the input area's place — one question at a time, clearly separate from the chat transcript — and finishes with a one-line `⎿` result; loading states stay on the ephemeral status line instead of piling into the transcript. These commands are not available when connected to a remote server with `--url`, and when a turn fails because AI Gateway authentication is missing or stale, the error points you at `/vercel` directly. The TUI also checks at startup: a missing model-provider setup surfaces as an attention line — `⚠ 1 setup issue: model provider not linked · /vercel` — so the fix is visible before the first message fails, and each command's outcome hangs under it with the `⎿` connector. Local sessions also get `/model`: bare `/model` opens the same searchable model picker setup uses (the AI Gateway catalog, pre-selected on the model the runtime is serving), `/model <provider/model-id>` applies one directly, and the change is written into your agent's authored source — the command reports success only after the reloaded runtime confirms the new id.
|
|
26
28
|
|
|
27
29
|
The prompt input behaves like a shell line editor: `↑`/`↓` cycle through the messages you've sent this session, `←`/`→`, Home/End, and `Ctrl+A`/`Ctrl+E` move the caret, and `Ctrl+U`/`Ctrl+K`/`Ctrl+W` kill the line, the rest of the line, or the previous word. If a turn fails terminally — the server session dies or the connection drops — the TUI starts a fresh session and notes it inline so you can keep going (server-side context resets with the old session). Errors render compactly, with docs links highlighted, and a code bug escaping your agent's own code shows its stack trace dim beneath the error headline. Captured server `stdout`/`stderr` renders as dim, indented log runs behind a `│` rule — consecutive lines from the same source share one label, and nothing is ever hidden.
|
|
28
30
|
|
|
@@ -14,6 +14,8 @@ The `eve` binary (`bin: eve`) runs from your app root, and every command loads `
|
|
|
14
14
|
| `eve start` | Serve the built `.output/` app; prints the listening URL |
|
|
15
15
|
| `eve dev` | Start the local dev server and open the terminal UI |
|
|
16
16
|
| `eve dev <url>` | Connect the UI to an existing server URL (e.g. a remote deployment) instead of booting a local server |
|
|
17
|
+
| `eve link` | Link the directory to a Vercel project and pull AI Gateway credentials |
|
|
18
|
+
| `eve deploy` | Deploy the agent to Vercel production (links first if needed) |
|
|
17
19
|
| `eve eval` | Run evals against the local app or a remote target |
|
|
18
20
|
| `eve channels add [kind]` | Scaffold a channel interactively, or by kind (`slack` \| `web`) |
|
|
19
21
|
| `eve channels list` | List user-authored channels |
|
|
@@ -90,6 +92,22 @@ Pass a bare URL as the only argument and the UI connects to that server instead
|
|
|
90
92
|
|
|
91
93
|
Local dev keeps immutable runtime source snapshots under `.eve/dev-runtime/snapshots/` so in-flight sessions keep a consistent code revision while new prompts pick up rebuilds. `eve dev` prunes stale runtime snapshots and old local sandbox templates in the background on startup; stopping `eve dev` and deleting `.eve/dev-runtime/snapshots/` or `.eve/sandbox-cache/local/templates/` is safe when you want a manual cleanup.
|
|
92
94
|
|
|
95
|
+
## `eve link`
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
eve link
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Links the current directory to a Vercel project through interactive team/project pickers, then pulls the project's environment so an AI Gateway credential (`VERCEL_OIDC_TOKEN` or `AI_GATEWAY_API_KEY`) lands in `.env.local`, and verifies one actually did. Running it again re-links: the pickers always run, and the new choice wins. Interactive only — in CI, use `vercel link --project <name> --yes` instead. A running `eve dev` reloads env files automatically, so no restart is needed after the pull.
|
|
102
|
+
|
|
103
|
+
## `eve deploy`
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
eve deploy
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Deploys the agent to Vercel production (`vercel deploy --prod`), installing dependencies first and pulling environment variables after. An already-linked project deploys with or without a TTY (non-interactive runs pass the non-interactive `vercel` flags); an unlinked directory walks the `eve link` pickers when a terminal is present, and exits with guidance otherwise.
|
|
110
|
+
|
|
93
111
|
## `eve eval`
|
|
94
112
|
|
|
95
113
|
```bash
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assertCanAddSelectedChannels,inspectExistingChannelRegistrations}from"./channel-add-conflicts.js";import{isEveProject,listAuthoredChannels}from"#setup/scaffold/index.js";import{interactiveAsker}from"#setup/ask.js";import{addChannels}from"#setup/boxes/add-channels.js";import{deployProject}from"#setup/boxes/deploy-project.js";import{selectChannels}from"#setup/boxes/select-channels.js";import{detectDeployment,projectResolutionFromDeployment}from"#setup/project-resolution.js";import{createPrompter}from"#setup/prompter.js";import{runInteractive}from"#setup/runner.js";import{createDefaultSetupState,snapshotSetupState}from"#setup/state.js";const
|
|
1
|
+
import{assertCanAddSelectedChannels,inspectExistingChannelRegistrations}from"./channel-add-conflicts.js";import{NOT_AN_AGENT_MESSAGE}from"./preconditions.js";import{isEveProject,listAuthoredChannels}from"#setup/scaffold/index.js";import{interactiveAsker}from"#setup/ask.js";import{addChannels}from"#setup/boxes/add-channels.js";import{deployProject}from"#setup/boxes/deploy-project.js";import{selectChannels}from"#setup/boxes/select-channels.js";import{detectDeployment,projectResolutionFromDeployment}from"#setup/project-resolution.js";import{createPrompter}from"#setup/prompter.js";import{runInteractive}from"#setup/runner.js";import{createDefaultSetupState,snapshotSetupState}from"#setup/state.js";const KNOWN_CHANNEL_KINDS=[`slack`,`web`];function isChannelKind(e){return KNOWN_CHANNEL_KINDS.includes(e)}function parseChannelKind(e){if(!isChannelKind(e))throw Error(`Unknown channel kind "${e}". Known: ${KNOWN_CHANNEL_KINDS.join(`, `)}.`);return e}const defaultChannelsAddDependencies={detectDeployment};async function runAddChannelsFlow(n,r,i,s){if(r===void 0&&(i.yes||!process.stdin.isTTY||!process.stdout.isTTY))throw Error(`Pass a channel kind: \`eve channels add <${KNOWN_CHANNEL_KINDS.join(`|`)}>\`.`);let c=s.createPrompter?.()??createPrompter();c.intro(`Add channels to your Eve agent`),c.log.message(`Checking the current Vercel project...`);let l={...createDefaultSetupState(),project:projectResolutionFromDeployment(await s.detectDeployment(n)),projectPath:{kind:`resolved`,inPlace:!0,path:n}},u;function inspectRegistrations(){return u===void 0&&(c.log.message(`Inspecting existing channel registrations...`),u=inspectExistingChannelRegistrations(n)),u}let d=r===void 0?(await inspectRegistrations()).disabledChannelReasons:void 0,f=await runInteractive([selectChannels({asker:interactiveAsker(c),variant:`channels-add`,presetChannels:r===void 0?void 0:[r],disabledChannelReasons:d,validateSelection:async t=>{!t.includes(`web`)&&!t.includes(`slack`)||assertCanAddSelectedChannels(t,await inspectRegistrations())}}),addChannels({asker:interactiveAsker(c),prompter:c,presetCreateSlackbot:i.yes?!0:void 0,force:i.force,configureVercelServices:!0,ensureLinkedProject:`interactive-vercel-link`,deps:s.addChannelsDeps}),deployProject({prompter:c,ensureLinkedProject:`interactive-vercel-link`,deps:s.deployProjectDeps})],l,{write:e=>c.log.message(e)},{snapshot:snapshotSetupState});f.kind!==`cancelled`&&c.outro(f.state.channels.length===0?`No channels added.`:`Channels added.`)}async function runChannelsAddCommand(e,t,i,a=defaultChannelsAddDependencies){if(!await isEveProject(t)){e.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}try{await runAddChannelsFlow(t,i.kind===void 0?void 0:parseChannelKind(i.kind),i.options,a)}catch(t){e.error(t instanceof Error?t.message:String(t)),process.exitCode=1}}async function runChannelsListCommand(e,t,a){if(!await isEveProject(t)){e.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}let o=await listAuthoredChannels(t);if(a.json){e.log(JSON.stringify({channels:o},null,2));return}if(o.length===0){e.log("No channels defined. Run `eve channels add` to add one.");return}for(let t of o)e.log(t)}export{runChannelsAddCommand,runChannelsListCommand};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type DeployFlowDeps } from "#setup/flows/deploy.js";
|
|
2
|
+
import { type Prompter } from "#setup/prompter.js";
|
|
3
|
+
export interface DeployCliLogger {
|
|
4
|
+
error(message: string): void;
|
|
5
|
+
log(message: string): void;
|
|
6
|
+
}
|
|
7
|
+
export interface DeployCommandDependencies {
|
|
8
|
+
createPrompter?: () => Prompter;
|
|
9
|
+
isEveProject(projectPath: string): Promise<boolean>;
|
|
10
|
+
hasInteractiveTerminal(): boolean;
|
|
11
|
+
/** Test seam into the flow's detection and box effects. */
|
|
12
|
+
flowDeps?: Partial<DeployFlowDeps>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* `eve deploy`: deploy the agent to Vercel production. An already-linked
|
|
16
|
+
* project deploys straight away (interactively or not); an unlinked one walks
|
|
17
|
+
* the same team/project pickers as onboarding when a terminal is present, and
|
|
18
|
+
* refuses with `eve link` guidance otherwise. The flow itself is
|
|
19
|
+
* {@link runDeployFlow}, shared with the dev TUI's `/deploy`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function runDeployCommand(logger: DeployCliLogger, appRoot: string, dependencies?: DeployCommandDependencies): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{NOT_AN_AGENT_MESSAGE,hasInteractiveTerminal}from"./preconditions.js";import{isEveProject}from"#setup/scaffold/index.js";import{createPrompter}from"#setup/prompter.js";import{runDeployFlow}from"#setup/flows/deploy.js";const defaultDependencies={isEveProject,hasInteractiveTerminal};async function runDeployCommand(t,n,r=defaultDependencies){if(!await r.isEveProject(n)){t.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}let i=r.createPrompter?.()??createPrompter();i.intro(`Deploy your Eve agent to Vercel`);try{let e=await runDeployFlow({appRoot:n,prompter:i,interactive:r.hasInteractiveTerminal(),deps:r.flowDeps});if(e.kind===`needs-link`){t.error("This directory is not linked to a Vercel project. Run `eve link` first (or `vercel link --project <name> --yes` in CI), then re-run `eve deploy`."),process.exitCode=1;return}i.outro(e.kind===`cancelled`?`Cancelled.`:e.productionUrl===void 0?`Deployed.`:`Deployed: ${e.productionUrl}`)}catch(e){t.error(e instanceof Error?e.message:String(e)),process.exitCode=1}}export{runDeployCommand};
|
|
@@ -1 +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{tryInitializeGit}from"./init-git.js";import{join,resolve}from"node:path";import{ensureChannel,scaffoldBaseProject}from"#setup/scaffold/index.js";import{mkdtemp,rename,rm}from"node:fs/promises";import{EVE_WORDMARK}from"#cli/banner.js";import{DEFAULT_AGENT_MODEL_ID}from"#shared/default-agent-model.js";import{SPINNER_FRAMES,SPINNER_FRAME_MS}from"#setup/cli/rail-log.js";import{pathExists}from"#setup/path-exists.js";import{parseProjectName}from"#setup/project-name.js";import{runPnpmInstall,spawnPnpm}from"#setup/primitives/index.js";var import_picocolors=__toESM(require_picocolors(),1);const defaultDependencies={ensureChannel,runPnpmInstall,scaffoldBaseProject,spawnPnpm,tryInitializeGit}
|
|
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{tryInitializeGit}from"./init-git.js";import{join,resolve}from"node:path";import{ensureChannel,scaffoldBaseProject}from"#setup/scaffold/index.js";import{mkdtemp,rename,rm}from"node:fs/promises";import{EVE_WORDMARK}from"#cli/banner.js";import{DEFAULT_AGENT_MODEL_ID}from"#shared/default-agent-model.js";import{SPINNER_FRAMES,SPINNER_FRAME_MS}from"#setup/cli/rail-log.js";import{pathExists}from"#setup/path-exists.js";import{parseProjectName}from"#setup/project-name.js";import{runPnpmInstall,spawnPnpm}from"#setup/primitives/index.js";var import_picocolors=__toESM(require_picocolors(),1);const defaultDependencies={ensureChannel,runPnpmInstall,scaffoldBaseProject,spawnPnpm,tryInitializeGit},EVE_INIT_PACKAGE_VERSION=`beta`;async function scaffoldProject(e,t,n,a){let o=resolve(e),u=join(o,t);if(await pathExists(u))throw Error(`Cannot create project because "${u}" already exists.`);let d=await mkdtemp(join(o,`.eve-init-`));try{let e=await a.scaffoldBaseProject({projectName:t,model:DEFAULT_AGENT_MODEL_ID,targetDirectory:d,evePackageVersion:EVE_INIT_PACKAGE_VERSION});return n.web===!0&&await a.ensureChannel({projectRoot:e,kind:`web`,configureVercelServices:!1,webPackageVersions:{evePackageVersion:EVE_INIT_PACKAGE_VERSION}}),await rename(e,u),u}finally{await rm(d,{recursive:!0,force:!0})}}function startSpinner(e,t){if(process.stdout.isTTY!==!0)return e.log(t),{stop(){}};let row=e=>`${import_picocolors.default.green(e)} ${t}`;process.stdout.write(row(SPINNER_FRAMES[0]));let n=0,r=setInterval(()=>{n+=1;let e=SPINNER_FRAMES[n%SPINNER_FRAMES.length]??SPINNER_FRAMES[0];process.stdout.write(`\r\u001B[K${row(e)}`)},SPINNER_FRAME_MS);r.unref?.();let i=!1;return{stop(){i||(i=!0,clearInterval(r),process.stdout.write(`\r\x1B[K`))}}}async function runInitCommand(e,t,n,r,i=defaultDependencies){let a=await scaffoldProject(t,parseProjectName(n),r,i);e.log(`${import_picocolors.default.green(`✓`)} Created an ${EVE_WORDMARK} agent in ${import_picocolors.default.bold(a)}`);let o=[],s=startSpinner(e,`Installing dependencies...`),c;try{c=await i.runPnpmInstall(a,{onOutput:e=>o.push(e.text)})}finally{s.stop()}if(!c){for(let t of o)e.error(t);throw Error(`Failed to install dependencies in "${a}".`)}e.log(`${import_picocolors.default.green(`✓`)} Installed dependencies`);let l=i.tryInitializeGit(a);if(l.kind===`failed`&&e.error(import_picocolors.default.yellow(`Git initialization failed: ${l.reason}`)),!await i.spawnPnpm(a,[`run`,`dev`]))throw Error(`Development server exited unsuccessfully in "${a}".`)}export{runInitCommand};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type LinkFlowDeps } from "#setup/flows/link.js";
|
|
2
|
+
import { type Prompter } from "#setup/prompter.js";
|
|
3
|
+
export interface LinkCliLogger {
|
|
4
|
+
error(message: string): void;
|
|
5
|
+
log(message: string): void;
|
|
6
|
+
}
|
|
7
|
+
export interface LinkCommandDependencies {
|
|
8
|
+
createPrompter?: () => Prompter;
|
|
9
|
+
isEveProject(projectPath: string): Promise<boolean>;
|
|
10
|
+
hasInteractiveTerminal(): boolean;
|
|
11
|
+
/** Test seam into the flow's detection and box effects. */
|
|
12
|
+
flowDeps?: Partial<LinkFlowDeps>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* `eve link`: pick a Vercel team and project (re-linking when one is already
|
|
16
|
+
* linked), run `vercel link`, then pull env so the AI Gateway credential lands
|
|
17
|
+
* in `.env.local`. The flow itself is {@link runLinkFlow}, shared with the dev
|
|
18
|
+
* TUI's `/vercel`. Interactive only: the pickers are the point of the command,
|
|
19
|
+
* so a non-TTY run refuses with guidance instead of guessing a project.
|
|
20
|
+
*/
|
|
21
|
+
export declare function runLinkCommand(logger: LinkCliLogger, appRoot: string, dependencies?: LinkCommandDependencies): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{NOT_AN_AGENT_MESSAGE,hasInteractiveTerminal}from"./preconditions.js";import{isEveProject}from"#setup/scaffold/index.js";import{createPrompter}from"#setup/prompter.js";import{runLinkFlow}from"#setup/flows/link.js";const defaultDependencies={isEveProject,hasInteractiveTerminal};async function runLinkCommand(t,n,r=defaultDependencies){if(!await r.isEveProject(n)){t.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}if(!r.hasInteractiveTerminal()){t.error("`eve link` needs an interactive terminal to pick the team and project. In CI, run `vercel link --project <name> --yes` instead."),process.exitCode=1;return}let i=r.createPrompter?.()??createPrompter();i.intro(`Link your Eve agent to Vercel`);try{let e=await runLinkFlow({appRoot:n,prompter:i,deps:r.flowDeps});i.outro(e.kind===`cancelled`?`Cancelled.`:`Project linked.`)}catch(e){t.error(e instanceof Error?e.message:String(e)),process.exitCode=1}}export{runLinkCommand};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refusal shown by agent-scoped commands (`eve link`, `eve deploy`,
|
|
3
|
+
* `eve channels …`) when the working directory holds no Eve agent.
|
|
4
|
+
*/
|
|
5
|
+
export declare const NOT_AN_AGENT_MESSAGE = "No Eve agent in this directory. Run `eve init <name>`, then run this command from inside the new project.";
|
|
6
|
+
/** True when stdin and stdout are both TTYs — the default interactivity gate. */
|
|
7
|
+
export declare function hasInteractiveTerminal(): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const NOT_AN_AGENT_MESSAGE="No Eve agent in this directory. Run `eve init <name>`, then run this command from inside the new project.";function hasInteractiveTerminal(){return!!(process.stdin.isTTY&&process.stdout.isTTY)}export{NOT_AN_AGENT_MESSAGE,hasInteractiveTerminal};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Command } from "#compiled/commander/index.js";
|
|
2
|
+
interface ProjectCommandLogger {
|
|
3
|
+
error(message: string): void;
|
|
4
|
+
log(message: string): void;
|
|
5
|
+
}
|
|
6
|
+
/** Registers project-level Vercel commands without eagerly loading their flows. */
|
|
7
|
+
export declare function registerProjectCommands(input: {
|
|
8
|
+
program: Command;
|
|
9
|
+
logger: ProjectCommandLogger;
|
|
10
|
+
appRoot: string;
|
|
11
|
+
}): void;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function registerProjectCommands(e){e.program.command(`link`).description(`Link this directory to a Vercel project and pull AI Gateway credentials.`).action(async()=>{let{runLinkCommand:t}=await import(`./link.js`);await t(e.logger,e.appRoot)}),e.program.command(`deploy`).description(`Deploy the agent to Vercel production (links first if needed).`).action(async()=>{let{runDeployCommand:t}=await import(`./deploy.js`);await t(e.logger,e.appRoot)})}export{registerProjectCommands};
|
|
@@ -18,6 +18,8 @@ export interface AgentHeaderInput {
|
|
|
18
18
|
theme: Theme;
|
|
19
19
|
/** Available terminal width. */
|
|
20
20
|
width: number;
|
|
21
|
+
/** Mention /model, /vercel, /channels, /deploy in the key hints (local sessions only). */
|
|
22
|
+
setupCommands?: boolean;
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* Returns the styled rows of the startup header (no trailing blank line is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{truncate}from"./tool-format.js";function buildAgentHeader(t){let{theme:n,info:r,name:i,serverUrl:a,width:o}=t,s=n.colors,c=[];if(r){c.push({label:`Model`,value:r.agent.model.id}),r.instructions.static&&c.push({label:`Instructions`,value:r.instructions.static.logicalPath});let e=[...r.tools.authored,...r.tools.dynamic.filter(e=>e.origin===`authored`).map(e=>({name:e.slug}))];e.length>0&&c.push({label:`Tools`,value:joinNames(e)});let t=[...r.skills.static,...r.skills.dynamic.filter(e=>e.origin===`authored`).map(e=>({name:e.slug}))];t.length>0&&c.push({label:`Skills`,value:joinNames(t)}),r.subagents.local.length>0&&c.push({label:`Subagents`,value:joinNames(r.subagents.local)}),r.schedules.length>0&&c.push({label:`Schedules`,value:joinNames(r.schedules)}),r.sandbox&&c.push({label:`Sandbox`,value:r.sandbox.logicalPath})}c.push({label:`Server`,value:a,link:!0});let l=c.reduce((e,t)=>Math.max(e,t.label.length),0),u=Math.max(8,o-l-6),d=[];if(d.push(` ${s.bold(`${n.glyph.brand} ${i}`)}`),r&&(r.diagnostics.discoveryErrors>0||r.diagnostics.discoveryWarnings>0)){let e=[];r.diagnostics.discoveryErrors>0&&e.push(s.red(`${r.diagnostics.discoveryErrors} error${plural(r.diagnostics.discoveryErrors)}`)),r.diagnostics.discoveryWarnings>0&&e.push(s.yellow(`${r.diagnostics.discoveryWarnings} warning${plural(r.diagnostics.discoveryWarnings)}`)),d.push(` ${s.dim(n.glyph.warning)} ${e.join(s.dim(` · `))}`)}for(let t of c){let r=s.dim(n.glyph.dot)+` `+s.gray(t.label.padEnd(l)),i=truncate(t.value,u);d.push(` ${r} ${t.link?s.cyan(i):i}`)}
|
|
1
|
+
import{truncate}from"./tool-format.js";function buildAgentHeader(t){let{theme:n,info:r,name:i,serverUrl:a,width:o}=t,s=n.colors,c=[];if(r){c.push({label:`Model`,value:r.agent.model.id}),r.instructions.static&&c.push({label:`Instructions`,value:r.instructions.static.logicalPath});let e=[...r.tools.authored,...r.tools.dynamic.filter(e=>e.origin===`authored`).map(e=>({name:e.slug}))];e.length>0&&c.push({label:`Tools`,value:joinNames(e)});let t=[...r.skills.static,...r.skills.dynamic.filter(e=>e.origin===`authored`).map(e=>({name:e.slug}))];t.length>0&&c.push({label:`Skills`,value:joinNames(t)}),r.subagents.local.length>0&&c.push({label:`Subagents`,value:joinNames(r.subagents.local)}),r.schedules.length>0&&c.push({label:`Schedules`,value:joinNames(r.schedules)}),r.sandbox&&c.push({label:`Sandbox`,value:r.sandbox.logicalPath})}c.push({label:`Server`,value:a,link:!0});let l=c.reduce((e,t)=>Math.max(e,t.label.length),0),u=Math.max(8,o-l-6),d=[];if(d.push(` ${s.bold(`${n.glyph.brand} ${i}`)}`),r&&(r.diagnostics.discoveryErrors>0||r.diagnostics.discoveryWarnings>0)){let e=[];r.diagnostics.discoveryErrors>0&&e.push(s.red(`${r.diagnostics.discoveryErrors} error${plural(r.diagnostics.discoveryErrors)}`)),r.diagnostics.discoveryWarnings>0&&e.push(s.yellow(`${r.diagnostics.discoveryWarnings} warning${plural(r.diagnostics.discoveryWarnings)}`)),d.push(` ${s.dim(n.glyph.warning)} ${e.join(s.dim(` · `))}`)}for(let t of c){let r=s.dim(n.glyph.dot)+` `+s.gray(t.label.padEnd(l)),i=truncate(t.value,u);d.push(` ${r} ${t.link?s.cyan(i):i}`)}d.push(``);let f=t.setupCommands?` ${n.glyph.dot} /model /vercel /channels /deploy`:``;return d.push(` ${s.dim(`Type to chat ${n.glyph.dot} ↑ history ${n.glyph.dot} /new reset session${f} ${n.glyph.dot} /exit quit ${n.glyph.dot} Ctrl+C interrupt`)}`),d}function joinNames(e){return e.map(e=>e.name).join(`, `)}function plural(e){return e===1?``:`s`}export{buildAgentHeader};
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { Theme } from "./theme.js";
|
|
13
13
|
export type ToolStatus = "running" | "done" | "error" | "denied" | "approval";
|
|
14
|
-
export type BlockKind = "user" | "assistant" | "reasoning" | "tool" | "error" | "notice" | "question" | "subagent" | "subagent-step" | "subagent-tool" | "connection-auth" | "log";
|
|
14
|
+
export type BlockKind = "user" | "assistant" | "reasoning" | "tool" | "error" | "notice" | "warning" | "result" | "flow" | "command" | "question" | "subagent" | "subagent-step" | "subagent-tool" | "connection-auth" | "log";
|
|
15
15
|
/**
|
|
16
16
|
* One renderable transcript unit. Fields are interpreted per `kind`; unset
|
|
17
17
|
* fields are simply omitted from the rendered output.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{formatValuePretty,truncate}from"./tool-format.js";import{sliceVisible,visibleLength,wrapVisibleLine}from"./terminal-text.js";import{renderMarkdown}from"./markdown.js";function renderBlockLines(e,t,n,i){let a=nestingPrefix(e.depth??0,n);return renderBody(e,Math.max(8,t-visibleLength(a)),n,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`question`:case`connection-auth`:return renderPreformatted(e,t,n);case`log`:return renderLog(e,t,n,r);case`subagent`:return renderSubagentHeader(e,t,n)}}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,n){let r=[],o=e.kind===`subagent-step`,s=o?``:`${n.colors.bold(n.colors.white(n.glyph.brand))} `,c=o?``:` `;e.reasoning&&e.reasoning.trim().length>0&&r.push(...renderReasoningLines(e.reasoning,t,n));let l=(e.body??``).trim();return l.length===0&&r.length===0?[`${s}${n.colors.dim(`thinking${n.glyph.ellipsis}`)}`]:(l.length>0&&renderMarkdown(l).split(`
|
|
1
|
+
import{formatValuePretty,truncate}from"./tool-format.js";import{sliceVisible,visibleLength,wrapVisibleLine}from"./terminal-text.js";import{renderMarkdown}from"./markdown.js";import{isPromptControlCommand}from"./prompt-commands.js";function renderBlockLines(e,t,n,i){let a=nestingPrefix(e.depth??0,n);return renderBody(e,Math.max(8,t-visibleLength(a)),n,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`log`:return renderLog(e,t,n,r);case`subagent`:return renderSubagentHeader(e,t,n)}}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,n){let r=[],o=e.kind===`subagent-step`,s=o?``:`${n.colors.bold(n.colors.white(n.glyph.brand))} `,c=o?``:` `;e.reasoning&&e.reasoning.trim().length>0&&r.push(...renderReasoningLines(e.reasoning,t,n));let l=(e.body??``).trim();return l.length===0&&r.length===0?[`${s}${n.colors.dim(`thinking${n.glyph.ellipsis}`)}`]:(l.length>0&&renderMarkdown(l).split(`
|
|
2
2
|
`).flatMap(e=>wrapVisibleLine(e,t-c.length)).forEach((e,t)=>{t===0&&!o&&r.length===0?r.push(`${s}${e}`):r.push(`${c}${e}`)}),r.length>0?r:[`${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,n,r,i){let{icon:a,accent:o}=toolGlyph(e.status??`running`,r,i),s=e.title??`tool`,c=n-2,l=truncatePlain(s,c),u=`${a} ${r.colors.bold(l)}`,d=c-l.length-2,f=e.subtitle??``;f.length>0&&d>=6&&(u+=` ${r.colors.gray(truncate(f,d))}`);let p=[u];return e.expanded?p.push(...renderToolExpanded(e,n,r)):e.status===`done`&&e.result&&e.result.length>0?p.push(resultLine(r.glyph.arrow,e.result,n,r,o)):e.status===`error`&&e.result?p.push(resultLine(r.glyph.arrow,e.result,n,r,r.colors.red)):e.status===`denied`&&p.push(resultLine(r.glyph.arrow,`denied`,n,r,r.colors.yellow)),p}function renderToolExpanded(t,n,r){let i=[],push=(t,a,o)=>{if(a!==void 0){i.push(` ${r.colors.dim(t)}`);for(let t of wrap(formatValuePretty(a),n-4))i.push(` ${o(t)}`)}};return push(`input`,t.toolInput,r.colors.gray),t.status===`error`&&t.result?push(`error`,t.result,r.colors.red):push(`output`,t.toolOutput,r.colors.gray),i}function resultLine(e,n,r,i,a){let o=r-4;return` ${i.colors.dim(e)} ${a(truncate(n,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(`
|
|
3
|
-
`),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 renderPreformatted(e,t,n){let r=e.kind===`connection-auth`?n.colors.yellow(n.glyph.connection):n.colors.yellow(n.colors.bold(n.glyph.question)),a=e.title??``,o=[`${r} ${n.colors.bold(a)}`];for(let n of(e.body??``).split(`
|
|
3
|
+
`),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 renderWarning(e,t,n){let r=n.colors.yellow(n.glyph.warning);return wrap(e.body??``,t-2).map((e,t)=>`${t===0?r:` `} ${paintCommands(e,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;return[`${n.cyan(t.glyph.user)} ${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);return i.length===0?[` ${r}`]:i.map((e,t)=>t===0?` ${r} ${n.colors.dim(e)}`:` ${n.colors.dim(e)}`)}function renderPreformatted(e,t,n){let r=e.kind===`connection-auth`?n.colors.yellow(n.glyph.connection):n.colors.yellow(n.colors.bold(n.glyph.question)),a=e.title??``,o=[`${r} ${n.colors.bold(a)}`];for(let n of(e.body??``).split(`
|
|
4
4
|
`))for(let e of wrapVisibleLine(n,t-2))o.push(` ${e}`);return o}function renderLog(e,t,n,a){let o=e.title===`stderr`,s=o?n.colors.red:n.colors.gray,c=n.colors.dim(n.glyph.rule),l=o?`stderr`:`stdout`,u=n.colors.dim(`${l} ${n.glyph.dot} `),d=visibleLength(u),f=` `.repeat(d),p=a.previous?.kind===`log`&&a.previous.title===e.title,m=(e.body??``).split(`
|
|
5
5
|
`),h=[];for(let e of m){let r=wrapVisibleLine(e,Math.max(1,t-2-d));for(let e of r){let t=h.length===0&&!p?u:f;h.push(`${c} ${t}${n.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(`
|
|
6
6
|
`).flatMap(e=>wrapVisibleLine(e,Math.max(1,t)))}function truncatePlain(e,t){return visibleLength(e)<=t?e:sliceVisible(e,t)}export{renderBlockLines};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure state and rendering for the prompt's slash-command typeahead: the
|
|
3
|
+
* filtered suggestion list shown above the input while the draft looks like
|
|
4
|
+
* the start of a command. The renderer owns keys and lifecycle; this module
|
|
5
|
+
* owns which commands match, which row is highlighted, and what the rows
|
|
6
|
+
* look like — so the whole interaction is unit-testable without a TTY.
|
|
7
|
+
*/
|
|
8
|
+
import type { PromptCommandSpec } from "./prompt-commands.js";
|
|
9
|
+
import type { Theme } from "./theme.js";
|
|
10
|
+
export interface CommandTypeaheadState {
|
|
11
|
+
/** The prompt text the matches were derived from. */
|
|
12
|
+
readonly query: string;
|
|
13
|
+
readonly matches: readonly PromptCommandSpec[];
|
|
14
|
+
readonly selectedIndex: number;
|
|
15
|
+
/** Esc pressed; the list stays hidden until the query text changes. */
|
|
16
|
+
readonly dismissed: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Derives the typeahead for `text`, carrying the highlight and dismissal
|
|
20
|
+
* over from `previous`. Commands match while the draft is a lone `/`-token
|
|
21
|
+
* (no whitespace yet) prefixing a name or alias; an exact match stays in the
|
|
22
|
+
* list so the highlight confirms what Enter will run. The previous highlight
|
|
23
|
+
* survives narrowing by identity, not index; dismissal survives only while
|
|
24
|
+
* the text is unchanged, so caret moves keep it and any edit reopens.
|
|
25
|
+
*/
|
|
26
|
+
export declare function typeaheadFor(commands: readonly PromptCommandSpec[], text: string, previous?: CommandTypeaheadState): CommandTypeaheadState;
|
|
27
|
+
/** True when the list should render and own the up/down/tab/enter keys. */
|
|
28
|
+
export declare function isTypeaheadOpen(state: CommandTypeaheadState): boolean;
|
|
29
|
+
/** Moves the highlight one row, wrapping at both ends. */
|
|
30
|
+
export declare function moveTypeaheadSelection(state: CommandTypeaheadState, delta: 1 | -1): CommandTypeaheadState;
|
|
31
|
+
/** Hides the list until the input text changes. */
|
|
32
|
+
export declare function dismissTypeahead(state: CommandTypeaheadState): CommandTypeaheadState;
|
|
33
|
+
/** The highlighted command, when the list has one. */
|
|
34
|
+
export declare function selectedTypeaheadCommand(state: CommandTypeaheadState): PromptCommandSpec | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* The editor text accepting `spec` produces: the canonical invocation, plus
|
|
37
|
+
* a trailing space when the command takes an argument so the caret lands
|
|
38
|
+
* ready for typing it.
|
|
39
|
+
*/
|
|
40
|
+
export declare function typeaheadCompletion(spec: PromptCommandSpec): string;
|
|
41
|
+
/**
|
|
42
|
+
* Paints the suggestion rows (the select-question grammar): the highlight
|
|
43
|
+
* carries the cursor glyph and a blue name, every row shows its argument
|
|
44
|
+
* hint, aliases, and description dim, and overflow windows around the
|
|
45
|
+
* highlight.
|
|
46
|
+
*/
|
|
47
|
+
export declare function renderCommandSuggestions(state: CommandTypeaheadState, theme: Theme, width: number): string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{sliceVisible,visibleLength}from"./terminal-text.js";function typeaheadFor(e,t,n){let r=matchingCommands(e,t),i=n===void 0?void 0:n.matches[n.selectedIndex],a=i===void 0?-1:r.indexOf(i);return{query:t,matches:r,selectedIndex:a>=0?a:0,dismissed:n!==void 0&&n.dismissed&&n.query===t}}function matchingCommands(e,t){if(!t.startsWith(`/`)||/\s/.test(t))return[];let n=t.slice(1);return e.filter(e=>[e.name,...e.aliases].some(e=>e.startsWith(n)))}function isTypeaheadOpen(e){return e.matches.length>0&&!e.dismissed}function moveTypeaheadSelection(e,t){let n=e.matches.length;if(n===0)return e;let r=(e.selectedIndex+t+n)%n;return{...e,selectedIndex:r}}function dismissTypeahead(e){return e.dismissed?e:{...e,dismissed:!0}}function selectedTypeaheadCommand(e){return e.matches[e.selectedIndex]}function typeaheadCompletion(e){return`/${e.name}${e.takesArgument?` `:``}`}function renderCommandSuggestions(n,r,i){let a=r.colors,o=n.matches.length,s=Math.min(o,6),c=Math.max(0,Math.min(n.selectedIndex-Math.floor(s/2),o-s)),l=Math.min(c+s,o),u=n.matches.slice(c,l),invocation=e=>{let t=e.argumentHint===void 0?``:` ${e.argumentHint}`,n=e.aliases.map(e=>` (/${e})`).join(``);return`/${e.name}${t}${n}`},d=Math.max(...u.map(e=>invocation(e).length))+2;return u.map((e,t)=>{let i=c+t===n.selectedIndex,o=i?a.cyan(r.glyph.prompt):` `,s=i?a.blue(`/${e.name}`):`/${e.name}`,l=invocation(e).slice(`/${e.name}`.length),u=` `.repeat(d-invocation(e).length);return`${o} ${s}${a.dim(l)}${u}${a.dim(e.description)}`}).map(n=>visibleLength(n)>i?sliceVisible(n,i):n)}export{dismissTypeahead,isTypeaheadOpen,moveTypeaheadSelection,renderCommandSuggestions,selectedTypeaheadCommand,typeaheadCompletion,typeaheadFor};
|
|
@@ -50,3 +50,21 @@ export declare function formatFailureMessage(event: FailureStreamEvent): string;
|
|
|
50
50
|
* `undefined` for them and the headline stands alone.
|
|
51
51
|
*/
|
|
52
52
|
export declare function formatFailureDetail(event: FailureStreamEvent): string | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Minimal TUI rendering for a gateway-auth failure when `/vercel` is available
|
|
55
|
+
* locally. Replaces the harness's full summary — whose remediation names CLI
|
|
56
|
+
* commands and dashboard URLs — with one actionable line; the caller drops
|
|
57
|
+
* the diagnostic detail along with it. The variant is picked off the summary
|
|
58
|
+
* message the harness wrote, so a stale key, an expired OIDC token, and
|
|
59
|
+
* missing credentials each get the fix that actually applies.
|
|
60
|
+
*/
|
|
61
|
+
export declare function formatGatewayAuthFailureNotice(event: FailureStreamEvent): string;
|
|
62
|
+
/**
|
|
63
|
+
* Recognizes a model-call failure caused by AI Gateway authentication. The
|
|
64
|
+
* primary signal is the machine-readable `gatewayName` the harness merges
|
|
65
|
+
* into every model-call failure's details (`extractModelCallErrorDetails`);
|
|
66
|
+
* the summary name is the fallback for payloads whose gateway error was not
|
|
67
|
+
* preserved on the cause chain. Both identifiers are imported from the
|
|
68
|
+
* harness module that writes them, so the two sides cannot drift.
|
|
69
|
+
*/
|
|
70
|
+
export declare function isGatewayAuthFailure(event: FailureStreamEvent): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var InterruptedError=class extends Error{constructor(){super(`Interrupted`),this.name=`InterruptedError`}};function interruptedError(){return new InterruptedError}function isInterruptedError(e){return e instanceof InterruptedError}function isAbortLikeError(e){return e instanceof Error?e.name===`AbortError`||/\babort(?:ed)?\b/iu.test(e.message):!1}function failureKey(e){return`${e.data.code}:${e.data.message}`}function formatFailureMessage(e){let{code:t,message:n}=e.data;return!t||n===t||n.startsWith(`${t}:`)||n.startsWith(`${t} `)?n:`${t}: ${n}`}function formatFailureDetail(e){let t=e.data.details;if(typeof t!=`object`||!t)return;let n=t.detail;if(typeof n!=`string`)return;let r=n.trim();if(!(r.length===0||r===e.data.message.trim()))return r}export{InterruptedError,failureKey,formatFailureDetail,formatFailureMessage,interruptedError,isAbortLikeError,isInterruptedError};
|
|
1
|
+
import{GATEWAY_AUTHENTICATION_ERROR_NAME,GATEWAY_AUTH_FAILURE_SUMMARY_NAME}from"#harness/model-call-error.js";var InterruptedError=class extends Error{constructor(){super(`Interrupted`),this.name=`InterruptedError`}};function interruptedError(){return new InterruptedError}function isInterruptedError(e){return e instanceof InterruptedError}function isAbortLikeError(e){return e instanceof Error?e.name===`AbortError`||/\babort(?:ed)?\b/iu.test(e.message):!1}function failureKey(e){return`${e.data.code}:${e.data.message}`}function formatFailureMessage(e){let{code:t,message:n}=e.data;return!t||n===t||n.startsWith(`${t}:`)||n.startsWith(`${t} `)?n:`${t}: ${n}`}function formatFailureDetail(e){let t=e.data.details;if(typeof t!=`object`||!t)return;let n=t.detail;if(typeof n!=`string`)return;let r=n.trim();if(!(r.length===0||r===e.data.message.trim()))return r}function formatGatewayAuthFailureNotice(e){let t=e.data.message;return/rejected the provided API key|Invalid API key/i.test(t)?`AI Gateway rejected your AI_GATEWAY_API_KEY. Run /vercel to refresh credentials, or update it in .env.local (a stale shell export can shadow it).`:/rejected the OIDC token|Invalid OIDC token/i.test(t)?`Your AI Gateway OIDC token is invalid or expired. Run /vercel to refresh it, or set AI_GATEWAY_API_KEY in .env.local.`:`There is no AI_GATEWAY_API_KEY set. Run /vercel to connect this to a project and refresh AI Gateway credentials, or set it manually in .env.local.`}function isGatewayAuthFailure(n){let r=n.data.details;if(typeof r!=`object`||!r)return!1;let i=r;return i.gatewayName===GATEWAY_AUTHENTICATION_ERROR_NAME||i.name===GATEWAY_AUTH_FAILURE_SUMMARY_NAME}export{InterruptedError,failureKey,formatFailureDetail,formatFailureMessage,formatGatewayAuthFailureNotice,interruptedError,isAbortLikeError,isGatewayAuthFailure,isInterruptedError};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PromptCommandHandler } from "./runner.js";
|
|
2
|
+
export interface PromptCommandHandlerOptions {
|
|
3
|
+
readonly appRoot?: string;
|
|
4
|
+
/** Test seam; defaults to the model flow's shared source-change apply. */
|
|
5
|
+
readonly applyModel?: (input: {
|
|
6
|
+
appRoot: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
}) => Promise<string>;
|
|
9
|
+
}
|
|
10
|
+
export declare function createPromptCommandHandler(options: PromptCommandHandlerOptions): PromptCommandHandler;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function createPromptCommandHandler(e){return{async handle(t,n){let r=e.appRoot;if(r===void 0)return`/${t.name} needs eve dev running the local server (it is not available with --url).`;if(t.name===`model`&&t.argument.length>0){let n=e.applyModel??(await import(`#setup/flows/model.js`)).changeAgentModel;try{return await n({appRoot:r,slug:t.argument})}catch(e){return`Couldn't change the model: ${e instanceof Error?e.message:String(e)}`}}let i=n.renderer.setupFlow;if(i===void 0)return`/${t.name} is not supported by this renderer.`;let{runTuiSetupCommand:a,SETUP_FLOW_TITLES:o}=await import(`./setup-commands.js`);i.begin(o[t.name]);let s=!0;try{let e=await a({command:t.name,appRoot:r,renderer:i});return s=e.preserveFlowDiagnostics,e.message}finally{i.end({preserveDiagnostics:s})}}}}export{createPromptCommandHandler};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export type PromptCommandExtensionName = "model" | "vercel" | "channels" | "deploy";
|
|
2
|
+
/** The slash commands the prompt accepts. */
|
|
3
|
+
export type PromptCommand = {
|
|
4
|
+
type: "new";
|
|
5
|
+
} | {
|
|
6
|
+
type: "exit";
|
|
7
|
+
} | {
|
|
8
|
+
type: "help";
|
|
9
|
+
} | {
|
|
10
|
+
type: "extension";
|
|
11
|
+
name: PromptCommandExtensionName;
|
|
12
|
+
argument: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Metadata for one slash command. The registry describes commands — their
|
|
16
|
+
* names, aliases, and discovery copy — it never executes them: dispatch stays
|
|
17
|
+
* with the runner and the prompt-command handler.
|
|
18
|
+
*/
|
|
19
|
+
export interface PromptCommandSpec {
|
|
20
|
+
/** Canonical name without the slash, e.g. "model". */
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly aliases: readonly string[];
|
|
23
|
+
/** One-line discovery copy shown by the typeahead. */
|
|
24
|
+
readonly description: string;
|
|
25
|
+
/** Argument shape shown dim after the name, e.g. "[provider/model]". */
|
|
26
|
+
readonly argumentHint?: string;
|
|
27
|
+
/** Accepts a trailing argument (enables `/name <arg>` parsing). */
|
|
28
|
+
readonly takesArgument: boolean;
|
|
29
|
+
/** Maps a recognized invocation to its parsed command. */
|
|
30
|
+
readonly build: (argument: string) => PromptCommand;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Every slash command the prompt accepts, in typeahead display order. One
|
|
34
|
+
* module owns the command list so the runner's dispatch, the renderer's
|
|
35
|
+
* transcript-echo suppression, and command discovery cannot drift apart.
|
|
36
|
+
*/
|
|
37
|
+
export declare const PROMPT_COMMANDS: readonly PromptCommandSpec[];
|
|
38
|
+
/**
|
|
39
|
+
* Recognizes the slash commands the prompt accepts. `/new` clears the
|
|
40
|
+
* session and transcript; `/exit` (and `/quit`) terminate the TUI like
|
|
41
|
+
* Ctrl+C; extension commands are dispatched outside the runner. Anything
|
|
42
|
+
* else — including unknown `/text` — is a normal message.
|
|
43
|
+
*/
|
|
44
|
+
export declare function parsePromptCommand(prompt: string): PromptCommand | null;
|
|
45
|
+
/** True for prompts that are commands, which never echo as user messages. */
|
|
46
|
+
export declare function isPromptControlCommand(prompt: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* The table `/help` prints: one line per command — slash name, argument
|
|
49
|
+
* hint, and aliases padded into a column, description after.
|
|
50
|
+
*/
|
|
51
|
+
export declare function formatPromptCommandHelp(): string;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const PROMPT_COMMANDS=[{name:`help`,aliases:[],description:`Show available commands`,takesArgument:!1,build:()=>({type:`help`})},{name:`new`,aliases:[],description:`Start a fresh session`,takesArgument:!1,build:()=>({type:`new`})},{name:`model`,aliases:[],description:`Pick or set the agent's model`,argumentHint:`[provider/model]`,takesArgument:!0,build:e=>({type:`extension`,name:`model`,argument:e})},{name:`vercel`,aliases:[],description:`Link the project to Vercel`,takesArgument:!1,build:()=>({type:`extension`,name:`vercel`,argument:``})},{name:`channels`,aliases:[],description:`Add chat channels to the agent`,takesArgument:!1,build:()=>({type:`extension`,name:`channels`,argument:``})},{name:`deploy`,aliases:[],description:`Deploy the agent to Vercel`,takesArgument:!1,build:()=>({type:`extension`,name:`deploy`,argument:``})},{name:`exit`,aliases:[`quit`],description:`Quit the TUI`,takesArgument:!1,build:()=>({type:`exit`})}];function parsePromptCommand(t){let n=t.trim();if(!n.startsWith(`/`))return null;for(let t of PROMPT_COMMANDS)for(let e of[t.name,...t.aliases]){let r=`/${e}`;if(n===r)return t.build(``);if(t.takesArgument&&n.startsWith(`${r} `))return t.build(n.slice(r.length).trim())}return null}function isPromptControlCommand(e){return parsePromptCommand(e)!==null}function formatPromptCommandHelp(){let t=PROMPT_COMMANDS.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}}),n=Math.max(...t.map(e=>e.invocation.length))+2;return t.map(e=>e.invocation.padEnd(n)+e.description).join(`
|
|
2
|
+
`)}export{PROMPT_COMMANDS,formatPromptCommandHelp,isPromptControlCommand,parsePromptCommand};
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { type AgentInfoResult, type ConnectionAuthorizationOutcome, type InputRequest, Client, ClientSession } from "#client/index.js";
|
|
2
|
+
import { type PromptCommand } from "./prompt-commands.js";
|
|
3
|
+
import { type BootDetection } from "./setup-issues.js";
|
|
4
|
+
import type { SetupFlowRenderer } from "./setup-flow.js";
|
|
2
5
|
import type { AssistantResponseStatsMode, TerminalPartDisplayMode, TuiDisplayOptions } from "./types.js";
|
|
3
6
|
import { type TerminalInput, type TerminalOutput } from "./terminal-renderer.js";
|
|
7
|
+
export { parsePromptCommand, type PromptCommand } from "./prompt-commands.js";
|
|
4
8
|
export type AgentTUIStreamResult = {
|
|
5
9
|
events: AsyncIterable<AgentTUIStreamEvent> | ReadableStream<AgentTUIStreamEvent>;
|
|
6
10
|
abort?: () => void;
|
|
@@ -104,6 +108,7 @@ export type AgentTUIAgentHeader = {
|
|
|
104
108
|
name: string;
|
|
105
109
|
serverUrl: string;
|
|
106
110
|
info?: AgentInfoResult;
|
|
111
|
+
setupCommands?: boolean;
|
|
107
112
|
};
|
|
108
113
|
export type AgentTUIRenderer = {
|
|
109
114
|
/**
|
|
@@ -118,6 +123,9 @@ export type AgentTUIRenderer = {
|
|
|
118
123
|
* recovery and slash-command results. Optional.
|
|
119
124
|
*/
|
|
120
125
|
renderNotice?(text: string): void;
|
|
126
|
+
renderSetupWarning?(text: string): void;
|
|
127
|
+
renderCommandResult?(text: string): void;
|
|
128
|
+
readonly setupFlow?: SetupFlowRenderer;
|
|
121
129
|
readPrompt?(options?: AgentTUISessionOptions): Promise<string | undefined>;
|
|
122
130
|
readToolApproval?(request: AgentTUIToolApprovalRequest, options?: AgentTUISessionOptions): Promise<AgentTUIToolApprovalResponse>;
|
|
123
131
|
readInputQuestion?(question: AgentTUIInputQuestion, options?: AgentTUISessionOptions): Promise<AgentTUIInputQuestionResponse | undefined>;
|
|
@@ -166,21 +174,14 @@ export type AgentTUIRenderer = {
|
|
|
166
174
|
*/
|
|
167
175
|
shutdown?(): void;
|
|
168
176
|
};
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
export interface
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
*/
|
|
178
|
-
listChoices(): Promise<ReadonlyArray<{
|
|
179
|
-
readonly id: string;
|
|
180
|
-
readonly label: string;
|
|
181
|
-
}>>;
|
|
182
|
-
/** Applies a chosen model id to the authored source and returns a result line. */
|
|
183
|
-
apply(slug: string): Promise<string>;
|
|
177
|
+
export interface PromptCommandHandlerContext {
|
|
178
|
+
readonly renderer: AgentTUIRenderer;
|
|
179
|
+
readonly title: string;
|
|
180
|
+
}
|
|
181
|
+
export interface PromptCommandHandler {
|
|
182
|
+
handle(command: Extract<PromptCommand, {
|
|
183
|
+
type: "extension";
|
|
184
|
+
}>, context: PromptCommandHandlerContext): Promise<string | undefined>;
|
|
184
185
|
}
|
|
185
186
|
export type EveTUIRunnerOptions = TuiDisplayOptions & {
|
|
186
187
|
session: ClientSession;
|
|
@@ -210,32 +211,18 @@ export type EveTUIRunnerOptions = TuiDisplayOptions & {
|
|
|
210
211
|
* artifacts; input-response resumes keep the current session.
|
|
211
212
|
*/
|
|
212
213
|
serverUrl?: string;
|
|
213
|
-
/**
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
214
|
+
/** Absolute local application root; omitted for remote `--url` sessions. */
|
|
215
|
+
appRoot?: string;
|
|
216
|
+
/** Handles non-core slash commands without adding feature branches to the runner. */
|
|
217
|
+
promptCommandHandler?: PromptCommandHandler;
|
|
218
|
+
/** Boot-time installation-state checks; defaults to the built-ins. */
|
|
219
|
+
bootDetections?: readonly BootDetection[];
|
|
218
220
|
};
|
|
219
221
|
export declare class EveTUIRunner {
|
|
220
222
|
#private;
|
|
221
223
|
constructor(options: EveTUIRunnerOptions);
|
|
222
224
|
run(): Promise<void>;
|
|
223
225
|
}
|
|
224
|
-
/**
|
|
225
|
-
* Recognizes the slash commands the prompt accepts. `/new` clears the
|
|
226
|
-
* session and transcript; `/exit` (and `/quit`) terminate the TUI like
|
|
227
|
-
* Ctrl+C; `/model <slug>` edits the agent's model. Anything else is a normal
|
|
228
|
-
* message.
|
|
229
|
-
*/
|
|
230
|
-
export type PromptCommand = {
|
|
231
|
-
type: "new";
|
|
232
|
-
} | {
|
|
233
|
-
type: "exit";
|
|
234
|
-
} | {
|
|
235
|
-
type: "model";
|
|
236
|
-
slug: string;
|
|
237
|
-
};
|
|
238
|
-
export declare function parsePromptCommand(prompt: string): PromptCommand | null;
|
|
239
226
|
type SubagentChildStep = {
|
|
240
227
|
reasoning: string;
|
|
241
228
|
message: string;
|
|
@@ -300,4 +287,3 @@ export type ConnectionAuthUpdate = {
|
|
|
300
287
|
challenge?: ConnectionAuthChallenge;
|
|
301
288
|
reason?: string;
|
|
302
289
|
};
|
|
303
|
-
export {};
|