@orchagent/cli 0.3.55 → 0.3.56
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/commands/transfer.js +119 -35
- package/package.json +1 -1
|
@@ -11,6 +11,18 @@ const api_1 = require("../lib/api");
|
|
|
11
11
|
const errors_1 = require("../lib/errors");
|
|
12
12
|
const analytics_1 = require("../lib/analytics");
|
|
13
13
|
const output_1 = require("../lib/output");
|
|
14
|
+
function getTransferAuthError(err) {
|
|
15
|
+
if (!(err instanceof api_1.ApiError) || err.status !== 403) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const message = err.message.toLowerCase();
|
|
19
|
+
if (message.includes('personal workspace session key') ||
|
|
20
|
+
message.includes('user authentication') ||
|
|
21
|
+
message.includes('clerk jwt')) {
|
|
22
|
+
return new errors_1.CliError('Transfer requires a user session key. Run `orch login` (browser sign-in, without `--key`) and retry.');
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
14
26
|
async function promptText(message) {
|
|
15
27
|
const rl = promises_1.default.createInterface({
|
|
16
28
|
input: process.stdin,
|
|
@@ -25,31 +37,49 @@ function registerTransferCommand(program) {
|
|
|
25
37
|
.command('transfer <agent-name>')
|
|
26
38
|
.description('Transfer an agent to another workspace')
|
|
27
39
|
.requiredOption('--to <workspace-slug>', 'Target workspace slug')
|
|
40
|
+
.option('-w, --workspace <workspace-slug>', 'Source workspace slug (defaults to active workspace)')
|
|
28
41
|
.option('-y, --yes', 'Skip confirmation prompt')
|
|
29
42
|
.option('--dry-run', 'Show what would be transferred without making changes')
|
|
30
43
|
.option('--json', 'Output result as JSON')
|
|
31
44
|
.addHelpText('after', `
|
|
32
45
|
Examples:
|
|
33
46
|
orch transfer my-agent --to team-workspace # Transfer agent to another workspace
|
|
47
|
+
orch transfer my-agent --to team-workspace --workspace my-team
|
|
34
48
|
orch transfer my-agent --to team-workspace --dry-run # Preview transfer
|
|
35
49
|
orch transfer my-agent --to team-workspace --yes # Skip confirmation
|
|
36
50
|
`)
|
|
37
51
|
.action(async (agentName, options) => {
|
|
52
|
+
const write = (message) => {
|
|
53
|
+
if (!options.json)
|
|
54
|
+
process.stdout.write(message);
|
|
55
|
+
};
|
|
38
56
|
const config = await (0, config_1.getResolvedConfig)();
|
|
57
|
+
const configFile = await (0, config_1.loadConfig)();
|
|
39
58
|
if (!config.apiKey) {
|
|
40
59
|
throw new errors_1.CliError('Not logged in. Run `orchagent login` first.');
|
|
41
60
|
}
|
|
42
|
-
|
|
43
|
-
// Fetch
|
|
44
|
-
const
|
|
45
|
-
(0, api_1.request)(config, 'GET', '/workspaces'),
|
|
46
|
-
(0, api_1.listMyAgents)(config),
|
|
47
|
-
]);
|
|
61
|
+
write('Finding agent and workspaces...\n');
|
|
62
|
+
// Fetch workspace list first (needed to resolve source/target IDs).
|
|
63
|
+
const workspacesResponse = await (0, api_1.request)(config, 'GET', '/workspaces');
|
|
48
64
|
// Find the target workspace by slug
|
|
49
65
|
const targetWorkspace = workspacesResponse.workspaces.find((w) => w.slug === options.to);
|
|
50
66
|
if (!targetWorkspace) {
|
|
51
67
|
throw new errors_1.CliError(`Workspace '${options.to}' not found. Run \`orchagent workspace list\` to see available workspaces.`);
|
|
52
68
|
}
|
|
69
|
+
// Resolve source workspace (optional). If set, list agents from that workspace.
|
|
70
|
+
const sourceWorkspaceSlug = options.workspace ?? configFile.workspace;
|
|
71
|
+
const sourceWorkspace = sourceWorkspaceSlug
|
|
72
|
+
? workspacesResponse.workspaces.find((w) => w.slug === sourceWorkspaceSlug)
|
|
73
|
+
: null;
|
|
74
|
+
if (sourceWorkspaceSlug && !sourceWorkspace) {
|
|
75
|
+
throw new errors_1.CliError(`Source workspace '${sourceWorkspaceSlug}' not found. Run \`orchagent workspace list\` to see available workspaces.`);
|
|
76
|
+
}
|
|
77
|
+
if (sourceWorkspace && sourceWorkspace.id === targetWorkspace.id) {
|
|
78
|
+
throw new errors_1.CliError('Source and target workspaces must be different.');
|
|
79
|
+
}
|
|
80
|
+
const agents = sourceWorkspace
|
|
81
|
+
? await (0, api_1.request)(config, 'GET', `/agents?workspace_id=${encodeURIComponent(sourceWorkspace.id)}`)
|
|
82
|
+
: (await (0, api_1.listMyAgents)(config));
|
|
53
83
|
// Find the agent by name
|
|
54
84
|
const matching = agents.filter((a) => a.name === agentName);
|
|
55
85
|
if (matching.length === 0) {
|
|
@@ -58,64 +88,118 @@ Examples:
|
|
|
58
88
|
// Use the most recent version to get the agent ID
|
|
59
89
|
const agent = matching.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0];
|
|
60
90
|
// Check transfer eligibility
|
|
61
|
-
|
|
91
|
+
let check;
|
|
92
|
+
try {
|
|
93
|
+
check = await (0, api_1.checkAgentTransfer)(config, agent.id, targetWorkspace.id);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
const authErr = getTransferAuthError(err);
|
|
97
|
+
if (authErr)
|
|
98
|
+
throw authErr;
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
62
101
|
// Show transfer summary
|
|
63
|
-
|
|
64
|
-
|
|
102
|
+
write(`\n${chalk_1.default.bold('Agent:')} ${agent.name}\n`);
|
|
103
|
+
write(`${chalk_1.default.bold('Target workspace:')} ${targetWorkspace.name} (${targetWorkspace.slug})\n`);
|
|
65
104
|
const { details } = check;
|
|
66
|
-
|
|
105
|
+
write(`${chalk_1.default.bold('Versions:')} ${details.version_count}\n`);
|
|
67
106
|
if (details.grants_count > 0) {
|
|
68
|
-
|
|
107
|
+
write(`${chalk_1.default.bold('Grants to revoke:')} ${details.grants_count}\n`);
|
|
69
108
|
}
|
|
70
109
|
if (details.keys_count > 0) {
|
|
71
|
-
|
|
110
|
+
write(`${chalk_1.default.bold('Keys to delete:')} ${details.keys_count}\n`);
|
|
72
111
|
}
|
|
73
112
|
if (details.schedules_count > 0) {
|
|
74
|
-
|
|
113
|
+
write(`${chalk_1.default.bold('Schedules to disable:')} ${details.schedules_count}\n`);
|
|
75
114
|
}
|
|
76
|
-
|
|
115
|
+
write('\n');
|
|
77
116
|
// Show warnings
|
|
78
117
|
if (check.warnings.length > 0) {
|
|
79
118
|
for (const warning of check.warnings) {
|
|
80
|
-
|
|
119
|
+
write(chalk_1.default.yellow(`Warning: ${warning}\n`));
|
|
81
120
|
}
|
|
82
|
-
|
|
121
|
+
write('\n');
|
|
83
122
|
}
|
|
84
123
|
// Show blockers and exit if any
|
|
85
124
|
if (check.blockers.length > 0) {
|
|
125
|
+
if (options.json) {
|
|
126
|
+
(0, output_1.printJson)({
|
|
127
|
+
can_transfer: false,
|
|
128
|
+
blockers: check.blockers,
|
|
129
|
+
warnings: check.warnings,
|
|
130
|
+
details,
|
|
131
|
+
agent_name: agent.name,
|
|
132
|
+
target_workspace: {
|
|
133
|
+
id: targetWorkspace.id,
|
|
134
|
+
slug: targetWorkspace.slug,
|
|
135
|
+
name: targetWorkspace.name,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
86
140
|
for (const blocker of check.blockers) {
|
|
87
|
-
|
|
141
|
+
write(chalk_1.default.red(`Blocker: ${blocker}\n`));
|
|
88
142
|
}
|
|
89
|
-
|
|
143
|
+
write(chalk_1.default.red('\nTransfer cannot proceed due to blockers above.\n'));
|
|
90
144
|
process.exit(1);
|
|
91
145
|
}
|
|
92
146
|
// Handle dry-run
|
|
93
147
|
if (options.dryRun) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
148
|
+
if (options.json) {
|
|
149
|
+
(0, output_1.printJson)({
|
|
150
|
+
dry_run: true,
|
|
151
|
+
can_transfer: true,
|
|
152
|
+
agent_name: agent.name,
|
|
153
|
+
target_workspace: {
|
|
154
|
+
id: targetWorkspace.id,
|
|
155
|
+
slug: targetWorkspace.slug,
|
|
156
|
+
name: targetWorkspace.name,
|
|
157
|
+
},
|
|
158
|
+
details,
|
|
159
|
+
warnings: check.warnings,
|
|
160
|
+
blockers: check.blockers,
|
|
161
|
+
});
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
write('DRY RUN - No changes will be made\n\n');
|
|
165
|
+
write(`Would transfer: ${agent.name} (${details.version_count} version(s))\n`);
|
|
166
|
+
write(`Target: ${targetWorkspace.name} (${targetWorkspace.slug})\n`);
|
|
97
167
|
if (details.grants_count > 0 || details.keys_count > 0 || details.schedules_count > 0) {
|
|
98
|
-
|
|
168
|
+
write(chalk_1.default.yellow(`Cleanup: ${details.grants_count} grant(s) revoked, ${details.keys_count} key(s) deleted, ${details.schedules_count} schedule(s) disabled\n`));
|
|
99
169
|
}
|
|
100
|
-
|
|
170
|
+
write('\nNo changes made (dry run)\n');
|
|
101
171
|
return;
|
|
102
172
|
}
|
|
103
173
|
// Prompt for confirmation
|
|
104
174
|
if (!options.yes) {
|
|
105
|
-
|
|
106
|
-
|
|
175
|
+
write(chalk_1.default.yellow('This will transfer the agent and all its versions to the target workspace.\n'));
|
|
176
|
+
write(chalk_1.default.yellow('Existing grants, keys, and schedules in the source workspace will be cleaned up.\n\n'));
|
|
107
177
|
const confirmName = await promptText(`Type "${agent.name}" to confirm transfer: `);
|
|
108
178
|
if (confirmName !== agent.name) {
|
|
109
|
-
|
|
179
|
+
if (options.json) {
|
|
180
|
+
(0, output_1.printJson)({ cancelled: true, reason: 'confirmation_mismatch' });
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
write(chalk_1.default.red('\nTransfer cancelled. Name did not match.\n'));
|
|
184
|
+
}
|
|
110
185
|
process.exit(1);
|
|
111
186
|
}
|
|
112
187
|
}
|
|
113
188
|
// Perform transfer
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
189
|
+
write('Transferring agent...\n');
|
|
190
|
+
let result;
|
|
191
|
+
try {
|
|
192
|
+
result = await (0, api_1.transferAgent)(config, agent.id, {
|
|
193
|
+
target_workspace_id: targetWorkspace.id,
|
|
194
|
+
confirmation_name: agent.name,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
const authErr = getTransferAuthError(err);
|
|
199
|
+
if (authErr)
|
|
200
|
+
throw authErr;
|
|
201
|
+
throw err;
|
|
202
|
+
}
|
|
119
203
|
await (0, analytics_1.track)('cli_transfer', {
|
|
120
204
|
agent_name: result.agent_name,
|
|
121
205
|
versions_transferred: result.versions_transferred,
|
|
@@ -125,11 +209,11 @@ Examples:
|
|
|
125
209
|
(0, output_1.printJson)(result);
|
|
126
210
|
return;
|
|
127
211
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
212
|
+
write(`\n${chalk_1.default.green('+')} Transferred ${result.agent_name} (${result.versions_transferred} version(s))\n`);
|
|
213
|
+
write(` From: ${result.source_workspace.name} (${result.source_workspace.slug})\n`);
|
|
214
|
+
write(` To: ${result.target_workspace.name} (${result.target_workspace.slug})\n`);
|
|
131
215
|
if (result.cleanup.grants_revoked > 0 || result.cleanup.keys_deleted > 0 || result.cleanup.schedules_disabled > 0) {
|
|
132
|
-
|
|
216
|
+
write(chalk_1.default.gray(`\nCleanup: ${result.cleanup.grants_revoked} grant(s) revoked, ${result.cleanup.keys_deleted} key(s) deleted, ${result.cleanup.schedules_disabled} schedule(s) disabled\n`));
|
|
133
217
|
}
|
|
134
218
|
});
|
|
135
219
|
}
|
package/package.json
CHANGED