agent-control-plane 0.1.0 → 0.1.2

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.
@@ -553,7 +553,7 @@ Usage:
553
553
 
554
554
  Commands:
555
555
  quota [label] Check Claude usage (default command)
556
- add [label] Add a Claude credential (via OAuth or manual entry)
556
+ add [label] Add a Claude credential via OAuth
557
557
  reauth <label> Re-authenticate an existing Claude account via OAuth
558
558
  switch <label> Switch Claude Code, OpenCode, and pi credentials
559
559
  sync Sync activeLabel to Claude Code, OpenCode, and pi
@@ -564,14 +564,13 @@ Options:
564
564
  --json Output result in JSON format
565
565
  --dry-run Preview sync without writing files
566
566
  --oauth Use OAuth browser authentication (recommended)
567
- --manual Use manual token entry
568
567
  --no-browser Print OAuth URL instead of opening browser
569
568
  --help, -h Show this help
570
569
 
571
570
  Examples:
572
571
  ${PRIMARY_CMD} claude Check Claude usage
573
572
  ${PRIMARY_CMD} claude quota work Check Claude usage for "work"
574
- ${PRIMARY_CMD} claude add Add Claude credential (prompts for method)
573
+ ${PRIMARY_CMD} claude add Add Claude credential via OAuth
575
574
  ${PRIMARY_CMD} claude add work --oauth Add via OAuth browser flow
576
575
  ${PRIMARY_CMD} claude reauth work Re-authenticate "work" account
577
576
  ${PRIMARY_CMD} claude switch work Switch Claude Code/OpenCode/pi to "work"
@@ -582,7 +581,7 @@ Examples:
582
581
 
583
582
  Notes:
584
583
  - switch and sync update activeLabel in ~/.claude-accounts.json when available
585
- - session-key-only accounts cannot be synced (OAuth required)
584
+ - Claude accounts are OAuth-only in the bundled public package
586
585
  `);
587
586
  }
588
587
 
@@ -598,8 +597,6 @@ Arguments:
598
597
  Options:
599
598
  --oauth Use OAuth browser authentication (recommended)
600
599
  Opens browser for secure authentication
601
- --manual Use manual token entry
602
- Paste sessionKey or OAuth token directly
603
600
  --no-browser Print OAuth URL instead of opening browser
604
601
  Use this in headless/SSH environments
605
602
  --json Output result in JSON format
@@ -608,18 +605,14 @@ Options:
608
605
  Description:
609
606
  Adds a Claude credential to ~/.claude-accounts.json.
610
607
 
611
- OAuth flow (recommended):
608
+ OAuth flow:
612
609
  1. Opens browser for authentication at claude.ai
613
610
  2. User copies code#state from browser
614
611
  3. Tool exchanges code for tokens automatically
615
-
616
- Manual flow:
617
- Prompts for sessionKey or OAuth token (one is required).
618
612
 
619
613
  Examples:
620
- ${PRIMARY_CMD} claude add Interactive (prompts for method)
614
+ ${PRIMARY_CMD} claude add Interactive OAuth flow
621
615
  ${PRIMARY_CMD} claude add work --oauth OAuth browser flow
622
- ${PRIMARY_CMD} claude add work --manual Manual token entry
623
616
  ${PRIMARY_CMD} claude add work --oauth --no-browser OAuth without opening browser
624
617
  ${PRIMARY_CMD} claude add work --json JSON output for scripting
625
618
  `);
@@ -787,8 +780,7 @@ Options:
787
780
 
788
781
  Description:
789
782
  Displays usage statistics for Claude accounts. Tokens are refreshed when
790
- available. Uses OAuth credentials when possible and falls back to legacy
791
- session credentials.
783
+ available. Uses OAuth credentials only.
792
784
  OAuth-based accounts are checked for divergence in Claude CLI stores.
793
785
  Use --local to suppress harness checks and only use stored account files.
794
786
 
@@ -71,7 +71,6 @@ import {
71
71
  getClaudeLabels,
72
72
  getClaudeActiveLabelInfo,
73
73
  readClaudeActiveStoreContainer,
74
- findClaudeSessionKey,
75
74
  } from "./claude-accounts.js";
