berget 2.2.5 → 2.2.7

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 (148) hide show
  1. package/.github/workflows/publish.yml +8 -8
  2. package/.github/workflows/test.yml +12 -6
  3. package/.husky/pre-commit +1 -0
  4. package/.prettierignore +15 -0
  5. package/.prettierrc +5 -3
  6. package/CONTRIBUTING.md +38 -0
  7. package/README.md +2 -148
  8. package/dist/index.js +21 -21
  9. package/dist/package.json +30 -2
  10. package/dist/src/agents/app.js +28 -0
  11. package/dist/src/agents/backend.js +25 -0
  12. package/dist/src/agents/devops.js +34 -0
  13. package/dist/src/agents/frontend.js +25 -0
  14. package/dist/src/agents/fullstack.js +25 -0
  15. package/dist/src/agents/index.js +61 -0
  16. package/dist/src/agents/quality.js +70 -0
  17. package/dist/src/agents/security.js +26 -0
  18. package/dist/src/agents/types.js +2 -0
  19. package/dist/src/client.js +54 -62
  20. package/dist/src/commands/api-keys.js +132 -140
  21. package/dist/src/commands/auth.js +9 -9
  22. package/dist/src/commands/autocomplete.js +9 -9
  23. package/dist/src/commands/billing.js +7 -9
  24. package/dist/src/commands/chat.js +90 -92
  25. package/dist/src/commands/clusters.js +12 -12
  26. package/dist/src/commands/code/__tests__/auth-sync.test.js +348 -0
  27. package/dist/src/commands/code/__tests__/fake-api-key-service.js +23 -0
  28. package/dist/src/commands/code/__tests__/fake-auth-service.js +55 -0
  29. package/dist/src/commands/code/__tests__/fake-command-runner.js +50 -0
  30. package/dist/src/commands/code/__tests__/fake-file-store.js +55 -0
  31. package/dist/src/commands/code/__tests__/fake-prompter.js +133 -0
  32. package/dist/src/commands/code/__tests__/setup-flow.test.js +505 -0
  33. package/dist/src/commands/code/adapters/clack-prompter.js +81 -0
  34. package/dist/src/commands/code/adapters/fs-file-store.js +80 -0
  35. package/dist/src/commands/code/adapters/spawn-command-runner.js +53 -0
  36. package/dist/src/commands/code/auth-sync.js +283 -0
  37. package/dist/src/commands/code/errors.js +27 -0
  38. package/dist/src/commands/code/ports/auth-services.js +2 -0
  39. package/dist/src/commands/code/ports/command-runner.js +2 -0
  40. package/dist/src/commands/code/ports/file-store.js +2 -0
  41. package/dist/src/commands/code/ports/prompter.js +2 -0
  42. package/dist/src/commands/code/setup.js +533 -0
  43. package/dist/src/commands/code.js +223 -779
  44. package/dist/src/commands/models.js +13 -15
  45. package/dist/src/commands/users.js +6 -8
  46. package/dist/src/constants/command-structure.js +116 -114
  47. package/dist/src/services/api-key-service.js +43 -48
  48. package/dist/src/services/auth-service.js +60 -299
  49. package/dist/src/services/browser-auth.js +278 -0
  50. package/dist/src/services/chat-service.js +78 -91
  51. package/dist/src/services/cluster-service.js +6 -6
  52. package/dist/src/services/collaborator-service.js +5 -8
  53. package/dist/src/services/flux-service.js +5 -8
  54. package/dist/src/services/helm-service.js +5 -8
  55. package/dist/src/services/kubectl-service.js +7 -10
  56. package/dist/src/utils/config-checker.js +5 -5
  57. package/dist/src/utils/config-loader.js +25 -25
  58. package/dist/src/utils/default-api-key.js +23 -23
  59. package/dist/src/utils/env-manager.js +7 -7
  60. package/dist/src/utils/error-handler.js +60 -61
  61. package/dist/src/utils/logger.js +7 -7
  62. package/dist/src/utils/markdown-renderer.js +2 -2
  63. package/dist/src/utils/opencode-validator.js +17 -20
  64. package/dist/src/utils/token-manager.js +38 -11
  65. package/dist/tests/commands/chat.test.js +24 -24
  66. package/dist/tests/commands/code.test.js +169 -138
  67. package/dist/tests/utils/config-loader.test.js +114 -114
  68. package/dist/tests/utils/env-manager.test.js +57 -57
  69. package/dist/tests/utils/opencode-validator.test.js +44 -43
  70. package/dist/vitest.config.js +1 -1
  71. package/eslint.config.mjs +47 -0
  72. package/index.ts +42 -48
  73. package/package.json +30 -2
  74. package/src/agents/app.ts +27 -0
  75. package/src/agents/backend.ts +24 -0
  76. package/src/agents/devops.ts +33 -0
  77. package/src/agents/frontend.ts +24 -0
  78. package/src/agents/fullstack.ts +24 -0
  79. package/src/agents/index.ts +71 -0
  80. package/src/agents/quality.ts +69 -0
  81. package/src/agents/security.ts +26 -0
  82. package/src/agents/types.ts +17 -0
  83. package/src/client.ts +125 -167
  84. package/src/commands/api-keys.ts +261 -358
  85. package/src/commands/auth.ts +24 -30
  86. package/src/commands/autocomplete.ts +12 -12
  87. package/src/commands/billing.ts +22 -27
  88. package/src/commands/chat.ts +230 -323
  89. package/src/commands/clusters.ts +33 -33
  90. package/src/commands/code/__tests__/auth-sync.test.ts +481 -0
  91. package/src/commands/code/__tests__/fake-api-key-service.ts +13 -0
  92. package/src/commands/code/__tests__/fake-auth-service.ts +50 -0
  93. package/src/commands/code/__tests__/fake-command-runner.ts +44 -0
  94. package/src/commands/code/__tests__/fake-file-store.ts +44 -0
  95. package/src/commands/code/__tests__/fake-prompter.ts +121 -0
  96. package/src/commands/code/__tests__/setup-flow.test.ts +628 -0
  97. package/src/commands/code/adapters/clack-prompter.ts +55 -0
  98. package/src/commands/code/adapters/fs-file-store.ts +37 -0
  99. package/src/commands/code/adapters/spawn-command-runner.ts +40 -0
  100. package/src/commands/code/auth-sync.ts +329 -0
  101. package/src/commands/code/errors.ts +23 -0
  102. package/src/commands/code/ports/auth-services.ts +14 -0
  103. package/src/commands/code/ports/command-runner.ts +10 -0
  104. package/src/commands/code/ports/file-store.ts +7 -0
  105. package/src/commands/code/ports/prompter.ts +29 -0
  106. package/src/commands/code/setup.ts +630 -0
  107. package/src/commands/code.ts +335 -1074
  108. package/src/commands/index.ts +19 -19
  109. package/src/commands/models.ts +32 -37
  110. package/src/commands/users.ts +15 -22
  111. package/src/constants/command-structure.ts +120 -140
  112. package/src/services/api-key-service.ts +96 -113
  113. package/src/services/auth-service.ts +92 -339
  114. package/src/services/browser-auth.ts +296 -0
  115. package/src/services/chat-service.ts +246 -279
  116. package/src/services/cluster-service.ts +29 -32
  117. package/src/services/collaborator-service.ts +13 -18
  118. package/src/services/flux-service.ts +16 -18
  119. package/src/services/helm-service.ts +16 -18
  120. package/src/services/kubectl-service.ts +12 -14
  121. package/src/types/api.d.ts +924 -926
  122. package/src/types/json.d.ts +3 -3
  123. package/src/utils/config-checker.ts +10 -10
  124. package/src/utils/config-loader.ts +110 -127
  125. package/src/utils/default-api-key.ts +81 -93
  126. package/src/utils/env-manager.ts +36 -40
  127. package/src/utils/error-handler.ts +83 -78
  128. package/src/utils/logger.ts +41 -41
  129. package/src/utils/markdown-renderer.ts +11 -11
  130. package/src/utils/opencode-validator.ts +51 -56
  131. package/src/utils/token-manager.ts +84 -64
  132. package/templates/agents/app.md +23 -0
  133. package/templates/agents/backend.md +23 -0
  134. package/templates/agents/devops.md +30 -0
  135. package/templates/agents/frontend.md +25 -0
  136. package/templates/agents/fullstack.md +23 -0
  137. package/templates/agents/quality.md +69 -0
  138. package/templates/agents/security.md +21 -0
  139. package/tests/commands/chat.test.ts +60 -70
  140. package/tests/commands/code.test.ts +346 -345
  141. package/tests/utils/config-loader.test.ts +260 -260
  142. package/tests/utils/env-manager.test.ts +127 -134
  143. package/tests/utils/opencode-validator.test.ts +65 -69
  144. package/tsconfig.json +2 -2
  145. package/vitest.config.ts +3 -3
  146. package/AGENTS.md +0 -374
  147. package/TODO.md +0 -19
  148. package/opencode.json +0 -146
