@orchagent/cli 0.3.99 → 0.3.101

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.
@@ -8,6 +8,7 @@ const promises_1 = __importDefault(require("readline/promises"));
8
8
  const chalk_1 = __importDefault(require("chalk"));
9
9
  const config_1 = require("../lib/config");
10
10
  const api_1 = require("../lib/api");
11
+ const agent_ref_1 = require("../lib/agent-ref");
11
12
  const errors_1 = require("../lib/errors");
12
13
  const analytics_1 = require("../lib/analytics");
13
14
  const output_1 = require("../lib/output");
@@ -34,7 +35,7 @@ async function promptText(message) {
34
35
  }
35
36
  function registerTransferCommand(program) {
36
37
  program
37
- .command('transfer <agent-name>')
38
+ .command('transfer <agent>')
38
39
  .description('Transfer an agent to another workspace')
39
40
  .requiredOption('--to <workspace-slug>', 'Target workspace slug')
40
41
  .option('-w, --workspace <workspace-slug>', 'Source workspace slug (defaults to active workspace)')
@@ -43,12 +44,13 @@ function registerTransferCommand(program) {
43
44
  .option('--json', 'Output result as JSON')
44
45
  .addHelpText('after', `
45
46
  Examples:
46
- orch transfer my-agent --to team-workspace # Transfer agent to another workspace
47
+ orch transfer my-agent --to team-workspace # Transfer by name
48
+ orch transfer my-org/my-agent --to team-workspace # Transfer using org/agent format
47
49
  orch transfer my-agent --to team-workspace --workspace my-team
48
50
  orch transfer my-agent --to team-workspace --dry-run # Preview transfer
49
51
  orch transfer my-agent --to team-workspace --yes # Skip confirmation
50
52
  `)
51
- .action(async (agentName, options) => {
53
+ .action(async (agentArg, options) => {
52
54
  const write = (message) => {
53
55
  if (!options.json)
54
56
  process.stdout.write(message);
@@ -58,6 +60,14 @@ Examples:
58
60
  if (!config.apiKey) {
59
61
  throw new errors_1.CliError('Not logged in. Run `orchagent login` first.');
60
62
  }
63
+ // Parse org/agent[@version] or bare agent name
64
+ const parsed = (0, agent_ref_1.parseAgentRef)(agentArg);
65
+ const agentName = parsed.agent;
66
+ // If org was provided via org/agent format, use it as source workspace
67
+ // --workspace flag takes precedence if both are given
68
+ if (parsed.org && options.workspace && parsed.org !== options.workspace) {
69
+ throw new errors_1.CliError(`Conflicting source workspace: '${parsed.org}' (from agent ref) vs '${options.workspace}' (from --workspace flag).`);
70
+ }
61
71
  write('Finding agent and workspaces...\n');
62
72
  // Fetch workspace list first (needed to resolve source/target IDs).
63
73
  const workspacesResponse = await (0, api_1.request)(config, 'GET', '/workspaces');
@@ -66,8 +76,8 @@ Examples:
66
76
  if (!targetWorkspace) {
67
77
  throw new errors_1.CliError(`Workspace '${options.to}' not found. Run \`orchagent workspace list\` to see available workspaces.`);
68
78
  }
69
- // Resolve source workspace (optional). If set, list agents from that workspace.
70
- const sourceWorkspaceSlug = options.workspace ?? configFile.workspace;
79
+ // Resolve source workspace: --workspace flag > org from ref > config workspace
80
+ const sourceWorkspaceSlug = options.workspace ?? parsed.org ?? configFile.workspace;
71
81
  const sourceWorkspace = sourceWorkspaceSlug
72
82
  ? workspacesResponse.workspaces.find((w) => w.slug === sourceWorkspaceSlug)
73
83
  : null;
@@ -27,7 +27,21 @@ function registerTreeCommand(program) {
27
27
  throw new errors_1.CliError('Missing org. Use org/agent format or set default org.');
28
28
  }
29
29
  const { agent, version } = parsed;
30
- const tree = await (0, api_1.request)(config, 'GET', `/agents/${org}/${agent}/${version}/tree`);
30
+ // Public-first fallback: try public tree endpoint (works for any public
31
+ // agent regardless of caller context), then fall back to authenticated
32
+ // endpoint with workspace header for private agents. Matches the pattern
33
+ // used by info/fork/estimate commands. (T12-04)
34
+ let tree;
35
+ try {
36
+ tree = await (0, api_1.publicRequest)(config, `/public/agents/${org}/${agent}/${version}/tree`);
37
+ }
38
+ catch (err) {
39
+ if (!(err instanceof api_1.ApiError) || err.status !== 404)
40
+ throw err;
41
+ // Public endpoint returned 404 — try authenticated endpoint for private agents
42
+ const workspaceId = await (0, api_1.resolveWorkspaceIdForOrg)(config, org);
43
+ tree = await (0, api_1.request)(config, 'GET', `/agents/${org}/${agent}/${version}/tree`, workspaceId ? { headers: { 'X-Workspace-Id': workspaceId } } : undefined);
44
+ }
31
45
  if (options.json) {
32
46
  console.log(JSON.stringify(tree, null, 2));
33
47
  return;
package/dist/lib/api.js CHANGED
@@ -284,8 +284,14 @@ async function updateOrg(config, payload) {
284
284
  async function getPublicAgent(config, org, agent, version) {
285
285
  return publicRequest(config, `/public/agents/${org}/${agent}/${version}`);
286
286
  }
287
- async function getAgentCostEstimate(config, org, agent, version) {
288
- return publicRequest(config, `/public/agents/${org}/${agent}/${version}/cost-estimate`);
287
+ async function getAgentCostEstimate(config, org, agent, version, workspaceId) {
288
+ const path = `/public/agents/${org}/${agent}/${version}/cost-estimate`;
289
+ if (workspaceId && config.apiKey) {
290
+ return request(config, 'GET', path, {
291
+ headers: { 'X-Workspace-Id': workspaceId },
292
+ });
293
+ }
294
+ return publicRequest(config, path);
289
295
  }
290
296
  async function listMyAgents(config, workspaceId) {
291
297
  const headers = {};
@@ -402,15 +408,16 @@ async function resolveWorkspaceIdForOrg(config, orgSlug) {
402
408
  /**
403
409
  * Download a tool bundle for a private agent using authenticated endpoint.
404
410
  */
405
- async function downloadCodeBundleAuthenticated(config, agentId) {
411
+ async function downloadCodeBundleAuthenticated(config, agentId, workspaceId) {
406
412
  if (!config.apiKey) {
407
413
  throw new ApiError('Missing API key for authenticated bundle download', 401);
408
414
  }
409
- const response = await safeFetch(`${config.apiUrl.replace(/\/$/, '')}/agents/${agentId}/bundle`, {
410
- headers: {
411
- Authorization: `Bearer ${config.apiKey}`,
412
- },
413
- });
415
+ const headers = {
416
+ Authorization: `Bearer ${config.apiKey}`,
417
+ };
418
+ if (workspaceId)
419
+ headers['X-Workspace-Id'] = workspaceId;
420
+ const response = await safeFetch(`${config.apiUrl.replace(/\/$/, '')}/agents/${agentId}/bundle`, { headers });
414
421
  if (!response.ok) {
415
422
  const text = await response.text();
416
423
  let message = response.statusText;
@@ -548,12 +555,21 @@ async function setWorkspaceDefaultEnvironment(config, workspaceId, environmentId
548
555
  headers: { 'Content-Type': 'application/json' },
549
556
  });
550
557
  }
551
- async function listAgentKeys(config, agentId) {
552
- return request(config, 'GET', `/agents/${agentId}/keys`);
558
+ async function listAgentKeys(config, agentId, workspaceId) {
559
+ const headers = {};
560
+ if (workspaceId)
561
+ headers['X-Workspace-Id'] = workspaceId;
562
+ return request(config, 'GET', `/agents/${agentId}/keys`, { headers });
553
563
  }
554
- async function createAgentKey(config, agentId) {
555
- return request(config, 'POST', `/agents/${agentId}/keys`);
564
+ async function createAgentKey(config, agentId, workspaceId) {
565
+ const headers = {};
566
+ if (workspaceId)
567
+ headers['X-Workspace-Id'] = workspaceId;
568
+ return request(config, 'POST', `/agents/${agentId}/keys`, { headers });
556
569
  }
557
- async function deleteAgentKey(config, agentId, keyId) {
558
- return request(config, 'DELETE', `/agents/${agentId}/keys/${keyId}`);
570
+ async function deleteAgentKey(config, agentId, keyId, workspaceId) {
571
+ const headers = {};
572
+ if (workspaceId)
573
+ headers['X-Workspace-Id'] = workspaceId;
574
+ return request(config, 'DELETE', `/agents/${agentId}/keys/${keyId}`, { headers });
559
575
  }
@@ -137,18 +137,23 @@ async function createCodeBundle(sourceDir, outputPath, options = {}) {
137
137
  const output = (0, fs_1.createWriteStream)(outputPath);
138
138
  const archive = (0, archiver_1.default)('zip', { zlib: { level: 9 } });
139
139
  let fileCount = 0;
140
+ const files = [];
140
141
  output.on('close', () => {
141
142
  resolve({
142
143
  path: outputPath,
143
144
  sizeBytes: archive.pointer(),
144
145
  fileCount,
146
+ files,
145
147
  });
146
148
  });
147
149
  archive.on('error', (err) => {
148
150
  reject(err);
149
151
  });
150
- archive.on('entry', () => {
152
+ archive.on('entry', (entry) => {
151
153
  fileCount++;
154
+ if (entry.name) {
155
+ files.push(entry.name);
156
+ }
152
157
  });
153
158
  archive.pipe(output);
154
159
  // Add directory contents with exclusions
@@ -235,6 +240,7 @@ async function previewBundle(sourceDir, options = {}) {
235
240
  totalSizeBytes,
236
241
  entrypoint,
237
242
  excludePatterns,
243
+ files,
238
244
  };
239
245
  }
240
246
  /**
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveOrg = resolveOrg;
4
+ exports.resolveAgentContext = resolveAgentContext;
5
+ const agent_ref_1 = require("./agent-ref");
6
+ const config_1 = require("./config");
7
+ const api_1 = require("./api");
8
+ const errors_1 = require("./errors");
9
+ /**
10
+ * Resolve the org from a parsed AgentRef using the standard fallback chain:
11
+ * 1. Explicit org from ref (org/agent@version)
12
+ * 2. Workspace from config file
13
+ * 3. defaultOrg from resolved config
14
+ *
15
+ * Throws CliError if no org can be determined.
16
+ */
17
+ async function resolveOrg(parsed, config, options) {
18
+ if (parsed.org)
19
+ return parsed.org;
20
+ const configFile = await (0, config_1.loadConfig)();
21
+ const org = configFile.workspace ?? config.defaultOrg;
22
+ if (!org) {
23
+ throw new errors_1.CliError(options?.missingOrgMessage ??
24
+ 'Missing org. Use org/agent format or set default org.');
25
+ }
26
+ return org;
27
+ }
28
+ /**
29
+ * Central agent-reference resolution pipeline used by all commands.
30
+ *
31
+ * Takes a raw agent reference string (e.g., "org/agent@v2", "agent", "agent@latest")
32
+ * and resolves it to a full context with org, agent name, version, and workspace ID.
33
+ *
34
+ * Resolution steps:
35
+ * 1. Parse the ref string into { org?, agent, version }
36
+ * 2. Resolve org via fallback chain: ref → config workspace → defaultOrg
37
+ * 3. Resolve workspace ID for team workspace context (optional)
38
+ *
39
+ * @example
40
+ * const ctx = await resolveAgentContext('acme/my-agent@v2', config)
41
+ * // ctx = { org: 'acme', agent: 'my-agent', version: 'v2', workspaceId: 'ws-123' }
42
+ *
43
+ * @example
44
+ * const ctx = await resolveAgentContext('my-agent', config)
45
+ * // ctx = { org: 'default-org', agent: 'my-agent', version: 'latest', workspaceId: undefined }
46
+ */
47
+ async function resolveAgentContext(agentRefString, config, options) {
48
+ const parsed = (0, agent_ref_1.parseAgentRef)(agentRefString);
49
+ const org = await resolveOrg(parsed, config, {
50
+ missingOrgMessage: options?.missingOrgMessage,
51
+ });
52
+ let workspaceId;
53
+ if (!options?.skipWorkspaceResolution) {
54
+ workspaceId = await (0, api_1.resolveWorkspaceIdForOrg)(config, org);
55
+ }
56
+ return {
57
+ org,
58
+ agent: parsed.agent,
59
+ version: parsed.version,
60
+ workspaceId,
61
+ };
62
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchagent/cli",
3
- "version": "0.3.99",
3
+ "version": "0.3.101",
4
4
  "description": "Command-line interface for orchagent — deploy and run AI agents for your team",
5
5
  "license": "MIT",
6
6
  "author": "orchagent <hello@orchagent.io>",