@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.
- package/LICENSE +1 -1
- package/README.md +8 -465
- package/cli/index.js +101 -5231
- package/package.json +16 -130
- package/CHANGELOG.md +0 -537
- package/cli/commands/providers.js +0 -149
- package/cli/lib/first-run.js +0 -211
- package/cli/lib/update-checker.js +0 -281
- package/cli/message-formatter-utils.js +0 -75
- package/cli/message-formatters-normal.js +0 -275
- package/cli/message-formatters-watch.js +0 -181
- package/cluster-templates/base-templates/debug-workflow.json +0 -375
- package/cluster-templates/base-templates/full-workflow.json +0 -581
- package/cluster-templates/base-templates/single-worker.json +0 -63
- package/cluster-templates/base-templates/worker-validator.json +0 -208
- package/cluster-templates/conductor-bootstrap.json +0 -124
- package/docker/zeroshot-cluster/Dockerfile +0 -152
- package/docker/zeroshot-cluster/pre-baked-deps.json +0 -28
- package/lib/completion.js +0 -174
- package/lib/docker-config.js +0 -220
- package/lib/git-remote-utils.js +0 -165
- package/lib/id-detector.js +0 -56
- package/lib/provider-defaults.js +0 -62
- package/lib/provider-detection.js +0 -59
- package/lib/provider-names.js +0 -57
- package/lib/settings/claude-auth.js +0 -78
- package/lib/settings.js +0 -503
- package/lib/stream-json-parser.js +0 -10
- package/scripts/fix-node-pty-permissions.js +0 -75
- package/scripts/record-demo.sh +0 -279
- package/scripts/setup-merge-queue.sh +0 -170
- package/scripts/test-install.sh +0 -40
- package/scripts/validate-templates.js +0 -100
- package/src/agent/agent-config.js +0 -246
- package/src/agent/agent-context-builder.js +0 -444
- package/src/agent/agent-hook-executor.js +0 -599
- package/src/agent/agent-lifecycle.js +0 -743
- package/src/agent/agent-stuck-detector.js +0 -256
- package/src/agent/agent-task-executor.js +0 -1690
- package/src/agent/agent-trigger-evaluator.js +0 -67
- package/src/agent/output-extraction.js +0 -217
- package/src/agent/output-reformatter.js +0 -175
- package/src/agent/schema-utils.js +0 -146
- package/src/agent-wrapper.js +0 -579
- package/src/agents/git-pusher-template.js +0 -285
- package/src/attach/attach-client.js +0 -438
- package/src/attach/attach-server.js +0 -543
- package/src/attach/index.js +0 -35
- package/src/attach/protocol.js +0 -220
- package/src/attach/ring-buffer.js +0 -121
- package/src/attach/socket-discovery.js +0 -267
- package/src/claude-task-runner.js +0 -574
- package/src/config-router.js +0 -80
- package/src/config-validator.js +0 -1925
- package/src/copy-worker.js +0 -43
- package/src/input-helpers.js +0 -65
- package/src/isolation-manager.js +0 -1471
- package/src/issue-providers/README.md +0 -305
- package/src/issue-providers/azure-devops-provider.js +0 -273
- package/src/issue-providers/base-provider.js +0 -232
- package/src/issue-providers/github-provider.js +0 -179
- package/src/issue-providers/gitlab-provider.js +0 -241
- package/src/issue-providers/index.js +0 -196
- package/src/issue-providers/jira-provider.js +0 -239
- package/src/ledger.js +0 -631
- package/src/lib/safe-exec.js +0 -88
- package/src/logic-engine.js +0 -223
- package/src/message-bus-bridge.js +0 -139
- package/src/message-bus.js +0 -249
- package/src/name-generator.js +0 -232
- package/src/orchestrator.js +0 -2815
- package/src/preflight.js +0 -639
- package/src/process-metrics.js +0 -608
- package/src/providers/anthropic/cli-builder.js +0 -73
- package/src/providers/anthropic/index.js +0 -204
- package/src/providers/anthropic/models.js +0 -23
- package/src/providers/anthropic/output-parser.js +0 -177
- package/src/providers/base-provider.js +0 -251
- package/src/providers/capabilities.js +0 -60
- package/src/providers/google/cli-builder.js +0 -55
- package/src/providers/google/index.js +0 -116
- package/src/providers/google/models.js +0 -24
- package/src/providers/google/output-parser.js +0 -101
- package/src/providers/index.js +0 -91
- package/src/providers/openai/cli-builder.js +0 -133
- package/src/providers/openai/index.js +0 -136
- package/src/providers/openai/models.js +0 -21
- package/src/providers/openai/output-parser.js +0 -143
- package/src/providers/opencode/cli-builder.js +0 -42
- package/src/providers/opencode/index.js +0 -103
- package/src/providers/opencode/models.js +0 -55
- package/src/providers/opencode/output-parser.js +0 -122
- package/src/schemas/sub-cluster.js +0 -185
- package/src/status-footer.js +0 -1026
- package/src/sub-cluster-wrapper.js +0 -601
- package/src/task-runner.js +0 -30
- package/src/template-resolver.js +0 -372
- package/src/tui/CHANGES.txt +0 -133
- package/src/tui/LAYOUT.md +0 -261
- package/src/tui/README.txt +0 -192
- package/src/tui/TWO-LEVEL-NAVIGATION.md +0 -186
- package/src/tui/data-poller.js +0 -349
- package/src/tui/demo.js +0 -208
- package/src/tui/formatters.js +0 -129
- package/src/tui/index.js +0 -193
- package/src/tui/keybindings.js +0 -324
- package/src/tui/layout.js +0 -334
- package/src/tui/renderer.js +0 -184
- package/task-lib/attachable-watcher.js +0 -309
- package/task-lib/claude-recovery.js +0 -156
- package/task-lib/commands/clean.js +0 -50
- package/task-lib/commands/episodes.js +0 -105
- package/task-lib/commands/get-log-path.js +0 -23
- package/task-lib/commands/kill.js +0 -32
- package/task-lib/commands/list.js +0 -105
- package/task-lib/commands/logs.js +0 -453
- package/task-lib/commands/resume.js +0 -42
- package/task-lib/commands/run.js +0 -57
- package/task-lib/commands/schedule.js +0 -105
- package/task-lib/commands/scheduler-cmd.js +0 -96
- package/task-lib/commands/schedules.js +0 -148
- package/task-lib/commands/status.js +0 -44
- package/task-lib/commands/unschedule.js +0 -16
- package/task-lib/completion.js +0 -9
- package/task-lib/config.js +0 -8
- package/task-lib/name-generator.js +0 -230
- package/task-lib/package.json +0 -3
- package/task-lib/runner.js +0 -201
- package/task-lib/scheduler.js +0 -252
- package/task-lib/store.js +0 -529
- package/task-lib/tui/formatters.js +0 -215
- package/task-lib/tui/index.js +0 -197
- package/task-lib/tui/layout.js +0 -111
- package/task-lib/tui/renderer.js +0 -129
- package/task-lib/tui.js +0 -425
- 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
|
-
};
|