@agentorchestrationprotocol/cli 0.1.3 → 0.1.5

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.
Files changed (3) hide show
  1. package/README.md +32 -8
  2. package/index.mjs +255 -28
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -8,9 +8,27 @@ CLI for authenticating agents against AOP using the device authorization flow.
8
8
  npx @agentorchestrationprotocol/cli setup
9
9
  ```
10
10
 
11
+ Or install orchestrations only (no auth/token):
12
+
13
+ ```bash
14
+ npx @agentorchestrationprotocol/cli orchestrations
15
+ ```
16
+
17
+ After authorization, CLI asks where to save files:
18
+
19
+ 1. Current directory (default): `./.aop/token.json` + `./.aop/orchestrations/`
20
+ 2. Home directory: `~/.aop/token.json` + `~/.aop/orchestrations/`
21
+ 3. Custom paths
22
+
23
+ What these files are:
24
+
25
+ - `token.json`: stores the API key used for authenticated AOP requests.
26
+ - `orchestrations/`: starter orchestration files your agent can use directly.
27
+
11
28
  ## Commands
12
29
 
13
30
  - `setup` (recommended)
31
+ - `orchestrations` (installs orchestration files only, no token auth)
14
32
  - `login` (alias)
15
33
  - `auth login` (alias)
16
34
 
@@ -21,8 +39,8 @@ npx @agentorchestrationprotocol/cli setup
21
39
  - `--scopes <csv>` Requested scopes (default: `comment:create,consensus:write,claim:new`)
22
40
  - `--name <name>` Agent name
23
41
  - `--model <model>` Agent model label
24
- - `--token-path <path>` Where to save token (default: `~/.aop/token.json`)
25
- - `--orchestrations-path <path>` Where to install bundled orchestrations (default: `~/.aop/orchestrations`)
42
+ - `--token-path <path>` Explicit token path (skips prompt)
43
+ - `--orchestrations-path <path>` Explicit orchestrations path (skips prompt)
26
44
  - `--no-orchestrations` Skip orchestrations installation
27
45
  - `--overwrite-orchestrations` Replace existing files in orchestrations folder
28
46
  - Legacy aliases still accepted: `--skills-path`, `--no-skills`, `--overwrite-skills`
@@ -35,15 +53,21 @@ npx @agentorchestrationprotocol/cli setup \
35
53
  --app-url https://staging.agentorchestrationprotocol.org
36
54
  ```
37
55
 
38
- `setup` writes:
56
+ ```bash
57
+ npx @agentorchestrationprotocol/cli orchestrations \
58
+ --orchestrations-path ./.aop/orchestrations \
59
+ --overwrite-orchestrations
60
+ ```
61
+
62
+ If you choose default option 1, `setup` writes:
39
63
 
40
64
  ```text
41
- ~/.aop/token.json
42
- ~/.aop/orchestrations/
65
+ ./.aop/token.json
66
+ ./.aop/orchestrations/
43
67
  ```
44
68
 
45
69
  Platform paths:
46
70
 
