@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,55 +0,0 @@
|
|
|
1
|
-
function buildCommand(context, options = {}) {
|
|
2
|
-
const { modelSpec, outputFormat, jsonSchema, cwd, autoApprove, cliFeatures = {} } = options;
|
|
3
|
-
|
|
4
|
-
// Augment context with schema if provided (Gemini CLI doesn't support native schema enforcement)
|
|
5
|
-
let finalContext = context;
|
|
6
|
-
if (jsonSchema) {
|
|
7
|
-
// CRITICAL: Inject schema into prompt since Gemini CLI has no --output-schema flag
|
|
8
|
-
// Without this, model outputs free-form text instead of JSON
|
|
9
|
-
const schemaStr =
|
|
10
|
-
typeof jsonSchema === 'string' ? jsonSchema : JSON.stringify(jsonSchema, null, 2);
|
|
11
|
-
finalContext =
|
|
12
|
-
context +
|
|
13
|
-
`\n\n## OUTPUT FORMAT (CRITICAL - REQUIRED)
|
|
14
|
-
|
|
15
|
-
You MUST respond with a JSON object that exactly matches this schema. NO markdown, NO explanation, NO code blocks. ONLY the raw JSON object.
|
|
16
|
-
|
|
17
|
-
Schema:
|
|
18
|
-
\`\`\`json
|
|
19
|
-
${schemaStr}
|
|
20
|
-
\`\`\`
|
|
21
|
-
|
|
22
|
-
Your response must be ONLY valid JSON. Start with { and end with }. Nothing else.`;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const args = ['-p', finalContext];
|
|
26
|
-
|
|
27
|
-
if (
|
|
28
|
-
(outputFormat === 'stream-json' || outputFormat === 'json') &&
|
|
29
|
-
cliFeatures.supportsStreamJson
|
|
30
|
-
) {
|
|
31
|
-
args.push('--output-format', 'stream-json');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (modelSpec?.model) {
|
|
35
|
-
args.push('-m', modelSpec.model);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (cwd && cliFeatures.supportsCwd) {
|
|
39
|
-
args.push('--cwd', cwd);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (autoApprove && cliFeatures.supportsAutoApprove) {
|
|
43
|
-
args.push('--yolo');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return {
|
|
47
|
-
binary: 'gemini',
|
|
48
|
-
args,
|
|
49
|
-
env: {},
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
module.exports = {
|
|
54
|
-
buildCommand,
|
|
55
|
-
};
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
const BaseProvider = require('../base-provider');
|
|
2
|
-
const { commandExists, getCommandPath, getHelpOutput } = require('../../../lib/provider-detection');
|
|
3
|
-
const { buildCommand } = require('./cli-builder');
|
|
4
|
-
const { parseEvent } = require('./output-parser');
|
|
5
|
-
const {
|
|
6
|
-
MODEL_CATALOG,
|
|
7
|
-
LEVEL_MAPPING,
|
|
8
|
-
DEFAULT_LEVEL,
|
|
9
|
-
DEFAULT_MAX_LEVEL,
|
|
10
|
-
DEFAULT_MIN_LEVEL,
|
|
11
|
-
} = require('./models');
|
|
12
|
-
|
|
13
|
-
const warned = new Set();
|
|
14
|
-
|
|
15
|
-
class GoogleProvider extends BaseProvider {
|
|
16
|
-
constructor() {
|
|
17
|
-
super({ name: 'gemini', displayName: 'Gemini', cliCommand: 'gemini' });
|
|
18
|
-
this._cliFeatures = null;
|
|
19
|
-
this._unknownEventCounts = new Map();
|
|
20
|
-
this._parserState = { lastToolId: null };
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// SDK not implemented - uses CLI only
|
|
24
|
-
// See BaseProvider for SDK extension point documentation
|
|
25
|
-
|
|
26
|
-
isAvailable() {
|
|
27
|
-
return commandExists(this.cliCommand);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
getCliPath() {
|
|
31
|
-
return getCommandPath(this.cliCommand) || this.cliCommand;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
getInstallInstructions() {
|
|
35
|
-
return 'npm install -g @google/gemini-cli';
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
getAuthInstructions() {
|
|
39
|
-
return 'gemini auth login';
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
getCliFeatures() {
|
|
43
|
-
if (this._cliFeatures) return this._cliFeatures;
|
|
44
|
-
const help = getHelpOutput(this.cliCommand);
|
|
45
|
-
const unknown = !help;
|
|
46
|
-
|
|
47
|
-
const features = {
|
|
48
|
-
supportsStreamJson: unknown ? true : /--output-format\b/.test(help),
|
|
49
|
-
supportsAutoApprove: unknown ? true : /--yolo\b/.test(help),
|
|
50
|
-
supportsCwd: unknown ? true : /--cwd\b/.test(help),
|
|
51
|
-
supportsModel: unknown ? true : /\s-m\b/.test(help) || /--model\b/.test(help),
|
|
52
|
-
unknown,
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
this._cliFeatures = features;
|
|
56
|
-
return features;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
getCredentialPaths() {
|
|
60
|
-
return ['~/.config/gcloud', '~/.config/gemini', '~/.gemini'];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
buildCommand(context, options) {
|
|
64
|
-
const cliFeatures = options.cliFeatures || {};
|
|
65
|
-
|
|
66
|
-
if (options.autoApprove && cliFeatures.supportsAutoApprove === false) {
|
|
67
|
-
this._warnOnce(
|
|
68
|
-
'gemini-auto-approve',
|
|
69
|
-
'Gemini CLI does not support --yolo; continuing without auto-approve.'
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return buildCommand(context, { ...options, cliFeatures });
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
parseEvent(line) {
|
|
77
|
-
return parseEvent(line, this._parserState, {
|
|
78
|
-
onUnknown: (type) => this._logUnknown(type),
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
getModelCatalog() {
|
|
83
|
-
return MODEL_CATALOG;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
getLevelMapping() {
|
|
87
|
-
return LEVEL_MAPPING;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
getDefaultLevel() {
|
|
91
|
-
return DEFAULT_LEVEL;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
getDefaultMaxLevel() {
|
|
95
|
-
return DEFAULT_MAX_LEVEL;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
getDefaultMinLevel() {
|
|
99
|
-
return DEFAULT_MIN_LEVEL;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
_warnOnce(key, message) {
|
|
103
|
-
if (warned.has(key)) return;
|
|
104
|
-
warned.add(key);
|
|
105
|
-
console.warn(`⚠️ ${message}`);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
_logUnknown(type) {
|
|
109
|
-
const current = this._unknownEventCounts.get(type) || 0;
|
|
110
|
-
if (current >= 5) return;
|
|
111
|
-
this._unknownEventCounts.set(type, current + 1);
|
|
112
|
-
console.debug(`[gemini] Unknown event type: ${type}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
module.exports = GoogleProvider;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// Gemini CLI model names
|
|
2
|
-
// Model is optional - Gemini defaults to best available
|
|
3
|
-
const MODEL_CATALOG = {
|
|
4
|
-
'gemini-2.5-pro': { rank: 3 },
|
|
5
|
-
'gemini-2.0-flash': { rank: 1 },
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
const LEVEL_MAPPING = {
|
|
9
|
-
level1: { rank: 1, model: null },
|
|
10
|
-
level2: { rank: 2, model: null },
|
|
11
|
-
level3: { rank: 3, model: null },
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const DEFAULT_LEVEL = 'level2';
|
|
15
|
-
const DEFAULT_MAX_LEVEL = 'level3';
|
|
16
|
-
const DEFAULT_MIN_LEVEL = 'level1';
|
|
17
|
-
|
|
18
|
-
module.exports = {
|
|
19
|
-
MODEL_CATALOG,
|
|
20
|
-
LEVEL_MAPPING,
|
|
21
|
-
DEFAULT_LEVEL,
|
|
22
|
-
DEFAULT_MAX_LEVEL,
|
|
23
|
-
DEFAULT_MIN_LEVEL,
|
|
24
|
-
};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
function normalizeMessageContent(content) {
|
|
2
|
-
if (typeof content === 'string') return content;
|
|
3
|
-
if (Array.isArray(content)) {
|
|
4
|
-
return content.map((item) => (typeof item === 'string' ? item : item?.text || '')).join('');
|
|
5
|
-
}
|
|
6
|
-
if (content && typeof content === 'object') {
|
|
7
|
-
if (typeof content.text === 'string') return content.text;
|
|
8
|
-
}
|
|
9
|
-
return '';
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function parseMessageEvent(event) {
|
|
13
|
-
if (event.role === 'assistant') {
|
|
14
|
-
const text = normalizeMessageContent(event.content);
|
|
15
|
-
if (text) {
|
|
16
|
-
return { type: 'text', text };
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function parseToolUseEvent(event, state) {
|
|
23
|
-
const toolId = event.tool_call_id || event.tool_id || event.id || state.lastToolId;
|
|
24
|
-
const toolName = event.tool_name || event.name;
|
|
25
|
-
state.lastToolId = toolId;
|
|
26
|
-
return {
|
|
27
|
-
type: 'tool_call',
|
|
28
|
-
toolName,
|
|
29
|
-
toolId,
|
|
30
|
-
input: event.parameters || event.input || {},
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function parseToolResultEvent(event, state) {
|
|
35
|
-
const toolId = event.tool_call_id || event.tool_id || event.id || state.lastToolId;
|
|
36
|
-
return {
|
|
37
|
-
type: 'tool_result',
|
|
38
|
-
toolId,
|
|
39
|
-
content: event.output ?? event.content ?? '',
|
|
40
|
-
isError: event.success === false,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function parseResultEvent(event) {
|
|
45
|
-
return {
|
|
46
|
-
type: 'result',
|
|
47
|
-
success: event.success !== false,
|
|
48
|
-
result: event.result || '',
|
|
49
|
-
error: event.success === false ? event.error || 'Result failed' : null,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function parseEvent(line, state = {}, options = {}) {
|
|
54
|
-
let event;
|
|
55
|
-
try {
|
|
56
|
-
event = JSON.parse(line);
|
|
57
|
-
} catch {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
switch (event.type) {
|
|
62
|
-
case 'init':
|
|
63
|
-
return null;
|
|
64
|
-
case 'message':
|
|
65
|
-
return parseMessageEvent(event);
|
|
66
|
-
case 'tool_use':
|
|
67
|
-
return parseToolUseEvent(event, state);
|
|
68
|
-
case 'tool_result':
|
|
69
|
-
return parseToolResultEvent(event, state);
|
|
70
|
-
case 'result':
|
|
71
|
-
return parseResultEvent(event);
|
|
72
|
-
default:
|
|
73
|
-
if (options.onUnknown) {
|
|
74
|
-
options.onUnknown(event.type, event);
|
|
75
|
-
}
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function parseChunk(chunk, state = {}, options = {}) {
|
|
81
|
-
const events = [];
|
|
82
|
-
const lines = chunk.split('\n');
|
|
83
|
-
|
|
84
|
-
for (const line of lines) {
|
|
85
|
-
if (!line.trim()) continue;
|
|
86
|
-
const event = parseEvent(line, state, options);
|
|
87
|
-
if (!event) continue;
|
|
88
|
-
if (Array.isArray(event)) {
|
|
89
|
-
events.push(...event);
|
|
90
|
-
} else {
|
|
91
|
-
events.push(event);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return events;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
module.exports = {
|
|
99
|
-
parseEvent,
|
|
100
|
-
parseChunk,
|
|
101
|
-
};
|
package/src/providers/index.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
const AnthropicProvider = require('./anthropic');
|
|
2
|
-
const OpenAIProvider = require('./openai');
|
|
3
|
-
const GoogleProvider = require('./google');
|
|
4
|
-
const OpencodeProvider = require('./opencode');
|
|
5
|
-
const { normalizeProviderName } = require('../../lib/provider-names');
|
|
6
|
-
|
|
7
|
-
const PROVIDERS = {
|
|
8
|
-
claude: AnthropicProvider,
|
|
9
|
-
codex: OpenAIProvider,
|
|
10
|
-
gemini: GoogleProvider,
|
|
11
|
-
opencode: OpencodeProvider,
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
function getProvider(name) {
|
|
15
|
-
const normalized = normalizeProviderName(name || '');
|
|
16
|
-
const Provider = PROVIDERS[normalized];
|
|
17
|
-
if (!Provider) {
|
|
18
|
-
throw new Error(`Unknown provider: ${name}. Valid: ${Object.keys(PROVIDERS).join(', ')}`);
|
|
19
|
-
}
|
|
20
|
-
return new Provider();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async function detectProviders() {
|
|
24
|
-
const results = {};
|
|
25
|
-
for (const [name, Provider] of Object.entries(PROVIDERS)) {
|
|
26
|
-
const provider = new Provider();
|
|
27
|
-
results[name] = {
|
|
28
|
-
available: await provider.isAvailable(),
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
return results;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function listProviders() {
|
|
35
|
-
return Object.keys(PROVIDERS);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function stripTimestampPrefix(line) {
|
|
39
|
-
if (!line || typeof line !== 'string') return '';
|
|
40
|
-
let trimmed = line.trim().replace(/\r$/, '');
|
|
41
|
-
if (!trimmed) return '';
|
|
42
|
-
|
|
43
|
-
const tsMatch = trimmed.match(/^\[(\d{13})\](.*)$/);
|
|
44
|
-
if (tsMatch) trimmed = (tsMatch[2] || '').trimStart();
|
|
45
|
-
|
|
46
|
-
// In cluster logs, lines are often prefixed like:
|
|
47
|
-
// "validator | {json...}"
|
|
48
|
-
// Strip the "<agent> | " prefix so provider parsers can JSON.parse the event.
|
|
49
|
-
if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
|
|
50
|
-
const pipeMatch = trimmed.match(/^[^|]{1,40}\|\s*(.*)$/);
|
|
51
|
-
if (pipeMatch) {
|
|
52
|
-
const afterPipe = (pipeMatch[1] || '').trimStart();
|
|
53
|
-
if (afterPipe.startsWith('{') || afterPipe.startsWith('[')) return afterPipe;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return trimmed;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function parseChunkWithProvider(provider, chunk) {
|
|
61
|
-
if (!chunk) return [];
|
|
62
|
-
const events = [];
|
|
63
|
-
const lines = chunk.split('\n');
|
|
64
|
-
|
|
65
|
-
for (const line of lines) {
|
|
66
|
-
const content = stripTimestampPrefix(line);
|
|
67
|
-
if (!content) continue;
|
|
68
|
-
const event = provider.parseEvent(content);
|
|
69
|
-
if (!event) continue;
|
|
70
|
-
if (Array.isArray(event)) {
|
|
71
|
-
events.push(...event);
|
|
72
|
-
} else {
|
|
73
|
-
events.push(event);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return events;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function parseProviderChunk(providerName, chunk) {
|
|
81
|
-
const provider = getProvider(providerName || 'claude');
|
|
82
|
-
return parseChunkWithProvider(provider, chunk);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
module.exports = {
|
|
86
|
-
getProvider,
|
|
87
|
-
detectProviders,
|
|
88
|
-
listProviders,
|
|
89
|
-
parseProviderChunk,
|
|
90
|
-
parseChunkWithProvider,
|
|
91
|
-
};
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const os = require('os');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* OpenAI structured outputs have strict schema requirements:
|
|
7
|
-
* 1. additionalProperties: false on ALL object schemas
|
|
8
|
-
* 2. 'required' must include ALL keys in 'properties'
|
|
9
|
-
* This function recursively enforces both constraints.
|
|
10
|
-
* @param {Object} schema - JSON Schema object
|
|
11
|
-
* @returns {Object} - Modified schema compliant with OpenAI structured output requirements
|
|
12
|
-
*/
|
|
13
|
-
function enforceStrictSchema(schema) {
|
|
14
|
-
if (!schema || typeof schema !== 'object') return schema;
|
|
15
|
-
|
|
16
|
-
const result = { ...schema };
|
|
17
|
-
|
|
18
|
-
// Add additionalProperties: false to object types
|
|
19
|
-
// OpenAI also requires 'required' to include ALL property keys
|
|
20
|
-
if (result.type === 'object') {
|
|
21
|
-
result.additionalProperties = false;
|
|
22
|
-
if (result.properties) {
|
|
23
|
-
result.required = Object.keys(result.properties);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Recurse into properties
|
|
28
|
-
if (result.properties) {
|
|
29
|
-
result.properties = {};
|
|
30
|
-
for (const [key, value] of Object.entries(schema.properties)) {
|
|
31
|
-
result.properties[key] = enforceStrictSchema(value);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Recurse into items (arrays)
|
|
36
|
-
if (result.items) {
|
|
37
|
-
result.items = enforceStrictSchema(schema.items);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Recurse into anyOf/oneOf/allOf
|
|
41
|
-
for (const key of ['anyOf', 'oneOf', 'allOf']) {
|
|
42
|
-
if (Array.isArray(result[key])) {
|
|
43
|
-
result[key] = result[key].map(enforceStrictSchema);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Recurse into additionalProperties if it's a schema
|
|
48
|
-
if (result.additionalProperties && typeof result.additionalProperties === 'object') {
|
|
49
|
-
result.additionalProperties = enforceStrictSchema(result.additionalProperties);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return result;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function buildCommand(context, options = {}) {
|
|
56
|
-
const { modelSpec, outputFormat, jsonSchema, cwd, autoApprove, cliFeatures = {} } = options;
|
|
57
|
-
|
|
58
|
-
const args = ['exec'];
|
|
59
|
-
const cleanup = []; // Files to cleanup after command completes
|
|
60
|
-
|
|
61
|
-
if ((outputFormat === 'stream-json' || outputFormat === 'json') && cliFeatures.supportsJson) {
|
|
62
|
-
args.push('--json');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (modelSpec?.model) {
|
|
66
|
-
args.push('-m', modelSpec.model);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (modelSpec?.reasoningEffort && cliFeatures.supportsConfigOverride) {
|
|
70
|
-
args.push('--config', `model_reasoning_effort="${modelSpec.reasoningEffort}"`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (cwd && cliFeatures.supportsCwd) {
|
|
74
|
-
args.push('-C', cwd);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (autoApprove && cliFeatures.supportsAutoApprove) {
|
|
78
|
-
args.push('--dangerously-bypass-approvals-and-sandbox');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Always skip git repo check - zeroshot runs non-interactively and may run in any directory
|
|
82
|
-
if (cliFeatures.supportsSkipGitRepoCheck !== false) {
|
|
83
|
-
args.push('--skip-git-repo-check');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Augment context with schema if CLI doesn't support native --output-schema
|
|
87
|
-
let finalContext = context;
|
|
88
|
-
if (jsonSchema && cliFeatures.supportsOutputSchema) {
|
|
89
|
-
// CRITICAL: Codex --output-schema takes a FILE PATH, not a JSON string
|
|
90
|
-
// Write schema to temp file and pass the path
|
|
91
|
-
// Codex requires additionalProperties: false on all object schemas
|
|
92
|
-
const parsedSchema = typeof jsonSchema === 'string' ? JSON.parse(jsonSchema) : jsonSchema;
|
|
93
|
-
const strictSchema = enforceStrictSchema(parsedSchema);
|
|
94
|
-
const schemaStr = JSON.stringify(strictSchema, null, 2);
|
|
95
|
-
const schemaFile = path.join(
|
|
96
|
-
os.tmpdir(),
|
|
97
|
-
`zeroshot-schema-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
|
|
98
|
-
);
|
|
99
|
-
fs.writeFileSync(schemaFile, schemaStr);
|
|
100
|
-
cleanup.push(schemaFile);
|
|
101
|
-
args.push('--output-schema', schemaFile);
|
|
102
|
-
} else if (jsonSchema) {
|
|
103
|
-
// CRITICAL: Inject schema into prompt when CLI doesn't support --output-schema
|
|
104
|
-
// Without this, model outputs free-form text instead of JSON
|
|
105
|
-
const schemaStr =
|
|
106
|
-
typeof jsonSchema === 'string' ? jsonSchema : JSON.stringify(jsonSchema, null, 2);
|
|
107
|
-
finalContext =
|
|
108
|
-
context +
|
|
109
|
-
`\n\n## OUTPUT FORMAT (CRITICAL - REQUIRED)
|
|
110
|
-
|
|
111
|
-
You MUST respond with a JSON object that exactly matches this schema. NO markdown, NO explanation, NO code blocks. ONLY the raw JSON object.
|
|
112
|
-
|
|
113
|
-
Schema:
|
|
114
|
-
\`\`\`json
|
|
115
|
-
${schemaStr}
|
|
116
|
-
\`\`\`
|
|
117
|
-
|
|
118
|
-
Your response must be ONLY valid JSON. Start with { and end with }. Nothing else.`;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
args.push(finalContext);
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
binary: 'codex',
|
|
125
|
-
args,
|
|
126
|
-
env: {},
|
|
127
|
-
cleanup, // Temp files to delete after command completes
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
module.exports = {
|
|
132
|
-
buildCommand,
|
|
133
|
-
};
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
const BaseProvider = require('../base-provider');
|
|
2
|
-
const { commandExists, getCommandPath, getHelpOutput } = require('../../../lib/provider-detection');
|
|
3
|
-
const { buildCommand } = require('./cli-builder');
|
|
4
|
-
const { parseEvent } = require('./output-parser');
|
|
5
|
-
const {
|
|
6
|
-
MODEL_CATALOG,
|
|
7
|
-
LEVEL_MAPPING,
|
|
8
|
-
DEFAULT_LEVEL,
|
|
9
|
-
DEFAULT_MAX_LEVEL,
|
|
10
|
-
DEFAULT_MIN_LEVEL,
|
|
11
|
-
} = require('./models');
|
|
12
|
-
|
|
13
|
-
const warned = new Set();
|
|
14
|
-
|
|
15
|
-
class OpenAIProvider extends BaseProvider {
|
|
16
|
-
constructor() {
|
|
17
|
-
super({ name: 'codex', displayName: 'Codex', cliCommand: 'codex' });
|
|
18
|
-
this._cliFeatures = null;
|
|
19
|
-
this._unknownEventCounts = new Map();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// SDK not implemented - uses CLI only
|
|
23
|
-
// See BaseProvider for SDK extension point documentation
|
|
24
|
-
|
|
25
|
-
isAvailable() {
|
|
26
|
-
return commandExists(this.cliCommand);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
getCliPath() {
|
|
30
|
-
return getCommandPath(this.cliCommand) || this.cliCommand;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
getInstallInstructions() {
|
|
34
|
-
return 'npm install -g @openai/codex';
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
getAuthInstructions() {
|
|
38
|
-
return 'codex login';
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
getCliFeatures() {
|
|
42
|
-
if (this._cliFeatures) return this._cliFeatures;
|
|
43
|
-
// CRITICAL: Check 'codex exec --help' not 'codex --help'
|
|
44
|
-
// The --output-schema flag is on the exec subcommand, not the main command
|
|
45
|
-
const help = getHelpOutput(this.cliCommand, ['exec']);
|
|
46
|
-
const unknown = !help;
|
|
47
|
-
|
|
48
|
-
const features = {
|
|
49
|
-
supportsJson: unknown ? true : /--json\b/.test(help),
|
|
50
|
-
supportsOutputSchema: unknown ? true : /--output-schema\b/.test(help),
|
|
51
|
-
supportsAutoApprove: unknown
|
|
52
|
-
? true
|
|
53
|
-
: /--dangerously-bypass-approvals-and-sandbox\b/.test(help),
|
|
54
|
-
supportsCwd: unknown ? true : /\s-C\b/.test(help) || /--cwd\b/.test(help),
|
|
55
|
-
supportsConfigOverride: unknown ? true : /--config\b/.test(help),
|
|
56
|
-
supportsModel: unknown ? true : /\s-m\b/.test(help) || /--model\b/.test(help),
|
|
57
|
-
supportsSkipGitRepoCheck: unknown ? true : /--skip-git-repo-check\b/.test(help),
|
|
58
|
-
unknown,
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
this._cliFeatures = features;
|
|
62
|
-
return features;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
getCredentialPaths() {
|
|
66
|
-
return ['~/.config/codex', '~/.codex'];
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
buildCommand(context, options) {
|
|
70
|
-
const cliFeatures = options.cliFeatures || {};
|
|
71
|
-
|
|
72
|
-
if (options.autoApprove && cliFeatures.supportsAutoApprove === false) {
|
|
73
|
-
this._warnOnce(
|
|
74
|
-
'codex-auto-approve',
|
|
75
|
-
'Codex CLI does not support auto-approve; continuing without bypass flag.'
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (options.jsonSchema && cliFeatures.supportsOutputSchema === false) {
|
|
80
|
-
this._warnOnce(
|
|
81
|
-
'codex-jsonschema',
|
|
82
|
-
'Codex CLI does not support --output-schema; skipping schema flag.'
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (options.modelSpec?.reasoningEffort && cliFeatures.supportsConfigOverride === false) {
|
|
87
|
-
this._warnOnce(
|
|
88
|
-
'codex-reasoning',
|
|
89
|
-
'Codex CLI does not support --config overrides; skipping reasoningEffort.'
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return buildCommand(context, { ...options, cliFeatures });
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
parseEvent(line) {
|
|
97
|
-
return parseEvent(line, {
|
|
98
|
-
onUnknown: (type) => this._logUnknown(type),
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
getModelCatalog() {
|
|
103
|
-
return MODEL_CATALOG;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
getLevelMapping() {
|
|
107
|
-
return LEVEL_MAPPING;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
getDefaultLevel() {
|
|
111
|
-
return DEFAULT_LEVEL;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
getDefaultMaxLevel() {
|
|
115
|
-
return DEFAULT_MAX_LEVEL;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
getDefaultMinLevel() {
|
|
119
|
-
return DEFAULT_MIN_LEVEL;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
_warnOnce(key, message) {
|
|
123
|
-
if (warned.has(key)) return;
|
|
124
|
-
warned.add(key);
|
|
125
|
-
console.warn(`⚠️ ${message}`);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
_logUnknown(type) {
|
|
129
|
-
const current = this._unknownEventCounts.get(type) || 0;
|
|
130
|
-
if (current >= 5) return;
|
|
131
|
-
this._unknownEventCounts.set(type, current + 1);
|
|
132
|
-
console.debug(`[codex] Unknown event type: ${type}`);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
module.exports = OpenAIProvider;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// Codex CLI - use null to let CLI pick its default model
|
|
2
|
-
// Levels vary by reasoning effort only
|
|
3
|
-
const MODEL_CATALOG = {};
|
|
4
|
-
|
|
5
|
-
const LEVEL_MAPPING = {
|
|
6
|
-
level1: { rank: 1, model: null, reasoningEffort: 'low' },
|
|
7
|
-
level2: { rank: 2, model: null, reasoningEffort: 'medium' },
|
|
8
|
-
level3: { rank: 3, model: null, reasoningEffort: 'high' },
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const DEFAULT_LEVEL = 'level2';
|
|
12
|
-
const DEFAULT_MAX_LEVEL = 'level3';
|
|
13
|
-
const DEFAULT_MIN_LEVEL = 'level1';
|
|
14
|
-
|
|
15
|
-
module.exports = {
|
|
16
|
-
MODEL_CATALOG,
|
|
17
|
-
LEVEL_MAPPING,
|
|
18
|
-
DEFAULT_LEVEL,
|
|
19
|
-
DEFAULT_MAX_LEVEL,
|
|
20
|
-
DEFAULT_MIN_LEVEL,
|
|
21
|
-
};
|