berget 2.2.7 → 2.2.9

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.
Files changed (130) hide show
  1. package/.github/workflows/publish.yml +6 -6
  2. package/.github/workflows/test.yml +1 -1
  3. package/.prettierrc +5 -3
  4. package/dist/index.js +24 -25
  5. package/dist/package.json +7 -3
  6. package/dist/src/agents/app.js +8 -8
  7. package/dist/src/agents/backend.js +3 -3
  8. package/dist/src/agents/devops.js +8 -8
  9. package/dist/src/agents/frontend.js +3 -3
  10. package/dist/src/agents/fullstack.js +3 -3
  11. package/dist/src/agents/index.js +18 -18
  12. package/dist/src/agents/quality.js +8 -8
  13. package/dist/src/agents/security.js +8 -8
  14. package/dist/src/client.js +115 -127
  15. package/dist/src/commands/api-keys.js +181 -202
  16. package/dist/src/commands/auth.js +16 -25
  17. package/dist/src/commands/autocomplete.js +8 -8
  18. package/dist/src/commands/billing.js +10 -19
  19. package/dist/src/commands/chat.js +139 -170
  20. package/dist/src/commands/clusters.js +21 -30
  21. package/dist/src/commands/code/__tests__/auth-sync.test.js +189 -186
  22. package/dist/src/commands/code/__tests__/fake-api-key-service.js +3 -13
  23. package/dist/src/commands/code/__tests__/fake-auth-service.js +21 -29
  24. package/dist/src/commands/code/__tests__/fake-command-runner.js +22 -33
  25. package/dist/src/commands/code/__tests__/fake-file-store.js +19 -41
  26. package/dist/src/commands/code/__tests__/fake-prompter.js +81 -97
  27. package/dist/src/commands/code/__tests__/setup-flow.test.js +295 -295
  28. package/dist/src/commands/code/adapters/clack-prompter.js +15 -32
  29. package/dist/src/commands/code/adapters/fs-file-store.js +25 -44
  30. package/dist/src/commands/code/adapters/spawn-command-runner.js +27 -41
  31. package/dist/src/commands/code/auth-sync.js +215 -228
  32. package/dist/src/commands/code/errors.js +15 -12
  33. package/dist/src/commands/code/setup.js +390 -425
  34. package/dist/src/commands/code.js +279 -294
  35. package/dist/src/commands/index.js +5 -5
  36. package/dist/src/commands/models.js +16 -25
  37. package/dist/src/commands/users.js +9 -18
  38. package/dist/src/constants/command-structure.js +138 -138
  39. package/dist/src/services/api-key-service.js +132 -152
  40. package/dist/src/services/auth-service.js +81 -95
  41. package/dist/src/services/browser-auth.js +121 -131
  42. package/dist/src/services/chat-service.js +369 -386
  43. package/dist/src/services/cluster-service.js +47 -62
  44. package/dist/src/services/collaborator-service.js +9 -21
  45. package/dist/src/services/flux-service.js +13 -25
  46. package/dist/src/services/helm-service.js +9 -21
  47. package/dist/src/services/kubectl-service.js +15 -29
  48. package/dist/src/utils/config-checker.js +8 -8
  49. package/dist/src/utils/config-loader.js +109 -109
  50. package/dist/src/utils/default-api-key.js +129 -139
  51. package/dist/src/utils/env-manager.js +55 -66
  52. package/dist/src/utils/error-handler.js +62 -62
  53. package/dist/src/utils/logger.js +74 -67
  54. package/dist/src/utils/markdown-renderer.js +28 -28
  55. package/dist/src/utils/opencode-validator.js +67 -69
  56. package/dist/src/utils/token-manager.js +67 -65
  57. package/dist/tests/commands/chat.test.js +30 -39
  58. package/dist/tests/commands/code.test.js +186 -195
  59. package/dist/tests/utils/config-loader.test.js +107 -107
  60. package/dist/tests/utils/env-manager.test.js +81 -90
  61. package/dist/tests/utils/opencode-validator.test.js +42 -41
  62. package/dist/vitest.config.js +1 -1
  63. package/eslint.config.mjs +65 -30
  64. package/index.ts +30 -31
  65. package/package.json +7 -3
  66. package/src/agents/app.ts +9 -9
  67. package/src/agents/backend.ts +4 -4
  68. package/src/agents/devops.ts +9 -9
  69. package/src/agents/frontend.ts +4 -4
  70. package/src/agents/fullstack.ts +4 -4
  71. package/src/agents/index.ts +27 -25
  72. package/src/agents/quality.ts +9 -9
  73. package/src/agents/security.ts +9 -9
  74. package/src/agents/types.ts +10 -10
  75. package/src/client.ts +85 -77
  76. package/src/commands/api-keys.ts +180 -185
  77. package/src/commands/auth.ts +15 -14
  78. package/src/commands/autocomplete.ts +10 -10
  79. package/src/commands/billing.ts +13 -12
  80. package/src/commands/chat.ts +145 -142
  81. package/src/commands/clusters.ts +20 -19
  82. package/src/commands/code/__tests__/auth-sync.test.ts +176 -175
  83. package/src/commands/code/__tests__/fake-api-key-service.ts +2 -2
  84. package/src/commands/code/__tests__/fake-auth-service.ts +18 -18
  85. package/src/commands/code/__tests__/fake-command-runner.ts +28 -22
  86. package/src/commands/code/__tests__/fake-file-store.ts +15 -15
  87. package/src/commands/code/__tests__/fake-prompter.ts +86 -85
  88. package/src/commands/code/__tests__/setup-flow.test.ts +253 -251
  89. package/src/commands/code/adapters/clack-prompter.ts +32 -30
  90. package/src/commands/code/adapters/fs-file-store.ts +18 -17
  91. package/src/commands/code/adapters/spawn-command-runner.ts +20 -15
  92. package/src/commands/code/auth-sync.ts +210 -210
  93. package/src/commands/code/errors.ts +11 -11
  94. package/src/commands/code/ports/auth-services.ts +7 -7
  95. package/src/commands/code/ports/command-runner.ts +2 -2
  96. package/src/commands/code/ports/file-store.ts +3 -3
  97. package/src/commands/code/ports/prompter.ts +13 -13
  98. package/src/commands/code/setup.ts +408 -406
  99. package/src/commands/code.ts +288 -287
  100. package/src/commands/index.ts +11 -10
  101. package/src/commands/models.ts +19 -18
  102. package/src/commands/users.ts +11 -10
  103. package/src/constants/command-structure.ts +159 -159
  104. package/src/services/api-key-service.ts +85 -85
  105. package/src/services/auth-service.ts +55 -54
  106. package/src/services/browser-auth.ts +62 -62
  107. package/src/services/chat-service.ts +170 -171
  108. package/src/services/cluster-service.ts +28 -28
  109. package/src/services/collaborator-service.ts +6 -6
  110. package/src/services/flux-service.ts +17 -17
  111. package/src/services/helm-service.ts +11 -11
  112. package/src/services/kubectl-service.ts +12 -12
  113. package/src/types/api.d.ts +1933 -1933
  114. package/src/types/json.d.ts +1 -1
  115. package/src/utils/config-checker.ts +7 -7
  116. package/src/utils/config-loader.ts +130 -129
  117. package/src/utils/default-api-key.ts +81 -80
  118. package/src/utils/env-manager.ts +37 -37
  119. package/src/utils/error-handler.ts +64 -64
  120. package/src/utils/logger.ts +72 -66
  121. package/src/utils/markdown-renderer.ts +28 -28
  122. package/src/utils/opencode-validator.ts +72 -71
  123. package/src/utils/token-manager.ts +69 -68
  124. package/tests/commands/chat.test.ts +32 -31
  125. package/tests/commands/code.test.ts +182 -181
  126. package/tests/utils/config-loader.test.ts +111 -110
  127. package/tests/utils/env-manager.test.ts +83 -79
  128. package/tests/utils/opencode-validator.test.ts +43 -42
  129. package/tsconfig.json +2 -1
  130. package/vitest.config.ts +2 -2
