@covibes/zeroshot 5.4.0 → 5.4.1

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 (136) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +8 -465
  3. package/cli/index.js +101 -5231
  4. package/package.json +16 -130
  5. package/CHANGELOG.md +0 -537
  6. package/cli/commands/providers.js +0 -149
  7. package/cli/lib/first-run.js +0 -211
  8. package/cli/lib/update-checker.js +0 -281
  9. package/cli/message-formatter-utils.js +0 -75
  10. package/cli/message-formatters-normal.js +0 -275
  11. package/cli/message-formatters-watch.js +0 -181
  12. package/cluster-templates/base-templates/debug-workflow.json +0 -375
  13. package/cluster-templates/base-templates/full-workflow.json +0 -581
  14. package/cluster-templates/base-templates/single-worker.json +0 -63
  15. package/cluster-templates/base-templates/worker-validator.json +0 -208
  16. package/cluster-templates/conductor-bootstrap.json +0 -124
  17. package/docker/zeroshot-cluster/Dockerfile +0 -152
  18. package/docker/zeroshot-cluster/pre-baked-deps.json +0 -28
  19. package/lib/completion.js +0 -174
  20. package/lib/docker-config.js +0 -220
  21. package/lib/git-remote-utils.js +0 -165
  22. package/lib/id-detector.js +0 -56
  23. package/lib/provider-defaults.js +0 -62
  24. package/lib/provider-detection.js +0 -59
  25. package/lib/provider-names.js +0 -57
  26. package/lib/settings/claude-auth.js +0 -78
  27. package/lib/settings.js +0 -503
  28. package/lib/stream-json-parser.js +0 -10
  29. package/scripts/fix-node-pty-permissions.js +0 -75
  30. package/scripts/record-demo.sh +0 -279
  31. package/scripts/setup-merge-queue.sh +0 -170
  32. package/scripts/test-install.sh +0 -40
  33. package/scripts/validate-templates.js +0 -100
  34. package/src/agent/agent-config.js +0 -246
  35. package/src/agent/agent-context-builder.js +0 -444
  36. package/src/agent/agent-hook-executor.js +0 -599
  37. package/src/agent/agent-lifecycle.js +0 -743
  38. package/src/agent/agent-stuck-detector.js +0 -256
  39. package/src/agent/agent-task-executor.js +0 -1690
  40. package/src/agent/agent-trigger-evaluator.js +0 -67
  41. package/src/agent/output-extraction.js +0 -217
  42. package/src/agent/output-reformatter.js +0 -175
  43. package/src/agent/schema-utils.js +0 -146
  44. package/src/agent-wrapper.js +0 -579
  45. package/src/agents/git-pusher-template.js +0 -285
  46. package/src/attach/attach-client.js +0 -438
  47. package/src/attach/attach-server.js +0 -543
  48. package/src/attach/index.js +0 -35
  49. package/src/attach/protocol.js +0 -220
  50. package/src/attach/ring-buffer.js +0 -121
  51. package/src/attach/socket-discovery.js +0 -267
  52. package/src/claude-task-runner.js +0 -574
  53. package/src/config-router.js +0 -80
  54. package/src/config-validator.js +0 -1925
  55. package/src/copy-worker.js +0 -43
  56. package/src/input-helpers.js +0 -65
  57. package/src/isolation-manager.js +0 -1471
  58. package/src/issue-providers/README.md +0 -305
  59. package/src/issue-providers/azure-devops-provider.js +0 -273
  60. package/src/issue-providers/base-provider.js +0 -232
  61. package/src/issue-providers/github-provider.js +0 -179
  62. package/src/issue-providers/gitlab-provider.js +0 -241
  63. package/src/issue-providers/index.js +0 -196
  64. package/src/issue-providers/jira-provider.js +0 -239
  65. package/src/ledger.js +0 -631
  66. package/src/lib/safe-exec.js +0 -88
  67. package/src/logic-engine.js +0 -223
  68. package/src/message-bus-bridge.js +0 -139
  69. package/src/message-bus.js +0 -249
  70. package/src/name-generator.js +0 -232
  71. package/src/orchestrator.js +0 -2815
  72. package/src/preflight.js +0 -639
  73. package/src/process-metrics.js +0 -608
  74. package/src/providers/anthropic/cli-builder.js +0 -73
  75. package/src/providers/anthropic/index.js +0 -204
  76. package/src/providers/anthropic/models.js +0 -23
  77. package/src/providers/anthropic/output-parser.js +0 -177
  78. package/src/providers/base-provider.js +0 -251
  79. package/src/providers/capabilities.js +0 -60
  80. package/src/providers/google/cli-builder.js +0 -55
  81. package/src/providers/google/index.js +0 -116
  82. package/src/providers/google/models.js +0 -24
  83. package/src/providers/google/output-parser.js +0 -101
  84. package/src/providers/index.js +0 -91
  85. package/src/providers/openai/cli-builder.js +0 -133
  86. package/src/providers/openai/index.js +0 -136
  87. package/src/providers/openai/models.js +0 -21
  88. package/src/providers/openai/output-parser.js +0 -143
  89. package/src/providers/opencode/cli-builder.js +0 -42
  90. package/src/providers/opencode/index.js +0 -103
  91. package/src/providers/opencode/models.js +0 -55
  92. package/src/providers/opencode/output-parser.js +0 -122
  93. package/src/schemas/sub-cluster.js +0 -185
  94. package/src/status-footer.js +0 -1026
  95. package/src/sub-cluster-wrapper.js +0 -601
  96. package/src/task-runner.js +0 -30
  97. package/src/template-resolver.js +0 -372
  98. package/src/tui/CHANGES.txt +0 -133
  99. package/src/tui/LAYOUT.md +0 -261
  100. package/src/tui/README.txt +0 -192
  101. package/src/tui/TWO-LEVEL-NAVIGATION.md +0 -186
  102. package/src/tui/data-poller.js +0 -349
  103. package/src/tui/demo.js +0 -208
  104. package/src/tui/formatters.js +0 -129
  105. package/src/tui/index.js +0 -193
  106. package/src/tui/keybindings.js +0 -324
  107. package/src/tui/layout.js +0 -334
  108. package/src/tui/renderer.js +0 -184
  109. package/task-lib/attachable-watcher.js +0 -309
  110. package/task-lib/claude-recovery.js +0 -156
  111. package/task-lib/commands/clean.js +0 -50
  112. package/task-lib/commands/episodes.js +0 -105
  113. package/task-lib/commands/get-log-path.js +0 -23
  114. package/task-lib/commands/kill.js +0 -32
  115. package/task-lib/commands/list.js +0 -105
  116. package/task-lib/commands/logs.js +0 -453
  117. package/task-lib/commands/resume.js +0 -42
  118. package/task-lib/commands/run.js +0 -57
  119. package/task-lib/commands/schedule.js +0 -105
  120. package/task-lib/commands/scheduler-cmd.js +0 -96
  121. package/task-lib/commands/schedules.js +0 -148
  122. package/task-lib/commands/status.js +0 -44
  123. package/task-lib/commands/unschedule.js +0 -16
  124. package/task-lib/completion.js +0 -9
  125. package/task-lib/config.js +0 -8
  126. package/task-lib/name-generator.js +0 -230
  127. package/task-lib/package.json +0 -3
  128. package/task-lib/runner.js +0 -201
  129. package/task-lib/scheduler.js +0 -252
  130. package/task-lib/store.js +0 -529
  131. package/task-lib/tui/formatters.js +0 -215
  132. package/task-lib/tui/index.js +0 -197
  133. package/task-lib/tui/layout.js +0 -111
  134. package/task-lib/tui/renderer.js +0 -129
  135. package/task-lib/tui.js +0 -425
  136. package/task-lib/watcher.js +0 -226
