Skip to content

Commit 3339179

Browse files
committed
feat(cli): default output to JSON for coding agents
1 parent 2bb1173 commit 3339179

5 files changed

Lines changed: 45 additions & 5 deletions

File tree

apps/cli/src/legacy/cli/root.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ import { OutputFormatFlag } from "../../shared/cli/global-flags.ts";
3939
import { outputLayerFor } from "../../shared/output/output.layer.ts";
4040
import { legacyQuietProgressTextOutputLayer } from "../output/legacy-quiet-progress-text-output.layer.ts";
4141
import { makeGoProxyLayer } from "../../shared/legacy/go-proxy.layer.ts";
42+
import { AiTool } from "../../shared/telemetry/ai-tool.service.ts";
43+
import { aiToolLayer } from "../../shared/telemetry/ai-tool.layer.ts";
44+
import { resolveAgentOutputFormat } from "../../shared/cli/agent-output.ts";
4245
import {
4346
LEGACY_GLOBAL_FLAGS,
4447
LegacyAgentFlag,
@@ -96,7 +99,7 @@ export const legacyRoot = Command.make("supabase").pipe(
9699
Command.provide(
97100
Layer.unwrap(
98101
Effect.gen(function* () {
99-
const outputFormat = yield* OutputFormatFlag;
102+
const explicitOutputFormat = yield* OutputFormatFlag;
100103
const goOutput = yield* LegacyOutputFlag;
101104
const profile = yield* LegacyProfileFlag;
102105
const debug = yield* LegacyDebugFlag;
@@ -108,6 +111,10 @@ export const legacyRoot = Command.make("supabase").pipe(
108111
const createTicket = yield* LegacyCreateTicketFlag;
109112
const agent = yield* LegacyAgentFlag;
110113

114+
const aiTool = yield* AiTool.pipe(Effect.provide(aiToolLayer));
115+
const isCodingAgent = agent === "yes" || (agent !== "no" && Option.isSome(aiTool.name));
116+
const outputFormat = resolveAgentOutputFormat(explicitOutputFormat, isCodingAgent);
117+
111118
// Build args to prepend to every proxy exec call.
112119
// --output: use explicit --output if set, otherwise map from --output-format.
113120
const globalArgs: string[] = [];

apps/cli/src/next/cli/root.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import { Effect, Layer } from "effect";
1+
import { Effect, Layer, Option } from "effect";
22
import { CliOutput, Command } from "effect/unstable/cli";
33
import { OutputFormatFlag } from "../../shared/cli/global-flags.ts";
4+
import { AiTool } from "../../shared/telemetry/ai-tool.service.ts";
5+
import { aiToolLayer } from "../../shared/telemetry/ai-tool.layer.ts";
6+
import { resolveAgentOutputFormat } from "../../shared/cli/agent-output.ts";
47
import { branchesCommand } from "../commands/branches/branches.command.ts";
58
import { functionsCommand } from "../commands/functions/functions.command.ts";
69
import { linkCommand } from "../commands/link/link.command.ts";
@@ -47,7 +50,10 @@ export const nextRoot = Command.make("supabase").pipe(
4750
Command.provide(
4851
Layer.unwrap(
4952
Effect.gen(function* () {
50-
const outputFormat = yield* OutputFormatFlag;
53+
const explicitOutputFormat = yield* OutputFormatFlag;
54+
const aiTool = yield* AiTool.pipe(Effect.provide(aiToolLayer));
55+
const isCodingAgent = Option.isSome(aiTool.name);
56+
const outputFormat = resolveAgentOutputFormat(explicitOutputFormat, isCodingAgent);
5157
const base = outputLayerFor(outputFormat);
5258
if (outputFormat === "text") return base;
5359
return Layer.merge(base, CliOutput.layer(jsonCliOutputFormatter()));
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Option } from "effect";
2+
import type { OutputFormat } from "../output/types.ts";
3+
4+
export function resolveAgentOutputFormat(
5+
explicit: Option.Option<OutputFormat>,
6+
isCodingAgent: boolean,
7+
): OutputFormat {
8+
return Option.getOrElse(explicit, () => (isCodingAgent ? "json" : "text"));
9+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Option } from "effect";
2+
import { describe, expect, it } from "vitest";
3+
import { resolveAgentOutputFormat } from "./agent-output.ts";
4+
5+
describe("resolveAgentOutputFormat", () => {
6+
it("defaults a coding agent to json", () => {
7+
expect(resolveAgentOutputFormat(Option.none(), true)).toBe("json");
8+
});
9+
10+
it("defaults a non-agent to text", () => {
11+
expect(resolveAgentOutputFormat(Option.none(), false)).toBe("text");
12+
});
13+
14+
it("honors an explicit format over agent detection", () => {
15+
expect(resolveAgentOutputFormat(Option.some("text"), true)).toBe("text");
16+
expect(resolveAgentOutputFormat(Option.some("stream-json"), false)).toBe("stream-json");
17+
expect(resolveAgentOutputFormat(Option.some("json"), true)).toBe("json");
18+
});
19+
});
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { Flag, GlobalFlag } from "effect/unstable/cli";
2-
import type { OutputFormat } from "../output/types.ts";
32

43
export const OutputFormatFlag = GlobalFlag.setting("output-format")({
54
flag: Flag.choice("output-format", ["text", "json", "stream-json"]).pipe(
65
Flag.withDescription("Output format: text (default), json, or stream-json (NDJSON)"),
7-
Flag.withDefault("text" as OutputFormat),
6+
Flag.optional,
87
),
98
});

0 commit comments

Comments
 (0)