Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions packages/eve/src/cli/dev/tui/terminal-renderer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3035,6 +3035,28 @@ describe("TerminalRenderer (inline scrollback)", () => {
expect(screen.snapshot()).toContain("tui/setup-panel.ts changed · rebuilt");
});

it("updates the rebuild status before the watcher writes a newline", () => {
const screen = new MockScreen({ columns: 100, rows: 30 });
const input = new MockUserInput();
const renderer = new TerminalRenderer({
input,
output: screen,
captureForeignOutput: true,
logs: "all",
unicode: true,
});
renderer.renderAgentHeader({ name: "Weather Agent", serverUrl: "http://localhost:3000" });

process.stdout.write(
formatChangeDetectedLogLine("/app", [{ event: "change", path: "/app/package.json" }]),
);

const snapshot = screen.snapshot();
expect(snapshot).toContain("package.json changed · rebuilding…");
expect(snapshot).not.toContain("[eve:dev] change detected");
renderer.shutdown();
});

it("flips the status row to reloading on a structural change", () => {
const screen = new MockScreen({ columns: 100, rows: 30 });
const input = new MockUserInput();
Expand Down
7 changes: 7 additions & 0 deletions packages/eve/src/cli/dev/tui/terminal-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4121,6 +4121,13 @@ export class TerminalRenderer implements AgentTUIRenderer {

#handleForeignOutput(source: "stdout" | "stderr", text: string): void {
const combined = (source === "stdout" ? this.#stdoutLogBuffer : this.#stderrLogBuffer) + text;
if (source === "stdout" && parseDevRebuildLogLine(combined.trimEnd()) !== undefined) {
this.#stdoutLogBuffer = "";
this.#diagnostics?.append({ source, detail: combined.trimEnd() });
this.#handleCapturedStdout(combined.trimEnd());
this.#paint();
return;
}
const lastNewline = combined.lastIndexOf("\n");
const remainder = lastNewline === -1 ? combined : combined.slice(lastNewline + 1);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ describe("channel setup environment", () => {
);
});

it("reports the portable fallback when logged out", () => {
it("reports the credential choice when logged out", () => {
const environment = channelSetupEnvironment("logged-out", { kind: "unresolved" });
expect(environment).toEqual({ vercel: { kind: "unavailable", reason: "logged-out" } });
expect(describeChannelSetupEnvironment(environment)).toBe(
"No authenticated Vercel account found; using portable channel setup.",
"No authenticated Vercel account found; choose Vercel Connect or portable credentials.",
);
});
});
6 changes: 3 additions & 3 deletions packages/eve/src/setup/integrations/channels/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ export function describeChannelSetupEnvironment(environment: ChannelSetupEnviron
}
switch (environment.vercel.reason) {
case "logged-out":
return "No authenticated Vercel account found; using portable channel setup.";
return "No authenticated Vercel account found; choose Vercel Connect or portable credentials.";
case "cli-missing":
return "Vercel CLI not found; using portable channel setup.";
return "Vercel CLI not found; choose Vercel Connect or portable credentials.";
case "unavailable":
return "Could not verify the Vercel account; using portable channel setup.";
return "Could not verify the Vercel account; choose Vercel Connect or portable credentials.";
}
}

Expand Down
6 changes: 5 additions & 1 deletion packages/eve/src/setup/integrations/channels/slack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { WizardCancelledError } from "../../step.js";
async function choosePortableCredentials(
context: Parameters<ChannelSetupIntegration["setup"]>[0],
): Promise<"vercel-connect" | "environment" | "cancelled"> {
if (context.environment.vercel.kind === "available") return "vercel-connect";
if (context.presetPortableCredentials !== undefined) {
return context.presetPortableCredentials ? "environment" : "vercel-connect";
}
Expand Down Expand Up @@ -41,6 +40,11 @@ export const SLACK_CHANNEL_SETUP: ChannelSetupIntegration = {
async setup(context) {
const credentials = await choosePortableCredentials(context);
if (credentials === "cancelled") return { kind: "cancelled" };
if (credentials === "vercel-connect" && context.environment.vercel.kind === "unavailable") {
throw new Error(
"Vercel Connect requires an authenticated Vercel CLI. Run `vercel login`, then retry Slack setup.",
);
}

const result = await runChannelSetup(
context,
Expand Down
Loading