add antigravity print feature and update configs
This commit is contained in:
parent
0679621190
commit
9d8cafe3b7
8 changed files with 347 additions and 6 deletions
|
|
@ -38,7 +38,7 @@ ops console은 edge-local diagnostic surface이고, HTTP/API는 central/remote m
|
|||
|
||||
**전제 조건**: `configs/edge.yaml`의 `console.target`이 가리키는 CLI profile command가 node 호스트에서 실행 가능해야 한다. 기본 예시는 `opencode`이며, `claude`, `claude-tui`, `antigravity`, `codex`, `cline-dgx` 등으로 바꿀 수 있다.
|
||||
|
||||
같은 `cli` 어댑터 안에 `claude`, `claude-tui`, `antigravity`, `codex`, `opencode`, `cline` profile을 포함할 수 있다. 예를 들어 `claude`는 `claude -p` 기반 one-shot profile로 두고, `claude-tui`는 `persistent: true`, `terminal: true`, `mode: "persistent-lazy"`로 첫 요청 시 일반 Claude Code TUI 세션을 띄운다. `agy --dangerously-skip-permissions --print <prompt>`, `codex exec --dangerously-bypass-approvals-and-sandbox`, `cline -y --json --config /config/.cline/profiles/ollama-dgx <prompt>`처럼 headless 조합도 설정할 수 있다. `opencode`는 `mode: "opencode-sse"` profile로 `opencode serve`의 HTTP/SSE 인터페이스를 사용하며, args의 `--model`, `--dangerously-skip-permissions`, `--title` 등은 그대로 유지하면 된다.
|
||||
같은 `cli` 어댑터 안에 `claude`, `claude-tui`, `antigravity`, `codex`, `opencode`, `cline` profile을 포함할 수 있다. 예를 들어 `claude`는 `claude -p` 기반 one-shot profile로 두고, `claude-tui`는 `persistent: true`, `terminal: true`, `mode: "persistent-lazy"`로 첫 요청 시 일반 Claude Code TUI 세션을 띄운다. `antigravity`는 `mode: "antigravity-print"`로 `agy --dangerously-skip-permissions --print <prompt>`를 실행하고, 같은 IOP session의 다음 요청은 `agy --conversation <conversation_id> --print <prompt>` 형태로 이어간다. `codex exec --dangerously-bypass-approvals-and-sandbox`, `cline -y --json --config /config/.cline/profiles/ollama-dgx <prompt>`처럼 다른 headless 조합도 설정할 수 있다. `opencode`는 `mode: "opencode-sse"` profile로 `opencode serve`의 HTTP/SSE 인터페이스를 사용하며, args의 `--model`, `--dangerously-skip-permissions`, `--title` 등은 그대로 유지하면 된다.
|
||||
|
||||
실행 순서:
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,8 @@ Ollama adapter는 edge에서 받은 내부 target을 Ollama model 이름으로
|
|||
|
||||
Claude는 용도별로 두 profile을 둔다. `claude`는 `claude -p` 기반 one-shot profile이며 Agent SDK/credit 경로 검증용으로 유지한다. `claude-tui`는 `persistent: true`, `terminal: true`, `mode: "persistent-lazy"`로 일반 Claude Code TUI를 첫 요청 시 lazy start한다. TUI 출력은 structured JSON이 아니므로 idle timeout 기반으로 completion을 판단한다.
|
||||
|
||||
Antigravity는 `mode: "antigravity-print"`로 설정해 TUI가 아닌 print mode에서도 IOP `session_id`별 conversation을 이어간다. 첫 실행은 `agy --print <prompt>`로 새 conversation을 만들고 로그에서 conversation id를 읽어 저장한다. 같은 IOP session의 다음 실행은 `resume_args`를 사용해 `agy --conversation <conversation_id> --print <prompt>` 형태로 재개한다.
|
||||
|
||||
`opencode`는 profile `mode: "opencode-sse"`로 설정해 `opencode serve`의 HTTP/SSE 인터페이스를 사용한다. `profile.Command`가 가리키는 opencode 바이너리를 `serve --hostname 127.0.0.1 --port 0`으로 띄우고 `/global/event` SSE에서 text delta를 `RuntimeEvent` delta로 relay한다. 외부에서 이미 실행 중인 server에 연결하려면 `--attach <url>`을 args에 추가한다. legacy `output_format: "opencode-json"` stdout JSONL 경로는 `opencode run --format json` 사용 시에만 의미가 있다.
|
||||
|
||||
Cline은 mutable `--config` 디렉터리를 프로필처럼 나눈다. `/config/.cline/profiles/ollama-dgx`와 `/config/.cline/profiles/ollama-m1`는 `opencode`의 `ollama-dgx`/`ollama-m1` provider 설정을 Cline의 `ollama` provider 설정으로 변환한 값이다.
|
||||
|
|
|
|||
127
apps/node/internal/adapters/cli/antigravity_print.go
Normal file
127
apps/node/internal/adapters/cli/antigravity_print.go
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"iop/apps/node/internal/runtime"
|
||||
"iop/packages/config"
|
||||
)
|
||||
|
||||
var antigravityConversationPatterns = []*regexp.Regexp{
|
||||
regexp.MustCompile(`(?m)Created conversation (` + uuidPattern + `)`),
|
||||
regexp.MustCompile(`(?m)Streaming conversation (` + uuidPattern + `)`),
|
||||
regexp.MustCompile(`(?m)Print mode: conversation=(` + uuidPattern + `)`),
|
||||
regexp.MustCompile(`(?m)conversationID="(` + uuidPattern + `)"`),
|
||||
}
|
||||
|
||||
const uuidPattern = `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}`
|
||||
|
||||
func (c *CLI) executeAntigravityPrint(ctx context.Context, spec runtime.ExecutionSpec, profile config.CLIProfileConf, sink runtime.EventSink) error {
|
||||
if len(profile.ResumeArgs) == 0 {
|
||||
return fmt.Errorf("cli adapter: antigravity-print mode requires resume_args in profile %q", spec.Target)
|
||||
}
|
||||
|
||||
sess, err := c.resolveAntigravitySession(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sess.mu.Lock()
|
||||
defer sess.mu.Unlock()
|
||||
|
||||
logFile, cleanup, err := createAntigravityLogFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
prompt := extractPrompt(spec.Input)
|
||||
args := antigravityPrintArgs(profile, sess.conversationID, logFile, prompt)
|
||||
output, err := c.executeCommand(ctx, spec, profile, args, prompt, sink)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logOutput, readErr := os.ReadFile(logFile)
|
||||
if readErr != nil {
|
||||
return fmt.Errorf("cli adapter: read antigravity log: %w", readErr)
|
||||
}
|
||||
if conversationID := parseAntigravityConversationID(string(logOutput) + output); conversationID != "" {
|
||||
sess.conversationID = conversationID
|
||||
}
|
||||
if sess.conversationID == "" {
|
||||
return fmt.Errorf("cli adapter: antigravity-print did not report a conversation id")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CLI) resolveAntigravitySession(spec runtime.ExecutionSpec) (*antigravitySession, error) {
|
||||
target := cliTargetName(spec)
|
||||
key := sessionKey{target: target, sessionID: normalizeSessionID(spec.SessionID)}
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if sess, ok := c.agySessions[key]; ok {
|
||||
return sess, nil
|
||||
}
|
||||
if spec.SessionMode == runtime.SessionModeRequireExisting {
|
||||
return nil, fmt.Errorf("cli adapter: no antigravity conversation for target %q session %q", target, key.sessionID)
|
||||
}
|
||||
sess := &antigravitySession{key: key}
|
||||
c.agySessions[key] = sess
|
||||
return sess, nil
|
||||
}
|
||||
|
||||
func antigravityPrintArgs(profile config.CLIProfileConf, conversationID, logFile, prompt string) []string {
|
||||
args := []string{"--log-file", logFile}
|
||||
if conversationID == "" {
|
||||
args = append(args, profile.Args...)
|
||||
} else {
|
||||
args = append(args, removeAntigravityPrintFlag(profile.ResumeArgs)...)
|
||||
args = append(args, conversationID)
|
||||
args = append(args, "--print")
|
||||
}
|
||||
return append(args, prompt)
|
||||
}
|
||||
|
||||
func removeAntigravityPrintFlag(args []string) []string {
|
||||
filtered := make([]string, 0, len(args))
|
||||
for _, arg := range args {
|
||||
switch arg {
|
||||
case "--print", "--prompt", "-p":
|
||||
continue
|
||||
default:
|
||||
filtered = append(filtered, arg)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func createAntigravityLogFile() (string, func(), error) {
|
||||
f, err := os.CreateTemp("", "iop-antigravity-*.log")
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("cli adapter: create antigravity log file: %w", err)
|
||||
}
|
||||
path := f.Name()
|
||||
if err := f.Close(); err != nil {
|
||||
_ = os.Remove(path)
|
||||
return "", nil, fmt.Errorf("cli adapter: close antigravity log file: %w", err)
|
||||
}
|
||||
return path, func() { _ = os.Remove(path) }, nil
|
||||
}
|
||||
|
||||
func parseAntigravityConversationID(s string) string {
|
||||
var id string
|
||||
for _, re := range antigravityConversationPatterns {
|
||||
for _, match := range re.FindAllStringSubmatch(s, -1) {
|
||||
if len(match) >= 2 {
|
||||
id = match[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
package cli_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
clipkg "iop/apps/node/internal/adapters/cli"
|
||||
"iop/apps/node/internal/adapters/cli/internal/testutil"
|
||||
noderuntime "iop/apps/node/internal/runtime"
|
||||
"iop/packages/config"
|
||||
)
|
||||
|
||||
func TestCLIExecuteAntigravityPrintResumesLogicalSession(t *testing.T) {
|
||||
testutil.RequireUnixShell(t)
|
||||
|
||||
agy := writeFakeAgy(t, `#!/usr/bin/env sh
|
||||
log_file=""
|
||||
conversation=""
|
||||
prompt=""
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--log-file)
|
||||
log_file="$2"
|
||||
shift 2
|
||||
;;
|
||||
--conversation)
|
||||
conversation="$2"
|
||||
shift 2
|
||||
;;
|
||||
--print-timeout)
|
||||
shift 2
|
||||
;;
|
||||
--dangerously-skip-permissions|--print)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
prompt="$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$log_file" ]; then
|
||||
echo "missing --log-file" >&2
|
||||
exit 9
|
||||
fi
|
||||
|
||||
if [ -z "$conversation" ]; then
|
||||
printf 'I0000 server.go:747] Created conversation 11111111-2222-3333-4444-555555555555\n' >> "$log_file"
|
||||
printf 'reply:first:%s\n' "$prompt"
|
||||
else
|
||||
printf 'I0000 printmode.go:71] Print mode: starting (promptLength=1, model="", conversationID="%s")\n' "$conversation" >> "$log_file"
|
||||
printf 'reply:resume:%s:%s\n' "$conversation" "$prompt"
|
||||
fi
|
||||
`)
|
||||
cfg := config.CLIConf{
|
||||
Enabled: true,
|
||||
Profiles: map[string]config.CLIProfileConf{
|
||||
"antigravity": {
|
||||
Command: agy,
|
||||
Args: []string{
|
||||
"--dangerously-skip-permissions",
|
||||
"--print-timeout",
|
||||
"10m",
|
||||
"--print",
|
||||
},
|
||||
Mode: "antigravity-print",
|
||||
ResumeArgs: []string{
|
||||
"--dangerously-skip-permissions",
|
||||
"--print-timeout",
|
||||
"10m",
|
||||
"--conversation",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
c := clipkg.New(cfg, zap.NewNop())
|
||||
ctx := context.Background()
|
||||
|
||||
first := &testutil.FakeSink{}
|
||||
if err := c.Execute(ctx, noderuntime.ExecutionSpec{
|
||||
RunID: "run-1",
|
||||
Target: "antigravity",
|
||||
SessionID: "session-a",
|
||||
Input: map[string]any{"prompt": "first"},
|
||||
}, first); err != nil {
|
||||
t.Fatalf("first execute: %v", err)
|
||||
}
|
||||
if combined := testutil.CollectDeltas(first.Events()); !strings.Contains(combined, "reply:first:first") {
|
||||
t.Fatalf("first execute output: %q", combined)
|
||||
}
|
||||
|
||||
second := &testutil.FakeSink{}
|
||||
if err := c.Execute(ctx, noderuntime.ExecutionSpec{
|
||||
RunID: "run-2",
|
||||
Target: "antigravity",
|
||||
SessionID: "session-a",
|
||||
Input: map[string]any{"prompt": "second"},
|
||||
}, second); err != nil {
|
||||
t.Fatalf("second execute: %v", err)
|
||||
}
|
||||
if combined := testutil.CollectDeltas(second.Events()); !strings.Contains(combined, "reply:resume:11111111-2222-3333-4444-555555555555:second") {
|
||||
t.Fatalf("second execute output: %q", combined)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCLIExecuteAntigravityPrint_MissingResumeArgsErrors(t *testing.T) {
|
||||
testutil.RequireUnixShell(t)
|
||||
|
||||
agy := writeFakeAgy(t, `#!/usr/bin/env sh
|
||||
echo "should not be called when resume_args is missing" >&2
|
||||
exit 42
|
||||
`)
|
||||
cfg := config.CLIConf{
|
||||
Enabled: true,
|
||||
Profiles: map[string]config.CLIProfileConf{
|
||||
"antigravity": {
|
||||
Command: agy,
|
||||
Args: []string{"--print"},
|
||||
Mode: "antigravity-print",
|
||||
ResumeArgs: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
c := clipkg.New(cfg, zap.NewNop())
|
||||
err := c.Execute(context.Background(), noderuntime.ExecutionSpec{
|
||||
RunID: "run-1",
|
||||
Target: "antigravity",
|
||||
SessionID: "session-a",
|
||||
Input: map[string]any{"prompt": "first"},
|
||||
}, &testutil.FakeSink{})
|
||||
if err == nil {
|
||||
t.Fatalf("expected error due to missing resume_args, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "resume_args") {
|
||||
t.Fatalf("expected error to mention resume_args, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeFakeAgy(t *testing.T, script string) string {
|
||||
t.Helper()
|
||||
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "agy")
|
||||
if err := os.WriteFile(path, []byte(script), 0o755); err != nil {
|
||||
t.Fatalf("write fake agy: %v", err)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ const Name = "cli"
|
|||
|
||||
const (
|
||||
modeCodexExec = "codex-exec"
|
||||
modeAntigravity = "antigravity-print"
|
||||
modeOpencodeSSE = "opencode-sse"
|
||||
modePersistentLazy = "persistent-lazy"
|
||||
)
|
||||
|
|
@ -61,11 +62,18 @@ type codexExecSession struct {
|
|||
mu sync.Mutex
|
||||
}
|
||||
|
||||
type antigravitySession struct {
|
||||
key sessionKey
|
||||
conversationID string
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
type CLI struct {
|
||||
mu sync.Mutex
|
||||
profiles map[string]config.CLIProfileConf
|
||||
sessions map[sessionKey]*profileSession
|
||||
codexSessions map[sessionKey]*codexExecSession
|
||||
agySessions map[sessionKey]*antigravitySession
|
||||
opencodeSessions map[sessionKey]*opencodeSSESession
|
||||
logger *zap.Logger
|
||||
|
||||
|
|
@ -78,6 +86,7 @@ func New(cfg config.CLIConf, logger *zap.Logger) *CLI {
|
|||
profiles: cfg.Profiles,
|
||||
sessions: make(map[sessionKey]*profileSession),
|
||||
codexSessions: make(map[sessionKey]*codexExecSession),
|
||||
agySessions: make(map[sessionKey]*antigravitySession),
|
||||
opencodeSessions: make(map[sessionKey]*opencodeSSESession),
|
||||
logger: logger,
|
||||
}
|
||||
|
|
@ -131,6 +140,7 @@ func (c *CLI) Start(ctx context.Context) error {
|
|||
func shouldAutostartPersistentProfile(profile config.CLIProfileConf) bool {
|
||||
return profile.Persistent &&
|
||||
profile.Mode != modeCodexExec &&
|
||||
profile.Mode != modeAntigravity &&
|
||||
profile.Mode != modeOpencodeSSE &&
|
||||
profile.Mode != modePersistentLazy
|
||||
}
|
||||
|
|
@ -157,6 +167,7 @@ func (c *CLI) Stop(_ context.Context) error {
|
|||
}
|
||||
c.sessions = make(map[sessionKey]*profileSession)
|
||||
c.codexSessions = make(map[sessionKey]*codexExecSession)
|
||||
c.agySessions = make(map[sessionKey]*antigravitySession)
|
||||
opencodeCopy := make(map[sessionKey]*opencodeSSESession, len(c.opencodeSessions))
|
||||
for key, sess := range c.opencodeSessions {
|
||||
opencodeCopy[key] = sess
|
||||
|
|
@ -186,6 +197,9 @@ func (c *CLI) Execute(ctx context.Context, spec runtime.ExecutionSpec, sink runt
|
|||
if profile.Mode == modeCodexExec {
|
||||
return c.executeCodexExec(ctx, spec, profile, sink)
|
||||
}
|
||||
if profile.Mode == modeAntigravity {
|
||||
return c.executeAntigravityPrint(ctx, spec, profile, sink)
|
||||
}
|
||||
if profile.Mode == modeOpencodeSSE {
|
||||
return c.executeOpencodeSSE(ctx, spec, profile, sink)
|
||||
}
|
||||
|
|
@ -232,13 +246,16 @@ func (c *CLI) handleUsageStatus(ctx context.Context, req runtime.CommandRequest)
|
|||
|
||||
func (c *CLI) handleSessionList(req runtime.CommandRequest) runtime.CommandResponse {
|
||||
c.mu.Lock()
|
||||
entries := make([]string, 0, len(c.sessions)+len(c.codexSessions)+len(c.opencodeSessions))
|
||||
entries := make([]string, 0, len(c.sessions)+len(c.codexSessions)+len(c.agySessions)+len(c.opencodeSessions))
|
||||
for k := range c.sessions {
|
||||
entries = append(entries, fmt.Sprintf("persistent:%s/%s", k.target, k.sessionID))
|
||||
}
|
||||
for k := range c.codexSessions {
|
||||
entries = append(entries, fmt.Sprintf("codex-exec:%s/%s", k.target, k.sessionID))
|
||||
}
|
||||
for k := range c.agySessions {
|
||||
entries = append(entries, fmt.Sprintf("antigravity-print:%s/%s", k.target, k.sessionID))
|
||||
}
|
||||
for k := range c.opencodeSessions {
|
||||
entries = append(entries, fmt.Sprintf("opencode-sse:%s/%s", k.target, k.sessionID))
|
||||
}
|
||||
|
|
@ -273,6 +290,18 @@ func (c *CLI) TerminateSession(_ context.Context, target, sessionID string) erro
|
|||
}
|
||||
return nil
|
||||
}
|
||||
if profile, ok := c.profiles[target]; ok && profile.Mode == modeAntigravity {
|
||||
c.mu.Lock()
|
||||
_, ok := c.agySessions[key]
|
||||
if ok {
|
||||
delete(c.agySessions, key)
|
||||
}
|
||||
c.mu.Unlock()
|
||||
if !ok {
|
||||
return fmt.Errorf("cli adapter: no session %q for target %q", key.sessionID, target)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if profile, ok := c.profiles[target]; ok && profile.Mode == modeOpencodeSSE {
|
||||
c.mu.Lock()
|
||||
sess, ok := c.opencodeSessions[key]
|
||||
|
|
|
|||
|
|
@ -367,11 +367,13 @@ func TestHandleSessionList_PopulatedSnapshot(t *testing.T) {
|
|||
c := &CLI{
|
||||
sessions: make(map[sessionKey]*profileSession),
|
||||
codexSessions: make(map[sessionKey]*codexExecSession),
|
||||
agySessions: make(map[sessionKey]*antigravitySession),
|
||||
opencodeSessions: make(map[sessionKey]*opencodeSSESession),
|
||||
}
|
||||
c.sessions[sessionKey{target: "claude", sessionID: "default"}] = &profileSession{}
|
||||
c.sessions[sessionKey{target: "claude", sessionID: "alt"}] = &profileSession{}
|
||||
c.codexSessions[sessionKey{target: "codex", sessionID: "default"}] = &codexExecSession{}
|
||||
c.agySessions[sessionKey{target: "antigravity", sessionID: "main"}] = &antigravitySession{}
|
||||
c.opencodeSessions[sessionKey{target: "opencode", sessionID: "main"}] = &opencodeSSESession{}
|
||||
|
||||
resp := c.handleSessionList(runtime.CommandRequest{
|
||||
|
|
@ -380,10 +382,10 @@ func TestHandleSessionList_PopulatedSnapshot(t *testing.T) {
|
|||
Adapter: "cli",
|
||||
})
|
||||
|
||||
if resp.Result["count"] != "4" {
|
||||
t.Fatalf("count: got %q want %q", resp.Result["count"], "4")
|
||||
if resp.Result["count"] != "5" {
|
||||
t.Fatalf("count: got %q want %q", resp.Result["count"], "5")
|
||||
}
|
||||
want := "codex-exec:codex/default,opencode-sse:opencode/main,persistent:claude/alt,persistent:claude/default"
|
||||
want := "antigravity-print:antigravity/main,codex-exec:codex/default,opencode-sse:opencode/main,persistent:claude/alt,persistent:claude/default"
|
||||
if got := resp.Result["sessions"]; got != want {
|
||||
t.Fatalf("sessions: got %q want %q", got, want)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ openai:
|
|||
|
||||
console:
|
||||
adapter: "cli"
|
||||
target: "claude-tui"
|
||||
target: "antigravity"
|
||||
session_id: "default"
|
||||
background: false
|
||||
timeout_sec: 300
|
||||
|
|
@ -91,9 +91,15 @@ nodes:
|
|||
- "--print-timeout"
|
||||
- "10m"
|
||||
- "--print"
|
||||
resume_args:
|
||||
- "--dangerously-skip-permissions"
|
||||
- "--print-timeout"
|
||||
- "10m"
|
||||
- "--conversation"
|
||||
env: []
|
||||
persistent: false
|
||||
terminal: false
|
||||
mode: "antigravity-print"
|
||||
codex:
|
||||
command: "codex"
|
||||
args:
|
||||
|
|
|
|||
|
|
@ -324,6 +324,12 @@ nodes:
|
|||
- "--print-timeout"
|
||||
- "10m"
|
||||
- "--print"
|
||||
resume_args:
|
||||
- "--dangerously-skip-permissions"
|
||||
- "--print-timeout"
|
||||
- "10m"
|
||||
- "--conversation"
|
||||
mode: "antigravity-print"
|
||||
`
|
||||
if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil {
|
||||
t.Fatalf("write yaml: %v", err)
|
||||
|
|
@ -356,6 +362,18 @@ nodes:
|
|||
if agy.OutputFormat != "" {
|
||||
t.Errorf("expected empty output format, got %q", agy.OutputFormat)
|
||||
}
|
||||
if agy.Mode != "antigravity-print" {
|
||||
t.Errorf("expected mode antigravity-print, got %q", agy.Mode)
|
||||
}
|
||||
expectedResume := []string{"--dangerously-skip-permissions", "--print-timeout", "10m", "--conversation"}
|
||||
if len(agy.ResumeArgs) != len(expectedResume) {
|
||||
t.Fatalf("expected %d resume_args, got %d: %v", len(expectedResume), len(agy.ResumeArgs), agy.ResumeArgs)
|
||||
}
|
||||
for i, v := range expectedResume {
|
||||
if agy.ResumeArgs[i] != v {
|
||||
t.Errorf("resume_args[%d]: expected %q, got %q", i, v, agy.ResumeArgs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCLIProfileConf_CompletionMarkerUnmarshal(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue