返回 DeepSeek-Reasonix
tab_profile_test.go
根目录 / desktop / tab_profile_test.go
1 package main
2
3 import (
4 "context"
5 "os"
6 "path/filepath"
7 "strings"
8 "testing"
9
10 "reasonix/internal/boot"
11 "reasonix/internal/control"
12 )
13
14 func testTab(id, root string) *WorkspaceTab {
15 return &WorkspaceTab{
16 ID: id,
17 Scope: "project",
18 WorkspaceRoot: root,
19 Ready: true,
20 Ctrl: control.New(control.Options{Label: id}),
21 model: "deepseek-flash/deepseek-v4-flash",
22 mode: "normal",
23 disabledMCP: map[string]ServerView{},
24 }
25 }
26
27 func TestSetEffortForTabIsTabLocal(t *testing.T) {
28 isolateDesktopUserDirs(t)
29
30 rootA := t.TempDir()
31 rootB := t.TempDir()
32 app := NewApp()
33 app.ctx = context.Background()
34 app.readyHook = func() {}
35 tabA := testTab("a", rootA)
36 tabB := testTab("b", rootB)
37 tabA.sink = &tabEventSink{tabID: tabA.ID, app: app}
38 tabB.sink = &tabEventSink{tabID: tabB.ID, app: app}
39 app.tabs = map[string]*WorkspaceTab{tabA.ID: tabA, tabB.ID: tabB}
40 app.tabOrder = []string{tabA.ID, tabB.ID}
41 app.activeTabID = tabA.ID
42 defer func() {
43 for _, tab := range app.tabs {
44 if tab.Ctrl != nil {
45 tab.Ctrl.Close()
46 }
47 }
48 }()
49
50 if err := app.SetEffortForTab(tabA.ID, "max"); err != nil {
51 t.Fatalf("SetEffortForTab: %v", err)
52 }
53 if got := app.EffortForTab(tabA.ID).Current; got != "max" {
54 t.Fatalf("tab A effort = %q, want max", got)
55 }
56 if got := app.EffortForTab(tabB.ID).Current; got != "auto" {
57 t.Fatalf("tab B effort = %q, want auto", got)
58 }
59 if tabB.effort != nil {
60 t.Fatalf("tab B stored effort = %q, want nil", *tabB.effort)
61 }
62 body, err := os.ReadFile(userConfigPathForTest())
63 if err == nil && strings.Contains(string(body), `effort`) {
64 t.Fatalf("tab-local effort should not write provider config:\n%s", body)
65 }
66 }
67
68 func TestEffortForTabResolvesProjectProviderConfig(t *testing.T) {
69 isolateDesktopUserDirs(t)
70
71 projectRoot := t.TempDir()
72 configBody := `default_model = "project-provider/deepseek-v4-flash"
73 [[providers]]
74 name = "project-provider"
75 kind = "openai"
76 base_url = "https://api.deepseek.com"
77 model = "deepseek-v4-flash"
78 api_key_env = "PROJECT_API_KEY"
79 effort = "max"
80 `
81 if err := os.WriteFile(filepath.Join(projectRoot, "reasonix.toml"), []byte(configBody), 0o644); err != nil {
82 t.Fatal(err)
83 }
84 approveWorkspace(t, projectRoot)
85
86 app := NewApp()
87 tab := testTab("project", projectRoot)
88 tab.model = "project-provider/deepseek-v4-flash"
89 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
90 app.activeTabID = tab.ID
91 defer tab.Ctrl.Close()
92
93 got := app.EffortForTab(tab.ID)
94 if !got.Supported || got.Current != "max" {
95 t.Fatalf("EffortForTab project config = %+v, want supported max", got)
96 }
97 }
98
99 func TestEffortForTabUsesKnownModelRegistry(t *testing.T) {
100 isolateDesktopUserDirs(t)
101
102 projectRoot := t.TempDir()
103 configBody := `default_model = "project-provider/deepseek-v4-flash"
104 [[providers]]
105 name = "project-provider"
106 kind = "openai"
107 base_url = "https://proxy.example.com/v1"
108 model = "deepseek-v4-flash"
109 api_key_env = "PROJECT_API_KEY"
110 `
111 if err := os.WriteFile(filepath.Join(projectRoot, "reasonix.toml"), []byte(configBody), 0o644); err != nil {
112 t.Fatal(err)
113 }
114 approveWorkspace(t, projectRoot)
115
116 app := NewApp()
117 tab := testTab("project", projectRoot)
118 tab.model = "project-provider/deepseek-v4-flash"
119 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
120 app.activeTabID = tab.ID
121 defer tab.Ctrl.Close()
122
123 got := app.EffortForTab(tab.ID)
124 if !got.Supported || got.Current != "auto" || got.Default != "high" {
125 t.Fatalf("EffortForTab model registry = %+v, want supported auto/high", got)
126 }
127 wantLevels := []string{"auto", "disabled", "low", "high", "max"}
128 if len(got.Levels) != len(wantLevels) {
129 t.Fatalf("levels = %v, want %v", got.Levels, wantLevels)
130 }
131 for i, want := range wantLevels {
132 if got.Levels[i] != want {
133 t.Fatalf("levels[%d] = %q, want %q", i, got.Levels[i], want)
134 }
135 }
136 }
137
138 func TestSaveTabsPersistsModelAndEffort(t *testing.T) {
139 isolateDesktopUserDirs(t)
140
141 effort := "max"
142 app := NewApp()
143 tab := testTab("a", t.TempDir())
144 tab.effort = &effort
145 tab.model = "deepseek/deepseek-v4-pro"
146 tab.mode = "plan"
147 tab.Ctrl.SetPlanMode(true)
148 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
149 app.tabOrder = []string{tab.ID}
150 app.activeTabID = tab.ID
151
152 app.mu.Lock()
153 app.saveTabsLocked()
154 app.mu.Unlock()
155
156 got := loadTabsFile()
157 if len(got.Tabs) != 1 {
158 t.Fatalf("tabs len = %d, want 1", len(got.Tabs))
159 }
160 if got.Tabs[0].Model != tab.model {
161 t.Fatalf("saved model = %q, want %q", got.Tabs[0].Model, tab.model)
162 }
163 if got.Tabs[0].Effort == nil || *got.Tabs[0].Effort != effort {
164 t.Fatalf("saved effort = %#v, want %q", got.Tabs[0].Effort, effort)
165 }
166 if got.Tabs[0].Mode != "plan" {
167 t.Fatalf("saved mode = %q, want plan", got.Tabs[0].Mode)
168 }
169 }
170
171 func TestBuildTabControllerMigratesPersistedBareMimoModel(t *testing.T) {
172 isolateDesktopUserDirs(t)
173
174 root := t.TempDir()
175 configBody := `default_model = "deepseek-flash"
176 [[providers]]
177 name = "deepseek-flash"
178 kind = "openai"
179 base_url = "https://example.invalid/v1"
180 model = "deepseek-v4-flash"
181 api_key_env = "REASONIX_TEST_KEY_UNSET"
182 `
183 if err := os.WriteFile(filepath.Join(root, "reasonix.toml"), []byte(configBody), 0o644); err != nil {
184 t.Fatal(err)
185 }
186 approveWorkspace(t, root)
187
188 app := NewApp()
189 app.readyHook = func() {}
190 tab := testTab("mimo", root)
191 tab.model = "mimo-v2.5-pro"
192 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
193 app.tabOrder = []string{tab.ID}
194 app.activeTabID = tab.ID
195
196 app.buildTabController(tab)
197 if tab.StartupErr != "" {
198 t.Fatalf("tab startup error = %q", tab.StartupErr)
199 }
200 defer tab.Ctrl.Close()
201 if tab.model != "mimo-pro/mimo-v2.5-pro" {
202 t.Fatalf("tab model = %q, want migrated MiMo provider ref", tab.model)
203 }
204 }
205
206 func TestSaveTabsPersistsNonBalancedTokenModes(t *testing.T) {
207 // New writes pin the deprecated dual-write compat labels; economy/delivery
208 // must not be persisted as live modes.
209 isolateDesktopUserDirs(t)
210
211 app := NewApp()
212 tab := testTab("a", t.TempDir())
213 tab.qualityFloor = control.QualityFloorStandard
214 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
215 app.tabOrder = []string{tab.ID}
216 app.activeTabID = tab.ID
217
218 for _, inMemory := range []string{"", "delivery", ""} {
219 tab.qualityFloor = inMemory
220 app.mu.Lock()
221 app.saveTabsLocked()
222 app.mu.Unlock()
223
224 got := loadTabsFile()
225 if len(got.Tabs) != 1 {
226 t.Fatalf("tabs len = %d, want 1", len(got.Tabs))
227 }
228 wantToken, wantPreset := boot.TokenModeFull, boot.AgentPresetStandard
229 if got.Tabs[0].TokenMode != wantToken || got.Tabs[0].AgentPreset != wantPreset {
230 t.Fatalf("saved compat after in-memory %q = token:%q preset:%q, want %q/%q",
231 inMemory, got.Tabs[0].TokenMode, got.Tabs[0].AgentPreset, wantToken, wantPreset)
232 }
233 }
234 }
235
236 func TestLoadTabsFileDecodesLegacyTokenModes(t *testing.T) {
237 isolateDesktopUserDirs(t)
238 dir := desktopConfigDir()
239 if err := os.MkdirAll(dir, 0o755); err != nil {
240 t.Fatal(err)
241 }
242 body := `{"tabs":[{"id":"old","scope":"global","tokenMode":"economy","agentPreset":"light"}],"activeTab":"old"}`
243 if err := os.WriteFile(filepath.Join(dir, tabsFileName), []byte(body), 0o644); err != nil {
244 t.Fatal(err)
245 }
246 got := loadTabsFile()
247 if len(got.Tabs) != 1 || got.Tabs[0].TokenMode != "economy" || got.Tabs[0].AgentPreset != "light" {
248 t.Fatalf("legacy tabs decode = %+v", got.Tabs)
249 }
250 }
251
252 func TestSaveTabsPersistsFullAccessSeparatelyFromCollaborationMode(t *testing.T) {
253 isolateDesktopUserDirs(t)
254
255 app := NewApp()
256 tab := testTab("a", t.TempDir())
257 tab.mode = "normal"
258 tab.toolApprovalMode = control.ToolApprovalDangerFullAccess
259 tab.Ctrl.SetToolApprovalMode(control.ToolApprovalDangerFullAccess)
260 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
261 app.tabOrder = []string{tab.ID}
262 app.activeTabID = tab.ID
263
264 app.mu.Lock()
265 app.saveTabsLocked()
266 app.mu.Unlock()
267
268 got := loadTabsFile()
269 if len(got.Tabs) != 1 {
270 t.Fatalf("tabs len = %d, want 1", len(got.Tabs))
271 }
272 if got.Tabs[0].Mode != "" || got.Tabs[0].ToolApprovalMode != control.ToolApprovalDangerFullAccess {
273 t.Fatalf("saved profile = mode:%q permission:%q, want normal/full access", got.Tabs[0].Mode, got.Tabs[0].ToolApprovalMode)
274 }
275 }
276
277 func TestSaveTabsPersistsPlanAndFullAccessAsIndependentAxes(t *testing.T) {
278 isolateDesktopUserDirs(t)
279
280 app := NewApp()
281 tab := testTab("a", t.TempDir())
282 tab.mode = "plan"
283 tab.toolApprovalMode = control.ToolApprovalDangerFullAccess
284 tab.Ctrl.SetPlanMode(true)
285 tab.Ctrl.SetToolApprovalMode(control.ToolApprovalDangerFullAccess)
286 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
287 app.tabOrder = []string{tab.ID}
288 app.activeTabID = tab.ID
289
290 app.mu.Lock()
291 app.saveTabsLocked()
292 app.mu.Unlock()
293
294 got := loadTabsFile()
295 if len(got.Tabs) != 1 {
296 t.Fatalf("tabs len = %d, want 1", len(got.Tabs))
297 }
298 if got.Tabs[0].Mode != "plan" || got.Tabs[0].ToolApprovalMode != control.ToolApprovalDangerFullAccess {
299 t.Fatalf("saved profile = mode:%q permission:%q, want plan/full access", got.Tabs[0].Mode, got.Tabs[0].ToolApprovalMode)
300 }
301 }
302
303 func TestSaveTabsPersistsGoalAndToolApprovalMode(t *testing.T) {
304 isolateDesktopUserDirs(t)
305
306 app := NewApp()
307 tab := testTab("a", t.TempDir())
308 tab.goal = "finish the mode redesign"
309 tab.toolApprovalMode = control.ToolApprovalAuto
310 tab.Ctrl.SetGoal(tab.goal)
311 tab.Ctrl.SetToolApprovalMode(control.ToolApprovalAuto)
312 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
313 app.tabOrder = []string{tab.ID}
314 app.activeTabID = tab.ID
315
316 app.mu.Lock()
317 app.saveTabsLocked()
318 app.mu.Unlock()
319
320 got := loadTabsFile()
321 if len(got.Tabs) != 1 {
322 t.Fatalf("tabs len = %d, want 1", len(got.Tabs))
323 }
324 if got.Tabs[0].Goal != "finish the mode redesign" {
325 t.Fatalf("saved goal = %q", got.Tabs[0].Goal)
326 }
327 if got.Tabs[0].ToolApprovalMode != control.ToolApprovalAuto {
328 t.Fatalf("saved tool approval mode = %q, want auto", got.Tabs[0].ToolApprovalMode)
329 }
330 }
331
332 func TestCollaborationModesPreserveToolApprovalMode(t *testing.T) {
333 isolateDesktopUserDirs(t)
334
335 app := NewApp()
336 tab := testTab("a", t.TempDir())
337 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
338 app.tabOrder = []string{tab.ID}
339 app.activeTabID = tab.ID
340 defer tab.Ctrl.Close()
341
342 app.SetToolApprovalModeForTab(tab.ID, control.ToolApprovalAuto)
343 app.SetGoalForTab(tab.ID, "finish the approval redesign")
344 if got := currentTabCollaborationMode(tab); got != "goal" {
345 t.Fatalf("collaboration mode = %q, want goal", got)
346 }
347 if tab.Ctrl.PlanMode() {
348 t.Fatal("goal mode should leave plan mode off")
349 }
350 if got := tab.Ctrl.ToolApprovalMode(); got != control.ToolApprovalAuto {
351 t.Fatalf("tool approval after goal = %q, want auto", got)
352 }
353
354 app.SetCollaborationModeForTab(tab.ID, "plan")
355 if got := currentTabCollaborationMode(tab); got != "plan" {
356 t.Fatalf("collaboration mode = %q, want plan", got)
357 }
358 if got := tab.Ctrl.Goal(); got != "" {
359 t.Fatalf("plan mode should clear goal, got %q", got)
360 }
361 if got := tab.Ctrl.ToolApprovalMode(); got != control.ToolApprovalAuto {
362 t.Fatalf("tool approval after plan = %q, want auto", got)
363 }
364
365 app.SetCollaborationModeForTab(tab.ID, "normal")
366 if got := currentTabCollaborationMode(tab); got != "normal" {
367 t.Fatalf("collaboration mode = %q, want normal", got)
368 }
369 if tab.Ctrl.PlanMode() {
370 t.Fatal("normal mode should leave plan mode off")
371 }
372 if got := tab.Ctrl.ToolApprovalMode(); got != control.ToolApprovalAuto {
373 t.Fatalf("tool approval after normal = %q, want auto", got)
374 }
375 }
376
377 func TestToolApprovalModesPreserveCollaborationMode(t *testing.T) {
378 isolateDesktopUserDirs(t)
379
380 app := NewApp()
381 tab := testTab("a", t.TempDir())
382 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
383 app.tabOrder = []string{tab.ID}
384 app.activeTabID = tab.ID
385 defer tab.Ctrl.Close()
386
387 app.SetCollaborationModeForTab(tab.ID, "plan")
388 for _, mode := range []string{control.ToolApprovalAsk, control.ToolApprovalAuto, control.ToolApprovalYolo} {
389 app.SetToolApprovalModeForTab(tab.ID, mode)
390 if got := currentTabCollaborationMode(tab); got != "plan" {
391 t.Fatalf("collaboration after tool mode %q = %q, want plan", mode, got)
392 }
393 if got := tab.Ctrl.ToolApprovalMode(); got != mode {
394 t.Fatalf("tool approval = %q, want %q", got, mode)
395 }
396 }
397
398 app.SetGoalForTab(tab.ID, "ship the goal runner")
399 app.SetToolApprovalModeForTab(tab.ID, control.ToolApprovalAsk)
400 if got := currentTabCollaborationMode(tab); got != "goal" {
401 t.Fatalf("collaboration after ask = %q, want goal", got)
402 }
403 app.SetToolApprovalModeForTab(tab.ID, control.ToolApprovalAuto)
404 if got := currentTabCollaborationMode(tab); got != "goal" {
405 t.Fatalf("collaboration after auto = %q, want goal", got)
406 }
407 app.SetToolApprovalModeForTab(tab.ID, control.ToolApprovalYolo)
408 if got := currentTabCollaborationMode(tab); got != "goal" {
409 t.Fatalf("collaboration after yolo = %q, want goal", got)
410 }
411 }
412
413 func TestSetComposerProfileForTabAppliesAllAxes(t *testing.T) {
414 isolateDesktopUserDirs(t)
415
416 app := NewApp()
417 if drained, err := app.SetComposerProfileForTab("missing", "normal", control.ToolApprovalAsk, ""); err == nil || drained == nil {
418 t.Fatal("missing tab returned a nil drained-id slice")
419 }
420 tab := testTab("a", t.TempDir())
421 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
422 app.tabOrder = []string{tab.ID}
423 app.activeTabID = tab.ID
424 defer tab.Ctrl.Close()
425
426 if _, err := app.SetComposerProfileForTab(tab.ID, "plan", control.ToolApprovalYolo, ""); err != nil {
427 t.Fatal(err)
428 }
429 if got := currentTabCollaborationMode(tab); got != "plan" {
430 t.Fatalf("collaboration mode = %q, want plan", got)
431 }
432 if !tab.Ctrl.PlanMode() {
433 t.Fatal("controller plan mode is off")
434 }
435 if got := tab.Ctrl.ToolApprovalMode(); got != control.ToolApprovalYolo {
436 t.Fatalf("tool approval mode = %q, want yolo", got)
437 }
438
439 if _, err := app.SetComposerProfileForTab(tab.ID, "goal", control.ToolApprovalAuto, "finish the profile migration"); err != nil {
440 t.Fatal(err)
441 }
442 if got := currentTabCollaborationMode(tab); got != "goal" {
443 t.Fatalf("collaboration mode = %q, want goal", got)
444 }
445 if tab.Ctrl.PlanMode() {
446 t.Fatal("goal profile kept controller plan mode on")
447 }
448 if got := tab.Ctrl.ToolApprovalMode(); got != control.ToolApprovalAuto {
449 t.Fatalf("tool approval mode = %q, want auto", got)
450 }
451 if got := tab.Ctrl.Goal(); got != "finish the profile migration" {
452 t.Fatalf("controller goal = %q", got)
453 }
454
455 got := loadTabsFile()
456 if len(got.Tabs) != 1 || got.Tabs[0].Goal != "finish the profile migration" || got.Tabs[0].ToolApprovalMode != control.ToolApprovalAuto {
457 t.Fatalf("persisted profile = %+v", got.Tabs)
458 }
459 }
460
461 func TestMetaReportsGoalStatus(t *testing.T) {
462 isolateDesktopUserDirs(t)
463
464 app := NewApp()
465 tab := testTab("a", t.TempDir())
466 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
467 app.tabOrder = []string{tab.ID}
468 app.activeTabID = tab.ID
469 defer tab.Ctrl.Close()
470
471 meta := app.MetaForTab(tab.ID)
472 if meta.GoalStatus != control.GoalStatusStopped {
473 t.Fatalf("initial goal status = %q, want stopped", meta.GoalStatus)
474 }
475 if meta.CollaborationMode != "normal" {
476 t.Fatalf("initial collaboration mode = %q, want normal", meta.CollaborationMode)
477 }
478
479 app.SetGoalForTab(tab.ID, "finish the goal runner")
480 meta = app.MetaForTab(tab.ID)
481 if meta.Goal != "finish the goal runner" || meta.GoalStatus != control.GoalStatusRunning || meta.CollaborationMode != "goal" {
482 t.Fatalf("goal meta = %+v, want running goal", meta)
483 }
484
485 app.ClearGoalForTab(tab.ID)
486 meta = app.MetaForTab(tab.ID)
487 if meta.Goal != "" || meta.GoalStatus != control.GoalStatusStopped || meta.CollaborationMode != "normal" {
488 t.Fatalf("cleared goal meta = %+v, want stopped empty goal", meta)
489 }
490
491 app.SetCollaborationModeForTab(tab.ID, "plan")
492 app.mu.Lock()
493 tab.qualityFloor = ""
494 app.mu.Unlock()
495 meta = app.MetaForTab(tab.ID)
496 if meta.CollaborationMode != "plan" || meta.TokenMode != boot.TokenModeFull || meta.AgentPreset != boot.AgentPresetStandard {
497 t.Fatalf("profile meta = %+v, want plan + full/standard", meta)
498 }
499 }
500
501 func TestMetaReportsStoredCollaborationModeWhileControllerRebuilds(t *testing.T) {
502 isolateDesktopUserDirs(t)
503
504 app := NewApp()
505 tab := testTab("a", t.TempDir())
506 tab.Ctrl.Close()
507 tab.Ctrl = nil
508 tab.mode = "plan-yolo"
509 tab.toolApprovalMode = control.ToolApprovalYolo
510 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
511 app.tabOrder = []string{tab.ID}
512 app.activeTabID = tab.ID
513
514 meta := app.MetaForTab(tab.ID)
515 if meta.CollaborationMode != "plan" || meta.ToolApprovalMode != control.ToolApprovalYolo {
516 t.Fatalf("rebuilding plan-yolo meta = %+v, want plan/yolo", meta)
517 }
518
519 tab.mode = "normal"
520 tab.goal = "finish the goal runner"
521 meta = app.MetaForTab(tab.ID)
522 if meta.CollaborationMode != "goal" || meta.Goal != "finish the goal runner" || meta.GoalStatus != control.GoalStatusRunning {
523 t.Fatalf("rebuilding goal meta = %+v, want running goal", meta)
524 }
525 }
526
527 func TestSetPlanModePreservesFullAccess(t *testing.T) {
528 isolateDesktopUserDirs(t)
529
530 app := NewApp()
531 tab := testTab("a", t.TempDir())
532 tab.Ctrl.SetToolApprovalMode(control.ToolApprovalDangerFullAccess)
533 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
534 app.tabOrder = []string{tab.ID}
535 app.activeTabID = tab.ID
536
537 app.SetPlanMode(true)
538 if !tab.Ctrl.PlanMode() || !tab.Ctrl.AutoApproveTools() {
539 t.Fatalf("after SetPlanMode(true): plan=%v autoApproveTools=%v, want true/true", tab.Ctrl.PlanMode(), tab.Ctrl.AutoApproveTools())
540 }
541 if got := currentTabCollaborationMode(tab); got != "plan" {
542 t.Fatalf("collaboration mode = %q, want plan", got)
543 }
544
545 app.SetPlanMode(false)
546 if tab.Ctrl.PlanMode() || !tab.Ctrl.AutoApproveTools() {
547 t.Fatalf("after SetPlanMode(false): plan=%v autoApproveTools=%v, want false/true", tab.Ctrl.PlanMode(), tab.Ctrl.AutoApproveTools())
548 }
549 }
550
551 func TestLegacyBypassMigratesToWorkspaceWriteAndPreservesPlanMode(t *testing.T) {
552 isolateDesktopUserDirs(t)
553
554 app := NewApp()
555 tab := testTab("a", t.TempDir())
556 tab.Ctrl.SetPlanMode(true)
557 app.tabs = map[string]*WorkspaceTab{tab.ID: tab}
558 app.tabOrder = []string{tab.ID}
559 app.activeTabID = tab.ID
560
561 app.SetBypass(true)
562 if !tab.Ctrl.PlanMode() || tab.Ctrl.ToolApprovalMode() != control.ToolApprovalWorkspaceWrite {
563 t.Fatalf("after SetBypass(true): plan=%v permission=%v, want true/workspace-write", tab.Ctrl.PlanMode(), tab.Ctrl.ToolApprovalMode())
564 }
565 if got := currentTabCollaborationMode(tab); got != "plan" {
566 t.Fatalf("collaboration mode = %q, want plan", got)
567 }
568
569 app.SetBypass(false)
570 if !tab.Ctrl.PlanMode() || tab.Ctrl.ToolApprovalMode() != control.ToolApprovalWorkspaceWrite {
571 t.Fatalf("after SetBypass(false): plan=%v permission=%v, want true/workspace-write", tab.Ctrl.PlanMode(), tab.Ctrl.ToolApprovalMode())
572 }
573 }
574
575 func userConfigPathForTest() string {
576 if dir, err := os.UserConfigDir(); err == nil {
577 return dir + "/reasonix/reasonix.toml"
578 }
579 return ""
580 }
581
581 lines GO