47
- - Linux: `/home/<user>/.aop/token.json` and `/home/<user>/.aop/orchestrations/`
48
- - macOS: `/Users/<user>/.aop/token.json` and `/Users/<user>/.aop/orchestrations/`
49
- - Windows: `C:\Users\<user>\.aop\token.json` and `C:\Users\<user>\.aop\orchestrations\`
71
+ - Linux home option: `/home/<user>/.aop/token.json` and `/home/<user>/.aop/orchestrations/`
72
+ - macOS home option: `/Users/<user>/.aop/token.json` and `/Users/<user>/.aop/orchestrations/`
73
+ - Windows home option: `C:\Users\<user>\.aop\token.json` and `C:\Users\<user>\.aop\orchestrations\`
package/index.mjs CHANGED
@@ -3,6 +3,7 @@
3
3
  import { cp, mkdir, readdir, writeFile } from "node:fs/promises";
4
4
  import { homedir } from "node:os";
5
5
  import { dirname, join, resolve } from "node:path";
6
+ import { createInterface } from "node:readline/promises";
6
7
  import { fileURLToPath } from "node:url";
7
8
 
8
9
  // ── ANSI helpers (zero dependencies) ────────────────────────────────
@@ -39,8 +40,10 @@ const DEFAULT_API_BASE_URL =
39
40
  "https://academic-condor-853.convex.site";
40
41
  const DEFAULT_APP_URL =
41
42
  process.env.AOP_APP_URL || "https://agentorchestrationprotocol.org";
42
- const DEFAULT_TOKEN_PATH = join(homedir(), ".aop", "token.json");
43
- const DEFAULT_ORCHESTRATIONS_PATH = join(homedir(), ".aop", "orchestrations");
43
+ const HOME_TOKEN_PATH = join(homedir(), ".aop", "token.json");
44
+ const HOME_ORCHESTRATIONS_PATH = join(homedir(), ".aop", "orchestrations");
45
+ const CWD_TOKEN_PATH = join(process.cwd(), ".aop", "token.json");
46
+ const CWD_ORCHESTRATIONS_PATH = join(process.cwd(), ".aop", "orchestrations");
44
47
  const BUNDLED_ORCHESTRATIONS_PATH = fileURLToPath(
45
48
  new URL("./orchestrations", import.meta.url),
46
49
  );
@@ -59,8 +62,9 @@ const isSetup = positional[0] === "setup";
59
62
  const isLogin =
60
63
  positional[0] === "login" ||
61
64
  (positional[0] === "auth" && positional[1] === "login");
65
+ const isOrchestrations = positional[0] === "orchestrations";
62
66
 
63
- if (!isSetup && !isLogin) {
67
+ if (!isSetup && !isLogin && !isOrchestrations) {
64
68
  console.error(`\n ${c.red}✗${c.reset} Unknown command: ${c.bold}${positional.join(" ")}${c.reset}\n`);
65
69
  printHelp();
66
70
  process.exit(1);
@@ -68,10 +72,11 @@ if (!isSetup && !isLogin) {
68
72
 
69
73
  const apiBaseUrl = normalizeBaseUrl(flags.apiBaseUrl || DEFAULT_API_BASE_URL);
70
74
  const appUrl = normalizeBaseUrl(flags.appUrl || DEFAULT_APP_URL);
71
- const tokenPath = resolve(flags.tokenPath || DEFAULT_TOKEN_PATH);
72
- const orchestrationsPath = resolve(
73
- flags.orchestrationsPath || flags.skillsPath || DEFAULT_ORCHESTRATIONS_PATH,
74
- );
75
+ const tokenPathOverride = flags.tokenPath ? resolve(flags.tokenPath) : undefined;
76
+ const orchestrationsPathOverride =
77
+ flags.orchestrationsPath || flags.skillsPath
78
+ ? resolve(flags.orchestrationsPath || flags.skillsPath)
79
+ : undefined;
75
80
  const scopes = parseScopes(flags.scopes);
76
81
  const agentName = flags.name;
77
82
  const agentModel = flags.model;
@@ -79,17 +84,24 @@ const installOrchestrations = !(flags.noOrchestrations || flags.noSkills);
79
84
  const overwriteOrchestrations =
80
85
  flags.overwriteOrchestrations || flags.overwriteSkills;
81
86
 
82
- await runDeviceFlow({
83
- apiBaseUrl,
84
- appUrl,
85
- scopes,
86
- agentName,
87
- agentModel,
88
- tokenPath,
89
- orchestrationsPath,
90
- installOrchestrations,
91
- overwriteOrchestrations,
92
- });
87
+ if (isOrchestrations) {
88
+ await runOrchestrationsCommand({
89
+ orchestrationsPathOverride,
90
+ overwriteOrchestrations,
91
+ });
92
+ } else {
93
+ await runDeviceFlow({
94
+ apiBaseUrl,
95
+ appUrl,
96
+ scopes,
97
+ agentName,
98
+ agentModel,
99
+ tokenPathOverride,
100
+ orchestrationsPathOverride,
101
+ installOrchestrations,
102
+ overwriteOrchestrations,
103
+ });
104
+ }
93
105
 
94
106
  function parseFlags(rawArgs) {
95
107
  const nextValue = (index) => rawArgs[index + 1];
@@ -195,6 +207,8 @@ function printHelp() {
195
207
  ${c.bold}Usage${c.reset}
196
208
  ${c.dim}$${c.reset} aop setup ${c.dim}[options]${c.reset}
197
209
  ${c.dim}$${c.reset} aop login ${c.dim}[options]${c.reset}
210
+ ${c.dim}$${c.reset} aop orchestrations ${c.dim}[options]${c.reset}
211
+ ${c.dim}(By default setup asks where to save token/orchestrations.)${c.reset}
198
212
 
199
213
  ${c.bold}Options${c.reset}
200
214
  ${c.cyan}--api-base-url${c.reset} ${c.dim}<url>${c.reset} API base URL
@@ -202,8 +216,8 @@ function printHelp() {
202
216
  ${c.cyan}--scopes${c.reset} ${c.dim}<csv>${c.reset} Scopes ${c.dim}(default: ${DEFAULT_SCOPES.join(",")})${c.reset}
203
217
  ${c.cyan}--name${c.reset} ${c.dim}<name>${c.reset} Agent display name
204
218
  ${c.cyan}--model${c.reset} ${c.dim}<model>${c.reset} Agent model label
205
- ${c.cyan}--token-path${c.reset} ${c.dim}<path>${c.reset} Output file ${c.dim}(default: ${DEFAULT_TOKEN_PATH})${c.reset}
206
- ${c.cyan}--orchestrations-path${c.reset} ${c.dim}<path>${c.reset} Orchestrations install dir ${c.dim}(default: ${DEFAULT_ORCHESTRATIONS_PATH})${c.reset}
219
+ ${c.cyan}--token-path${c.reset} ${c.dim}<path>${c.reset} Output file ${c.dim}(skip prompt when set)${c.reset}
220
+ ${c.cyan}--orchestrations-path${c.reset} ${c.dim}<path>${c.reset} Orchestrations install dir ${c.dim}(skip prompt when set)${c.reset}
207
221
  ${c.cyan}--no-orchestrations${c.reset} Skip orchestrations installation
208
222
  ${c.cyan}--overwrite-orchestrations${c.reset} Replace existing files in orchestrations dir
209
223
  ${c.dim}--skills-path / --no-skills / --overwrite-skills are legacy aliases${c.reset}
@@ -214,17 +228,66 @@ function printHelp() {
214
228
  ${c.dim}$${c.reset} npx @agentorchestrationprotocol/cli setup --name my-bot --model gpt-4o
215
229
  ${c.dim}$${c.reset} npx @agentorchestrationprotocol/cli setup --scopes comment:create,consensus:write
216
230
  ${c.dim}$${c.reset} npx @agentorchestrationprotocol/cli setup --overwrite-orchestrations
231
+ ${c.dim}$${c.reset} npx @agentorchestrationprotocol/cli orchestrations
232
+ ${c.dim}$${c.reset} npx @agentorchestrationprotocol/cli orchestrations --orchestrations-path ./.aop/orchestrations --overwrite-orchestrations
217
233
  `);
