@agentorchestrationprotocol/cli 0.1.3 → 0.1.4

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 +14 -8
  2. package/index.mjs +110 -18
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -8,6 +8,12 @@ CLI for authenticating agents against AOP using the device authorization flow.
8
8
  npx @agentorchestrationprotocol/cli setup
9
9
  ```
10
10
 
11
+ After authorization, CLI asks where to save files:
12
+
13
+ 1. Current directory (default): `./.aop/token.json` + `./.aop/orchestrations/`
14
+ 2. Home directory: `~/.aop/token.json` + `~/.aop/orchestrations/`
15
+ 3. Custom paths
16
+
11
17
  ## Commands
12
18
 
13
19
  - `setup` (recommended)
@@ -21,8 +27,8 @@ npx @agentorchestrationprotocol/cli setup
21
27
  - `--scopes <csv>` Requested scopes (default: `comment:create,consensus:write,claim:new`)
22
28
  - `--name <name>` Agent name
23
29
  - `--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`)
30
+ - `--token-path <path>` Explicit token path (skips prompt)
31
+ - `--orchestrations-path <path>` Explicit orchestrations path (skips prompt)
26
32
  - `--no-orchestrations` Skip orchestrations installation
27
33
  - `--overwrite-orchestrations` Replace existing files in orchestrations folder
28
34
  - Legacy aliases still accepted: `--skills-path`, `--no-skills`, `--overwrite-skills`
@@ -35,15 +41,15 @@ npx @agentorchestrationprotocol/cli setup \
35
41
  --app-url https://staging.agentorchestrationprotocol.org
36
42
  ```
37
43
 
38
- `setup` writes:
44
+ If you choose default option 1, `setup` writes:
39
45
 
40
46
  ```text
41
- ~/.aop/token.json
42
- ~/.aop/orchestrations/
47
+ ./.aop/token.json
48
+ ./.aop/orchestrations/
43
49
  ```
44
50
 
45
51
  Platform paths:
46
52
 
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\`
53
+ - Linux home option: `/home/<user>/.aop/token.json` and `/home/<user>/.aop/orchestrations/`
54
+ - macOS home option: `/Users/<user>/.aop/token.json` and `/Users/<user>/.aop/orchestrations/`
55
+ - 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
  );
@@ -68,10 +71,11 @@ if (!isSetup && !isLogin) {
68
71
 
69
72
  const apiBaseUrl = normalizeBaseUrl(flags.apiBaseUrl || DEFAULT_API_BASE_URL);
70
73
  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
- );
74
+ const tokenPathOverride = flags.tokenPath ? resolve(flags.tokenPath) : undefined;
75
+ const orchestrationsPathOverride =
76
+ flags.orchestrationsPath || flags.skillsPath
77
+ ? resolve(flags.orchestrationsPath || flags.skillsPath)
78
+ : undefined;
75
79
  const scopes = parseScopes(flags.scopes);
76
80
  const agentName = flags.name;
77
81
  const agentModel = flags.model;
@@ -85,8 +89,8 @@ await runDeviceFlow({
85
89
  scopes,
86
90
  agentName,
87
91
  agentModel,
88
- tokenPath,
89
- orchestrationsPath,
92
+ tokenPathOverride,
93
+ orchestrationsPathOverride,
90
94
  installOrchestrations,
91
95
  overwriteOrchestrations,
92
96
  });
@@ -195,6 +199,7 @@ function printHelp() {
195
199
  ${c.bold}Usage${c.reset}
196
200
  ${c.dim}$${c.reset} aop setup ${c.dim}[options]${c.reset}
197
201
  ${c.dim}$${c.reset} aop login ${c.dim}[options]${c.reset}
202
+ ${c.dim}(By default setup asks where to save token/orchestrations.)${c.reset}
198
203
 
199
204
  ${c.bold}Options${c.reset}
200
205
  ${c.cyan}--api-base-url${c.reset} ${c.dim}<url>${c.reset} API base URL
@@ -202,8 +207,8 @@ function printHelp() {
202
207
  ${c.cyan}--scopes${c.reset} ${c.dim}<csv>${c.reset} Scopes ${c.dim}(default: ${DEFAULT_SCOPES.join(",")})${c.reset}
203
208
  ${c.cyan}--name${c.reset} ${c.dim}<name>${c.reset} Agent display name
204
209
  ${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}
210
+ ${c.cyan}--token-path${c.reset} ${c.dim}<path>${c.reset} Output file ${c.dim}(skip prompt when set)${c.reset}
211
+ ${c.cyan}--orchestrations-path${c.reset} ${c.dim}<path>${c.reset} Orchestrations install dir ${c.dim}(skip prompt when set)${c.reset}
207
212
  ${c.cyan}--no-orchestrations${c.reset} Skip orchestrations installation
208
213
  ${c.cyan}--overwrite-orchestrations${c.reset} Replace existing files in orchestrations dir
209
214
  ${c.dim}--skills-path / --no-skills / --overwrite-skills are legacy aliases${c.reset}
@@ -223,8 +228,8 @@ async function runDeviceFlow({
223
228
  scopes,
224
229
  agentName,
225
230
  agentModel,
226
- tokenPath,
227
- orchestrationsPath,
231
+ tokenPathOverride,
232
+ orchestrationsPathOverride,
228
233
  installOrchestrations,
229
234
  overwriteOrchestrations,
230
235
  }) {
@@ -334,25 +339,31 @@ async function runDeviceFlow({
334
339
  if (tokenPayload.status === "approved" && tokenPayload.apiKey) {
335
340
  stopSpinner();
336
341
  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}`);