@@ -1,505 +1,505 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  const vitest_1 = require("vitest");
13
- const setup_1 = require("../setup");
14
4
  const errors_1 = require("../errors");
15
- const fake_prompter_1 = require("./fake-prompter");
16
- const fake_file_store_1 = require("./fake-file-store");
17
- const fake_command_runner_1 = require("./fake-command-runner");
18
- const fake_auth_service_1 = require("./fake-auth-service");
5
+ const setup_1 = require("../setup");
19
6
  const fake_api_key_service_1 = require("./fake-api-key-service");
7
+ const fake_auth_service_1 = require("./fake-auth-service");
8
+ const fake_command_runner_1 = require("./fake-command-runner");
9
+ const fake_file_store_1 = require("./fake-file-store");
10
+ const fake_prompter_1 = require("./fake-prompter");
20
11
  const makeDeps = (overrides = {}) => {
21
- var _a, _b, _c, _d, _e;
22
- return Object.assign({ prompter: (_a = overrides.prompter) !== null && _a !== void 0 ? _a : new fake_prompter_1.FakePrompter([]), files: (_b = overrides.files) !== null && _b !== void 0 ? _b : new fake_file_store_1.FakeFileStore(), commands: (_c = overrides.commands) !== null && _c !== void 0 ? _c : new fake_command_runner_1.FakeCommandRunner()
23
- .handle("opencode --version", "mocked")
24
- .handle("pi --version", "mocked"), authService: (_d = overrides.authService) !== null && _d !== void 0 ? _d : new fake_auth_service_1.FakeAuthService(false), apiKeyService: (_e = overrides.apiKeyService) !== null && _e !== void 0 ? _e : new fake_api_key_service_1.FakeApiKeyService("sk_ber_test"), homeDir: "/home/user", cwd: "/home/user/project" }, Object.fromEntries(Object.entries(overrides).filter(([k]) => k !== "prompter" &&
25
- k !== "files" &&
26
- k !== "commands" &&
27
- k !== "authService" &&
28
- k !== "apiKeyService")));
12
+ return {
13
+ apiKeyService: overrides.apiKeyService ?? new fake_api_key_service_1.FakeApiKeyService('sk_ber_test'),
14
+ authService: overrides.authService ?? new fake_auth_service_1.FakeAuthService(false),
15
+ commands: overrides.commands ??
16
+ new fake_command_runner_1.FakeCommandRunner()
17
+ .handle('opencode --version', 'mocked')
18
+ .handle('pi --version', 'mocked'),
19
+ cwd: '/home/user/project',
20
+ files: overrides.files ?? new fake_file_store_1.FakeFileStore(),
21
+ homeDir: '/home/user',
22
+ prompter: overrides.prompter ?? new fake_prompter_1.FakePrompter([]),
23
+ ...Object.fromEntries(Object.entries(overrides).filter(([k]) => k !== 'prompter' &&
24
+ k !== 'files' &&
25
+ k !== 'commands' &&
26
+ k !== 'authService' &&
27
+ k !== 'apiKeyService')),
28
+ };
29
29
  };
30
30
  function base64urlEncode(data) {
31
- return Buffer.from(data).toString("base64url");
31
+ return Buffer.from(data).toString('base64url');
32
32
  }
33
33
  function makeJwt(payload) {
34
- const header = base64urlEncode(JSON.stringify({ alg: "none", typ: "JWT" }));
34
+ const header = base64urlEncode(JSON.stringify({ alg: 'none', typ: 'JWT' }));
35
35
  const body = base64urlEncode(JSON.stringify(payload));
36
36
  return `${header}.${body}.signature`;
37
37
  }