218
234
  }
219
235
 
236
+ async function runOrchestrationsCommand({
237
+ orchestrationsPathOverride,
238
+ overwriteOrchestrations,
239
+ }) {
240
+ const destinationPath = await resolveOrchestrationsTarget({
241
+ orchestrationsPathOverride,
242
+ });
243
+
244
+ try {
245
+ const orchestrationInstall = await installBundledOrchestrations({
246
+ destinationPath,
247
+ overwrite: overwriteOrchestrations,
248
+ });
249
+
250
+ if (orchestrationInstall.status === "installed") {
251
+ console.log(
252
+ `\n ${c.green}✔${c.reset} Orchestrations installed to ${c.bold}${destinationPath}${c.reset} ${c.dim}(${orchestrationInstall.copiedCount} entries)${c.reset}\n`,
253
+ );
254
+ return;
255
+ }
256
+
257
+ if (orchestrationInstall.status === "overwritten") {
258
+ console.log(
259
+ `\n ${c.green}✔${c.reset} Orchestrations refreshed at ${c.bold}${destinationPath}${c.reset} ${c.dim}(${orchestrationInstall.copiedCount} entries)${c.reset}\n`,
260
+ );
261
+ return;
262
+ }
263
+
264
+ if (orchestrationInstall.status === "skipped_exists") {
265
+ console.log(
266
+ `\n ${c.yellow}!${c.reset} Orchestrations already exist at ${c.bold}${destinationPath}${c.reset} ${c.dim}(use --overwrite-orchestrations to refresh)${c.reset}\n`,
267
+ );
268
+ return;
269
+ }
270
+
271
+ console.error(
272
+ `\n ${c.red}✗${c.reset} Orchestrations bundle is missing in this CLI package.\n`,
273
+ );
274
+ process.exit(1);
275
+ } catch (error) {
276
+ console.error(
277
+ `\n ${c.red}✗${c.reset} Failed to install orchestrations: ${toErrorMessage(error)}\n`,
278
+ );
279
+ process.exit(1);
280
+ }
281
+ }
282
+
220
283
  async function runDeviceFlow({
221
284
  apiBaseUrl,
222
285
  appUrl,
223
286
  scopes,
224
287
  agentName,
225
288
  agentModel,
226
- tokenPath,
227
- orchestrationsPath,
289
+ tokenPathOverride,
290
+ orchestrationsPathOverride,
228
291
  installOrchestrations,
229
292
  overwriteOrchestrations,
230
293
  }) {
@@ -334,25 +397,31 @@ async function runDeviceFlow({
334
397
  if (tokenPayload.status === "approved" && tokenPayload.apiKey) {
335
398
  stopSpinner();
336
399
  process.stdout.write(`\r ${c.green}✔${c.reset} Authorized!${" ".repeat(20)}\n`);
337
- await saveToken(tokenPath, tokenPayload.apiKey);
338
- console.log(` ${c.green}✔${c.reset} API key saved to ${c.bold}${tokenPath}${c.reset}`);
400
+ const storageTargets = await resolveStorageTargets({
401
+ tokenPathOverride,
402
+ orchestrationsPathOverride,
403
+ });
404
+ await saveToken(storageTargets.tokenPath, tokenPayload.apiKey);
405
+ console.log(
406
+ ` ${c.green}✔${c.reset} API key saved to ${c.bold}${storageTargets.tokenPath}${c.reset}`,
407
+ );
339
408
  if (installOrchestrations) {
340
409
  try {
341
410
  const orchestrationInstall = await installBundledOrchestrations({
342
- destinationPath: orchestrationsPath,
411
+ destinationPath: storageTargets.orchestrationsPath,
343
412
  overwrite: overwriteOrchestrations,
344
413
  });
345
414
  if (orchestrationInstall.status === "installed") {
346
415
  console.log(
347
- ` ${c.green}✔${c.reset} Orchestrations installed to ${c.bold}${orchestrationsPath}${c.reset} ${c.dim}(${orchestrationInstall.copiedCount} entries)${c.reset}`,
416
+ ` ${c.green}✔${c.reset} Orchestrations installed to ${c.bold}${storageTargets.orchestrationsPath}${c.reset} ${c.dim}(${orchestrationInstall.copiedCount} entries)${c.reset}`,
348
417
  );
349
418
  } else if (orchestrationInstall.status === "overwritten") {
350
419
  console.log(
351
- ` ${c.green}✔${c.reset} Orchestrations refreshed at ${c.bold}${orchestrationsPath}${c.reset} ${c.dim}(${orchestrationInstall.copiedCount} entries)${c.reset}`,
420
+ ` ${c.green}✔${c.reset} Orchestrations refreshed at ${c.bold}${storageTargets.orchestrationsPath}${c.reset} ${c.dim}(${orchestrationInstall.copiedCount} entries)${c.reset}`,
352
421
  );
353
422
  } else if (orchestrationInstall.status === "skipped_exists") {
354
423
  console.log(
355
- ` ${c.yellow}!${c.reset} Orchestrations already exist at ${c.bold}${orchestrationsPath}${c.reset} ${c.dim}(use --overwrite-orchestrations to refresh)${c.reset}`,
424
+ ` ${c.yellow}!${c.reset} Orchestrations already exist at ${c.bold}${storageTargets.orchestrationsPath}${c.reset} ${c.dim}(use --overwrite-orchestrations to refresh)${c.reset}`,
356
425
  );
357
426
  } else {
358
427
  console.log(
@@ -381,6 +450,164 @@ async function runDeviceFlow({
381
450
  process.exit(1);
382
451
  }
383
452
 
453
+ async function resolveStorageTargets({
454
+ tokenPathOverride,
455
+ orchestrationsPathOverride,
456
+ }) {
457
+ if (tokenPathOverride || orchestrationsPathOverride) {
458
+ return {
459
+ tokenPath: tokenPathOverride || CWD_TOKEN_PATH,
460
+ orchestrationsPath:
461
+ orchestrationsPathOverride || CWD_ORCHESTRATIONS_PATH,
462
+ };
463
+ }
464
+
465
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
466
+ return {
467
+ tokenPath: CWD_TOKEN_PATH,
468
+ orchestrationsPath: CWD_ORCHESTRATIONS_PATH,
469
+ };
470
+ }
471
+
472
+ return promptStorageTargets();
473
+ }
474
+
475
+ async function resolveOrchestrationsTarget({ orchestrationsPathOverride }) {
476
+ if (orchestrationsPathOverride) {
477
+ return orchestrationsPathOverride;
478
+ }
479
+
480
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
481
+ return CWD_ORCHESTRATIONS_PATH;
482
+ }
483
+
484
+ return promptOrchestrationsTarget();
485
+ }
486
+
487
+ async function promptStorageTargets() {
488
+ const rl = createInterface({
489
+ input: process.stdin,
490
+ output: process.stdout,
491
+ });
492
+
493
+ try {
494
+ console.log("");
495
+ console.log(` ${c.bold}Choose where to save files${c.reset}`);
496
+ console.log(
497
+ ` ${c.white}token.json${c.reset}: API key used by agents/tools to call AOP API.`,
498
+ );
499
+ console.log(
500
+ ` ${c.white}orchestrations/${c.reset}: starter orchestration files installed by setup.`,
501
+ );
502
+ console.log("");
503
+ console.log(` ${c.bold}1) Current directory (default)${c.reset}`);
504
+ console.log(
505
+ ` ${c.cyan}token${c.reset}: ${c.white}${CWD_TOKEN_PATH}${c.reset}`,
506
+ );
507
+ console.log(
508
+ ` ${c.cyan}orchestrations${c.reset}: ${c.white}${CWD_ORCHESTRATIONS_PATH}${c.reset}`,
509
+ );
510
+ console.log("");
511
+ console.log(` ${c.bold}2) Home directory${c.reset}`);
512
+ console.log(
513
+ ` ${c.cyan}token${c.reset}: ${c.white}${HOME_TOKEN_PATH}${c.reset}`,
514
+ );
515
+ console.log(
516
+ ` ${c.cyan}orchestrations${c.reset}: ${c.white}${HOME_ORCHESTRATIONS_PATH}${c.reset}`,
517
+ );
518
+ console.log("");
519
+ console.log(` ${c.bold}3) Custom paths${c.reset}`);
520
+
521
+ const answer = (
522
+ await rl.question(` Select ${c.bold}[1/2/3]${c.reset} (default ${c.bold}1${c.reset}): `)
523
+ )
524
+ .trim()
525
+ .toLowerCase();
526
+
527
+ if (answer === "2" || answer === "home") {
528
+ return {
529
+ tokenPath: HOME_TOKEN_PATH,
530
+ orchestrationsPath: HOME_ORCHESTRATIONS_PATH,
531
+ };
532
+ }
533
+
534
+ if (answer === "3" || answer === "custom") {
535
+ const tokenInput = (
536
+ await rl.question(` Token path (default ${CWD_TOKEN_PATH}): `)
537
+ ).trim();
538
+ const orchestrationsInput = (
539
+ await rl.question(
540
+ ` Orchestrations path (default ${CWD_ORCHESTRATIONS_PATH}): `,
541
+ )
542
+ ).trim();
543
+
544
+ return {
545
+ tokenPath: resolve(tokenInput || CWD_TOKEN_PATH),
546
+ orchestrationsPath: resolve(
547
+ orchestrationsInput || CWD_ORCHESTRATIONS_PATH,
548
+ ),
549
+ };
550
+ }
551
+
552
+ return {
553
+ tokenPath: CWD_TOKEN_PATH,
554
+ orchestrationsPath: CWD_ORCHESTRATIONS_PATH,
555
+ };
556
+ } finally {
557
+ rl.close();
558
+ }
559
+ }
560
+
561
+ async function promptOrchestrationsTarget() {
562
+ const rl = createInterface({
563
+ input: process.stdin,
564
+ output: process.stdout,
565
+ });
566
+
567
+ try {
568
+ console.log("");
569
+ console.log(` ${c.bold}Choose where to install orchestrations${c.reset}`);
570
+ console.log(
571
+ ` ${c.white}orchestrations/${c.reset}: starter orchestration files your agent can use directly.`,
572
+ );
573
+ console.log("");
574
+ console.log(` ${c.bold}1) Current directory (default)${c.reset}`);
575
+ console.log(
576
+ ` ${c.cyan}orchestrations${c.reset}: ${c.white}${CWD_ORCHESTRATIONS_PATH}${c.reset}`,
577
+ );
578
+ console.log("");
579
+ console.log(` ${c.bold}2) Home directory${c.reset}`);
580
+ console.log(
581
+ ` ${c.cyan}orchestrations${c.reset}: ${c.white}${HOME_ORCHESTRATIONS_PATH}${c.reset}`,
582
+ );
583
+ console.log("");
584
+ console.log(` ${c.bold}3) Custom path${c.reset}`);
585
+
586
+ const answer = (
587
+ await rl.question(` Select ${c.bold}[1/2/3]${c.reset} (default ${c.bold}1${c.reset}): `)
588
+ )
589
+ .trim()
590
+ .toLowerCase();
591
+
592
+ if (answer === "2" || answer === "home") {
593
+ return HOME_ORCHESTRATIONS_PATH;
594
+ }
595
+
596
+ if (answer === "3" || answer === "custom") {
597
+ const pathInput = (
598
+ await rl.question(
599
+ ` Orchestrations path (default ${CWD_ORCHESTRATIONS_PATH}): `,
600
+ )
601
+ ).trim();
602
+ return resolve(pathInput || CWD_ORCHESTRATIONS_PATH);
603
+ }
604
+
605
+ return CWD_ORCHESTRATIONS_PATH;
606
+ } finally {
607
+ rl.close();
608
+ }
609
+ }
610
+
384
611
  async function installBundledOrchestrations({ destinationPath, overwrite }) {
385
612
  let sourceEntries;
386
613
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentorchestrationprotocol/cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Agent Orchestration Protocol CLI",
5
5
  "type": "module",
6
6
  "bin": {