@@ -1,204 +0,0 @@
1
- const BaseProvider = require('../base-provider');
2
- const { getClaudeCommand, loadSettings } = require('../../../lib/settings');
3
- const { commandExists, getCommandPath, getHelpOutput } = require('../../../lib/provider-detection');
4
- const { resolveClaudeAuth } = require('../../../lib/settings/claude-auth');
5
- const { buildCommand } = require('./cli-builder');
6
- const { parseEvent } = require('./output-parser');
7
- const {
8
- MODEL_CATALOG,
9
- LEVEL_MAPPING,
10
- DEFAULT_LEVEL,
11
- DEFAULT_MAX_LEVEL,
12
- DEFAULT_MIN_LEVEL,
13
- } = require('./models');
14
-
15
- const warned = new Set();
16
-
17
- class AnthropicProvider extends BaseProvider {
18
- constructor() {
19
- super({ name: 'claude', displayName: 'Claude', cliCommand: 'claude' });
20
- this._cliFeatures = null;
21
- }
22
-
23
- // SDK not implemented - uses CLI only
24
- // See BaseProvider for SDK extension point documentation
25
-
26
- isAvailable() {
27
- const { command } = getClaudeCommand();
28
- return commandExists(command);
29
- }
30
-
31
- getCliPath() {
32
- const { command } = getClaudeCommand();
33
- return getCommandPath(command) || command;
34
- }
35
-
36
- getInstallInstructions() {
37
- return ['npm install -g @anthropic-ai/claude-code', 'Or (macOS): brew install claude'].join(
38
- '\n'
39
- );
40
- }
41
-
42
- getAuthInstructions() {
43
- return 'claude login';
44
- }
45
-
46
- getCliFeatures() {
47
- if (this._cliFeatures) return this._cliFeatures;
48
-
49
- const { command, args } = getClaudeCommand();
50
- const help = getHelpOutput(command, args);
51
- const unknown = !help;
52
-
53
- const features = {
54
- supportsOutputFormat: unknown ? true : /--output-format/.test(help),
55
- supportsStreamJson: unknown ? true : /stream-json/.test(help),
56
- supportsJsonSchema: unknown ? true : /--json-schema/.test(help),
57
- supportsAutoApprove: unknown ? true : /--dangerously-skip-permissions/.test(help),
58
- supportsIncludePartials: unknown ? true : /--include-partial-messages/.test(help),
59
- supportsVerbose: unknown ? true : /--verbose/.test(help),
60
- supportsModel: unknown ? true : /--model/.test(help),
61
- unknown,
62
- };
63
-
64
- this._cliFeatures = features;
65
- return features;
66
- }
67
-
68
- getCredentialPaths() {
69
- return ['~/.claude'];
70
- }
71
-
72
- /**
73
- * Resolve authentication environment variables for Claude CLI.
74
- * Handles Bedrock, API key, and OAuth authentication.
75
- * @returns {Object} Environment variables for authentication
76
- */
77
- resolveAuthEnv() {
78
- const settings = loadSettings();
79
- return resolveClaudeAuth(settings);
80
- }
81
-
82
- buildCommand(context, options) {
83
- const { command, args } = getClaudeCommand();
84
- const cliFeatures = options.cliFeatures || {};
85
-
86
- if (options.jsonSchema && options.outputFormat !== 'json' && !options.strictSchema) {
87
- this._warnOnce(
88
- 'claude-jsonschema-stream',
89
- 'jsonSchema requested with stream output; schema enforcement will be post-validated.'
90
- );
91
- }
92
-
93
- if (
94
- options.jsonSchema &&
95
- options.outputFormat === 'json' &&
96
- cliFeatures.supportsJsonSchema === false
97
- ) {
98
- this._warnOnce(
99
- 'claude-jsonschema-flag',
100
- 'Claude CLI does not support --json-schema; skipping schema flag.'
101
- );
102
- }
103
-
104
- if (options.autoApprove && cliFeatures.supportsAutoApprove === false) {
105
- this._warnOnce(
106
- 'claude-auto-approve',
107
- 'Claude CLI does not support --dangerously-skip-permissions; continuing without auto-approve.'
108
- );
109
- }
110
-
111
- const authEnv = this.resolveAuthEnv();
112
- const resolvedOptions = { ...options, cliFeatures, authEnv };
113
-
114
- return buildCommand(context, resolvedOptions, { command, args });
115
- }
116
-
117
- parseEvent(line) {
118
- return parseEvent(line);
119
- }
120
-
121
- getModelCatalog() {
122
- return MODEL_CATALOG;
123
- }
124
-
125
- getLevelMapping() {
126
- return LEVEL_MAPPING;
127
- }
128
-
129
- getDefaultLevel() {
130
- return DEFAULT_LEVEL;
131
- }
132
-
133
- getDefaultMaxLevel() {
134
- return DEFAULT_MAX_LEVEL;
135
- }
136
-
137
- getDefaultMinLevel() {
138
- return DEFAULT_MIN_LEVEL;
139
- }
140
-
141
- _warnOnce(key, message) {
142
- if (warned.has(key)) return;
143
- warned.add(key);
144
- console.warn(`⚠️ ${message}`);
145
- }
146
-
147
- /**
148
- * Get default settings including Claude-specific auth fields
149
- * @override
150
- */
151
- getDefaultSettings() {
152
- return {
153
- ...super.getDefaultSettings(),
154
- // Authentication (optional persistent storage)
155
- anthropicApiKey: null, // sk-ant-* key
156
- bedrockApiKey: null, // AWS_BEARER_TOKEN_BEDROCK value
157
- bedrockRegion: null, // AWS_REGION for Bedrock
158
- };
159
- }
160
-
161
- /**
162
- * Validate Claude-specific settings including auth fields
163
- * @override
164
- */
165
- validateSettings(settings) {
166
- // First validate base provider settings (levels, etc.)
167
- const baseError = super.validateSettings(settings);
168
- if (baseError) return baseError;
169
-
170
- // Claude-specific auth field validation
171
- const {
172
- isValidAnthropicKey,
173
- ANTHROPIC_KEY_PREFIX,
174
- } = require('../../../lib/settings/claude-auth');
175
-
176
- // Validate string-or-null fields
177
- for (const field of ['anthropicApiKey', 'bedrockApiKey', 'bedrockRegion']) {
178
- if (
179
- settings[field] !== undefined &&
180
- settings[field] !== null &&
181
- typeof settings[field] !== 'string'
182
- ) {
183
- return `providerSettings.claude.${field} must be a string or null`;
184
- }
185
- }
186
-
187
- // Additional prefix validation for Anthropic API key
188
- if (settings.anthropicApiKey && !isValidAnthropicKey(settings.anthropicApiKey)) {
189
- return `providerSettings.claude.anthropicApiKey must start with ${ANTHROPIC_KEY_PREFIX}`;
190
- }
191
-
192
- return null;
193
- }
194
-
195
- /**
196
- * Get Claude-specific setting field names
197
- * @override
198
- */
199
- getSettingsFields() {
200
- return [...super.getSettingsFields(), 'anthropicApiKey', 'bedrockApiKey', 'bedrockRegion'];
201
- }
202
- }
203
-
204
- module.exports = AnthropicProvider;
@@ -1,23 +0,0 @@
1
- const MODEL_CATALOG = {
2
- haiku: { rank: 1 },
3
- sonnet: { rank: 2 },
4
- opus: { rank: 3 },
5
- };
6
-
7
- const LEVEL_MAPPING = {
8
- level1: { rank: 1, model: 'haiku' },
9
- level2: { rank: 2, model: 'sonnet' },
10
- level3: { rank: 3, model: 'opus' },
11
- };
12
-
13
- const DEFAULT_LEVEL = 'level2';
14
- const DEFAULT_MAX_LEVEL = 'level3';
15
- const DEFAULT_MIN_LEVEL = 'level1';
16
-
17
- module.exports = {
18
- MODEL_CATALOG,
19
- LEVEL_MAPPING,
20
- DEFAULT_LEVEL,
21
- DEFAULT_MAX_LEVEL,
22
- DEFAULT_MIN_LEVEL,
23
- };
@@ -1,177 +0,0 @@
1
- /**
2
- * Stream JSON Parser for Claude Code output
3
- */
4
-
5
- /**
6
- * Parse result event type
7
- * @param {Object} event
8
- * @returns {Object}
9
- */
10
- function parseResultEvent(event) {
11
- const usage = event.usage || {};
12
- return {
13
- type: 'result',
14
- success: event.subtype === 'success',
15
- result: event.result,
16
- error: event.is_error ? event.result : null,
17
- cost: event.total_cost_usd,
18
- duration: event.duration_ms,
19
- inputTokens: usage.input_tokens || 0,
20
- outputTokens: usage.output_tokens || 0,
21
- cacheReadInputTokens: usage.cache_read_input_tokens || 0,
22
- cacheCreationInputTokens: usage.cache_creation_input_tokens || 0,
23
- modelUsage: event.modelUsage || null,
24
- };
25
- }
26
-
27
- /**
28
- * Parse a single JSON line and extract displayable content
29
- * @param {string} line
30
- * @returns {Object|null}
31
- */
32
- function parseEvent(line) {
33
- const trimmed = line.trim();
34
- if (!trimmed || !trimmed.startsWith('{') || !trimmed.endsWith('}')) {
35
- return null;
36
- }
37
-
38
- let event;
39
- try {
40
- event = JSON.parse(trimmed);
41
- } catch {
42
- return null;
43
- }
44
-
45
- if (event.type === 'stream_event' && event.event) {
46
- return parseStreamEvent(event.event);
47
- }
48
-
49
- if (event.type === 'assistant' && event.message?.content) {
50
- return parseAssistantMessage(event.message);
51
- }
52
-
53
- if (event.type === 'user' && event.message?.content) {
54
- return parseUserMessage(event.message);
55
- }
56
-
57
- if (event.type === 'result') {
58
- return parseResultEvent(event);
59
- }
60
-
61
- if (event.type === 'system') {
62
- return null;
63
- }
64
-
65
- return null;
66
- }
67
-
68
- function parseStreamEvent(inner) {
69
- if (inner.type === 'content_block_delta' && inner.delta) {
70
- const delta = inner.delta;
71
-
72
- if (delta.type === 'text_delta' && delta.text) {
73
- return {
74
- type: 'text',
75
- text: delta.text,
76
- };
77
- }
78
-
79
- if (delta.type === 'thinking_delta' && delta.thinking) {
80
- return {
81
- type: 'thinking',
82
- text: delta.thinking,
83
- };
84
- }
85
- }
86
-
87
- return null;
88
- }
89
-
90
- function parseAssistantMessage(message) {
91
- const results = [];
92
-
93
- for (const block of message.content) {
94
- // Handle text content blocks (CRITICAL for Haiku/weaker models that return JSON in text)
95
- // Issue #52: Haiku returns JSON in type:text blocks, not in result wrapper
96
- if (block.type === 'text' && block.text) {
97
- results.push({
98
- type: 'text',
99
- text: block.text,
100
- });
101
- }
102
-
103
- if (block.type === 'tool_use') {
104
- results.push({
105
- type: 'tool_call',
106
- toolName: block.name,
107
- toolId: block.id,
108
- input: block.input,
109
- });
110
- }
111
-
112
- if (block.type === 'thinking' && block.thinking) {
113
- results.push({
114
- type: 'thinking',
115
- text: block.thinking,
116
- });
117
- }
118
- }
119
-
120
- if (results.length === 1) {
121
- return results[0];
122
- }
123
-
124
- if (results.length > 1) {
125
- return results;
126
- }
127
-
128
- return null;
129
- }
130
-
131
- function parseUserMessage(message) {
132
- const results = [];
133
-
134
- for (const block of message.content) {
135
- if (block.type === 'tool_result') {
136
- results.push({
137
- type: 'tool_result',
138
- toolId: block.tool_use_id,
139
- content: typeof block.content === 'string' ? block.content : JSON.stringify(block.content),
140
- isError: block.is_error || false,
141
- });
142
- }
143
- }
144
-
145
- if (results.length === 1) {
146
- return results[0];
147
- }
148
-
149
- if (results.length > 1) {
150
- return results;
151
- }
152
-
153
- return null;
154
- }
155
-
156
- function parseChunk(chunk) {
157
- const events = [];
158
- const lines = chunk.split('\n');
159
-
160
- for (const line of lines) {
161
- const event = parseEvent(line);
162
- if (event) {
163
- if (Array.isArray(event)) {
164
- events.push(...event);
165
- } else {
166
- events.push(event);
167
- }
168
- }
169
- }
170
-
171
- return events;
172
- }
173
-
174
- module.exports = {
175
- parseEvent,
176
- parseChunk,
177
- };
@@ -1,251 +0,0 @@
1
- /**
2
- * BaseProvider - Abstract provider interface
3
- *
4
- * All providers support two execution paths:
5
- * 1. SDK (fast) - Direct API calls using provider's SDK (requires API key)
6
- * 2. CLI (slower) - Spawns provider's CLI tool (uses OAuth/login auth)
7
- *
8
- * Use callSimple() for simple prompts - it tries SDK first, falls back to CLI.
9
- */
10
- class BaseProvider {
11
- constructor(options = {}) {
12
- this.name = options.name || 'base';
13
- this.displayName = options.displayName || 'Base';
14
- this.cliCommand = options.cliCommand || null;
15
- }
16
-
17
- // ============================================================================
18
- // SDK SUPPORT (Future Extension Point)
19
- // ============================================================================
20
- //
21
- // SDK support is NOT IMPLEMENTED. These methods exist for future extension.
22
- // Currently, all providers use CLI (claude, codex, gemini) for execution.
23
- //
24
- // To add SDK support for a provider:
25
- // 1. Override getSDKEnvVar() to return the API key env var
26
- // 2. Override callSDK() to implement the actual API call
27
- // 3. The callSimple() method will then work automatically
28
- //
29
- // ============================================================================
30
-
31
- /**
32
- * Get the environment variable name for the API key
33
- * @returns {string} Environment variable name (e.g., 'ANTHROPIC_API_KEY')
34
- */
35
- getSDKEnvVar() {
36
- throw new Error(`${this.name}: SDK not implemented. Use CLI instead.`);
37
- }
38
-
39
- /**
40
- * Check if SDK is configured (API key is set)
41
- * @returns {boolean} True if API key is available
42
- */
43
- isSDKConfigured() {
44
- try {
45
- const envVar = this.getSDKEnvVar();
46
- return !!process.env[envVar];
47
- } catch {
48
- // getSDKEnvVar() throws if not implemented
49
- return false;
50
- }
51
- }
52
-
53
- /**
54
- * Make a simple API call via SDK (fast path)
55
- * NOT IMPLEMENTED - exists for future extension.
56
- *
57
- * @param {string} _prompt - The prompt to send
58
- * @param {Object} _options - Call options
59
- * @returns {Promise<{success: boolean, text: string, usage?: Object, error?: string}>}
60
- */
61
- callSDK(_prompt, _options) {
62
- return Promise.reject(new Error(`${this.name}: SDK not implemented. Use CLI instead.`));
63
- }
64
-
65
- /**
66
- * Make a simple API call via SDK
67
- * NOT IMPLEMENTED - exists for future extension.
68
- *
69
- * @param {string} _prompt - The prompt to send
70
- * @param {Object} _options - Call options
71
- * @returns {Promise<{success: boolean, text: string, usage?: Object, error?: string}>}
72
- */
73
- callSimple(_prompt, _options = {}) {
74
- return Promise.reject(new Error(`${this.name}: SDK not implemented. Use CLI instead.`));
75
- }
76
-
77
- isAvailable() {
78
- throw new Error('Not implemented');
79
- }
80
-
81
- getCliPath() {
82
- throw new Error('Not implemented');
83
- }
84
-
85
- getInstallInstructions() {
86
- throw new Error('Not implemented');
87
- }
88
-
89
- getAuthInstructions() {
90
- throw new Error('Not implemented');
91
- }
92
-
93
- getCliFeatures() {
94
- throw new Error('Not implemented');
95
- }
96
-
97
- getCredentialPaths() {
98
- return [];
99
- }
100
-
101
- buildCommand(_context, _options) {
102
- throw new Error('Not implemented');
103
- }
104
-
105
- parseEvent(_line) {
106
- throw new Error('Not implemented');
107
- }
108
-
109
- getModelCatalog() {
110
- throw new Error('Not implemented');
111
- }
112
-
113
- getLevelMapping() {
114
- throw new Error('Not implemented');
115
- }
116
-
117
- resolveModelSpec(level, overrides = {}) {
118
- const mapping = this.getLevelMapping();
119
- const base = mapping[level] || mapping[this.getDefaultLevel()];
120
- if (!base) {
121
- throw new Error(`Unknown level "${level}" for provider "${this.name}"`);
122
- }
123
- const override = overrides[level] || {};
124
- return {
125
- level,
126
- model: override.model || base.model,
127
- reasoningEffort: override.reasoningEffort || base.reasoningEffort,
128
- };
129
- }
130
-
131
- validateLevel(level, minLevel, maxLevel) {
132
- const mapping = this.getLevelMapping();
133
- const rank = (key) => mapping[key]?.rank;
134
-
135
- if (!mapping[level]) {
136
- throw new Error(`Invalid level "${level}" for provider "${this.name}"`);
137
- }
138
-
139
- if (minLevel && !mapping[minLevel]) {
140
- throw new Error(`Invalid minLevel "${minLevel}" for provider "${this.name}"`);
141
- }
142
-
143
- if (maxLevel && !mapping[maxLevel]) {
144
- throw new Error(`Invalid maxLevel "${maxLevel}" for provider "${this.name}"`);
145
- }
146
-
147
- if (minLevel && maxLevel && rank(minLevel) > rank(maxLevel)) {
148
- throw new Error(
149
- `minLevel "${minLevel}" exceeds maxLevel "${maxLevel}" for provider "${this.name}"`
150
- );
151
- }
152
-
153
- if (maxLevel && rank(level) > rank(maxLevel)) {
154
- throw new Error(
155
- `Level "${level}" exceeds maxLevel "${maxLevel}" for provider "${this.name}"`
156
- );
157
- }
158
-
159
- if (minLevel && rank(level) < rank(minLevel)) {
160
- throw new Error(
161
- `Level "${level}" is below minLevel "${minLevel}" for provider "${this.name}"`
162
- );
163
- }
164
-
165
- return level;
166
- }
167
-
168
- validateModelId(modelId) {
169
- const catalog = this.getModelCatalog();
170
- if (modelId && !catalog[modelId]) {
171
- throw new Error(`Invalid model "${modelId}" for provider "${this.name}"`);
172
- }
173
- return modelId;
174
- }
175
-
176
- /**
177
- * Resolve a model name to its CLI-compatible identifier.
178
- * Override in provider implementations that need model ID transformation
179
- * (e.g., Anthropic Bedrock mapping).
180
- * @param {string} model - Model name (e.g., 'opus', 'sonnet')
181
- * @param {Object} _authEnv - Authentication environment variables
182
- * @returns {string} CLI-compatible model identifier
183
- */
184
- resolveCliModel(model, _authEnv = {}) {
185
- return model;
186
- }
187
-
188
- getDefaultLevel() {
189
- throw new Error('Not implemented');
190
- }
191
-
192
- /**
193
- * Get default settings for this provider
194
- * Override in provider implementations to provide provider-specific defaults
195
- * @returns {Object} Default settings object
196
- */
197
- getDefaultSettings() {
198
- return {
199
- maxLevel: this.getDefaultMaxLevel?.() || 'level3',
200
- minLevel: this.getDefaultMinLevel?.() || 'level1',
201
- defaultLevel: this.getDefaultLevel() || 'level2',
202
- levelOverrides: {},
203
- };
204
- }
205
-
206
- /**
207
- * Validate provider-specific settings
208
- * Override in provider implementations to add custom validation
209
- * @param {Object} settings - Settings object to validate
210
- * @returns {string|null} Error message if invalid, null if valid
211
- */
212
- validateSettings(settings) {
213
- if (typeof settings !== 'object' || settings === null) {
214
- return `providerSettings.${this.name} must be an object`;
215
- }
216
-
217
- // Validate level fields
218
- const levelMapping = this.getLevelMapping();
219
- const validLevels = Object.keys(levelMapping);
220
-
221
- if (settings.maxLevel && !validLevels.includes(settings.maxLevel)) {
222
- return `Invalid maxLevel for ${this.name}: ${settings.maxLevel}`;
223
- }
224
- if (settings.minLevel && !validLevels.includes(settings.minLevel)) {
225
- return `Invalid minLevel for ${this.name}: ${settings.minLevel}`;
226
- }
227
- if (settings.defaultLevel && !validLevels.includes(settings.defaultLevel)) {
228
- return `Invalid defaultLevel for ${this.name}: ${settings.defaultLevel}`;
229
- }
230
-
231
- if (
232
- settings.levelOverrides &&
233
- (typeof settings.levelOverrides !== 'object' || Array.isArray(settings.levelOverrides))
234
- ) {
235
- return `levelOverrides for ${this.name} must be an object`;
236
- }
237
-
238
- return null;
239
- }
240
-
241
- /**
242
- * Get the list of setting field names specific to this provider
243
- * Override in provider implementations to declare custom fields
244
- * @returns {string[]} Array of field names
245
- */
246
- getSettingsFields() {
247
- return ['maxLevel', 'minLevel', 'defaultLevel', 'levelOverrides'];
248
- }
249
- }
250
-
251
- module.exports = BaseProvider;
@@ -1,60 +0,0 @@
1
- const { normalizeProviderName } = require('../../lib/provider-names');
2
-
3
- const CAPABILITIES = {
4
- claude: {
5
- dockerIsolation: true,
6
- worktreeIsolation: true,
7
- mcpServers: true,
8
- jsonSchema: true,
9
- streamJson: true,
10
- thinkingMode: true,
11
- reasoningEffort: false,
12
- },
13
- codex: {
14
- dockerIsolation: true,
15
- worktreeIsolation: true,
16
- mcpServers: true,
17
- jsonSchema: true,
18
- streamJson: true,
19
- thinkingMode: true,
20
- reasoningEffort: true,
21
- },
22
- gemini: {
23
- dockerIsolation: true,
24
- worktreeIsolation: true,
25
- mcpServers: true,
26
- jsonSchema: 'experimental',
27
- streamJson: true,
28
- thinkingMode: true,
29
- reasoningEffort: false,
30
- },
31
- opencode: {
32
- dockerIsolation: true,
33
- worktreeIsolation: true,
34
- mcpServers: true,
35
- jsonSchema: 'experimental',
36
- streamJson: true,
37
- thinkingMode: true,
38
- reasoningEffort: true,
39
- },
40
- };
41
-
42
- function checkCapability(provider, capability) {
43
- const caps = CAPABILITIES[normalizeProviderName(provider)];
44
- if (!caps) return false;
45
- return caps[capability] === true;
46
- }
47
-
48
- function warnIfExperimental(provider, capability) {
49
- const normalized = normalizeProviderName(provider);
50
- const caps = CAPABILITIES[normalized];
51
- if (caps?.[capability] === 'experimental') {
52
- console.warn(`⚠️ ${capability} is experimental for ${normalized} and may not work reliably`);
53
- }
54
- }
55
-
56
- module.exports = {
57
- CAPABILITIES,
58
- checkCapability,
59
- warnIfExperimental,
60
- };