@first087/agys 0.1.0 → 0.2.0

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/README.md CHANGED
@@ -12,19 +12,21 @@ Manage multiple antigravity-cli oauth token accounts with ease.
12
12
  ## Installation
13
13
 
14
14
  ```bash
15
- npm install -g agys
15
+ npm install -g @first087/agys
16
16
  # or
17
- bun install -g agys
17
+ bun install -g @first087/agys
18
18
  ```
19
19
 
20
20
  ## Usage
21
21
 
22
22
  ### Add a new account
23
+
23
24
  ```bash
24
25
  agys add <name>
25
26
  ```
26
27
 
27
28
  ### List all accounts
29
+
28
30
  ```bash
29
31
  agys list
30
32
  # or
@@ -32,7 +34,9 @@ agys ls
32
34
  ```
33
35
 
34
36
  ### Switch account
37
+
35
38
  Run `agys` without any arguments to open the interactive selection menu:
39
+
36
40
  ```bash
37
41
  agys
38
42
  # or explicitly
package/index.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env bun
2
- import { Command } from 'commander';
3
- import packageJson from './package.json' with { type: 'json' };
4
- import { addCommand } from './src/commands/add';
5
- import { listCommand, lsCommand } from './src/commands/list';
6
- import { switchCommand, handleSwitch } from './src/commands/switch';
2
+ import { Command } from "commander";
3
+ import packageJson from "./package.json" with { type: "json" };
4
+ import { addCommand } from "./src/commands/add";
5
+ import { listCommand, lsCommand } from "./src/commands/list";
6
+ import { switchCommand, handleSwitch } from "./src/commands/switch";
7
7
 
8
8
  const program = new Command();
9
9
 
10
10
  program
11
- .name('agys')
12
- .description('Manage multiple antigravity-cli oauth token accounts')
11
+ .name("agys")
12
+ .description(`${packageJson.description} (v${packageJson.version})`)
13
13
  .version(packageJson.version);
14
14
 
15
15
  program.addCommand(addCommand);
@@ -18,7 +18,9 @@ program.addCommand(lsCommand);
18
18
  program.addCommand(switchCommand);
19
19
 
20
20
  // Set description for switch command explicitly
21
- switchCommand.description('Switch to a different account (run agys without arguments)');
21
+ switchCommand.description(
22
+ "Switch to a different account (run agys without arguments)",
23
+ );
22
24
 
23
25
  // Set default action if no command is provided
24
26
  program.action(async () => {
@@ -27,4 +29,11 @@ program.action(async () => {
27
29
  }
28
30
  });
29
31
 
32
+ program.addHelpText(
33
+ "after",
34
+ `
35
+ GitHub Repository: https://github.com/first087/agy-switch
36
+ `,
37
+ );
38
+
30
39
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@first087/agys",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Manage multiple antigravity-cli oauth token accounts",
5
5
  "author": "Artit Kiuwilai",
6
6
  "repository": {
@@ -2,14 +2,20 @@ import { expect, test, spyOn } from "bun:test";
2
2
  import * as fileOps from "../utils/fileOperations";
3
3
 
4
4
  // Mocking the utility function
5
- spyOn(fileOps, "copyTokenToAccount").mockImplementation(() => Promise.resolve('/home/user/.agys/test-account'));
5
+ spyOn(fileOps, "copyTokenToAccount").mockImplementation(() =>
6
+ Promise.resolve("/home/user/.agys/test-account"),
7
+ );
6
8
 
7
9
  test("add command calls copyTokenToAccount with correct arguments", async () => {
8
10
  // Logic to test will be added as we implement the command
9
11
  const accountName = "test-account";
10
- const sourcePath = "/home/user/.gemini/antigravity-cli/antigravity-oauth-token";
11
-
12
+ const sourcePath =
13
+ "/home/user/.gemini/antigravity-cli/antigravity-oauth-token";
14
+
12
15
  await fileOps.copyTokenToAccount(accountName, sourcePath);
13
-
14
- expect(fileOps.copyTokenToAccount).toHaveBeenCalledWith(accountName, sourcePath);
16
+
17
+ expect(fileOps.copyTokenToAccount).toHaveBeenCalledWith(
18
+ accountName,
19
+ sourcePath,
20
+ );
15
21
  });
@@ -12,7 +12,12 @@ export const addCommand = new Command("add")
12
12
  addCommand.outputHelp();
13
13
  return;
14
14
  }
15
- const sourcePath = path.join(os.homedir(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
15
+ const sourcePath = path.join(
16
+ os.homedir(),
17
+ ".gemini",
18
+ "antigravity-cli",
19
+ "antigravity-oauth-token",
20
+ );
16
21
  try {
17
22
  await fileOps.copyTokenToAccount(name, sourcePath);
18
23
  console.log(chalk.green(`Account '${name}' added successfully.`));
@@ -2,14 +2,18 @@ import { expect, test, spyOn } from "bun:test";
2
2
  import * as fileOps from "../utils/fileOperations";
3
3
 
4
4
  // Mocking the utility functions
5
- spyOn(fileOps, "getAccounts").mockImplementation(() => Promise.resolve(['test', 'test2', 'test3']));
6
- spyOn(fileOps, "getActiveAccount").mockImplementation(() => Promise.resolve('test'));
5
+ spyOn(fileOps, "getAccounts").mockImplementation(() =>
6
+ Promise.resolve(["test", "test2", "test3"]),
7
+ );
8
+ spyOn(fileOps, "getActiveAccount").mockImplementation(() =>
9
+ Promise.resolve("test"),
10
+ );
7
11
 
8
12
  test("list command returns all accounts with active one marked", async () => {
9
13
  const accounts = await fileOps.getAccounts();
10
14
  const active = await fileOps.getActiveAccount();
11
-
12
- expect(accounts).toContain('test');
13
- expect(accounts).toContain('test2');
14
- expect(active).toBe('test');
15
+
16
+ expect(accounts).toContain("test");
17
+ expect(accounts).toContain("test2");
18
+ expect(active).toBe("test");
15
19
  });
@@ -32,4 +32,3 @@ export const listCommand = new Command("list")
32
32
  export const lsCommand = new Command("ls")
33
33
  .description("Alias for list")
34
34
  .action(listAction);
35
-
@@ -1,20 +1,26 @@
1
1
  import { expect, test, spyOn } from "bun:test";
2
2
  import * as fileOps from "../utils/fileOperations";
3
- import inquirer from 'inquirer';
3
+ import inquirer from "inquirer";
4
4
 
5
5
  // Mocking the utility functions and inquirer
6
- spyOn(fileOps, "getAccounts").mockImplementation(() => Promise.resolve(['test', 'test2', 'test3']));
6
+ spyOn(fileOps, "getAccounts").mockImplementation(() =>
7
+ Promise.resolve(["test", "test2", "test3"]),
8
+ );
7
9
  // @ts-ignore
8
- spyOn(inquirer, 'prompt').mockImplementation(() => Promise.resolve({ selectedAccount: 'test2' }));
10
+ spyOn(inquirer, "prompt").mockImplementation(() =>
11
+ Promise.resolve({ selectedAccount: "test2" }) as any,
12
+ );
9
13
 
10
14
  test("switch interactive menu returns selected account", async () => {
11
15
  const accounts = await fileOps.getAccounts();
12
- const answers = await inquirer.prompt([{
13
- type: 'list',
14
- name: 'selectedAccount',
15
- message: 'Select account:',
16
- choices: accounts
17
- }]);
18
-
19
- expect(answers.selectedAccount).toBe('test2');
16
+ const answers = await inquirer.prompt([
17
+ {
18
+ type: "list",
19
+ name: "selectedAccount",
20
+ message: "Select account:",
21
+ choices: accounts,
22
+ },
23
+ ]);
24
+
25
+ expect(answers.selectedAccount).toBe("test2");
20
26
  });
@@ -1,39 +1,65 @@
1
1
  import { Command } from "commander";
2
2
  import * as fileOps from "../utils/fileOperations";
3
- import inquirer from 'inquirer';
4
- import chalk from 'chalk';
5
- import path from 'path';
6
- import os from 'os';
7
- import fs from 'fs-extra';
3
+ import inquirer from "inquirer";
4
+ import chalk from "chalk";
5
+ import path from "path";
6
+ import os from "os";
7
+ import fs from "fs-extra";
8
+ import packageJson from "../../package.json" with { type: "json" };
8
9
 
9
10
  export async function handleSwitch() {
11
+ console.clear();
10
12
  try {
11
13
  const accounts = await fileOps.getAccounts();
12
14
  const active = await fileOps.getActiveAccount();
13
-
15
+
14
16
  if (accounts.length === 0) {
15
- console.log(chalk.yellow("No accounts found. Use 'agys add' to create one."));
17
+ console.log(
18
+ chalk.yellow("No accounts found. Use 'agys add' to create one."),
19
+ );
16
20
  return;
17
21
  }
18
22
 
19
- const { selectedAccount } = await inquirer.prompt([{
20
- type: 'select',
21
- name: 'selectedAccount',
22
- message: 'Select account (Press Ctrl+C to cancel):',
23
- choices: accounts.map((account: string) => ({
24
- name: account === active ? `${account} (active)` : account,
25
- value: account
26
- })),
27
- default: active
28
- }]).catch(() => {
23
+ const message = `[agys v${packageJson.version}] Select account (Press Ctrl+C to cancel)`;
24
+ const header = `
25
+ ${chalk.green("╭" + "─".repeat(message.length + 2) + "╮")}
26
+ ${chalk.green("│")} ${chalk.bold(message)} ${chalk.green("│")}
27
+ ${chalk.green("╰" + "─".repeat(message.length + 2) + "╯")}`;
28
+ console.log(header);
29
+
30
+ const { selectedAccount } = await inquirer
31
+ .prompt([
32
+ {
33
+ type: "select",
34
+ name: "selectedAccount",
35
+ message: "Account:",
36
+ choices: accounts.map((account: string) => ({
37
+ name: account === active ? `${account} (active)` : account,
38
+ value: account,
39
+ })),
40
+ default: active,
41
+ theme: {
42
+ icon: { cursor: "👉" },
43
+ style: {
44
+ highlight: chalk.green,
45
+ },
46
+ },
47
+ },
48
+ ])
49
+ .catch(() => {
29
50
  console.log(chalk.yellow("\nSwitching cancelled."));
30
51
  process.exit(0);
31
52
  });
32
53
 
33
54
  if (selectedAccount !== active) {
34
- const sourcePath = path.join(os.homedir(), '.agys', selectedAccount);
35
- const destPath = path.join(os.homedir(), '.gemini', 'antigravity-cli', 'antigravity-oauth-token');
36
-
55
+ const sourcePath = path.join(os.homedir(), ".agys", selectedAccount);
56
+ const destPath = path.join(
57
+ os.homedir(),
58
+ ".gemini",
59
+ "antigravity-cli",
60
+ "antigravity-oauth-token",
61
+ );
62
+
37
63
  // Use fs.copy to copy from source to dest (token file)
38
64
  await fs.copy(sourcePath, destPath);
39
65
  await fileOps.setActiveAccount(selectedAccount);
@@ -1,15 +1,18 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
3
- import os from 'os';
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+ import os from "os";
4
4
 
5
- const CONFIG_DIR = path.join(os.homedir(), '.agys');
6
- const ACTIVE_FILE = path.join(CONFIG_DIR, '.active');
5
+ const CONFIG_DIR = path.join(os.homedir(), ".agys");
6
+ const ACTIVE_FILE = path.join(CONFIG_DIR, ".active");
7
7
 
8
8
  export async function ensureConfigDir() {
9
9
  await fs.ensureDir(CONFIG_DIR);
10
10
  }
11
11
 
12
- export async function copyTokenToAccount(accountName: string, sourcePath: string) {
12
+ export async function copyTokenToAccount(
13
+ accountName: string,
14
+ sourcePath: string,
15
+ ) {
13
16
  const destPath = path.join(CONFIG_DIR, accountName);
14
17
  await fs.ensureDir(CONFIG_DIR);
15
18
  await fs.copy(sourcePath, destPath);
@@ -19,20 +22,20 @@ export async function copyTokenToAccount(accountName: string, sourcePath: string
19
22
  export async function getAccounts() {
20
23
  await ensureConfigDir();
21
24
  const files = await fs.readdir(CONFIG_DIR);
22
- return files.filter((file: string) => file !== '.active');
25
+ return files.filter((file: string) => file !== ".active");
23
26
  }
24
27
 
25
28
  export async function setActiveAccount(accountName: string) {
26
29
  await ensureConfigDir();
27
- await fs.writeFile(ACTIVE_FILE, accountName, 'utf-8');
30
+ await fs.writeFile(ACTIVE_FILE, accountName, "utf-8");
28
31
  }
29
32
 
30
33
  export async function getActiveAccount() {
31
34
  await ensureConfigDir();
32
-
35
+
33
36
  if (!fs.existsSync(ACTIVE_FILE)) {
34
37
  return null;
35
38
  }
36
39
 
37
- return await fs.readFile(ACTIVE_FILE, 'utf-8');
40
+ return await fs.readFile(ACTIVE_FILE, "utf-8");
38
41
  }