76
75
  import {
77
76
  updateOpencodeAuth,
@@ -92,9 +91,7 @@ import {
92
91
  loadClaudeOAuthFromOpenCode,
93
92
  loadClaudeOAuthFromEnv,
94
93
  loadAllClaudeOAuthAccounts,
95
- fetchClaudeOAuthUsage,
96
94
  fetchClaudeOAuthUsageForAccount,
97
- fetchClaudeUsage,
98
95
  deduplicateClaudeOAuthAccounts,
99
96
  deduplicateClaudeResultsByUsage,
100
97
  } from "./claude-usage.js";
@@ -832,7 +829,7 @@ export async function handleClaudeList(flags) {
832
829
  accounts: claudeAccounts.map(account => ({
833
830
  label: account.label,
834
831
  source: account.source,
835
- hasSessionKey: Boolean(account.sessionKey ?? findClaudeSessionKey(account.cookies)),
832
+ authType: account.oauthToken ? "oauth" : "unsupported",
836
833
  hasOauthToken: Boolean(account.oauthToken),
837
834
  orgId: account.orgId ?? null,
838
835
  isActive: activeLabel !== null && account.label === activeLabel,
@@ -873,14 +870,7 @@ export async function handleClaudeList(flags) {
873
870
  const isActive = activeLabel !== null && account.label === activeLabel;
874
871
  const marker = isActive ? "*" : " ";
875
872
  const statusText = isActive ? " [active]" : "";
876
- const authParts = [];
877
- if (account.sessionKey ?? findClaudeSessionKey(account.cookies)) {
878
- authParts.push("sessionKey");
879
- }
880
- if (account.oauthToken) {
881
- authParts.push("oauthToken");
882
- }
883
- const authDisplay = authParts.length ? authParts.join("+") : "unknown";
873
+ const authDisplay = account.oauthToken ? "oauthToken" : "unsupported";
884
874
  claudeLines.push(`${marker} ${account.label}${statusText}`);
885
875
  claudeLines.push(` Auth: ${authDisplay} | ${shortenPath(account.source)}`);
886
876
  if (i < claudeAccounts.length - 1) {
@@ -1428,6 +1418,9 @@ export async function handleClaudeAdd(args, flags) {
1428
1418
  if (flags.oauth && flags.manual) {
1429
1419
  throw new Error("Cannot use both --oauth and --manual flags. Choose one authentication method.");
1430
1420
  }
1421
+ if (flags.manual) {
1422
+ throw new Error("Manual Claude credential entry is no longer supported. Use OAuth authentication instead.");
1423
+ }
1431
1424
 
1432
1425
  const existingAccounts = loadClaudeAccounts();
1433
1426
  const existingLabels = new Set(existingAccounts.map(a => a.label));
@@ -1446,74 +1439,18 @@ export async function handleClaudeAdd(args, flags) {
1446
1439
  throw new Error(`Label "${label}" already exists. Choose a different label.`);
1447
1440
  }
1448
1441
 
1449
- // Determine authentication method
1450
- let useOAuth = flags.oauth;
1451
- if (!flags.oauth && !flags.manual) {
1452
- // Prompt for choice
1453
- console.log("\nChoose authentication method:");
1454
- console.log(" [1] OAuth (recommended) - Authenticate via browser");
1455
- console.log(" [2] Manual - Paste sessionKey/token directly\n");
1456
- const choice = (await promptInput("Enter choice (1 or 2): ")).trim();
1457
- useOAuth = choice === "1";
1458
- }
1459
-
1460
1442
  let newAccount;
1461
1443
  let viaMethod;
1462
-
1463
- if (useOAuth) {
1464
- // OAuth browser flow
1465
- const tokens = await handleClaudeOAuthFlow({ noBrowser: flags.noBrowser });
1466
- newAccount = {
1467
- label,
1468
- sessionKey: null,
1469
- oauthToken: tokens.accessToken,
1470
- oauthRefreshToken: tokens.refreshToken,
1471
- oauthExpiresAt: tokens.expiresAt,
1472
- oauthScopes: tokens.scopes,
1473
- cfClearance: null,
1474
- orgId: null,
1475
- };
1476
- viaMethod = "via OAuth";
1477
- } else {
1478
- // Manual entry flow
1479
- console.log("\nPaste your Claude sessionKey or OAuth token.");
1480
- const sessionKeyInput = await promptInput("sessionKey (sk-ant-...): ", { allowEmpty: true });
1481
- const oauthTokenInput = await promptInput("oauthToken (optional): ", { allowEmpty: true });
1482
- const cfClearanceInput = await promptInput("cfClearance (optional): ", { allowEmpty: true });
1483
- const orgIdInput = await promptInput("orgId (optional): ", { allowEmpty: true });
1484
-
1485
- let parsedInput = null;
1486
- if (sessionKeyInput && sessionKeyInput.trim().startsWith("{")) {
1487
- try {
1488
- parsedInput = JSON.parse(sessionKeyInput);
1489
- } catch {
1490
- parsedInput = null;
1491
- }
1492
- }
1493
-
1494
- const sessionKey = findClaudeSessionKey(parsedInput ?? sessionKeyInput) ?? null;
1495
- const oauthToken = oauthTokenInput?.trim()
1496
- || parsedInput?.claudeAiOauth?.accessToken
1497
- || parsedInput?.claude_ai_oauth?.accessToken
1498
- || parsedInput?.accessToken
1499
- || parsedInput?.access_token
1500
- || null;
1501
- const cfClearance = cfClearanceInput?.trim() || null;
1502
- const orgId = orgIdInput?.trim() || null;
1503
-
1504
- if (!sessionKey && !oauthToken) {
1505
- throw new Error("Provide at least a sessionKey or an OAuth token.");
1506
- }
1507
-
1508
- newAccount = {
1509
- label,
1510
- sessionKey,
1511
- oauthToken,
1512
- cfClearance,
1513
- orgId,
1514
- };
1515
- viaMethod = "";
1516
- }
1444
+ const tokens = await handleClaudeOAuthFlow({ noBrowser: flags.noBrowser });
1445
+ newAccount = {
1446
+ label,
1447
+ oauthToken: tokens.accessToken,
1448
+ oauthRefreshToken: tokens.refreshToken,
1449
+ oauthExpiresAt: tokens.expiresAt,
1450
+ oauthScopes: tokens.scopes,
1451
+ orgId: null,
1452
+ };
1453
+ viaMethod = "via OAuth";
1517
1454
 
1518
1455
  const { path: targetPath, container } = readClaudeActiveStoreContainer();
1519
1456
  const accounts = [...container.accounts, newAccount];
@@ -1521,11 +1458,11 @@ export async function handleClaudeAdd(args, flags) {
1521
1458
 
1522
1459
  if (flags.json) {
1523
1460
  console.log(JSON.stringify({
1524
- success: true,
1525
- label,
1526
- method: useOAuth ? "oauth" : "manual",
1527
- source: targetPath,
1528
- }, null, 2));
1461
+ success: true,
1462
+ label,
1463
+ method: "oauth",
1464
+ source: targetPath,
1465
+ }, null, 2));
1529
1466
  return;
1530
1467
  }
1531
1468
 
@@ -1887,42 +1824,21 @@ export async function handleQuota(args, flags, scope = "all") {
1887
1824
  filteredOauthAccounts.map(account => fetchClaudeOAuthUsageForAccount(account))
1888
1825
  );
1889
1826
  claudeResults = deduplicateClaudeResultsByUsage(rawResults);
1890
- } else {
1891
- const claudeAccounts = loadClaudeAccounts();
1892
- const filteredClaudeAccounts = wantsClaudeLabel
1893
- ? claudeAccounts.filter(account => account.label === labelFilter)
1894
- : claudeAccounts;
1895
-
1896
- if (filteredClaudeAccounts.length) {
1897
- const rawResults = await Promise.all(
1898
- filteredClaudeAccounts.map(account => fetchClaudeUsageForCredentials(account))
1899
- );
1900
- claudeResults = deduplicateClaudeResultsByUsage(rawResults);
1901
- } else if (wantsClaudeLabel) {
1902
- const availableLabels = new Set([
1903
- ...oauthAccounts.map(account => account.label),
1904
- ...claudeAccounts.map(account => account.label),
1905
- ]);
1906
- const labelList = Array.from(availableLabels);
1907
- if (flags.json) {
1908
- console.log(JSON.stringify({
1909
- success: false,
1910
- error: `Claude account "${labelFilter}" not found`,
1911
- availableLabels: labelList,
1912
- }, null, 2));
1913
- } else {
1914
- console.error(colorize(`Claude account "${labelFilter}" not found.`, RED));
1915
- if (labelList.length) {
1916
- console.error(`Available: ${labelList.join(", ")}`);
1917
- }
1918
- }
1919
- process.exit(1);
1827
+ } else if (wantsClaudeLabel) {
1828
+ const labelList = Array.from(new Set(oauthAccounts.map(account => account.label)));
1829
+ if (flags.json) {
1830
+ console.log(JSON.stringify({
1831
+ success: false,
1832
+ error: `Claude account "${labelFilter}" not found`,
1833
+ availableLabels: labelList,
1834
+ }, null, 2));
1920
1835
  } else {
1921
- const legacyResult = await fetchClaudeUsage();
1922
- if (legacyResult.success || legacyResult.usage) {
1923
- claudeResults = [legacyResult];
1836
+ console.error(colorize(`Claude account "${labelFilter}" not found.`, RED));
1837
+ if (labelList.length) {
1838
+ console.error(`Available: ${labelList.join(", ")}`);
1924
1839
  }
1925
1840
  }
1841
+ process.exit(1);
1926
1842
  }
1927
1843
  }
1928
1844
 
@@ -2057,4 +1973,3 @@ export async function handleQuota(args, flags, scope = "all") {
2057
1973
  }
2058
1974
  }
2059
1975
  }
2060
-
@@ -29,7 +29,6 @@ import {
29
29
  getClaudeLabels,
30
30
  readClaudeActiveStoreContainer,
31
31
  getClaudeActiveLabelInfo,
32
- findClaudeSessionKey,
33
32
  loadClaudeAccountsFromFile,
34
33
  } from "./claude-accounts.js";
35
34
  import {
@@ -652,16 +651,14 @@ export async function maybeImportClaudeOauthStores(options = {}) {
652
651
  console.error(colorize(`Skipping: label "${label}" already exists.`, YELLOW));
653
652
  continue;
654
653
  }
655
- const newAccount = {
656
- label,
657
- sessionKey: null,
658
- oauthToken: store.tokens.access,
659
- oauthRefreshToken: store.tokens.refresh ?? null,
660
- oauthExpiresAt: store.tokens.expires ?? null,
661
- oauthScopes: store.tokens.scopes ?? null,
662
- cfClearance: null,
663
- orgId: null,
664
- };
654
+ const newAccount = {
655
+ label,
656
+ oauthToken: store.tokens.access,
657
+ oauthRefreshToken: store.tokens.refresh ?? null,
658
+ oauthExpiresAt: store.tokens.expires ?? null,
659
+ oauthScopes: store.tokens.scopes ?? null,
660
+ orgId: null,
661
+ };
665
662
  container.accounts.push(newAccount);
666
663
  managedAccounts.push(normalizeClaudeAccount(newAccount, targetPath));
667
664
  existingLabels.add(label);
@@ -1430,9 +1427,7 @@ export async function handleClaudeSync(args, flags) {
1430
1427
 
1431
1428
  /**
1432
1429
  * Handle Claude add subcommand - add a Claude credential interactively
1433
- * Supports two authentication methods:
1434
- * - OAuth browser flow (--oauth): Opens browser for authentication
1435
- * - Manual entry (--manual): Paste sessionKey/token directly
1430
+ * Uses OAuth browser flow for authentication.
1436
1431
  * @param {string[]} args - Non-flag arguments (optional label)
1437
1432
  * @param {{ json: boolean, noBrowser: boolean, oauth: boolean, manual: boolean }} flags - Parsed flags
1438
1433
  */