orquesta-cli 0.2.93 → 0.2.95
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/dist/cli.js +8 -14
- package/dist/core/config/endpoint-override.d.ts +15 -0
- package/dist/core/config/endpoint-override.js +12 -0
- package/dist/core/llm/llm-client.js +3 -2
- package/dist/orchestration/audit-log.d.ts +1 -0
- package/dist/orchestration/audit-log.js +12 -0
- package/dist/prompts/agents/planning.js +5 -4
- package/dist/utils/file-system.js +15 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -17,6 +17,7 @@ import React from 'react';
|
|
|
17
17
|
import { render } from 'ink';
|
|
18
18
|
import { createRequire } from 'module';
|
|
19
19
|
import { configManager } from './core/config/config-manager.js';
|
|
20
|
+
import { resolveEndpointOverride } from './core/config/endpoint-override.js';
|
|
20
21
|
import { createLLMClient } from './core/llm/llm-client.js';
|
|
21
22
|
import { PlanExecuteApp } from './ui/components/PlanExecuteApp.js';
|
|
22
23
|
import { setAppendedSystemPrompt } from './orchestration/plan-executor.js';
|
|
@@ -152,20 +153,15 @@ program
|
|
|
152
153
|
if (options.appendSystemPrompt) {
|
|
153
154
|
setAppendedSystemPrompt(options.appendSystemPrompt);
|
|
154
155
|
}
|
|
156
|
+
await configManager.initialize();
|
|
157
|
+
await ensureBatutaFromEnv();
|
|
155
158
|
if (options.endpoint) {
|
|
156
|
-
await configManager.initialize();
|
|
157
|
-
await ensureBatutaFromEnv();
|
|
158
|
-
const wanted = String(options.endpoint).toLowerCase();
|
|
159
159
|
const all = configManager.getAllEndpoints();
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
await configManager.setCurrentEndpoint(ep.id);
|
|
166
|
-
const m = ep.models.find((x) => x.enabled) || ep.models[0];
|
|
167
|
-
if (m)
|
|
168
|
-
await configManager.setCurrentModel(m.id);
|
|
160
|
+
const resolved = resolveEndpointOverride(all, String(options.endpoint));
|
|
161
|
+
if (resolved) {
|
|
162
|
+
await configManager.setCurrentEndpoint(resolved.endpointId);
|
|
163
|
+
if (resolved.modelId)
|
|
164
|
+
await configManager.setCurrentModel(resolved.modelId);
|
|
169
165
|
}
|
|
170
166
|
else {
|
|
171
167
|
logger.warn(`--endpoint "${options.endpoint}" matched no configured endpoint (have: ${all.map(e => e.id).join(', ') || 'none'}); keeping current selection`);
|
|
@@ -188,8 +184,6 @@ program
|
|
|
188
184
|
disableHooks();
|
|
189
185
|
return;
|
|
190
186
|
}
|
|
191
|
-
await configManager.initialize();
|
|
192
|
-
await ensureBatutaFromEnv();
|
|
193
187
|
if (shouldShowOnboarding()) {
|
|
194
188
|
await runOnboarding();
|
|
195
189
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface OverrideEndpoint {
|
|
2
|
+
id: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
provider?: string;
|
|
5
|
+
models?: Array<{
|
|
6
|
+
id: string;
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
export interface ResolvedOverride {
|
|
11
|
+
endpointId: string;
|
|
12
|
+
modelId?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function resolveEndpointOverride(endpoints: OverrideEndpoint[], wanted: string): ResolvedOverride | null;
|
|
15
|
+
//# sourceMappingURL=endpoint-override.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function resolveEndpointOverride(endpoints, wanted) {
|
|
2
|
+
const w = String(wanted).toLowerCase();
|
|
3
|
+
const ep = w === 'batuta'
|
|
4
|
+
? endpoints.find((e) => e.id === 'batuta-proxy' || e.provider === 'batuta')
|
|
5
|
+
: endpoints.find((e) => e.id === wanted) ||
|
|
6
|
+
endpoints.find((e) => (e.name || '').toLowerCase() === w);
|
|
7
|
+
if (!ep)
|
|
8
|
+
return null;
|
|
9
|
+
const m = ep.models?.find((x) => x.enabled) || ep.models?.[0];
|
|
10
|
+
return { endpointId: ep.id, modelId: m?.id };
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=endpoint-override.js.map
|
|
@@ -424,9 +424,10 @@ export class LLMClient {
|
|
|
424
424
|
currentAttempt: currentAttempt + 1,
|
|
425
425
|
});
|
|
426
426
|
}
|
|
427
|
-
|
|
427
|
+
const upstream5xx = axios.isAxiosError(error) && (error.response?.status ?? 0) >= 500;
|
|
428
|
+
if (!this.triedBatutaFallback && (this.isConnectionError(error) || upstream5xx) && this.switchToBatutaProxy()) {
|
|
428
429
|
this.triedBatutaFallback = true;
|
|
429
|
-
logger.flow('Primary endpoint
|
|
430
|
+
logger.flow('Primary endpoint failed — falling back to Batuta');
|
|
430
431
|
return this.chatCompletion(options, { maxRetries, currentAttempt: 1 });
|
|
431
432
|
}
|
|
432
433
|
logger.flow('API call failed - Error handling');
|
|
@@ -15,6 +15,7 @@ declare class AuditLogger {
|
|
|
15
15
|
startRun(sessionId: string, data?: Record<string, unknown>): string;
|
|
16
16
|
emit(sessionId: string, kind: AuditEventKind, data?: Record<string, unknown>): void;
|
|
17
17
|
private write;
|
|
18
|
+
private rotateIfNeeded;
|
|
18
19
|
tail(n?: number): Promise<AuditEvent[]>;
|
|
19
20
|
stats(opts?: {
|
|
20
21
|
sinceDays?: number;
|
|
@@ -31,12 +31,24 @@ class AuditLogger {
|
|
|
31
31
|
await fs.mkdir(LOCAL_HOME_DIR, { recursive: true });
|
|
32
32
|
this.initialized = true;
|
|
33
33
|
}
|
|
34
|
+
await this.rotateIfNeeded();
|
|
34
35
|
await fs.appendFile(AUDIT_LOG_PATH, JSON.stringify(event) + '\n', 'utf8');
|
|
35
36
|
}
|
|
36
37
|
catch (error) {
|
|
37
38
|
logger.warn('Audit log write failed', { error: error.message });
|
|
38
39
|
}
|
|
39
40
|
}
|
|
41
|
+
async rotateIfNeeded() {
|
|
42
|
+
try {
|
|
43
|
+
const max = Number(process.env['ORQUESTA_AUDIT_MAX_BYTES']) || 10 * 1024 * 1024;
|
|
44
|
+
const { size } = await fs.stat(AUDIT_LOG_PATH);
|
|
45
|
+
if (size < max)
|
|
46
|
+
return;
|
|
47
|
+
await fs.rename(AUDIT_LOG_PATH, `${AUDIT_LOG_PATH}.1`).catch(() => undefined);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
}
|
|
51
|
+
}
|
|
40
52
|
async tail(n = 50) {
|
|
41
53
|
try {
|
|
42
54
|
const raw = await fs.readFile(AUDIT_LOG_PATH, 'utf8');
|
|
@@ -53,10 +53,11 @@ Use this ONLY for pure questions that need NO action:
|
|
|
53
53
|
## Guidelines
|
|
54
54
|
|
|
55
55
|
### For create_todos:
|
|
56
|
-
1. **
|
|
57
|
-
2. **
|
|
58
|
-
3. **
|
|
59
|
-
4. **
|
|
56
|
+
1. **Create the MINIMUM number of TODOs.** 1 task is the ideal and most common case. Only add more when the work is genuinely separable AND benefits from it. Debugging, investigation, and "figure out / fix X" are SEQUENTIAL by nature — each finding informs the next step — so they should be a SINGLE task, never split. Add multiple tasks only for genuinely independent, parallelizable implementation work (e.g. "build feature A" + "build unrelated feature B"). When unsure, prefer fewer.
|
|
57
|
+
2. **dependsOn for ordered steps** - If task B needs task A's result (build → upload → restart), set B.dependsOn=[A]. Tasks that touch the filesystem with no declared deps run sequentially in listed order.
|
|
58
|
+
3. **Actionable titles** - Clear what needs to be done
|
|
59
|
+
4. **Sequential order** - List tasks in execution order
|
|
60
|
+
5. **User's language** - Write titles in the same language as the user
|
|
60
61
|
|
|
61
62
|
### For respond_to_user:
|
|
62
63
|
1. **Clear and helpful** - Answer the question directly
|
|
@@ -4,7 +4,10 @@ import { promisify } from 'util';
|
|
|
4
4
|
const mkdir = promisify(fs.mkdir);
|
|
5
5
|
const readFile = promisify(fs.readFile);
|
|
6
6
|
const writeFile = promisify(fs.writeFile);
|
|
7
|
+
const rename = promisify(fs.rename);
|
|
8
|
+
const unlink = promisify(fs.unlink);
|
|
7
9
|
const access = promisify(fs.access);
|
|
10
|
+
let tmpCounter = 0;
|
|
8
11
|
const stat = promisify(fs.stat);
|
|
9
12
|
export async function directoryExists(dirPath) {
|
|
10
13
|
try {
|
|
@@ -51,7 +54,18 @@ export async function writeJsonFile(filePath, data) {
|
|
|
51
54
|
const dirPath = path.dirname(filePath);
|
|
52
55
|
await ensureDirectory(dirPath);
|
|
53
56
|
const content = JSON.stringify(data, null, 2);
|
|
54
|
-
|
|
57
|
+
const tmpPath = `${filePath}.tmp.${process.pid}.${tmpCounter++}`;
|
|
58
|
+
try {
|
|
59
|
+
await writeFile(tmpPath, content, 'utf-8');
|
|
60
|
+
await rename(tmpPath, filePath);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
try {
|
|
64
|
+
await unlink(tmpPath);
|
|
65
|
+
}
|
|
66
|
+
catch { }
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
55
69
|
}
|
|
56
70
|
catch (error) {
|
|
57
71
|
if (error instanceof Error) {
|