orquesta-cli 0.2.29 → 0.2.31
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/core/llm/llm-client.js +10 -0
- package/dist/core/slash-command-handler.js +71 -0
- package/dist/orchestration/plan-executor.js +7 -1
- package/dist/orquesta/config-sync.js +4 -0
- package/dist/orquesta/hook-init.d.ts +3 -1
- package/dist/orquesta/hook-init.js +12 -7
- package/dist/ui/components/PlanExecuteApp.js +2 -2
- package/dist/ui/hooks/slashCommandProcessor.js +8 -0
- package/package.json +1 -1
|
@@ -765,6 +765,16 @@ export class LLMClient {
|
|
|
765
765
|
};
|
|
766
766
|
}
|
|
767
767
|
handleError(error, requestContext) {
|
|
768
|
+
if (axios.isAxiosError(error) && error.response?.status === 401) {
|
|
769
|
+
const data = error.response.data;
|
|
770
|
+
const detail = data?.error?.message || data?.message || 'Unauthorized';
|
|
771
|
+
logger.error(`Not logged in to Orquesta (${detail}).`);
|
|
772
|
+
return new APIError('Not logged in to Orquesta', 401, this.baseUrl, {
|
|
773
|
+
isRecoverable: false,
|
|
774
|
+
userMessage: `You're not logged in to Orquesta (${detail}).\n` +
|
|
775
|
+
`Run \`orquesta --login\` to sign in again, then retry.`,
|
|
776
|
+
});
|
|
777
|
+
}
|
|
768
778
|
logger.error('LLM Client Error', error);
|
|
769
779
|
if (requestContext) {
|
|
770
780
|
logger.debug('Request Context', requestContext);
|
|
@@ -2,6 +2,9 @@ import { sessionManager } from './session/session-manager.js';
|
|
|
2
2
|
import { usageTracker } from './usage-tracker.js';
|
|
3
3
|
import { logger } from '../utils/logger.js';
|
|
4
4
|
import { fullSync } from '../orquesta/config-sync.js';
|
|
5
|
+
import { readHookConfig, writeHookFiles, disableHooks } from '../orquesta/hook-init.js';
|
|
6
|
+
import { checkForCliUpdate, runCliUpdate, setSkippedVersion } from '../utils/update-checker.js';
|
|
7
|
+
import { createRequire } from 'module';
|
|
5
8
|
import { configManager } from './config/config-manager.js';
|
|
6
9
|
import { getForcedTier, setForcedTier, resetBatutaSession } from './routing-state.js';
|
|
7
10
|
import { auditLog } from '../orchestration/audit-log.js';
|
|
@@ -511,6 +514,72 @@ ${executorLines}
|
|
|
511
514
|
context.setMessages(updatedMessages);
|
|
512
515
|
return { handled: true, shouldContinue: false, updatedContext: { messages: updatedMessages } };
|
|
513
516
|
}
|
|
517
|
+
if (trimmedCommand === '/update') {
|
|
518
|
+
logger.flow('Update command received');
|
|
519
|
+
const reply = (content) => {
|
|
520
|
+
const updatedMessages = [...context.messages, { role: 'assistant', content }];
|
|
521
|
+
context.setMessages(updatedMessages);
|
|
522
|
+
return { handled: true, shouldContinue: false, updatedContext: { messages: updatedMessages } };
|
|
523
|
+
};
|
|
524
|
+
let currentVersion = '0.0.0';
|
|
525
|
+
try {
|
|
526
|
+
const require = createRequire(import.meta.url);
|
|
527
|
+
currentVersion = require('../../package.json').version;
|
|
528
|
+
}
|
|
529
|
+
catch { }
|
|
530
|
+
const info = await checkForCliUpdate(currentVersion);
|
|
531
|
+
if (!info)
|
|
532
|
+
return reply(`✅ You're on the latest version (v${currentVersion}).`);
|
|
533
|
+
context.setMessages([...context.messages, { role: 'assistant', content: `🚀 Updating v${info.current} → v${info.latest}…` }]);
|
|
534
|
+
const result = await runCliUpdate(info.latest);
|
|
535
|
+
if (result.success) {
|
|
536
|
+
setSkippedVersion(info.latest);
|
|
537
|
+
return reply(`✅ Updated to v${info.latest}. Restart orquesta (\`/exit\` then run it again) to use it.`);
|
|
538
|
+
}
|
|
539
|
+
return reply(`❌ Update failed: ${result.error}`);
|
|
540
|
+
}
|
|
541
|
+
if (trimmedCommand === '/hook' || trimmedCommand.startsWith('/hook ')) {
|
|
542
|
+
logger.flow('Hook command received');
|
|
543
|
+
const sub = trimmedCommand.split(/\s+/)[1] || 'status';
|
|
544
|
+
const reply = (content) => {
|
|
545
|
+
const updatedMessages = [...context.messages, { role: 'assistant', content }];
|
|
546
|
+
context.setMessages(updatedMessages);
|
|
547
|
+
return { handled: true, shouldContinue: false, updatedContext: { messages: updatedMessages } };
|
|
548
|
+
};
|
|
549
|
+
const oc = configManager.getOrquestaConfig();
|
|
550
|
+
const binding = readHookConfig(process.cwd());
|
|
551
|
+
if (sub === 'status') {
|
|
552
|
+
if (!binding)
|
|
553
|
+
return reply('🔌 Claude Code hook: not enabled in this directory.\nEnable it with /hook enable.');
|
|
554
|
+
const name = oc?.projectId === binding.projectId && oc?.projectName ? oc.projectName : binding.projectId;
|
|
555
|
+
return reply(`🟢 Claude Code hook: enabled here → streaming into ${name}\n Project ID: ${binding.projectId}\n Disable with /hook disable.`);
|
|
556
|
+
}
|
|
557
|
+
if (sub === 'disable') {
|
|
558
|
+
if (!binding)
|
|
559
|
+
return reply('Nothing to do — no Orquesta hook is configured in this directory.');
|
|
560
|
+
const changed = disableHooks(process.cwd(), { quiet: true });
|
|
561
|
+
return reply(changed
|
|
562
|
+
? '✅ Hook disabled. Claude Code runs in this directory no longer report to Orquesta.'
|
|
563
|
+
: 'Nothing to do — no Orquesta hook was configured here.');
|
|
564
|
+
}
|
|
565
|
+
if (sub === 'enable') {
|
|
566
|
+
if (!oc?.token)
|
|
567
|
+
return reply('❌ Not logged in. Run /login first, then /hook enable.');
|
|
568
|
+
if (!oc.projectId) {
|
|
569
|
+
return reply('⚠️ No project selected for this session.\nRun `orquesta hook enable` (or `orquesta hook switch`) in a shell to pick one — it can show the project list interactively.');
|
|
570
|
+
}
|
|
571
|
+
const ok = writeHookFiles({
|
|
572
|
+
projectId: oc.projectId,
|
|
573
|
+
token: oc.token,
|
|
574
|
+
apiUrl: binding?.apiUrl || 'https://getorquesta.com',
|
|
575
|
+
quiet: true,
|
|
576
|
+
});
|
|
577
|
+
return reply(ok
|
|
578
|
+
? `🟢 Hook enabled → streaming into ${oc.projectName || oc.projectId}.\nRun \`claude\` in this directory and sessions stream into Orquesta.`
|
|
579
|
+
: '❌ Could not write hook files (check directory permissions).');
|
|
580
|
+
}
|
|
581
|
+
return reply('Usage: /hook status | /hook enable | /hook disable\n(To move a directory to a different project, run `orquesta hook switch` in a shell.)');
|
|
582
|
+
}
|
|
514
583
|
if (trimmedCommand === '/help') {
|
|
515
584
|
const helpMessage = `
|
|
516
585
|
Available commands:
|
|
@@ -529,6 +598,8 @@ Available commands:
|
|
|
529
598
|
/login - Sign in to Orquesta via browser (opens getorquesta.com)
|
|
530
599
|
/logout - Sign out of Orquesta (clears token, keeps local LLM configs)
|
|
531
600
|
/whoami - Show current Orquesta connection
|
|
601
|
+
/hook - Claude Code hook here: /hook status | enable | disable
|
|
602
|
+
/update - Update orquesta-cli to the latest version
|
|
532
603
|
|
|
533
604
|
Keyboard shortcuts:
|
|
534
605
|
Ctrl+C - Exit
|
|
@@ -14,6 +14,7 @@ import { logger } from '../utils/logger.js';
|
|
|
14
14
|
import { getStreamLogger } from '../utils/json-stream-logger.js';
|
|
15
15
|
import { detectGitRepo } from '../utils/git-utils.js';
|
|
16
16
|
import { formatErrorMessage, buildTodoContext, findActiveTodo, getTodoStats } from './utils.js';
|
|
17
|
+
import { BaseError } from '../errors/base.js';
|
|
17
18
|
import { runParallelGraph, shouldUseParallelOrchestrator } from './parallel-orchestrator.js';
|
|
18
19
|
import { memoryStore } from './memory-store.js';
|
|
19
20
|
import { auditLog } from './audit-log.js';
|
|
@@ -237,7 +238,12 @@ export class PlanExecutor {
|
|
|
237
238
|
}
|
|
238
239
|
runError = error;
|
|
239
240
|
auditLog.emit(auditSid, 'run.error', { runId, message: error?.message });
|
|
240
|
-
|
|
241
|
+
if (error instanceof BaseError) {
|
|
242
|
+
logger.error(`Plan mode execution failed: ${error.message}`);
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
logger.error('Plan mode execution failed', error);
|
|
246
|
+
}
|
|
241
247
|
const errorMessage = formatErrorMessage(error);
|
|
242
248
|
callbacks.setMessages((prev) => {
|
|
243
249
|
const updatedMessages = [
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { configManager } from '../core/config/config-manager.js';
|
|
2
2
|
import { logger } from '../utils/logger.js';
|
|
3
|
+
import { readHookConfig } from './hook-init.js';
|
|
3
4
|
const ORQUESTA_API = process.env['ORQUESTA_API_URL'] || 'https://getorquesta.com';
|
|
4
5
|
export async function fetchOrquestaProjects(token) {
|
|
5
6
|
try {
|
|
@@ -194,6 +195,8 @@ export async function submitPromptToOrquesta(prompt) {
|
|
|
194
195
|
if (!orquestaConfig?.token) {
|
|
195
196
|
return { success: false, error: 'Not connected to Orquesta' };
|
|
196
197
|
}
|
|
198
|
+
const cwd = prompt.context?.['cwd'] || process.cwd();
|
|
199
|
+
const effectiveProjectId = readHookConfig(cwd)?.projectId || orquestaConfig.projectId;
|
|
197
200
|
try {
|
|
198
201
|
const response = await fetch(`${ORQUESTA_API}/api/orquesta-cli/prompts`, {
|
|
199
202
|
method: 'POST',
|
|
@@ -206,6 +209,7 @@ export async function submitPromptToOrquesta(prompt) {
|
|
|
206
209
|
context: prompt.context,
|
|
207
210
|
cliType: 'orquesta-cli',
|
|
208
211
|
llmConfig: prompt.llmConfig,
|
|
212
|
+
projectId: effectiveProjectId,
|
|
209
213
|
}),
|
|
210
214
|
});
|
|
211
215
|
if (!response.ok) {
|
|
@@ -11,5 +11,7 @@ export declare function readHookConfig(cwd?: string): {
|
|
|
11
11
|
projectId: string;
|
|
12
12
|
apiUrl?: string;
|
|
13
13
|
} | null;
|
|
14
|
-
export declare function disableHooks(cwd?: string
|
|
14
|
+
export declare function disableHooks(cwd?: string, opts?: {
|
|
15
|
+
quiet?: boolean;
|
|
16
|
+
}): boolean;
|
|
15
17
|
//# sourceMappingURL=hook-init.d.ts.map
|
|
@@ -170,8 +170,10 @@ export function readHookConfig(cwd = process.cwd()) {
|
|
|
170
170
|
return null;
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
|
-
export function disableHooks(cwd = process.cwd()) {
|
|
174
|
-
|
|
173
|
+
export function disableHooks(cwd = process.cwd(), opts = {}) {
|
|
174
|
+
const log = (m) => { if (!opts.quiet)
|
|
175
|
+
console.log(m); };
|
|
176
|
+
log('\n Disabling Orquesta hook for this directory...\n');
|
|
175
177
|
let changed = false;
|
|
176
178
|
const settingsPath = path.join(cwd, '.claude', 'settings.json');
|
|
177
179
|
if (fs.existsSync(settingsPath)) {
|
|
@@ -194,11 +196,12 @@ export function disableHooks(cwd = process.cwd()) {
|
|
|
194
196
|
delete settings.hooks;
|
|
195
197
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
196
198
|
if (changed)
|
|
197
|
-
|
|
199
|
+
log(' Removed Orquesta hooks from .claude/settings.json');
|
|
198
200
|
}
|
|
199
201
|
}
|
|
200
202
|
catch {
|
|
201
|
-
|
|
203
|
+
if (!opts.quiet)
|
|
204
|
+
console.warn(' \x1b[33m⚠ Could not parse .claude/settings.json — left untouched.\x1b[0m');
|
|
202
205
|
}
|
|
203
206
|
}
|
|
204
207
|
const orquestaJson = path.join(cwd, '.orquesta.json');
|
|
@@ -206,14 +209,16 @@ export function disableHooks(cwd = process.cwd()) {
|
|
|
206
209
|
try {
|
|
207
210
|
fs.unlinkSync(orquestaJson);
|
|
208
211
|
changed = true;
|
|
209
|
-
|
|
212
|
+
log(' Removed .orquesta.json');
|
|
210
213
|
}
|
|
211
214
|
catch {
|
|
212
|
-
|
|
215
|
+
if (!opts.quiet)
|
|
216
|
+
console.warn(' \x1b[33m⚠ Could not remove .orquesta.json.\x1b[0m');
|
|
213
217
|
}
|
|
214
218
|
}
|
|
215
|
-
|
|
219
|
+
log(changed
|
|
216
220
|
? '\n Done. Claude Code runs in this directory no longer report to Orquesta.\n'
|
|
217
221
|
: '\n Nothing to do — no Orquesta hook was configured here.\n');
|
|
222
|
+
return changed;
|
|
218
223
|
}
|
|
219
224
|
//# sourceMappingURL=hook-init.js.map
|
|
@@ -515,7 +515,7 @@ export const PlanExecuteApp = ({ llmClient: initialLlmClient, modelInfo }) => {
|
|
|
515
515
|
logger.debug('Ctrl+C pressed - waiting for double-tap to exit');
|
|
516
516
|
return;
|
|
517
517
|
}
|
|
518
|
-
if (updatePhase === 'available' && !isProcessing
|
|
518
|
+
if (updatePhase === 'available' && !isProcessing) {
|
|
519
519
|
if (inputChar === 'y' || inputChar === 'Y') {
|
|
520
520
|
setUpdateError('');
|
|
521
521
|
setUpdateProgress('');
|
|
@@ -1344,7 +1344,7 @@ export const PlanExecuteApp = ({ llmClient: initialLlmClient, modelInfo }) => {
|
|
|
1344
1344
|
? "Press ESC to close settings..."
|
|
1345
1345
|
: showDocsBrowser
|
|
1346
1346
|
? "Select a doc source or press ESC..."
|
|
1347
|
-
: "Type your message... (@ files, / commands, Alt+Enter newline)", focus: !showSessionBrowser && !showSettings && !showDocsBrowser && !planExecutionState.askUserRequest })),
|
|
1347
|
+
: "Type your message... (@ files, / commands, Alt+Enter newline)", focus: !showSessionBrowser && !showSettings && !showDocsBrowser && !planExecutionState.askUserRequest && updatePhase === 'hidden' })),
|
|
1348
1348
|
input.length > 0 && (React.createElement(Text, { color: input.length > 4000 ? 'red' : input.length > 2000 ? 'yellow' : 'gray', dimColor: true }, input.length.toLocaleString())))),
|
|
1349
1349
|
fileBrowserState.showFileBrowser && !isProcessing && (React.createElement(Box, { marginTop: 0 }, fileBrowserState.isLoadingFiles ? (React.createElement(Box, { borderStyle: "single", borderColor: "yellow", paddingX: 1 },
|
|
1350
1350
|
React.createElement(Spinner, { type: "dots" }),
|
|
@@ -57,6 +57,14 @@ export const SLASH_COMMANDS = [
|
|
|
57
57
|
name: '/whoami',
|
|
58
58
|
description: 'Show current Orquesta connection',
|
|
59
59
|
},
|
|
60
|
+
{
|
|
61
|
+
name: '/hook',
|
|
62
|
+
description: 'Claude Code hook here: status | enable | disable',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: '/update',
|
|
66
|
+
description: 'Update orquesta-cli to the latest version',
|
|
67
|
+
},
|
|
60
68
|
{
|
|
61
69
|
name: '/help',
|
|
62
70
|
description: 'Show help message',
|