@@ -0,0 +1,44 @@
1
+ import type { FileStore } from "../ports/file-store";
2
+
3
+ export interface FileEntry {
4
+ content: string;
5
+ isDirectory?: boolean;
6
+ }
7
+
8
+ export class FakeFileStore implements FileStore {
9
+ private files: Map<string, string> = new Map();
10
+ private dirs: Set<string> = new Set();
11
+ private _chmodCalls: Array<{ path: string; mode: number }> = [];
12
+
13
+ seed(path: string, content: string): void {
14
+ this.files.set(path, content);
15
+ }
16
+
17
+ async exists(path: string): Promise<boolean> {
18
+ return this.files.has(path) || this.dirs.has(path);
19
+ }
20
+
21
+ async readFile(path: string): Promise<string | null> {
22
+ return this.files.get(path) ?? null;
23
+ }
24
+
25
+ async writeFile(path: string, content: string): Promise<void> {
26
+ this.files.set(path, content);
27
+ }
28
+
29
+ async mkdir(path: string): Promise<void> {
30
+ this.dirs.add(path);
31
+ }
32
+
33
+ async chmod(path: string, mode: number): Promise<void> {
34
+ this._chmodCalls.push({ path, mode });
35
+ }
36
+
37
+ getWrittenFiles(): Map<string, string> {
38
+ return new Map(this.files);
39
+ }
40
+
41
+ getChmodCalls(): Array<{ path: string; mode: number }> {
42
+ return this._chmodCalls;
43
+ }
44
+ }
@@ -0,0 +1,121 @@
1
+ import { CancelledError } from "../errors";
2
+ import type { Prompter, Spinner } from "../ports/prompter";
3
+
4
+ export const CANCEL = Symbol("cancel");
5
+
6
+ type PromptEntry =
7
+ | { kind: "select"; match?: RegExp; response: string | symbol }
8
+ | { kind: "confirm"; match?: RegExp; response: boolean | symbol }
9
+ | { kind: "text"; match?: RegExp; response: string | symbol }
10
+ | { kind: "multiselect"; match?: RegExp; response: (string | symbol)[] };
11
+
12
+ export const select = <T>(value: T | symbol, match?: string | RegExp): PromptEntry => ({
13
+ kind: "select",
14
+ match: typeof match === "string" ? new RegExp(match) : match,
15
+ response: typeof value === "symbol" ? value : String(value),
16
+ });
17
+
18
+ export const text = (value: string | symbol, match?: string | RegExp): PromptEntry => ({
19
+ kind: "text",
20
+ match: typeof match === "string" ? new RegExp(match) : match,
21
+ response: value,
22
+ });
23
+
24
+ export const confirm = (value: boolean | symbol, match?: string | RegExp): PromptEntry => ({
25
+ kind: "confirm",
26
+ match: typeof match === "string" ? new RegExp(match) : match,
27
+ response: value,
28
+ });
29
+
30
+ export const multiselect = <T>(values: T[] | symbol, match?: string | RegExp): PromptEntry => ({
31
+ kind: "multiselect",
32
+ match: typeof match === "string" ? new RegExp(match) : match,
33
+ response:
34
+ values === CANCEL ? [CANCEL] : ((values as T[]).map(v => String(v)) as (string | symbol)[]),
35
+ });
36
+
37
+ export class FakePrompter implements Prompter {
38
+ private _calls: Array<{ method: string; args: unknown }> = [];
39
+ private _cursor = 0;
40
+
41
+ constructor(private readonly _script: PromptEntry[]) {}
42
+
43
+ intro(message: string): void {
44
+ this._calls.push({ method: "intro", args: { message } });
45
+ }
46
+ outro(message: string): void {
47
+ this._calls.push({ method: "outro", args: { message } });
48
+ }
49
+ note(message: string, title?: string): void {
50
+ this._calls.push({ method: "note", args: { message, title } });
51
+ }
52
+ spinner(): Spinner {
53
+ return {
54
+ start: (msg: string) => {
55
+ this._calls.push({ method: "spinner.start", args: { message: msg } });
56
+ },
57
+ stop: (msg: string) => {
58
+ this._calls.push({ method: "spinner.stop", args: { message: msg } });
59
+ },
60
+ };
61
+ }
62
+
63
+ async select<T>(opts: { message: string }): Promise<T> {
64
+ this._calls.push({ method: "select", args: opts });
65
+ const entry = this._script[this._cursor++];
66
+ if (!entry) throw new Error(`No script entry for select #${this._cursor} (${opts.message})`);
67
+ if (entry.kind !== "select")
68
+ throw new Error(`Expected select, got ${entry.kind} for ${opts.message}`);
69
+ if (entry.match && !entry.match.test(opts.message))
70
+ throw new Error(`Message mismatch: got "${opts.message}"`);
71
+ if (entry.response === CANCEL) throw new CancelledError();
72
+ return entry.response as T;
73
+ }
74
+
75
+ async confirm(opts: { message: string }): Promise<boolean> {
76
+ this._calls.push({ method: "confirm", args: opts });
77
+ const entry = this._script[this._cursor++];
78
+ if (!entry) throw new Error(`No script entry for confirm #${this._cursor} (${opts.message})`);
79
+ if (entry.kind !== "confirm")
80
+ throw new Error(`Expected confirm, got ${entry.kind} for ${opts.message}`);
81
+ if (entry.match && !entry.match.test(opts.message))
82
+ throw new Error(`Message mismatch: got "${opts.message}"`);
83
+ if (entry.response === CANCEL) throw new CancelledError();
84
+ return entry.response as boolean;
85
+ }
86
+
87
+ async text(opts: { message: string }): Promise<string> {
88
+ this._calls.push({ method: "text", args: opts });
89
+ const entry = this._script[this._cursor++];
90
+ if (!entry) throw new Error(`No script entry for text #${this._cursor} (${opts.message})`);
91
+ if (entry.kind !== "text")
92
+ throw new Error(`Expected text, got ${entry.kind} for ${opts.message}`);
93
+ if (entry.match && !entry.match.test(opts.message))
94
+ throw new Error(`Message mismatch: got "${opts.message}"`);
95
+ if (entry.response === CANCEL) throw new CancelledError();
96
+ return entry.response as string;
97
+ }
98
+
99
+ async multiselect<T>(opts: { message: string }): Promise<T[]> {
100
+ this._calls.push({ method: "multiselect", args: opts });
101
+ const entry = this._script[this._cursor++];
102
+ if (!entry)
103
+ throw new Error(`No script entry for multiselect #${this._cursor} (${opts.message})`);
104
+ if (entry.kind !== "multiselect")
105
+ throw new Error(`Expected multiselect, got ${entry.kind} for ${opts.message}`);
106
+ if (entry.match && !entry.match.test(opts.message))
107
+ throw new Error(`Message mismatch: got "${opts.message}"`);
108
+ if (entry.response.includes(CANCEL)) throw new CancelledError();
109
+ return entry.response as T[];
110
+ }
111
+
112
+ get calls() {
113
+ return this._calls;
114
+ }
115
+
116
+ assertExhausted() {
117
+ if (this._cursor !== this._script.length) {
118
+ throw new Error(`Script not exhausted: ${this._script.length - this._cursor} entries left`);
119
+ }
120
+ }
121
+ }