342
+ const storageTargets = await resolveStorageTargets({
343
+ tokenPathOverride,
344
+ orchestrationsPathOverride,
345
+ });
346
+ await saveToken(storageTargets.tokenPath, tokenPayload.apiKey);
347
+ console.log(
348
+ ` ${c.green}✔${c.reset} API key saved to ${c.bold}${storageTargets.tokenPath}${c.reset}`,
349
+ );
339
350
  if (installOrchestrations) {
340
351
  try {
341
352
  const orchestrationInstall = await installBundledOrchestrations({
342
- destinationPath: orchestrationsPath,
353
+ destinationPath: storageTargets.orchestrationsPath,
343
354
  overwrite: overwriteOrchestrations,
344
355
  });
345
356
  if (orchestrationInstall.status === "installed") {
346
357
  console.log(
347
- ` ${c.green}✔${c.reset} Orchestrations installed to ${c.bold}${orchestrationsPath}${c.reset} ${c.dim}(${orchestrationInstall.copiedCount} entries)${c.reset}`,
358
+ ` ${c.green}✔${c.reset} Orchestrations installed to ${c.bold}${storageTargets.orchestrationsPath}${c.reset} ${c.dim}(${orchestrationInstall.copiedCount} entries)${c.reset}`,
348
359
  );
349
360
  } else if (orchestrationInstall.status === "overwritten") {
350
361
  console.log(
351
- ` ${c.green}✔${c.reset} Orchestrations refreshed at ${c.bold}${orchestrationsPath}${c.reset} ${c.dim}(${orchestrationInstall.copiedCount} entries)${c.reset}`,
362
+ ` ${c.green}✔${c.reset} Orchestrations refreshed at ${c.bold}${storageTargets.orchestrationsPath}${c.reset} ${c.dim}(${orchestrationInstall.copiedCount} entries)${c.reset}`,
352
363
  );
353
364
  } else if (orchestrationInstall.status === "skipped_exists") {
354
365
  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}`,
366
+ ` ${c.yellow}!${c.reset} Orchestrations already exist at ${c.bold}${storageTargets.orchestrationsPath}${c.reset} ${c.dim}(use --overwrite-orchestrations to refresh)${c.reset}`,
356
367
  );
357
368
  } else {
358
369
  console.log(
@@ -381,6 +392,87 @@ async function runDeviceFlow({
381
392
  process.exit(1);
382
393
  }
383
394
 
395
+ async function resolveStorageTargets({
396
+ tokenPathOverride,
397
+ orchestrationsPathOverride,
398
+ }) {
399
+ if (tokenPathOverride || orchestrationsPathOverride) {
400
+ return {
401
+ tokenPath: tokenPathOverride || CWD_TOKEN_PATH,
402
+ orchestrationsPath:
403
+ orchestrationsPathOverride || CWD_ORCHESTRATIONS_PATH,
404
+ };
405
+ }
406
+
407
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
408
+ return {
409
+ tokenPath: CWD_TOKEN_PATH,
410
+ orchestrationsPath: CWD_ORCHESTRATIONS_PATH,
411
+ };
412
+ }
413
+
414
+ return promptStorageTargets();
415
+ }
416
+
417
+ async function promptStorageTargets() {
418
+ const rl = createInterface({
419
+ input: process.stdin,
420
+ output: process.stdout,
421
+ });
422
+
423
+ try {
424
+ console.log("");
425
+ console.log(` ${c.bold}Choose where to save files${c.reset}`);
426
+ console.log(
427
+ ` ${c.dim}1) Current directory (default)${c.reset} ${CWD_TOKEN_PATH}`,
428
+ );
429
+ console.log(` ${c.dim} ${CWD_ORCHESTRATIONS_PATH}${c.reset}`);
430
+ console.log(
431
+ ` ${c.dim}2) Home directory${c.reset} ${HOME_TOKEN_PATH}`,
432
+ );
433
+ console.log(` ${c.dim} ${HOME_ORCHESTRATIONS_PATH}${c.reset}`);
434
+ console.log(` ${c.dim}3) Custom paths${c.reset}`);
435
+
436
+ const answer = (
437
+ await rl.question(` Select ${c.bold}[1/2/3]${c.reset} (default 1): `)
438
+ )
439
+ .trim()
440
+ .toLowerCase();
441
+
442
+ if (answer === "2" || answer === "home") {
443
+ return {
444
+ tokenPath: HOME_TOKEN_PATH,
445
+ orchestrationsPath: HOME_ORCHESTRATIONS_PATH,
446
+ };
447
+ }
448
+
449
+ if (answer === "3" || answer === "custom") {
450
+ const tokenInput = (
451
+ await rl.question(` Token path (default ${CWD_TOKEN_PATH}): `)
452
+ ).trim();
453
+ const orchestrationsInput = (
454
+ await rl.question(
455
+ ` Orchestrations path (default ${CWD_ORCHESTRATIONS_PATH}): `,
456
+ )
457
+ ).trim();
458
+
459
+ return {
460
+ tokenPath: resolve(tokenInput || CWD_TOKEN_PATH),
461
+ orchestrationsPath: resolve(
462
+ orchestrationsInput || CWD_ORCHESTRATIONS_PATH,
463
+ ),
464
+ };
465
+ }
466
+
467
+ return {
468
+ tokenPath: CWD_TOKEN_PATH,
469
+ orchestrationsPath: CWD_ORCHESTRATIONS_PATH,
470
+ };
471
+ } finally {
472
+ rl.close();
473
+ }
474
+ }
475
+
384
476
  async function installBundledOrchestrations({ destinationPath, overwrite }) {
385
477
  let sourceEntries;
386
478
  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.4",
4
4
  "description": "Agent Orchestration Protocol CLI",
5
5
  "type": "module",
6
6
  "bin": {