orquesta-cli 0.2.25 → 0.2.27
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 +18 -5
- package/dist/orquesta/hook-init.d.ts +6 -1
- package/dist/orquesta/hook-init.js +109 -16
- package/dist/setup/first-run-setup.js +15 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -53,7 +53,8 @@ program
|
|
|
53
53
|
.option('--sync', 'Sync configurations with Orquesta and exit')
|
|
54
54
|
.option('--scan', 'Scan for available LLM providers (env vars + local ports)')
|
|
55
55
|
.option('--add-provider <providerId>', 'Add a specific provider by ID (e.g., openai, anthropic, ollama)')
|
|
56
|
-
.option('--init', '
|
|
56
|
+
.option('--init', 'Enable the Claude Code hook in this directory (reuses your login; or pass --token)')
|
|
57
|
+
.option('--disable-hook', 'Disable the Claude Code hook in this directory')
|
|
57
58
|
.action(async (options) => {
|
|
58
59
|
if (options.appendSystemPrompt) {
|
|
59
60
|
setAppendedSystemPrompt(options.appendSystemPrompt);
|
|
@@ -63,12 +64,22 @@ program
|
|
|
63
64
|
return;
|
|
64
65
|
}
|
|
65
66
|
if (options.init) {
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
await configManager.initialize();
|
|
68
|
+
const saved = configManager.getOrquestaConfig();
|
|
69
|
+
const token = options.token || saved?.token;
|
|
70
|
+
if (!token) {
|
|
71
|
+
console.error(chalk.red('Error: not connected to Orquesta.'));
|
|
72
|
+
console.error('Run ' + chalk.cyan('orquesta --login') + ' first, or pass ' + chalk.cyan('orquesta --init --token oat_…') + '.');
|
|
68
73
|
process.exit(1);
|
|
69
74
|
}
|
|
70
75
|
const { initHooks } = await import('./orquesta/hook-init.js');
|
|
71
|
-
|
|
76
|
+
const preferredProjectId = options.project || (options.token ? undefined : saved?.projectId);
|
|
77
|
+
await initHooks(token, undefined, preferredProjectId);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (options.disableHook) {
|
|
81
|
+
const { disableHooks } = await import('./orquesta/hook-init.js');
|
|
82
|
+
disableHooks();
|
|
72
83
|
return;
|
|
73
84
|
}
|
|
74
85
|
await configManager.initialize();
|
|
@@ -312,7 +323,9 @@ program.on('command:*', () => {
|
|
|
312
323
|
console.log(chalk.white(' --token <token> Connect to Orquesta dashboard\n'));
|
|
313
324
|
console.log(chalk.white(' --project <id> Select project when connecting\n'));
|
|
314
325
|
console.log(chalk.white(' --switch-project [id] Switch to a different project\n'));
|
|
315
|
-
console.log(chalk.white(' --status Show
|
|
326
|
+
console.log(chalk.white(' --status Show connection + hook status\n'));
|
|
327
|
+
console.log(chalk.white(' --init Enable the Claude Code hook here\n'));
|
|
328
|
+
console.log(chalk.white(' --disable-hook Disable the Claude Code hook here\n'));
|
|
316
329
|
console.log(chalk.white(' --sync Sync configurations with Orquesta\n'));
|
|
317
330
|
console.log(chalk.white(' --disconnect Disconnect from Orquesta\n'));
|
|
318
331
|
console.log(chalk.white(' --scan Scan for available LLM providers\n'));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare function initHooks(token: string, apiUrl?: string): Promise<void>;
|
|
1
|
+
export declare function initHooks(token: string, apiUrl?: string, preferredProjectId?: string): Promise<void>;
|
|
2
2
|
export declare function writeHookFiles(opts: {
|
|
3
3
|
projectId: string;
|
|
4
4
|
token: string;
|
|
@@ -7,4 +7,9 @@ export declare function writeHookFiles(opts: {
|
|
|
7
7
|
agentBin?: string;
|
|
8
8
|
quiet?: boolean;
|
|
9
9
|
}): boolean;
|
|
10
|
+
export declare function readHookConfig(cwd?: string): {
|
|
11
|
+
projectId: string;
|
|
12
|
+
apiUrl?: string;
|
|
13
|
+
} | null;
|
|
14
|
+
export declare function disableHooks(cwd?: string): void;
|
|
10
15
|
//# sourceMappingURL=hook-init.d.ts.map
|
|
@@ -31,12 +31,47 @@ function resolveAgentBin() {
|
|
|
31
31
|
console.warn(' \x1b[33m npm install -g orquesta-agent\x1b[0m\n');
|
|
32
32
|
return 'orquesta-agent';
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
async function resolveTargetProject(projects, preferredProjectId) {
|
|
35
|
+
if (preferredProjectId) {
|
|
36
|
+
const match = projects.find((p) => p.id === preferredProjectId);
|
|
37
|
+
if (match) {
|
|
38
|
+
console.log(` Project: ${match.name}\n`);
|
|
39
|
+
return match;
|
|
40
|
+
}
|
|
41
|
+
console.warn(` \x1b[33m⚠ Your saved project isn't visible to this token — pick one below.\x1b[0m\n`);
|
|
42
|
+
}
|
|
43
|
+
if (projects.length === 1) {
|
|
44
|
+
console.log(` Project: ${projects[0].name}\n`);
|
|
45
|
+
return projects[0];
|
|
46
|
+
}
|
|
47
|
+
if (!process.stdin.isTTY) {
|
|
48
|
+
console.error(` Error: this token can reach ${projects.length} projects and none was specified.\n` +
|
|
49
|
+
` Re-run with: orquesta --init --project <projectId>`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
console.log(' Which project should this directory report to?\n');
|
|
53
|
+
projects.forEach((p, i) => console.log(` ${i + 1}. ${p.name}`));
|
|
54
|
+
console.log();
|
|
55
|
+
const readline = await import('readline');
|
|
56
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
57
|
+
const answer = await new Promise((resolve) => {
|
|
58
|
+
rl.question(` Enter number (1-${projects.length}): `, (a) => { rl.close(); resolve(a.trim()); });
|
|
59
|
+
});
|
|
60
|
+
const num = parseInt(answer, 10);
|
|
61
|
+
const pick = (!isNaN(num) && num >= 1 && num <= projects.length) ? projects[num - 1] : null;
|
|
62
|
+
if (!pick) {
|
|
63
|
+
console.error(' Invalid selection.');
|
|
64
|
+
process.exit(1);
|
|
65
|
+
throw new Error();
|
|
66
|
+
}
|
|
67
|
+
console.log(` Project: ${pick.name}\n`);
|
|
68
|
+
return pick;
|
|
69
|
+
}
|
|
70
|
+
export async function initHooks(token, apiUrl = 'https://getorquesta.com', preferredProjectId) {
|
|
35
71
|
console.log('\n Initializing Orquesta hook integration...\n');
|
|
36
72
|
const agentBin = resolveAgentBin();
|
|
37
73
|
console.log(' Validating token...');
|
|
38
|
-
let
|
|
39
|
-
let projectName;
|
|
74
|
+
let projects;
|
|
40
75
|
try {
|
|
41
76
|
const res = await fetch(`${apiUrl}/api/orquesta-cli/projects`, {
|
|
42
77
|
headers: { 'Authorization': `Bearer ${token}` },
|
|
@@ -46,27 +81,25 @@ export async function initHooks(token, apiUrl = 'https://getorquesta.com') {
|
|
|
46
81
|
console.error(` Error: Invalid token`);
|
|
47
82
|
process.exit(1);
|
|
48
83
|
}
|
|
49
|
-
|
|
50
|
-
if (!firstProject) {
|
|
51
|
-
console.error(' Error: No projects found for this token');
|
|
52
|
-
process.exit(1);
|
|
53
|
-
throw new Error();
|
|
54
|
-
}
|
|
55
|
-
projectId = firstProject.id;
|
|
56
|
-
projectName = firstProject.name;
|
|
57
|
-
console.log(` Connected to: ${projectName}\n`);
|
|
84
|
+
projects = data.projects ?? [];
|
|
58
85
|
}
|
|
59
86
|
catch (err) {
|
|
60
87
|
const msg = err instanceof Error ? err.message : 'Unknown error';
|
|
61
88
|
console.error(` Error: Could not reach ${apiUrl} (${msg})`);
|
|
62
89
|
process.exit(1);
|
|
90
|
+
throw new Error();
|
|
63
91
|
}
|
|
64
|
-
|
|
92
|
+
if (projects.length === 0) {
|
|
93
|
+
console.error(' Error: No projects found for this token');
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
const chosen = await resolveTargetProject(projects, preferredProjectId);
|
|
97
|
+
writeHookFiles({ projectId: chosen.id, token, apiUrl, agentBin });
|
|
65
98
|
console.log(`
|
|
66
|
-
Done!
|
|
67
|
-
|
|
99
|
+
Done! "${chosen.name}" is wired to this directory.
|
|
100
|
+
Run \`claude\` here and every session streams into Orquesta automatically.
|
|
68
101
|
|
|
69
|
-
Dashboard: ${apiUrl}/dashboard/projects/${
|
|
102
|
+
Dashboard: ${apiUrl}/dashboard/projects/${chosen.id}
|
|
70
103
|
`);
|
|
71
104
|
}
|
|
72
105
|
export function writeHookFiles(opts) {
|
|
@@ -123,4 +156,64 @@ export function writeHookFiles(opts) {
|
|
|
123
156
|
return false;
|
|
124
157
|
}
|
|
125
158
|
}
|
|
159
|
+
export function readHookConfig(cwd = process.cwd()) {
|
|
160
|
+
try {
|
|
161
|
+
const p = path.join(cwd, '.orquesta.json');
|
|
162
|
+
if (!fs.existsSync(p))
|
|
163
|
+
return null;
|
|
164
|
+
const data = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
165
|
+
if (!data.projectId)
|
|
166
|
+
return null;
|
|
167
|
+
return { projectId: data.projectId, apiUrl: data.apiUrl };
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
export function disableHooks(cwd = process.cwd()) {
|
|
174
|
+
console.log('\n Disabling Orquesta hook for this directory...\n');
|
|
175
|
+
let changed = false;
|
|
176
|
+
const settingsPath = path.join(cwd, '.claude', 'settings.json');
|
|
177
|
+
if (fs.existsSync(settingsPath)) {
|
|
178
|
+
try {
|
|
179
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
180
|
+
if (settings.hooks && typeof settings.hooks === 'object') {
|
|
181
|
+
for (const event of Object.keys(settings.hooks)) {
|
|
182
|
+
const before = settings.hooks[event];
|
|
183
|
+
if (!Array.isArray(before))
|
|
184
|
+
continue;
|
|
185
|
+
const after = before.filter((e) => !e.hooks?.some((h) => h.command?.includes('orquesta-agent hook')));
|
|
186
|
+
if (after.length !== before.length)
|
|
187
|
+
changed = true;
|
|
188
|
+
if (after.length === 0)
|
|
189
|
+
delete settings.hooks[event];
|
|
190
|
+
else
|
|
191
|
+
settings.hooks[event] = after;
|
|
192
|
+
}
|
|
193
|
+
if (Object.keys(settings.hooks).length === 0)
|
|
194
|
+
delete settings.hooks;
|
|
195
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
196
|
+
if (changed)
|
|
197
|
+
console.log(' Removed Orquesta hooks from .claude/settings.json');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
console.warn(' \x1b[33m⚠ Could not parse .claude/settings.json — left untouched.\x1b[0m');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const orquestaJson = path.join(cwd, '.orquesta.json');
|
|
205
|
+
if (fs.existsSync(orquestaJson)) {
|
|
206
|
+
try {
|
|
207
|
+
fs.unlinkSync(orquestaJson);
|
|
208
|
+
changed = true;
|
|
209
|
+
console.log(' Removed .orquesta.json');
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
console.warn(' \x1b[33m⚠ Could not remove .orquesta.json.\x1b[0m');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
console.log(changed
|
|
216
|
+
? '\n Done. Claude Code runs in this directory no longer report to Orquesta.\n'
|
|
217
|
+
: '\n Nothing to do — no Orquesta hook was configured here.\n');
|
|
218
|
+
}
|
|
126
219
|
//# sourceMappingURL=hook-init.js.map
|
|
@@ -4,7 +4,7 @@ import * as fs from 'fs';
|
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import { configManager } from '../core/config/config-manager.js';
|
|
6
6
|
import { syncOrquestaConfigs, fetchOrquestaProjects } from '../orquesta/config-sync.js';
|
|
7
|
-
import { writeHookFiles } from '../orquesta/hook-init.js';
|
|
7
|
+
import { writeHookFiles, readHookConfig } from '../orquesta/hook-init.js';
|
|
8
8
|
import { scanProviders, toEndpointConfig } from '../core/config/auto-detect.js';
|
|
9
9
|
const ORQUESTA_API_URL = process.env['ORQUESTA_API_URL'] || 'https://getorquesta.com';
|
|
10
10
|
export function needsFirstRunSetup() {
|
|
@@ -283,5 +283,19 @@ export function showConnectionStatus() {
|
|
|
283
283
|
console.log(chalk.dim(` Connected: ${orquestaConfig.connectedAt ? new Date(orquestaConfig.connectedAt).toLocaleString() : 'Unknown'}`));
|
|
284
284
|
console.log(chalk.dim(` Last sync: ${orquestaConfig.lastSyncAt ? new Date(orquestaConfig.lastSyncAt).toLocaleString() : 'Never'}`));
|
|
285
285
|
console.log(chalk.dim(` Auto-sync: ${orquestaConfig.autoSync !== false ? 'Enabled' : 'Disabled'}`));
|
|
286
|
+
const hook = readHookConfig();
|
|
287
|
+
console.log();
|
|
288
|
+
if (hook) {
|
|
289
|
+
const sameAsConnected = hook.projectId === orquestaConfig.projectId;
|
|
290
|
+
const name = sameAsConnected && orquestaConfig.projectName ? orquestaConfig.projectName : hook.projectId;
|
|
291
|
+
console.log(chalk.green('Claude Code hook: enabled in this directory'));
|
|
292
|
+
console.log(chalk.dim(` Streaming into: ${name}`));
|
|
293
|
+
console.log(chalk.dim(` Project ID: ${hook.projectId}`));
|
|
294
|
+
console.log(chalk.dim(` Disable with: orquesta --disable-hook`));
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
console.log(chalk.yellow('Claude Code hook: not enabled in this directory'));
|
|
298
|
+
console.log(chalk.dim(` Enable with: orquesta --init`));
|
|
299
|
+
}
|
|
286
300
|
}
|
|
287
301
|
//# sourceMappingURL=first-run-setup.js.map
|