38
- (0, vitest_1.describe)("runSetup", () => {
39
- (0, vitest_1.describe)("happy path", () => {
40
- (0, vitest_1.it)("sets up opencode project without existing config", () => __awaiter(void 0, void 0, void 0, function* () {
38
+ (0, vitest_1.describe)('runSetup', () => {
39
+ (0, vitest_1.describe)('happy path', () => {
40
+ (0, vitest_1.it)('sets up opencode project without existing config', async () => {
41
41
  const deps = makeDeps({
42
42
  prompter: new fake_prompter_1.FakePrompter([
43
- (0, fake_prompter_1.select)("opencode"),
44
- (0, fake_prompter_1.select)("project"),
45
- (0, fake_prompter_1.confirm)(true, "Create"), // Config write
43
+ (0, fake_prompter_1.select)('opencode'),
44
+ (0, fake_prompter_1.select)('project'),
45
+ (0, fake_prompter_1.confirm)(true, 'Create'), // Config write
46
46
  (0, fake_prompter_1.multiselect)([]), // No agents selected
47
47
  ]),
48
48
  });
49
- yield (0, setup_1.runSetup)(deps);
49
+ await (0, setup_1.runSetup)(deps);
50
50
  const files = deps.files;
51
51
  const written = files.getWrittenFiles();
52
- (0, vitest_1.expect)(written.has("/home/user/project/opencode.json")).toBe(true);
53
- const config = JSON.parse(written.get("/home/user/project/opencode.json"));
54
- (0, vitest_1.expect)(config.plugin).toContain("@bergetai/opencode-auth@1.0.16");
55
- }));
56
- (0, vitest_1.it)("sets up opencode globally without existing config", () => __awaiter(void 0, void 0, void 0, function* () {
52
+ (0, vitest_1.expect)(written.has('/home/user/project/opencode.json')).toBe(true);
53
+ const config = JSON.parse(written.get('/home/user/project/opencode.json'));
54
+ (0, vitest_1.expect)(config.plugin).toContain('@bergetai/opencode-auth');
55
+ });
56
+ (0, vitest_1.it)('sets up opencode globally without existing config', async () => {
57
57
  const deps = makeDeps({
58
58
  prompter: new fake_prompter_1.FakePrompter([
59
- (0, fake_prompter_1.select)("opencode"),
60
- (0, fake_prompter_1.select)("global"),
61
- (0, fake_prompter_1.confirm)(true, "Create"), // Config write
59
+ (0, fake_prompter_1.select)('opencode'),
60
+ (0, fake_prompter_1.select)('global'),
61
+ (0, fake_prompter_1.confirm)(true, 'Create'), // Config write
62
62
  (0, fake_prompter_1.multiselect)([]), // No agents selected
63
63
  ]),
64
64
  });
65
- yield (0, setup_1.runSetup)(deps);
65
+ await (0, setup_1.runSetup)(deps);
66
66
  const files = deps.files;
67
67
  const written = files.getWrittenFiles();
68
- (0, vitest_1.expect)(written.has("/home/user/.config/opencode/opencode.json")).toBe(true);
69
- }));
70
- (0, vitest_1.it)("sets up pi project with fresh install", () => __awaiter(void 0, void 0, void 0, function* () {
68
+ (0, vitest_1.expect)(written.has('/home/user/.config/opencode/opencode.json')).toBe(true);
69
+ });
70
+ (0, vitest_1.it)('sets up pi project with fresh install', async () => {
71
71
  const deps = makeDeps({
72
+ commands: new fake_command_runner_1.FakeCommandRunner()
73
+ .handle('pi --version', 'mocked') // For checkInstalled
74
+ .handle('pi install', ''), // For actual install
72
75
  prompter: new fake_prompter_1.FakePrompter([
73
- (0, fake_prompter_1.select)("pi"),
74
- (0, fake_prompter_1.select)("project"),
75
- (0, fake_prompter_1.select)("fullstack"), // Agent selection
76
- (0, fake_prompter_1.confirm)(true, "Create"),
76
+ (0, fake_prompter_1.select)('pi'),
77
+ (0, fake_prompter_1.select)('project'),
78
+ (0, fake_prompter_1.select)('fullstack'), // Agent selection
79
+ (0, fake_prompter_1.confirm)(true, 'Create'),
77
80
  ]),
78
- commands: new fake_command_runner_1.FakeCommandRunner()
79
- .handle("pi --version", "mocked") // For checkInstalled
80
- .handle("pi install", ""), // For actual install
81
81
  });
82
- yield (0, setup_1.runSetup)(deps);
82
+ await (0, setup_1.runSetup)(deps);
83
83
  const commands = deps.commands;
84
84
  (0, vitest_1.expect)(commands.calls.length).toBeGreaterThan(0);
85
- const installCall = commands.calls.find(c => c.command === "pi");
86
- (0, vitest_1.expect)(installCall === null || installCall === void 0 ? void 0 : installCall.args).toContain("npm:@bergetai/pi-provider");
87
- }));
88
- (0, vitest_1.it)("skips agent selection for pi project", () => __awaiter(void 0, void 0, void 0, function* () {
85
+ const installCall = commands.calls.find((c) => c.command === 'pi');
86
+ (0, vitest_1.expect)(installCall?.args).toContain('npm:@bergetai/pi-provider');
87
+ });
88
+ (0, vitest_1.it)('skips agent selection for pi project', async () => {
89
89
  const deps = makeDeps({
90
+ commands: new fake_command_runner_1.FakeCommandRunner()
91
+ .handle('pi --version', 'mocked') // For checkInstalled
92
+ .handle('pi install', ''), // For actual install
90
93
  prompter: new fake_prompter_1.FakePrompter([
91
- (0, fake_prompter_1.select)("pi"),
92
- (0, fake_prompter_1.select)("project"),
93
- (0, fake_prompter_1.select)("__skip__"), // Skip agent selection
94
+ (0, fake_prompter_1.select)('pi'),
95
+ (0, fake_prompter_1.select)('project'),
96
+ (0, fake_prompter_1.select)('__skip__'), // Skip agent selection
94
97
  ]),
95
- commands: new fake_command_runner_1.FakeCommandRunner()
96
- .handle("pi --version", "mocked") // For checkInstalled
97
- .handle("pi install", ""), // For actual install
98
98
  });
99
- yield (0, setup_1.runSetup)(deps);
99
+ await (0, setup_1.runSetup)(deps);
100
100
  const files = deps.files;
101
101
  const written = files.getWrittenFiles();
102
102
  // Should not create any agent files
103
103
  for (const path of written.keys()) {
104
- (0, vitest_1.expect)(path).not.toContain("SYSTEM.md");
104
+ (0, vitest_1.expect)(path).not.toContain('SYSTEM.md');
105
105
  }
106
- }));
106
+ });
107
107
  });
108
- (0, vitest_1.describe)("prerequisites", () => {
109
- (0, vitest_1.it)("throws PrerequisiteError when opencode is not installed", () => __awaiter(void 0, void 0, void 0, function* () {
108
+ (0, vitest_1.describe)('prerequisites', () => {
109
+ (0, vitest_1.it)('throws PrerequisiteError when opencode is not installed', async () => {
110
110
  const deps = makeDeps({
111
- prompter: new fake_prompter_1.FakePrompter([(0, fake_prompter_1.select)("opencode"), (0, fake_prompter_1.select)("project")]),
112
111
  commands: new fake_command_runner_1.FakeCommandRunner(),
112
+ prompter: new fake_prompter_1.FakePrompter([(0, fake_prompter_1.select)('opencode'), (0, fake_prompter_1.select)('project')]),
113
113
  });
114
114
  // Simulate opencode not being installed
115
- yield (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.PrerequisiteError);
116
- }));
115
+ await (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.PrerequisiteError);
116
+ });
117
117
  });
118
- (0, vitest_1.describe)("cancellation", () => {
119
- (0, vitest_1.it)("throws CancelledError when user cancels at tool selection", () => __awaiter(void 0, void 0, void 0, function* () {
118
+ (0, vitest_1.describe)('cancellation', () => {
119
+ (0, vitest_1.it)('throws CancelledError when user cancels at tool selection', async () => {
120
120
  const deps = makeDeps({
121
121
  prompter: new fake_prompter_1.FakePrompter([(0, fake_prompter_1.select)(fake_prompter_1.CANCEL)]),
122
122
  });
123
- yield (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.CancelledError);
124
- }));
125
- (0, vitest_1.it)("throws CancelledError when user cancels at write confirmation", () => __awaiter(void 0, void 0, void 0, function* () {
123
+ await (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.CancelledError);
124
+ });
125
+ (0, vitest_1.it)('throws CancelledError when user cancels at write confirmation', async () => {
126
126
  const deps = makeDeps({
127
127
  prompter: new fake_prompter_1.FakePrompter([
128
- (0, fake_prompter_1.select)("opencode"),
129
- (0, fake_prompter_1.select)("project"),
130
- (0, fake_prompter_1.confirm)(false, "Create"),
128
+ (0, fake_prompter_1.select)('opencode'),
129
+ (0, fake_prompter_1.select)('project'),
130
+ (0, fake_prompter_1.confirm)(false, 'Create'),
131
131
  ]),
132
132
  });
133
- yield (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.CancelledError);
134
- }));
135
- (0, vitest_1.it)("throws CancelledError when user cancels at agent write confirmation (opencode)", () => __awaiter(void 0, void 0, void 0, function* () {
133
+ await (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.CancelledError);
134
+ });
135
+ (0, vitest_1.it)('throws CancelledError when user cancels at agent write confirmation (opencode)', async () => {
136
136
  const deps = makeDeps({
137
137
  prompter: new fake_prompter_1.FakePrompter([
138
- (0, fake_prompter_1.select)("opencode"),
139
- (0, fake_prompter_1.select)("project"),
140
- (0, fake_prompter_1.confirm)(true, "Create"),
141
- (0, fake_prompter_1.multiselect)(["backend", "frontend"]),
142
- (0, fake_prompter_1.confirm)(false, "agent"),
138
+ (0, fake_prompter_1.select)('opencode'),
139
+ (0, fake_prompter_1.select)('project'),
140
+ (0, fake_prompter_1.confirm)(true, 'Create'),
141
+ (0, fake_prompter_1.multiselect)(['backend', 'frontend']),
142
+ (0, fake_prompter_1.confirm)(false, 'agent'),
143
143
  ]),
144
144
  });
145
- yield (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.CancelledError);
146
- }));
147
- (0, vitest_1.it)("throws CancelledError when user cancels at agent write confirmation (pi)", () => __awaiter(void 0, void 0, void 0, function* () {
145
+ await (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.CancelledError);
146
+ });
147
+ (0, vitest_1.it)('throws CancelledError when user cancels at agent write confirmation (pi)', async () => {
148
148
  const deps = makeDeps({
149
+ commands: new fake_command_runner_1.FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
149
150
  prompter: new fake_prompter_1.FakePrompter([
150
- (0, fake_prompter_1.select)("pi"),
151
- (0, fake_prompter_1.select)("project"),
152
- (0, fake_prompter_1.select)("fullstack"),
151
+ (0, fake_prompter_1.select)('pi'),
152
+ (0, fake_prompter_1.select)('project'),
153
+ (0, fake_prompter_1.select)('fullstack'),
153
154
  (0, fake_prompter_1.confirm)(false, /Create|Overwrite/),
154
155
  ]),
155
- commands: new fake_command_runner_1.FakeCommandRunner().handle("pi --version", "mocked").handle("pi install", ""),
156
156
  });
157
- yield (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.CancelledError);
158
- }));
157
+ await (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.CancelledError);
158
+ });
159
159
  });
160
- (0, vitest_1.describe)("file operations", () => {
161
- (0, vitest_1.it)("preserves existing configuration keys when updating", () => __awaiter(void 0, void 0, void 0, function* () {
160
+ (0, vitest_1.describe)('file operations', () => {
161
+ (0, vitest_1.it)('preserves existing configuration keys when updating', async () => {
162
162
  const deps = makeDeps({
163
163
  prompter: new fake_prompter_1.FakePrompter([
164
- (0, fake_prompter_1.select)("opencode"),
165
- (0, fake_prompter_1.select)("project"),
166
- (0, fake_prompter_1.confirm)(true, "Write"),
164
+ (0, fake_prompter_1.select)('opencode'),
165
+ (0, fake_prompter_1.select)('project'),
166
+ (0, fake_prompter_1.confirm)(true, 'Write'),
167
167
  (0, fake_prompter_1.multiselect)([]),
168
168
  ]),
169
169
  });
170
170
  const files = deps.files;
171
- files.seed("/home/user/project/opencode.json", JSON.stringify({
172
- customField: "should-preserve",
173
- plugin: ["other-plugin"],
171
+ files.seed('/home/user/project/opencode.json', JSON.stringify({
172
+ customField: 'should-preserve',
173
+ plugin: ['other-plugin'],
174
174
  }));
175
- yield (0, setup_1.runSetup)(deps);
175
+ await (0, setup_1.runSetup)(deps);
176
176
  const written = files.getWrittenFiles();
177
- const config = JSON.parse(written.get("/home/user/project/opencode.json"));
178
- (0, vitest_1.expect)(config.customField).toBe("should-preserve");
179
- (0, vitest_1.expect)(config.plugin).toContain("other-plugin");
180
- (0, vitest_1.expect)(config.plugin).toContain("@bergetai/opencode-auth@1.0.16");
181
- }));
182
- (0, vitest_1.it)("preserves jsonc comments when updating", () => __awaiter(void 0, void 0, void 0, function* () {
177
+ const config = JSON.parse(written.get('/home/user/project/opencode.json'));
178
+ (0, vitest_1.expect)(config.customField).toBe('should-preserve');
179
+ (0, vitest_1.expect)(config.plugin).toContain('other-plugin');
180
+ (0, vitest_1.expect)(config.plugin).toContain('@bergetai/opencode-auth');
181
+ });
182
+ (0, vitest_1.it)('preserves jsonc comments when updating', async () => {
183
183
  const deps = makeDeps({
184
184
  prompter: new fake_prompter_1.FakePrompter([
185
- (0, fake_prompter_1.select)("opencode"),
186
- (0, fake_prompter_1.select)("project"),
187
- (0, fake_prompter_1.confirm)(true, "Write"),
185
+ (0, fake_prompter_1.select)('opencode'),
186
+ (0, fake_prompter_1.select)('project'),
187
+ (0, fake_prompter_1.confirm)(true, 'Write'),
188
188
  (0, fake_prompter_1.multiselect)([]),
189
189
  ]),
190
190
  });
191
191
  const files = deps.files;
192
- files.seed("/home/user/project/opencode.jsonc", `{
192
+ files.seed('/home/user/project/opencode.jsonc', `{
193
193
  // This is my custom config
194
194
  "customField": "should-preserve",
195
195
  /* block comment explaining plugin */
196
196
  "plugin": ["other-plugin"]
197
197
  }`);
198
- yield (0, setup_1.runSetup)(deps);
198
+ await (0, setup_1.runSetup)(deps);
199
199
  const written = files.getWrittenFiles();
200
- const content = written.get("/home/user/project/opencode.jsonc");
201
- (0, vitest_1.expect)(content).toContain("// This is my custom config");
202
- (0, vitest_1.expect)(content).toContain("/* block comment explaining plugin */");
200
+ const content = written.get('/home/user/project/opencode.jsonc');
201
+ (0, vitest_1.expect)(content).toContain('// This is my custom config');
202
+ (0, vitest_1.expect)(content).toContain('/* block comment explaining plugin */');
203
203
  (0, vitest_1.expect)(content).toContain('"customField": "should-preserve"');
204
- (0, vitest_1.expect)(content).toContain("@bergetai/opencode-auth@1.0.16");
205
- }));
206
- (0, vitest_1.it)("shows no changes needed when config is already up to date", () => __awaiter(void 0, void 0, void 0, function* () {
204
+ (0, vitest_1.expect)(content).toContain('@bergetai/opencode-auth');
205
+ });
206
+ (0, vitest_1.it)('shows no changes needed when config is already up to date', async () => {
207
207
  const deps = makeDeps({
208
- prompter: new fake_prompter_1.FakePrompter([(0, fake_prompter_1.select)("opencode"), (0, fake_prompter_1.select)("project"), (0, fake_prompter_1.multiselect)([])]),
208
+ prompter: new fake_prompter_1.FakePrompter([(0, fake_prompter_1.select)('opencode'), (0, fake_prompter_1.select)('project'), (0, fake_prompter_1.multiselect)([])]),
209
209
  });
210
210
  const files = deps.files;
211
211
  // Already has the exact same plugin version
212
- files.seed("/home/user/project/opencode.json", JSON.stringify({
213
- $schema: "https://opencode.ai/config.json",
214
- plugin: ["@bergetai/opencode-auth@1.0.16"],
215
- }, null, 2) + "\n");
216
- yield (0, setup_1.runSetup)(deps);
212
+ files.seed('/home/user/project/opencode.json', JSON.stringify({
213
+ $schema: 'https://opencode.ai/config.json',
214
+ plugin: ['@bergetai/opencode-auth'],
215
+ }, null, 2) + '\n');
216
+ await (0, setup_1.runSetup)(deps);
217
217
  // Check that no write happened — content should be unchanged
218
218
  const written = files.getWrittenFiles();
219
- const content = written.get("/home/user/project/opencode.json");
219
+ const content = written.get('/home/user/project/opencode.json');
220
220
  const config = JSON.parse(content);
221
- (0, vitest_1.expect)(config.plugin).toEqual(["@bergetai/opencode-auth@1.0.16"]);
222
- (0, vitest_1.expect)(content).toContain("$schema");
223
- }));
224
- (0, vitest_1.it)("preserves existing Pi settings when setting defaultProvider", () => __awaiter(void 0, void 0, void 0, function* () {
221
+ (0, vitest_1.expect)(config.plugin).toEqual(['@bergetai/opencode-auth']);
222
+ (0, vitest_1.expect)(content).toContain('$schema');
223
+ });
224
+ (0, vitest_1.it)('preserves existing Pi settings when setting defaultProvider', async () => {
225
225
  const deps = makeDeps({
226
+ commands: new fake_command_runner_1.FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
226
227
  prompter: new fake_prompter_1.FakePrompter([
227
- (0, fake_prompter_1.select)("pi"),
228
- (0, fake_prompter_1.select)("project"),
229
- (0, fake_prompter_1.select)("fullstack"),
230
- (0, fake_prompter_1.confirm)(true, "Create"),
228
+ (0, fake_prompter_1.select)('pi'),
229
+ (0, fake_prompter_1.select)('project'),
230
+ (0, fake_prompter_1.select)('fullstack'),
231
+ (0, fake_prompter_1.confirm)(true, 'Create'),
231
232
  ]),
232
- commands: new fake_command_runner_1.FakeCommandRunner().handle("pi --version", "mocked").handle("pi install", ""),
233
233
  });
234
234
  const files = deps.files;
235
- files.seed("/home/user/project/.pi/settings.json", JSON.stringify({
236
- existingKey: "should-preserve",
235
+ files.seed('/home/user/project/.pi/settings.json', JSON.stringify({
237
236
  anotherSetting: true,
237
+ existingKey: 'should-preserve',
238
238
  }));
239
- yield (0, setup_1.runSetup)(deps);
239
+ await (0, setup_1.runSetup)(deps);
240
240
  const written = files.getWrittenFiles();
241
- const settings = JSON.parse(written.get("/home/user/project/.pi/settings.json"));
242
- (0, vitest_1.expect)(settings.existingKey).toBe("should-preserve");
241
+ const settings = JSON.parse(written.get('/home/user/project/.pi/settings.json'));
242
+ (0, vitest_1.expect)(settings.existingKey).toBe('should-preserve');
243
243
  (0, vitest_1.expect)(settings.anotherSetting).toBe(true);
244
- (0, vitest_1.expect)(settings.defaultProvider).toBe("berget");
245
- }));
246
- (0, vitest_1.it)("creates parent directories when writing files", () => __awaiter(void 0, void 0, void 0, function* () {
244
+ (0, vitest_1.expect)(settings.defaultProvider).toBe('berget');
245
+ });
246
+ (0, vitest_1.it)('creates parent directories when writing files', async () => {
247
247
  const deps = makeDeps({
248
248
  prompter: new fake_prompter_1.FakePrompter([
249
- (0, fake_prompter_1.select)("opencode"),
250
- (0, fake_prompter_1.select)("global"),
251
- (0, fake_prompter_1.confirm)(true, "Create"),
249
+ (0, fake_prompter_1.select)('opencode'),
250
+ (0, fake_prompter_1.select)('global'),
251
+ (0, fake_prompter_1.confirm)(true, 'Create'),
252
252
  (0, fake_prompter_1.multiselect)([]),
253
253
  ]),
254
254
  });
255
- yield (0, setup_1.runSetup)(deps);
255
+ await (0, setup_1.runSetup)(deps);
256
256
  const files = deps.files;
257
257
  const written = files.getWrittenFiles();
258
- (0, vitest_1.expect)(written.has("/home/user/.config/opencode/opencode.json")).toBe(true);
259
- }));
258
+ (0, vitest_1.expect)(written.has('/home/user/.config/opencode/opencode.json')).toBe(true);
259
+ });
260
260
  });
261
- (0, vitest_1.describe)("command execution", () => {
262
- (0, vitest_1.it)("passes arguments as array (no shell injection)", () => __awaiter(void 0, void 0, void 0, function* () {
261
+ (0, vitest_1.describe)('command execution', () => {
262
+ (0, vitest_1.it)('passes arguments as array (no shell injection)', async () => {
263
263
  const deps = makeDeps({
264
+ commands: new fake_command_runner_1.FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
264
265
  prompter: new fake_prompter_1.FakePrompter([
265
- (0, fake_prompter_1.select)("pi"),
266
- (0, fake_prompter_1.select)("project"),
267
- (0, fake_prompter_1.select)("fullstack"),
268
- (0, fake_prompter_1.confirm)(true, "Create"),
266
+ (0, fake_prompter_1.select)('pi'),
267
+ (0, fake_prompter_1.select)('project'),
268
+ (0, fake_prompter_1.select)('fullstack'),
269
+ (0, fake_prompter_1.confirm)(true, 'Create'),
269
270
  ]),
270
- commands: new fake_command_runner_1.FakeCommandRunner().handle("pi --version", "mocked").handle("pi install", ""),
271
271
  });
272
- yield (0, setup_1.runSetup)(deps);
272
+ await (0, setup_1.runSetup)(deps);
273
273
  const commands = deps.commands;
274
- const installCall = commands.calls.find(c => c.command === "pi");
275
- (0, vitest_1.expect)(installCall === null || installCall === void 0 ? void 0 : installCall.args).toContain("npm:@bergetai/pi-provider");
276
- (0, vitest_1.expect)(installCall === null || installCall === void 0 ? void 0 : installCall.args).toContain("-l");
277
- }));
274
+ const installCall = commands.calls.find((c) => c.command === 'pi');
275
+ (0, vitest_1.expect)(installCall?.args).toContain('npm:@bergetai/pi-provider');
276
+ (0, vitest_1.expect)(installCall?.args).toContain('-l');
277
+ });
278
278
  });
279
- (0, vitest_1.describe)("error handling", () => {
280
- (0, vitest_1.it)("throws CommandFailedError when pi install fails", () => __awaiter(void 0, void 0, void 0, function* () {
279
+ (0, vitest_1.describe)('error handling', () => {
280
+ (0, vitest_1.it)('throws CommandFailedError when pi install fails', async () => {
281
281
  const deps = makeDeps({
282
- prompter: new fake_prompter_1.FakePrompter([(0, fake_prompter_1.select)("pi"), (0, fake_prompter_1.select)("project")]),
283
282
  commands: new fake_command_runner_1.FakeCommandRunner()
284
- .handle("pi --version", "mocked")
285
- .handle("pi install", new Error("npm error")),
283
+ .handle('pi --version', 'mocked')
284
+ .handle('pi install', new Error('npm error')),
285
+ prompter: new fake_prompter_1.FakePrompter([(0, fake_prompter_1.select)('pi'), (0, fake_prompter_1.select)('project')]),
286
286
  });
287
- yield (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.CommandFailedError);
288
- }));
287
+ await (0, vitest_1.expect)((0, setup_1.runSetup)(deps)).rejects.toBeInstanceOf(errors_1.CommandFailedError);
288
+ });
289
289
  });
290
- (0, vitest_1.describe)("auth integration", () => {
291
- (0, vitest_1.it)("already authenticated shows simplified message", () => __awaiter(void 0, void 0, void 0, function* () {
290
+ (0, vitest_1.describe)('auth integration', () => {
291
+ (0, vitest_1.it)('already authenticated shows simplified message', async () => {
292
292
  const files = new fake_file_store_1.FakeFileStore();
293
- files.seed("/home/user/.local/share/opencode/auth.json", JSON.stringify({ berget: { type: "oauth" } }));
293
+ files.seed('/home/user/.local/share/opencode/auth.json', JSON.stringify({ berget: { type: 'oauth' } }));
294
294
  const deps = makeDeps({
295
+ files,
295
296
  prompter: new fake_prompter_1.FakePrompter([
296
- (0, fake_prompter_1.select)("opencode"),
297
- (0, fake_prompter_1.select)("project"),
298
- (0, fake_prompter_1.select)("keep"), // New: keep existing auth
299
- (0, fake_prompter_1.confirm)(true, "Create"), // Config write
297
+ (0, fake_prompter_1.select)('opencode'),
298
+ (0, fake_prompter_1.select)('project'),
299
+ (0, fake_prompter_1.select)('keep'), // New: keep existing auth
300
+ (0, fake_prompter_1.confirm)(true, 'Create'), // Config write
300
301
  (0, fake_prompter_1.multiselect)([]),
301
302
  ]),
302
- files,
303
303
  });
304
- yield (0, setup_1.runSetup)(deps);
304
+ await (0, setup_1.runSetup)(deps);
305
305
  const prompter = deps.prompter;
306
- const notes = prompter.calls.filter(c => c.method === "note");
307
- const lastNote = notes[notes.length - 1];
308
- (0, vitest_1.expect)(JSON.stringify(lastNote)).toContain("Run: opencode");
309
- (0, vitest_1.expect)(JSON.stringify(lastNote)).not.toContain("/connect");
310
- }));
311
- (0, vitest_1.it)("login failure shows manual auth instructions", () => __awaiter(void 0, void 0, void 0, function* () {
306
+ const notes = prompter.calls.filter((c) => c.method === 'note');
307
+ const lastNote = notes.at(-1);
308
+ (0, vitest_1.expect)(JSON.stringify(lastNote)).toContain('Run: opencode');
309
+ (0, vitest_1.expect)(JSON.stringify(lastNote)).not.toContain('/connect');
310
+ });
311
+ (0, vitest_1.it)('login failure shows manual auth instructions', async () => {
312
312
  const deps = makeDeps({
313
- prompter: new fake_prompter_1.FakePrompter([
314
- (0, fake_prompter_1.select)("pi"),
315
- (0, fake_prompter_1.select)("project"),
316
- (0, fake_prompter_1.select)("fullstack"),
317
- (0, fake_prompter_1.confirm)(true, "Create"),
318
- ]),
319
- commands: new fake_command_runner_1.FakeCommandRunner().handle("pi --version", "mocked").handle("pi install", ""),
320
313
  authService: new fake_auth_service_1.FakeAuthService(false),
314
+ commands: new fake_command_runner_1.FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
321
315
  files: new fake_file_store_1.FakeFileStore(), // No pre-seeded auth → auth flow runs
316
+ prompter: new fake_prompter_1.FakePrompter([
317
+ (0, fake_prompter_1.select)('pi'),
318
+ (0, fake_prompter_1.select)('project'),
319
+ (0, fake_prompter_1.select)('fullstack'),
320
+ (0, fake_prompter_1.confirm)(true, 'Create'),
321
+ ]),
322
322
  });
323
- yield (0, setup_1.runSetup)(deps);
323
+ await (0, setup_1.runSetup)(deps);
324
324
  const prompter = deps.prompter;
325
- const notes = prompter.calls.filter(c => c.method === "note");
326
- const lastNote = notes[notes.length - 1];
327
- (0, vitest_1.expect)(JSON.stringify(lastNote)).toContain("/login");
328
- }));
329
- (0, vitest_1.it)("creates api key for pi when no seat", () => __awaiter(void 0, void 0, void 0, function* () {
325
+ const notes = prompter.calls.filter((c) => c.method === 'note');
326
+ const lastNote = notes.at(-1);
327
+ (0, vitest_1.expect)(JSON.stringify(lastNote)).toContain('/login');
328
+ });
329
+ (0, vitest_1.it)('creates api key for pi when no seat', async () => {
330
330
  const files = new fake_file_store_1.FakeFileStore();
331
331
  const deps = makeDeps({
332
+ authService: new fake_auth_service_1.FakeAuthService(true, false), // succeed, no seat
333
+ commands: new fake_command_runner_1.FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
334
+ files,
332
335
  prompter: new fake_prompter_1.FakePrompter([
333
- (0, fake_prompter_1.select)("pi"),
334
- (0, fake_prompter_1.select)("project"),
336
+ (0, fake_prompter_1.select)('pi'),
337
+ (0, fake_prompter_1.select)('project'),
335
338
  (0, fake_prompter_1.confirm)(true), // API key creation prompt
336
- (0, fake_prompter_1.select)("fullstack"),
337
- (0, fake_prompter_1.confirm)(true, "Create"),
339
+ (0, fake_prompter_1.select)('fullstack'),
340
+ (0, fake_prompter_1.confirm)(true, 'Create'),
338
341
  ]),
339
- commands: new fake_command_runner_1.FakeCommandRunner().handle("pi --version", "mocked").handle("pi install", ""),
340
- authService: new fake_auth_service_1.FakeAuthService(true, false), // succeed, no seat
341
- files,
342
342
  });
343
- yield (0, setup_1.runSetup)(deps);
343
+ await (0, setup_1.runSetup)(deps);
344
344
  const written = files.getWrittenFiles();
345
- (0, vitest_1.expect)(written.has("/home/user/.pi/agent/auth.json")).toBe(true);
346
- const parsed = JSON.parse(written.get("/home/user/.pi/agent/auth.json"));
347
- (0, vitest_1.expect)(parsed.berget.type).toBe("api_key");
348
- }));
349
- (0, vitest_1.it)("uses subscription when berget_code_seat present", () => __awaiter(void 0, void 0, void 0, function* () {
345
+ (0, vitest_1.expect)(written.has('/home/user/.pi/agent/auth.json')).toBe(true);
346
+ const parsed = JSON.parse(written.get('/home/user/.pi/agent/auth.json'));
347
+ (0, vitest_1.expect)(parsed.berget.type).toBe('api_key');
348
+ });
349
+ (0, vitest_1.it)('uses subscription when berget_code_seat present', async () => {
350
350
  const files = new fake_file_store_1.FakeFileStore();
351
351
  const farFuture = Math.floor(Date.now() / 1000) + 3600 * 24 * 365; // 1 year from now in seconds
352
- files.seed("/home/user/.berget/auth.json", JSON.stringify({
353
- access_token: makeJwt({ realm_access: { roles: ["berget_code_seat"] }, exp: farFuture }),
354
- refresh_token: "ref",
352
+ files.seed('/home/user/.berget/auth.json', JSON.stringify({
353
+ access_token: makeJwt({ exp: farFuture, realm_access: { roles: ['berget_code_seat'] } }),
355
354
  expires_at: farFuture * 1000,
355
+ refresh_token: 'ref',
356
356
  }));
357
357
  const deps = makeDeps({
358
+ files,
358
359
  prompter: new fake_prompter_1.FakePrompter([
359
- (0, fake_prompter_1.select)("opencode"),
360
- (0, fake_prompter_1.select)("project"),
361
- (0, fake_prompter_1.select)("subscription"),
362
- (0, fake_prompter_1.confirm)(true, "Create"),
360
+ (0, fake_prompter_1.select)('opencode'),
361
+ (0, fake_prompter_1.select)('project'),
362
+ (0, fake_prompter_1.select)('subscription'),
363
+ (0, fake_prompter_1.confirm)(true, 'Create'),
363
364
  (0, fake_prompter_1.multiselect)([]),
364
365
  ]),
365
- files,
366
366
  });
367
- yield (0, setup_1.runSetup)(deps);
367
+ await (0, setup_1.runSetup)(deps);
368
368
  const written = files.getWrittenFiles();
369
- const parsed = JSON.parse(written.get("/home/user/.local/share/opencode/auth.json"));
370
- (0, vitest_1.expect)(parsed.berget.type).toBe("oauth");
371
- }));
369
+ const parsed = JSON.parse(written.get('/home/user/.local/share/opencode/auth.json'));
370
+ (0, vitest_1.expect)(parsed.berget.type).toBe('oauth');
371
+ });
372
372
  });
373
- (0, vitest_1.describe)("agent configuration", () => {
374
- (0, vitest_1.it)("sets up multiple agents for opencode project", () => __awaiter(void 0, void 0, void 0, function* () {
373
+ (0, vitest_1.describe)('agent configuration', () => {
374
+ (0, vitest_1.it)('sets up multiple agents for opencode project', async () => {
375
375
  const deps = makeDeps({
376
376
  prompter: new fake_prompter_1.FakePrompter([
377
- (0, fake_prompter_1.select)("opencode"),
378
- (0, fake_prompter_1.select)("project"),
379
- (0, fake_prompter_1.confirm)(true, "Create"),
380
- (0, fake_prompter_1.multiselect)(["backend", "frontend"]),
381
- (0, fake_prompter_1.confirm)(true, "agent"),
377
+ (0, fake_prompter_1.select)('opencode'),
378
+ (0, fake_prompter_1.select)('project'),
379
+ (0, fake_prompter_1.confirm)(true, 'Create'),
380
+ (0, fake_prompter_1.multiselect)(['backend', 'frontend']),
381
+ (0, fake_prompter_1.confirm)(true, 'agent'),
382
382
  ]),
383
383
  });
384
- yield (0, setup_1.runSetup)(deps);
384
+ await (0, setup_1.runSetup)(deps);
385
385
  const files = deps.files;
386
386
  const written = files.getWrittenFiles();
387
- (0, vitest_1.expect)(written.has("/home/user/project/.opencode/agents/backend.md")).toBe(true);
388
- (0, vitest_1.expect)(written.has("/home/user/project/.opencode/agents/frontend.md")).toBe(true);
389
- }));
390
- (0, vitest_1.it)("sets up no agents for opencode when none selected", () => __awaiter(void 0, void 0, void 0, function* () {
387
+ (0, vitest_1.expect)(written.has('/home/user/project/.opencode/agents/backend.md')).toBe(true);
388
+ (0, vitest_1.expect)(written.has('/home/user/project/.opencode/agents/frontend.md')).toBe(true);
389
+ });
390
+ (0, vitest_1.it)('sets up no agents for opencode when none selected', async () => {
391
391
  const deps = makeDeps({
392
392
  prompter: new fake_prompter_1.FakePrompter([
393
- (0, fake_prompter_1.select)("opencode"),
394
- (0, fake_prompter_1.select)("project"),
395
- (0, fake_prompter_1.confirm)(true, "Create"),
393
+ (0, fake_prompter_1.select)('opencode'),
394
+ (0, fake_prompter_1.select)('project'),
395
+ (0, fake_prompter_1.confirm)(true, 'Create'),
396
396
  (0, fake_prompter_1.multiselect)([]),
397
397
  ]),
398
398
  });
399
- yield (0, setup_1.runSetup)(deps);
399
+ await (0, setup_1.runSetup)(deps);
400
400
  const files = deps.files;
401
401
  const written = files.getWrittenFiles();
402
402
  for (const path of written.keys()) {
403
403
  (0, vitest_1.expect)(path).not.toMatch(/agents\/\w+\.md$/);
404
404
  }
405
- }));
406
- (0, vitest_1.it)("sets up agent globally for opencode", () => __awaiter(void 0, void 0, void 0, function* () {
405
+ });
406
+ (0, vitest_1.it)('sets up agent globally for opencode', async () => {
407
407
  const deps = makeDeps({
408
408
  prompter: new fake_prompter_1.FakePrompter([
409
- (0, fake_prompter_1.select)("opencode"),
410
- (0, fake_prompter_1.select)("global"),
411
- (0, fake_prompter_1.confirm)(true, "Create"),
412
- (0, fake_prompter_1.multiselect)(["fullstack"]),
413
- (0, fake_prompter_1.confirm)(true, "agent"),
409
+ (0, fake_prompter_1.select)('opencode'),
410
+ (0, fake_prompter_1.select)('global'),
411
+ (0, fake_prompter_1.confirm)(true, 'Create'),
412
+ (0, fake_prompter_1.multiselect)(['fullstack']),
413
+ (0, fake_prompter_1.confirm)(true, 'agent'),
414
414
  ]),
415
415
  });
416
- yield (0, setup_1.runSetup)(deps);
416
+ await (0, setup_1.runSetup)(deps);
417
417
  const files = deps.files;
418
418
  const written = files.getWrittenFiles();
419
- (0, vitest_1.expect)(written.has("/home/user/.config/opencode/agents/fullstack.md")).toBe(true);
420
- }));
421
- (0, vitest_1.it)("sets up agent for pi project", () => __awaiter(void 0, void 0, void 0, function* () {
419
+ (0, vitest_1.expect)(written.has('/home/user/.config/opencode/agents/fullstack.md')).toBe(true);
420
+ });
421
+ (0, vitest_1.it)('sets up agent for pi project', async () => {
422
422
  const deps = makeDeps({
423
+ commands: new fake_command_runner_1.FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
423
424
  prompter: new fake_prompter_1.FakePrompter([
424
- (0, fake_prompter_1.select)("pi"),
425
- (0, fake_prompter_1.select)("project"),
426
- (0, fake_prompter_1.select)("fullstack"),
427
- (0, fake_prompter_1.confirm)(true, "Create"),
425
+ (0, fake_prompter_1.select)('pi'),
426
+ (0, fake_prompter_1.select)('project'),
427
+ (0, fake_prompter_1.select)('fullstack'),
428
+ (0, fake_prompter_1.confirm)(true, 'Create'),
428
429
  ]),
429
- commands: new fake_command_runner_1.FakeCommandRunner().handle("pi --version", "mocked").handle("pi install", ""),
430
430
  });
431
- yield (0, setup_1.runSetup)(deps);
431
+ await (0, setup_1.runSetup)(deps);
432
432
  const files = deps.files;
433
433
  const written = files.getWrittenFiles();
434
- (0, vitest_1.expect)(written.has("/home/user/project/.pi/SYSTEM.md")).toBe(true);
435
- }));
436
- (0, vitest_1.it)("sets up agent for pi globally", () => __awaiter(void 0, void 0, void 0, function* () {
434
+ (0, vitest_1.expect)(written.has('/home/user/project/.pi/SYSTEM.md')).toBe(true);
435
+ });
436
+ (0, vitest_1.it)('sets up agent for pi globally', async () => {
437
437
  const deps = makeDeps({
438
+ commands: new fake_command_runner_1.FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
438
439
  prompter: new fake_prompter_1.FakePrompter([
439
- (0, fake_prompter_1.select)("pi"),
440
- (0, fake_prompter_1.select)("global"),
441
- (0, fake_prompter_1.select)("backend"),
442
- (0, fake_prompter_1.confirm)(true, "Create"),
440
+ (0, fake_prompter_1.select)('pi'),
441
+ (0, fake_prompter_1.select)('global'),
442
+ (0, fake_prompter_1.select)('backend'),
443
+ (0, fake_prompter_1.confirm)(true, 'Create'),
443
444
  ]),
444
- commands: new fake_command_runner_1.FakeCommandRunner().handle("pi --version", "mocked").handle("pi install", ""),
445
445
  });
446
- yield (0, setup_1.runSetup)(deps);
446
+ await (0, setup_1.runSetup)(deps);
447
447
  const files = deps.files;
448
448
  const written = files.getWrittenFiles();
449
- (0, vitest_1.expect)(written.has("/home/user/.pi/agent/SYSTEM.md")).toBe(true);
450
- }));
451
- (0, vitest_1.it)("skips writing identical opencode agent files", () => __awaiter(void 0, void 0, void 0, function* () {
449
+ (0, vitest_1.expect)(written.has('/home/user/.pi/agent/SYSTEM.md')).toBe(true);
450
+ });
451
+ (0, vitest_1.it)('skips writing identical opencode agent files', async () => {
452
452
  const deps = makeDeps({
453
453
  prompter: new fake_prompter_1.FakePrompter([
454
- (0, fake_prompter_1.select)("opencode"),
455
- (0, fake_prompter_1.select)("project"),
456
- (0, fake_prompter_1.confirm)(true, "Create"),
457
- (0, fake_prompter_1.multiselect)(["backend", "frontend"]),
458
- (0, fake_prompter_1.confirm)(true, "agent"),
454
+ (0, fake_prompter_1.select)('opencode'),
455
+ (0, fake_prompter_1.select)('project'),
456
+ (0, fake_prompter_1.confirm)(true, 'Create'),
457
+ (0, fake_prompter_1.multiselect)(['backend', 'frontend']),
458
+ (0, fake_prompter_1.confirm)(true, 'agent'),
459
459
  ]),
460
460
  });
461
461
  // First run writes the files
462
- yield (0, setup_1.runSetup)(deps);
462
+ await (0, setup_1.runSetup)(deps);
463
463
  const files = deps.files;
464
464
  const firstBackend = files
465
465
  .getWrittenFiles()
466
- .get("/home/user/project/.opencode/agents/backend.md");
466
+ .get('/home/user/project/.opencode/agents/backend.md');
467
467
  const firstFrontend = files
468
468
  .getWrittenFiles()
469
- .get("/home/user/project/.opencode/agents/frontend.md");
469
+ .get('/home/user/project/.opencode/agents/frontend.md');
470
470
  // Second run with exact same content should not prompt for overwrite
471
471
  const deps2 = makeDeps({
472
472
  files,
473
473
  prompter: new fake_prompter_1.FakePrompter([
474
- (0, fake_prompter_1.select)("opencode"),
475
- (0, fake_prompter_1.select)("project"),
476
- (0, fake_prompter_1.multiselect)(["backend", "frontend"]),
474
+ (0, fake_prompter_1.select)('opencode'),
475
+ (0, fake_prompter_1.select)('project'),
476
+ (0, fake_prompter_1.multiselect)(['backend', 'frontend']),
477
477
  ]),
478
478
  });
479
- yield (0, setup_1.runSetup)(deps2);
479
+ await (0, setup_1.runSetup)(deps2);
480
480
  // Content should be unchanged
481
- (0, vitest_1.expect)(files.getWrittenFiles().get("/home/user/project/.opencode/agents/backend.md")).toBe(firstBackend);
482
- (0, vitest_1.expect)(files.getWrittenFiles().get("/home/user/project/.opencode/agents/frontend.md")).toBe(firstFrontend);
483
- }));
484
- (0, vitest_1.it)("overwrites pi SYSTEM.md when content differs", () => __awaiter(void 0, void 0, void 0, function* () {
481
+ (0, vitest_1.expect)(files.getWrittenFiles().get('/home/user/project/.opencode/agents/backend.md')).toBe(firstBackend);
482
+ (0, vitest_1.expect)(files.getWrittenFiles().get('/home/user/project/.opencode/agents/frontend.md')).toBe(firstFrontend);
483
+ });
484
+ (0, vitest_1.it)('overwrites pi SYSTEM.md when content differs', async () => {
485
485
  const files = new fake_file_store_1.FakeFileStore();
486
- files.seed("/home/user/project/.pi/SYSTEM.md", "old agent content");
486
+ files.seed('/home/user/project/.pi/SYSTEM.md', 'old agent content');
487
487
  const deps = makeDeps({
488
+ commands: new fake_command_runner_1.FakeCommandRunner().handle('pi --version', 'mocked').handle('pi install', ''),
489
+ files,
488
490
  prompter: new fake_prompter_1.FakePrompter([
489
- (0, fake_prompter_1.select)("pi"),
490
- (0, fake_prompter_1.select)("project"),
491
- (0, fake_prompter_1.select)("fullstack"),
492
- (0, fake_prompter_1.confirm)(true, "Overwrite"),
491
+ (0, fake_prompter_1.select)('pi'),
492
+ (0, fake_prompter_1.select)('project'),
493
+ (0, fake_prompter_1.select)('fullstack'),
494
+ (0, fake_prompter_1.confirm)(true, 'Overwrite'),
493
495
  ]),
494
- files,
495
- commands: new fake_command_runner_1.FakeCommandRunner().handle("pi --version", "mocked").handle("pi install", ""),
496
496
  });
497
- yield (0, setup_1.runSetup)(deps);
497
+ await (0, setup_1.runSetup)(deps);
498
498
  const written = files.getWrittenFiles();
499
- const content = written.get("/home/user/project/.pi/SYSTEM.md");
500
- (0, vitest_1.expect)(content).not.toBe("old agent content");
499
+ const content = written.get('/home/user/project/.pi/SYSTEM.md');
500
+ (0, vitest_1.expect)(content).not.toBe('old agent content');
501
501
  // Pi doesn't use front matter, so check for system prompt content
502
- (0, vitest_1.expect)(content).toContain("Fullstack Agent");
503
- }));
502
+ (0, vitest_1.expect)(content).toContain('Fullstack Agent');
503
+ });
504
504
  });
505
505
  });