@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,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
- };
@@ -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
- };