agyx 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dongwook Chan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # agyx
2
+
3
+ `agyx` is a multi-account session supervisor for Google's Antigravity CLI
4
+ (`agy`). It can pause every managed terminal session, switch the shared macOS
5
+ Keychain credential, and restart each conversation in its original terminal.
6
+
7
+ ## Requirements
8
+
9
+ - macOS
10
+ - Node.js 20 or newer
11
+ - Google Antigravity CLI (`agy`)
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install -g agyx
17
+ agyx install
18
+ source ~/.zshrc
19
+ ```
20
+
21
+ The shell integration makes `agy` transparently run as:
22
+
23
+ ```text
24
+ agyx session -- <all original agy arguments>
25
+ ```
26
+
27
+ All original options are forwarded, including:
28
+
29
+ ```bash
30
+ agy --continue
31
+ agy --conversation <UUID>
32
+ agy --model <model>
33
+ agy --project <project-id>
34
+ agy --dangerously-skip-permissions
35
+ agy -p "one-shot prompt"
36
+ ```
37
+
38
+ One-shot `--print`/`--prompt` commands are not automatically restarted, which
39
+ prevents duplicate requests.
40
+
41
+ ## Account setup
42
+
43
+ Save the account currently stored by `agy`:
44
+
45
+ ```bash
46
+ agyx save personal --email you@example.com
47
+ ```
48
+
49
+ Add another account:
50
+
51
+ ```bash
52
+ agyx login work
53
+ ```
54
+
55
+ `agyx login` performs this transaction:
56
+
57
+ 1. Pause every supervised `agy` child process.
58
+ 2. Stop any unmanaged `agy` process that could overwrite the Keychain.
59
+ 3. Run the Google OAuth login flow.
60
+ 4. Save and activate the new credential.
61
+ 5. Restart every supervised session in its original terminal.
62
+
63
+ Use `--no-resume` to leave sessions paused after login.
64
+
65
+ ## Switching
66
+
67
+ ```bash
68
+ agyx list
69
+ agyx use work
70
+ agyx next
71
+ agyx status
72
+ ```
73
+
74
+ Each supervisor preserves its working directory and original arguments. It also
75
+ extracts the active conversation UUID from the session log and uses
76
+ `agy --conversation <UUID>` when restarting.
77
+
78
+ Conversation names are supported by `agy` through `/rename` and `/resume`, but
79
+ `agyx` tracks UUIDs because names can be changed or duplicated.
80
+
81
+ ## Security
82
+
83
+ - Credentials remain in macOS Keychain.
84
+ - Profile metadata only is stored in `~/.config/agyx/state.json` with mode 0600.
85
+ - Account changes wait for supervised sessions to stop before modifying the
86
+ shared `gemini/antigravity` Keychain item.
87
+
88
+ macOS may display a Keychain access prompt the first time an account is saved or
89
+ switched.
90
+
91
+ ## Current limitation
92
+
93
+ Antigravity stores conversations locally, but a conversation created by one
94
+ Google account may not be authorized for another account's backend project.
95
+ `agyx` restores the local conversation ID; cross-account backend access remains
96
+ subject to Antigravity's account permissions.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+ import { activateProfile, loginProfile, pauseAll, resumeAll, saveCurrent, sessionRecords, switchProfile, } from "./coordinator.js";
3
+ import { installShellIntegration, shellInit } from "./install.js";
4
+ import { keychain } from "./keychain.js";
5
+ import { findRealAgy } from "./processes.js";
6
+ import { loadState, saveState, validateProfileName } from "./config.js";
7
+ import { supervise } from "./session.js";
8
+ const help = `agyx — multi-account session supervisor for Antigravity CLI
9
+
10
+ Usage:
11
+ agyx install Install transparent agy shell shim
12
+ agyx session -- [agy options] Run agy under a restartable supervisor
13
+ agyx save <name> [--email EMAIL] Save the current Keychain account
14
+ agyx login <name> [--no-resume] Pause all sessions and add an account
15
+ agyx use <name> Switch account and resume every session
16
+ agyx next Rotate to the next saved account
17
+ agyx list List profiles
18
+ agyx current Print the active profile
19
+ agyx status List supervised terminal sessions
20
+ agyx pause | resume Pause or resume all supervised sessions
21
+ agyx remove <name> Delete a saved profile
22
+ agyx shell-init Print the shell integration function
23
+ agyx doctor Diagnose the installation
24
+
25
+ All arguments passed through "agy" are forwarded to the real agy executable.
26
+ Non-interactive --print/--prompt commands are not automatically restarted.`;
27
+ function takeOption(args, name) {
28
+ const index = args.indexOf(name);
29
+ if (index < 0)
30
+ return undefined;
31
+ if (!args[index + 1])
32
+ throw new Error(`${name} requires a value`);
33
+ return args.splice(index, 2)[1];
34
+ }
35
+ async function main() {
36
+ const args = process.argv.slice(2);
37
+ const command = args.shift();
38
+ if (!command || ["help", "--help", "-h"].includes(command)) {
39
+ console.log(help);
40
+ return 0;
41
+ }
42
+ switch (command) {
43
+ case "install": {
44
+ const path = await installShellIntegration();
45
+ console.log(`Installed agyx shell integration in ${path}`);
46
+ console.log("Open a new terminal or run: source " + path);
47
+ return 0;
48
+ }
49
+ case "shell-init":
50
+ console.log(shellInit());
51
+ return 0;
52
+ case "session":
53
+ if (args[0] === "--")
54
+ args.shift();
55
+ return await supervise(args);
56
+ case "save": {
57
+ const name = args.shift();
58
+ if (!name)
59
+ throw new Error("Usage: agyx save <name> [--email EMAIL]");
60
+ const email = takeOption(args, "--email");
61
+ if (args.length)
62
+ throw new Error(`Unknown arguments: ${args.join(" ")}`);
63
+ await saveCurrent(name, email);
64
+ console.log(`Saved and activated profile '${name}'.`);
65
+ return 0;
66
+ }
67
+ case "login": {
68
+ const name = args.shift();
69
+ if (!name)
70
+ throw new Error("Usage: agyx login <name> [--email EMAIL] [--no-resume]");
71
+ const email = takeOption(args, "--email");
72
+ const noResume = args.includes("--no-resume");
73
+ args.splice(args.indexOf("--no-resume"), noResume ? 1 : 0);
74
+ if (args.length)
75
+ throw new Error(`Unknown arguments: ${args.join(" ")}`);
76
+ await loginProfile(name, email, !noResume);
77
+ return 0;
78
+ }
79
+ case "use": {
80
+ const name = args.shift();
81
+ if (!name || args.length)
82
+ throw new Error("Usage: agyx use <name>");
83
+ await switchProfile(name);
84
+ console.log(`Activated profile '${name}' and resumed all sessions.`);
85
+ return 0;
86
+ }
87
+ case "next": {
88
+ const state = await loadState();
89
+ if (!state.profiles.length)
90
+ throw new Error("No saved profiles.");
91
+ const index = state.activeProfile
92
+ ? state.profiles.findIndex(({ name }) => name === state.activeProfile)
93
+ : -1;
94
+ const name = state.profiles[(index + 1) % state.profiles.length].name;
95
+ await switchProfile(name);
96
+ console.log(`Activated profile '${name}' and resumed all sessions.`);
97
+ return 0;
98
+ }
99
+ case "list": {
100
+ const state = await loadState();
101
+ if (!state.profiles.length)
102
+ console.log("No saved profiles.");
103
+ for (const profile of state.profiles) {
104
+ console.log(`${profile.name === state.activeProfile ? "*" : " "} ${profile.name}`
105
+ + (profile.email ? ` ${profile.email}` : ""));
106
+ }
107
+ return 0;
108
+ }
109
+ case "current":
110
+ console.log((await loadState()).activeProfile ?? "unmanaged");
111
+ return 0;
112
+ case "status": {
113
+ const records = await sessionRecords();
114
+ if (!records.length)
115
+ console.log("No supervised agy sessions.");
116
+ for (const record of records) {
117
+ console.log(`${record.id} pid=${record.pid} child=${record.childPid ?? "-"}`
118
+ + ` ${record.paused ? "paused" : "running"} cwd=${record.cwd}`
119
+ + (record.conversationId ? ` conversation=${record.conversationId}` : ""));
120
+ }
121
+ return 0;
122
+ }
123
+ case "pause": {
124
+ const records = await pauseAll();
125
+ console.log(`Paused ${records.length} supervised session(s).`);
126
+ return 0;
127
+ }
128
+ case "resume": {
129
+ const records = await sessionRecords();
130
+ await resumeAll(records);
131
+ console.log(`Resumed ${records.length} supervised session(s).`);
132
+ return 0;
133
+ }
134
+ case "remove": {
135
+ const name = args.shift();
136
+ if (!name || args.length)
137
+ throw new Error("Usage: agyx remove <name>");
138
+ validateProfileName(name);
139
+ await keychain.deleteProfile(name);
140
+ const state = await loadState();
141
+ state.profiles = state.profiles.filter((profile) => profile.name !== name);
142
+ if (state.activeProfile === name)
143
+ state.activeProfile = undefined;
144
+ await saveState(state);
145
+ console.log(`Removed profile '${name}'.`);
146
+ return 0;
147
+ }
148
+ case "doctor": {
149
+ const state = await loadState();
150
+ const sessions = await sessionRecords();
151
+ console.log(`agy: ${await findRealAgy()}`);
152
+ console.log(`platform: ${process.platform}`);
153
+ console.log(`profiles: ${state.profiles.length}`);
154
+ console.log(`active profile: ${state.activeProfile ?? "unmanaged"}`);
155
+ console.log(`supervised sessions: ${sessions.length}`);
156
+ return 0;
157
+ }
158
+ case "_activate":
159
+ await activateProfile(args[0] ?? "");
160
+ return 0;
161
+ default:
162
+ throw new Error(`Unknown command: ${command}\n\n${help}`);
163
+ }
164
+ }
165
+ main()
166
+ .then((code) => { process.exitCode = code; })
167
+ .catch((error) => {
168
+ console.error(`agyx: ${error.message}`);
169
+ process.exitCode = 1;
170
+ });
171
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface ProfileRecord {
2
+ name: string;
3
+ email?: string;
4
+ createdAt: string;
5
+ updatedAt: string;
6
+ }
7
+ export interface State {
8
+ version: 1;
9
+ activeProfile?: string;
10
+ realAgyPath?: string;
11
+ profiles: ProfileRecord[];
12
+ }
13
+ export declare const configDir: string;
14
+ export declare const runtimeDir: string;
15
+ export declare const logDir: string;
16
+ export declare const statePath: string;
17
+ export declare function ensureDirectories(): Promise<void>;
18
+ export declare function loadState(): Promise<State>;
19
+ export declare function saveState(state: State): Promise<void>;
20
+ export declare function upsertProfile(name: string, email: string | undefined, makeActive: boolean): Promise<void>;
21
+ export declare function cleanupRuntimeFile(path: string): Promise<void>;
22
+ export declare function validateProfileName(name: string): string;
23
+ export declare function ensureParent(path: string): Promise<void>;
@@ -0,0 +1,61 @@
1
+ import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ export const configDir = process.env.AGYX_CONFIG_DIR
5
+ ?? join(homedir(), ".config", "agyx");
6
+ export const runtimeDir = join(configDir, "run");
7
+ export const logDir = join(configDir, "logs");
8
+ export const statePath = join(configDir, "state.json");
9
+ export async function ensureDirectories() {
10
+ for (const directory of [configDir, runtimeDir, logDir]) {
11
+ await mkdir(directory, { recursive: true, mode: 0o700 });
12
+ await chmod(directory, 0o700);
13
+ }
14
+ }
15
+ export async function loadState() {
16
+ try {
17
+ return JSON.parse(await readFile(statePath, "utf8"));
18
+ }
19
+ catch (error) {
20
+ if (error.code === "ENOENT") {
21
+ return { version: 1, profiles: [] };
22
+ }
23
+ throw error;
24
+ }
25
+ }
26
+ export async function saveState(state) {
27
+ await ensureDirectories();
28
+ const temporary = `${statePath}.${process.pid}.tmp`;
29
+ await writeFile(temporary, `${JSON.stringify(state, null, 2)}\n`, { mode: 0o600 });
30
+ await chmod(temporary, 0o600);
31
+ await rename(temporary, statePath);
32
+ }
33
+ export async function upsertProfile(name, email, makeActive) {
34
+ const state = await loadState();
35
+ const now = new Date().toISOString();
36
+ const existing = state.profiles.find((profile) => profile.name === name);
37
+ if (existing) {
38
+ existing.email = email ?? existing.email;
39
+ existing.updatedAt = now;
40
+ }
41
+ else {
42
+ state.profiles.push({ name, email, createdAt: now, updatedAt: now });
43
+ }
44
+ state.profiles.sort((left, right) => left.name.localeCompare(right.name));
45
+ if (makeActive)
46
+ state.activeProfile = name;
47
+ await saveState(state);
48
+ }
49
+ export async function cleanupRuntimeFile(path) {
50
+ await rm(path, { force: true }).catch(() => undefined);
51
+ }
52
+ export function validateProfileName(name) {
53
+ if (!/^[A-Za-z0-9._-]+$/.test(name)) {
54
+ throw new Error(`Invalid profile name '${name}'. Use letters, numbers, '.', '_' or '-'.`);
55
+ }
56
+ return name;
57
+ }
58
+ export async function ensureParent(path) {
59
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
60
+ }
61
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { SessionRecord } from "./session.js";
2
+ export declare function sessionRecords(): Promise<SessionRecord[]>;
3
+ export declare function pauseAll(): Promise<SessionRecord[]>;
4
+ export declare function resumeAll(records: SessionRecord[]): Promise<void>;
5
+ export declare function saveCurrent(nameInput: string, email?: string): Promise<void>;
6
+ export declare function activateProfile(nameInput: string): Promise<void>;
7
+ export declare function switchProfile(name: string): Promise<void>;
8
+ export declare function detectEmail(content: string): string | undefined;
9
+ export declare function loginProfile(nameInput: string, explicitEmail?: string, resume?: boolean): Promise<void>;
@@ -0,0 +1,169 @@
1
+ import { spawn } from "node:child_process";
2
+ import { readdir, readFile, rm } from "node:fs/promises";
3
+ import { connect } from "node:net";
4
+ import { join } from "node:path";
5
+ import { ensureDirectories, loadState, logDir, runtimeDir, saveState, upsertProfile, validateProfileName, } from "./config.js";
6
+ import { keychain } from "./keychain.js";
7
+ import { findRealAgy, runningAgy, stopProcesses, } from "./processes.js";
8
+ async function send(socketPath, command) {
9
+ return await new Promise((resolvePromise, reject) => {
10
+ const socket = connect(socketPath);
11
+ let input = "";
12
+ socket.setEncoding("utf8");
13
+ socket.on("connect", () => socket.end(`${JSON.stringify({ command })}\n`));
14
+ socket.on("data", (chunk) => { input += chunk; });
15
+ socket.on("error", reject);
16
+ socket.on("close", () => {
17
+ try {
18
+ resolvePromise(JSON.parse(input));
19
+ }
20
+ catch {
21
+ reject(new Error(`Invalid response from session ${socketPath}`));
22
+ }
23
+ });
24
+ });
25
+ }
26
+ export async function sessionRecords() {
27
+ await ensureDirectories();
28
+ const entries = await readdir(runtimeDir);
29
+ const records = [];
30
+ for (const entry of entries.filter((name) => name.endsWith(".json"))) {
31
+ const path = join(runtimeDir, entry);
32
+ try {
33
+ const record = JSON.parse(await readFile(path, "utf8"));
34
+ process.kill(record.pid, 0);
35
+ records.push(record);
36
+ }
37
+ catch {
38
+ await rm(path, { force: true });
39
+ }
40
+ }
41
+ return records;
42
+ }
43
+ export async function pauseAll() {
44
+ const records = await sessionRecords();
45
+ const paused = [];
46
+ for (const record of records) {
47
+ const reply = await send(record.socketPath, "pause");
48
+ if (!reply.ok)
49
+ throw new Error(reply.error ?? `Failed to pause ${record.id}`);
50
+ paused.push(reply.record ?? record);
51
+ }
52
+ const managedPIDs = new Set(paused.map((record) => record.childPid).filter(Boolean));
53
+ const unmanaged = (await runningAgy()).filter(({ pid }) => !managedPIDs.has(pid));
54
+ if (unmanaged.length)
55
+ await stopProcesses(unmanaged);
56
+ return paused;
57
+ }
58
+ export async function resumeAll(records) {
59
+ for (const record of records) {
60
+ try {
61
+ const reply = await send(record.socketPath, "resume");
62
+ if (!reply.ok)
63
+ throw new Error(reply.error);
64
+ }
65
+ catch (error) {
66
+ console.error(`agyx: failed to resume session ${record.id}: ${error.message}`);
67
+ }
68
+ }
69
+ }
70
+ export async function saveCurrent(nameInput, email) {
71
+ const name = validateProfileName(nameInput);
72
+ const credential = await keychain.readActive();
73
+ await keychain.writeProfile(name, credential);
74
+ await upsertProfile(name, email, true);
75
+ }
76
+ export async function activateProfile(nameInput) {
77
+ const name = validateProfileName(nameInput);
78
+ const state = await loadState();
79
+ if (!state.profiles.some((profile) => profile.name === name)) {
80
+ throw new Error(`Profile not found: ${name}`);
81
+ }
82
+ const credential = await keychain.readProfile(name);
83
+ await keychain.writeActive(credential);
84
+ state.activeProfile = name;
85
+ await saveState(state);
86
+ }
87
+ export async function switchProfile(name) {
88
+ const sessions = await pauseAll();
89
+ try {
90
+ await activateProfile(name);
91
+ }
92
+ finally {
93
+ await resumeAll(sessions);
94
+ }
95
+ }
96
+ export function detectEmail(content) {
97
+ const matches = [...content.matchAll(/authenticated successfully as ([^\s]+@[^\s]+)/gi)];
98
+ return matches.at(-1)?.[1];
99
+ }
100
+ async function interactiveLogin(logPath) {
101
+ const realAgy = await findRealAgy();
102
+ return await new Promise((resolvePromise, reject) => {
103
+ const child = spawn(realAgy, ["--log-file", logPath], { stdio: "inherit" });
104
+ let detectedEmail;
105
+ let terminationTimer;
106
+ const interval = setInterval(async () => {
107
+ try {
108
+ const email = detectEmail(await readFile(logPath, "utf8"));
109
+ if (!email || detectedEmail)
110
+ return;
111
+ detectedEmail = email;
112
+ clearInterval(interval);
113
+ setTimeout(() => {
114
+ if (child.exitCode === null)
115
+ child.kill("SIGTERM");
116
+ terminationTimer = setTimeout(() => {
117
+ if (child.exitCode === null)
118
+ child.kill("SIGKILL");
119
+ }, 5000);
120
+ }, 750);
121
+ }
122
+ catch {
123
+ // Wait for the log file and successful OAuth line.
124
+ }
125
+ }, 200);
126
+ child.on("error", (error) => {
127
+ clearInterval(interval);
128
+ reject(error);
129
+ });
130
+ child.on("exit", () => {
131
+ clearInterval(interval);
132
+ if (terminationTimer)
133
+ clearTimeout(terminationTimer);
134
+ resolvePromise(detectedEmail);
135
+ });
136
+ });
137
+ }
138
+ export async function loginProfile(nameInput, explicitEmail, resume = true) {
139
+ const name = validateProfileName(nameInput);
140
+ const sessions = await pauseAll();
141
+ const state = await loadState();
142
+ const previousCredential = await keychain.readActive().catch(() => undefined);
143
+ if (state.activeProfile && previousCredential) {
144
+ await keychain.writeProfile(state.activeProfile, previousCredential);
145
+ }
146
+ const logPath = join(logDir, `login-${Date.now()}.log`);
147
+ try {
148
+ await keychain.deleteActive();
149
+ console.log("Complete Google sign-in in the browser. agyx will continue automatically.");
150
+ const detectedEmail = await interactiveLogin(logPath);
151
+ const credential = await keychain.readActive().catch(() => undefined);
152
+ if (!credential)
153
+ throw new Error("Login ended without creating an agy credential.");
154
+ await keychain.writeProfile(name, credential);
155
+ await upsertProfile(name, explicitEmail ?? detectedEmail, true);
156
+ console.log(`Captured and activated profile '${name}'.`);
157
+ }
158
+ catch (error) {
159
+ if (previousCredential)
160
+ await keychain.writeActive(previousCredential);
161
+ await saveState(state);
162
+ throw error;
163
+ }
164
+ finally {
165
+ if (resume)
166
+ await resumeAll(sessions);
167
+ }
168
+ }
169
+ //# sourceMappingURL=coordinator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../src/coordinator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function shellInit(): string;
2
+ export declare function installShellIntegration(): Promise<string>;
@@ -0,0 +1,32 @@
1
+ import { chmod, readFile, writeFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { ensureParent } from "./config.js";
5
+ import { findRealAgy } from "./processes.js";
6
+ const startMarker = "# >>> agyx >>>";
7
+ const endMarker = "# <<< agyx <<<";
8
+ export function shellInit() {
9
+ return `agy() { command agyx session -- "$@"; }`;
10
+ }
11
+ export async function installShellIntegration() {
12
+ await findRealAgy();
13
+ const shell = process.env.SHELL?.split("/").at(-1) ?? "zsh";
14
+ const rcPath = shell === "bash"
15
+ ? join(homedir(), ".bashrc")
16
+ : join(homedir(), ".zshrc");
17
+ await ensureParent(rcPath);
18
+ let content = "";
19
+ try {
20
+ content = await readFile(rcPath, "utf8");
21
+ }
22
+ catch { /* New shell rc file. */ }
23
+ const block = `${startMarker}\n${shellInit()}\n${endMarker}`;
24
+ const pattern = new RegExp(`${startMarker}[\\s\\S]*?${endMarker}`, "m");
25
+ content = pattern.test(content)
26
+ ? content.replace(pattern, block)
27
+ : `${content.trimEnd()}\n\n${block}\n`;
28
+ await writeFile(rcPath, content, { mode: 0o600 });
29
+ await chmod(rcPath, 0o600);
30
+ return rcPath;
31
+ }
32
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,WAAW,GAAG,gBAAgB,CAAC;AACrC,MAAM,SAAS,GAAG,gBAAgB,CAAC;AAEnC,MAAM,UAAU,SAAS;IACvB,OAAO,yCAAyC,CAAC;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAC3C,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;IAC5D,MAAM,MAAM,GAAG,KAAK,KAAK,MAAM;QAC7B,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC;QAC5B,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC9B,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,CAAC;QAAC,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,CAAC;IACjD,MAAM,CAAC,CAAC,wBAAwB,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,GAAG,WAAW,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,CAAC;IAC7D,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,GAAG,WAAW,aAAa,SAAS,EAAE,EAAE,GAAG,CAAC,CAAC;IACxE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;QAC7B,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC;QACjC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClD,MAAM,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC3B,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const keychain: {
2
+ readActive: () => Promise<Buffer<ArrayBufferLike>>;
3
+ writeActive(credential: Buffer): Promise<void>;
4
+ deleteActive: () => Promise<void>;
5
+ readProfile: (name: string) => Promise<Buffer<ArrayBufferLike>>;
6
+ writeProfile: (name: string, credential: Buffer) => Promise<void>;
7
+ deleteProfile: (name: string) => Promise<void>;
8
+ };
@@ -0,0 +1,43 @@
1
+ import { findRealAgy, run } from "./processes.js";
2
+ const security = "/usr/bin/security";
3
+ const activeService = "gemini";
4
+ const activeAccount = "antigravity";
5
+ const vaultService = "agyx";
6
+ async function read(service, account) {
7
+ const result = await run(security, ["find-generic-password", "-s", service, "-a", account, "-w"], { allowFailure: true });
8
+ if (result.code !== 0 || result.stdout.length === 0) {
9
+ throw new Error(`Credential not found: ${service}/${account}`);
10
+ }
11
+ let end = result.stdout.length;
12
+ while (end > 0 && [0x0a, 0x0d].includes(result.stdout[end - 1]))
13
+ end -= 1;
14
+ return result.stdout.subarray(0, end);
15
+ }
16
+ async function remove(service, account) {
17
+ await run(security, ["delete-generic-password", "-s", service, "-a", account], { allowFailure: true });
18
+ }
19
+ async function write(service, account, credential, trustedApplications) {
20
+ await remove(service, account);
21
+ const args = [
22
+ "add-generic-password",
23
+ "-s", service,
24
+ "-a", account,
25
+ "-l", `${service}:${account}`,
26
+ ];
27
+ for (const application of trustedApplications) {
28
+ args.push("-T", application);
29
+ }
30
+ args.push("-w");
31
+ await run(security, args, { input: Buffer.concat([credential, Buffer.from("\n")]) });
32
+ }
33
+ export const keychain = {
34
+ readActive: () => read(activeService, activeAccount),
35
+ async writeActive(credential) {
36
+ await write(activeService, activeAccount, credential, [await findRealAgy(), security]);
37
+ },
38
+ deleteActive: () => remove(activeService, activeAccount),
39
+ readProfile: (name) => read(vaultService, name),
40
+ writeProfile: (name, credential) => write(vaultService, name, credential, [security]),
41
+ deleteProfile: (name) => remove(vaultService, name),
42
+ };
43
+ //# sourceMappingURL=keychain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keychain.js","sourceRoot":"","sources":["../../src/keychain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,QAAQ,GAAG,mBAAmB,CAAC;AACrC,MAAM,aAAa,GAAG,QAAQ,CAAC;AAC/B,MAAM,aAAa,GAAG,aAAa,CAAC;AACpC,MAAM,YAAY,GAAG,MAAM,CAAC;AAE5B,KAAK,UAAU,IAAI,CAAC,OAAe,EAAE,OAAe;IAClD,MAAM,MAAM,GAAG,MAAM,GAAG,CACtB,QAAQ,EACR,CAAC,uBAAuB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAC7D,EAAE,YAAY,EAAE,IAAI,EAAE,CACvB,CAAC;IACF,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,yBAAyB,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;IAC/B,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAE,CAAC;QAAE,GAAG,IAAI,CAAC,CAAC;IAC3E,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACxC,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,OAAe,EAAE,OAAe;IACpD,MAAM,GAAG,CACP,QAAQ,EACR,CAAC,yBAAyB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,EACzD,EAAE,YAAY,EAAE,IAAI,EAAE,CACvB,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,KAAK,CAClB,OAAe,EACf,OAAe,EACf,UAAkB,EAClB,mBAA6B;IAE7B,MAAM,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,IAAI,GAAG;QACX,sBAAsB;QACtB,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,GAAG,OAAO,IAAI,OAAO,EAAE;KAC9B,CAAC;IACF,KAAK,MAAM,WAAW,IAAI,mBAAmB,EAAE,CAAC;QAC9C,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,MAAM,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACvF,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC;IACpD,KAAK,CAAC,WAAW,CAAC,UAAkB;QAClC,MAAM,KAAK,CACT,aAAa,EACb,aAAa,EACb,UAAU,EACV,CAAC,MAAM,WAAW,EAAE,EAAE,QAAQ,CAAC,CAChC,CAAC;IACJ,CAAC;IACD,YAAY,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE,aAAa,CAAC;IACxD,WAAW,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC;IACvD,YAAY,EAAE,CAAC,IAAY,EAAE,UAAkB,EAAE,EAAE,CACjD,KAAK,CAAC,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,QAAQ,CAAC,CAAC;IACnD,aAAa,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,CAAC;CAC5D,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface RunningAgy {
2
+ pid: number;
3
+ command: string;
4
+ }
5
+ export declare function run(executable: string, args: string[], options?: {
6
+ input?: Buffer;
7
+ allowFailure?: boolean;
8
+ }): Promise<{
9
+ code: number;
10
+ stdout: Buffer;
11
+ stderr: Buffer;
12
+ }>;
13
+ export declare function findRealAgy(): Promise<string>;
14
+ export declare function parsePS(output: string): RunningAgy[];
15
+ export declare function runningAgy(): Promise<RunningAgy[]>;
16
+ export declare function stopProcesses(processes: RunningAgy[]): Promise<void>;
17
+ export declare function isRestartable(args: string[]): boolean;
18
+ export declare function withConversation(args: string[], conversationId?: string): string[];
@@ -0,0 +1,140 @@
1
+ import { access, readFile } from "node:fs/promises";
2
+ import { constants } from "node:fs";
3
+ import { delimiter, resolve } from "node:path";
4
+ import { spawn } from "node:child_process";
5
+ import { loadState, saveState } from "./config.js";
6
+ export async function run(executable, args, options = {}) {
7
+ return await new Promise((resolvePromise, reject) => {
8
+ const child = spawn(executable, args, {
9
+ stdio: ["pipe", "pipe", "pipe"],
10
+ env: process.env,
11
+ });
12
+ const stdout = [];
13
+ const stderr = [];
14
+ child.stdout.on("data", (chunk) => stdout.push(chunk));
15
+ child.stderr.on("data", (chunk) => stderr.push(chunk));
16
+ child.on("error", reject);
17
+ child.on("close", (code) => {
18
+ const result = {
19
+ code: code ?? 1,
20
+ stdout: Buffer.concat(stdout),
21
+ stderr: Buffer.concat(stderr),
22
+ };
23
+ if (!options.allowFailure && result.code !== 0) {
24
+ reject(new Error(result.stderr.toString("utf8").trim()
25
+ || `${executable} exited with status ${result.code}`));
26
+ }
27
+ else {
28
+ resolvePromise(result);
29
+ }
30
+ });
31
+ if (options.input)
32
+ child.stdin.end(options.input);
33
+ else
34
+ child.stdin.end();
35
+ });
36
+ }
37
+ async function executable(path) {
38
+ try {
39
+ await access(path, constants.X_OK);
40
+ return true;
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ }
46
+ export async function findRealAgy() {
47
+ const override = process.env.AGYX_REAL_AGY;
48
+ if (override && await executable(override))
49
+ return resolve(override);
50
+ const state = await loadState();
51
+ if (state.realAgyPath && await executable(state.realAgyPath)) {
52
+ return state.realAgyPath;
53
+ }
54
+ const candidates = [
55
+ "/opt/homebrew/bin/agy",
56
+ "/usr/local/bin/agy",
57
+ ...((process.env.PATH ?? "").split(delimiter).map((directory) => resolve(directory, "agy"))),
58
+ ];
59
+ for (const candidate of [...new Set(candidates)]) {
60
+ if (!await executable(candidate))
61
+ continue;
62
+ try {
63
+ const header = await readFile(candidate, { encoding: "utf8" });
64
+ if (header.includes("agyx session"))
65
+ continue;
66
+ }
67
+ catch {
68
+ // Native binaries are expected to fail UTF-8 inspection.
69
+ }
70
+ state.realAgyPath = candidate;
71
+ await saveState(state);
72
+ return candidate;
73
+ }
74
+ throw new Error("The real agy executable was not found. Set AGYX_REAL_AGY.");
75
+ }
76
+ export function parsePS(output) {
77
+ return output.split("\n").flatMap((line) => {
78
+ const match = line.trim().match(/^(\d+)\s+(.+)$/);
79
+ if (!match)
80
+ return [];
81
+ const command = match[2];
82
+ const first = command.split(/\s+/, 1)[0];
83
+ if (first.split("/").at(-1) !== "agy")
84
+ return [];
85
+ return [{ pid: Number(match[1]), command }];
86
+ });
87
+ }
88
+ export async function runningAgy() {
89
+ const result = await run("/bin/ps", ["-axo", "pid=,command="]);
90
+ return parsePS(result.stdout.toString("utf8"));
91
+ }
92
+ export async function stopProcesses(processes) {
93
+ for (const processInfo of processes) {
94
+ try {
95
+ process.kill(processInfo.pid, "SIGTERM");
96
+ }
97
+ catch (error) {
98
+ if (error.code !== "ESRCH")
99
+ throw error;
100
+ }
101
+ }
102
+ const deadline = Date.now() + 5000;
103
+ let remaining = processes;
104
+ while (remaining.length && Date.now() < deadline) {
105
+ await new Promise((resolvePromise) => setTimeout(resolvePromise, 100));
106
+ const live = new Set((await runningAgy()).map(({ pid }) => pid));
107
+ remaining = processes.filter(({ pid }) => live.has(pid));
108
+ }
109
+ for (const processInfo of remaining) {
110
+ try {
111
+ process.kill(processInfo.pid, "SIGKILL");
112
+ }
113
+ catch (error) {
114
+ if (error.code !== "ESRCH")
115
+ throw error;
116
+ }
117
+ }
118
+ }
119
+ export function isRestartable(args) {
120
+ return !args.some((argument) => ["-p", "--print", "--prompt"].includes(argument));
121
+ }
122
+ export function withConversation(args, conversationId) {
123
+ if (!conversationId)
124
+ return [...args];
125
+ const result = [];
126
+ for (let index = 0; index < args.length; index += 1) {
127
+ const argument = args[index];
128
+ if (argument === "-c" || argument === "--continue")
129
+ continue;
130
+ if (argument === "--conversation") {
131
+ index += 1;
132
+ continue;
133
+ }
134
+ if (argument.startsWith("--conversation="))
135
+ continue;
136
+ result.push(argument);
137
+ }
138
+ return [...result, "--conversation", conversationId];
139
+ }
140
+ //# sourceMappingURL=processes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processes.js","sourceRoot":"","sources":["../../src/processes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface SessionRecord {
2
+ id: string;
3
+ pid: number;
4
+ childPid?: number;
5
+ cwd: string;
6
+ args: string[];
7
+ conversationId?: string;
8
+ socketPath: string;
9
+ logPath: string;
10
+ paused: boolean;
11
+ restartable: boolean;
12
+ startedAt: string;
13
+ }
14
+ export declare function detectConversation(content: string): string | undefined;
15
+ export declare function supervise(args: string[]): Promise<number>;
@@ -0,0 +1,177 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createServer } from "node:net";
3
+ import { readFile, writeFile } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ import { cleanupRuntimeFile, ensureDirectories, logDir, runtimeDir, } from "./config.js";
6
+ import { findRealAgy, isRestartable, withConversation, } from "./processes.js";
7
+ export function detectConversation(content) {
8
+ const patterns = [
9
+ /Created conversation ([0-9a-f-]{36})/gi,
10
+ /GetConversationDetail: found conversation ([0-9a-f-]{36})/gi,
11
+ /Conversation using ID: ([0-9a-f-]{36})/gi,
12
+ ];
13
+ let latest;
14
+ for (const pattern of patterns) {
15
+ for (const match of content.matchAll(pattern))
16
+ latest = match[1];
17
+ }
18
+ return latest;
19
+ }
20
+ function writeJSON(socket, value) {
21
+ socket.end(`${JSON.stringify(value)}\n`);
22
+ }
23
+ export async function supervise(args) {
24
+ if (!isRestartable(args)) {
25
+ const realAgy = await findRealAgy();
26
+ return await new Promise((resolvePromise, reject) => {
27
+ const child = spawn(realAgy, args, { stdio: "inherit", cwd: process.cwd() });
28
+ child.on("error", reject);
29
+ child.on("exit", (code, signal) => resolvePromise(code ?? (signal ? 128 : 1)));
30
+ });
31
+ }
32
+ await ensureDirectories();
33
+ const id = `${process.pid}-${crypto.randomUUID().slice(0, 8)}`;
34
+ // macOS limits Unix-domain socket paths to roughly 104 bytes. Keep the
35
+ // transport filename minimal; the full session identity remains in metadata.
36
+ const socketPath = join(runtimeDir, `${process.pid}.sock`);
37
+ const recordPath = join(runtimeDir, `${id}.json`);
38
+ const logPath = join(logDir, `session-${id}.log`);
39
+ const realAgy = await findRealAgy();
40
+ let child;
41
+ let paused = false;
42
+ let intentionalStop = false;
43
+ let conversationId;
44
+ let finalCode = 0;
45
+ const persist = async () => {
46
+ const record = {
47
+ id,
48
+ pid: process.pid,
49
+ childPid: child?.pid,
50
+ cwd: process.cwd(),
51
+ args,
52
+ conversationId,
53
+ socketPath,
54
+ logPath,
55
+ paused,
56
+ restartable: true,
57
+ startedAt: new Date().toISOString(),
58
+ };
59
+ await writeFile(recordPath, `${JSON.stringify(record, null, 2)}\n`, { mode: 0o600 });
60
+ };
61
+ const refreshConversation = async () => {
62
+ try {
63
+ conversationId = detectConversation(await readFile(logPath, "utf8"))
64
+ ?? conversationId;
65
+ }
66
+ catch {
67
+ // The log may not exist until agy has initialized.
68
+ }
69
+ };
70
+ const startChild = async () => {
71
+ intentionalStop = false;
72
+ paused = false;
73
+ const launchArgs = withConversation(args, conversationId);
74
+ if (!launchArgs.some((argument) => argument === "--log-file" || argument.startsWith("--log-file="))) {
75
+ launchArgs.push("--log-file", logPath);
76
+ }
77
+ child = spawn(realAgy, launchArgs, {
78
+ cwd: process.cwd(),
79
+ stdio: "inherit",
80
+ env: {
81
+ ...process.env,
82
+ AGYX_MANAGED: "1",
83
+ AGYX_SESSION_ID: id,
84
+ },
85
+ });
86
+ await persist();
87
+ child.on("exit", async (code, signal) => {
88
+ finalCode = code ?? (signal ? 128 : 1);
89
+ await refreshConversation();
90
+ child = undefined;
91
+ await persist();
92
+ if (!intentionalStop && !paused) {
93
+ await shutdown();
94
+ process.exit(finalCode);
95
+ }
96
+ });
97
+ };
98
+ const stopChild = async () => {
99
+ if (!child?.pid)
100
+ return;
101
+ intentionalStop = true;
102
+ const current = child;
103
+ current.kill("SIGTERM");
104
+ await new Promise((resolvePromise) => {
105
+ const timer = setTimeout(() => {
106
+ if (current.exitCode === null)
107
+ current.kill("SIGKILL");
108
+ }, 5000);
109
+ const finish = () => {
110
+ clearTimeout(timer);
111
+ resolvePromise();
112
+ };
113
+ current.once("exit", finish);
114
+ if (current.exitCode !== null || current.signalCode !== null)
115
+ finish();
116
+ });
117
+ await refreshConversation();
118
+ };
119
+ const server = createServer({ allowHalfOpen: true }, (socket) => {
120
+ let input = "";
121
+ socket.setEncoding("utf8");
122
+ socket.on("data", (chunk) => { input += chunk; });
123
+ socket.on("end", async () => {
124
+ try {
125
+ const request = JSON.parse(input);
126
+ if (request.command === "pause") {
127
+ paused = true;
128
+ await stopChild();
129
+ await persist();
130
+ writeJSON(socket, { ok: true, record: JSON.parse(await readFile(recordPath, "utf8")) });
131
+ }
132
+ else if (request.command === "resume") {
133
+ if (!child)
134
+ await startChild();
135
+ writeJSON(socket, { ok: true });
136
+ }
137
+ else if (request.command === "shutdown") {
138
+ await stopChild();
139
+ writeJSON(socket, { ok: true });
140
+ await shutdown();
141
+ process.exit(0);
142
+ }
143
+ else {
144
+ await refreshConversation();
145
+ await persist();
146
+ writeJSON(socket, { ok: true, record: JSON.parse(await readFile(recordPath, "utf8")) });
147
+ }
148
+ }
149
+ catch (error) {
150
+ writeJSON(socket, { ok: false, error: error.message });
151
+ }
152
+ });
153
+ });
154
+ const shutdown = async () => {
155
+ await cleanupRuntimeFile(socketPath);
156
+ await cleanupRuntimeFile(recordPath);
157
+ server.close();
158
+ };
159
+ await cleanupRuntimeFile(socketPath);
160
+ await new Promise((resolvePromise, reject) => {
161
+ server.once("error", reject);
162
+ server.listen(socketPath, () => resolvePromise());
163
+ });
164
+ process.on("SIGINT", async () => {
165
+ await stopChild();
166
+ await shutdown();
167
+ process.exit(130);
168
+ });
169
+ process.on("SIGTERM", async () => {
170
+ await stopChild();
171
+ await shutdown();
172
+ process.exit(143);
173
+ });
174
+ await startChild();
175
+ return await new Promise(() => undefined);
176
+ }
177
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAU,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,MAAM,EACN,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,WAAW,EACX,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAkBxB,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,QAAQ,GAAG;QACf,wCAAwC;QACxC,6DAA6D;QAC7D,0CAA0C;KAC3C,CAAC;IACF,IAAI,MAA0B,CAAC;IAC/B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,SAAS,CAAC,MAAc,EAAE,KAAc;IAC/C,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAc;IAC5C,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,CAAC;QACpC,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE;YAClD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAC7E,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC1B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,iBAAiB,EAAE,CAAC;IAC1B,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC/D,uEAAuE;IACvE,6EAA6E;IAC7E,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;IAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,CAAC;IACpC,IAAI,KAA+B,CAAC;IACpC,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,IAAI,cAAkC,CAAC;IACvC,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,MAAM,OAAO,GAAG,KAAK,IAAmB,EAAE;QACxC,MAAM,MAAM,GAAkB;YAC5B,EAAE;YACF,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,QAAQ,EAAE,KAAK,EAAE,GAAG;YACpB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,IAAI;YACJ,cAAc;YACd,UAAU;YACV,OAAO;YACP,MAAM;YACN,WAAW,EAAE,IAAI;YACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QACF,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACvF,CAAC,CAAC;IAEF,MAAM,mBAAmB,GAAG,KAAK,IAAmB,EAAE;QACpD,IAAI,CAAC;YACH,cAAc,GAAG,kBAAkB,CAAC,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;mBAC/D,cAAc,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,mDAAmD;QACrD,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,KAAK,IAAmB,EAAE;QAC3C,eAAe,GAAG,KAAK,CAAC;QACxB,MAAM,GAAG,KAAK,CAAC;QACf,MAAM,UAAU,GAAG,gBAAgB,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QAC1D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAChC,QAAQ,KAAK,YAAY,IAAI,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAChE,EAAE,CAAC;YACF,UAAU,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACzC,CAAC;QACD,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE;YACjC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,YAAY,EAAE,GAAG;gBACjB,eAAe,EAAE,EAAE;aACpB;SACF,CAAC,CAAC;QACH,MAAM,OAAO,EAAE,CAAC;QAChB,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;YACtC,SAAS,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACvC,MAAM,mBAAmB,EAAE,CAAC;YAC5B,KAAK,GAAG,SAAS,CAAC;YAClB,MAAM,OAAO,EAAE,CAAC;YAChB,IAAI,CAAC,eAAe,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChC,MAAM,QAAQ,EAAE,CAAC;gBACjB,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,KAAK,IAAmB,EAAE;QAC1C,IAAI,CAAC,KAAK,EAAE,GAAG;YAAE,OAAO;QACxB,eAAe,GAAG,IAAI,CAAC;QACvB,MAAM,OAAO,GAAG,KAAK,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxB,MAAM,IAAI,OAAO,CAAO,CAAC,cAAc,EAAE,EAAE;YACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI;oBAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACzD,CAAC,EAAE,IAAI,CAAC,CAAC;YACT,MAAM,MAAM,GAAG,GAAS,EAAE;gBACxB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,cAAc,EAAE,CAAC;YACnB,CAAC,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC7B,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,IAAI,OAAO,CAAC,UAAU,KAAK,IAAI;gBAAE,MAAM,EAAE,CAAC;QACzE,CAAC,CAAC,CAAC;QACH,MAAM,mBAAmB,EAAE,CAAC;IAC9B,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE;QAC9D,IAAI,KAAK,GAAG,EAAE,CAAC;QACf,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC3B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;YAC1B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAmB,CAAC;gBACpD,IAAI,OAAO,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;oBAChC,MAAM,GAAG,IAAI,CAAC;oBACd,MAAM,SAAS,EAAE,CAAC;oBAClB,MAAM,OAAO,EAAE,CAAC;oBAChB,SAAS,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC1F,CAAC;qBAAM,IAAI,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;oBACxC,IAAI,CAAC,KAAK;wBAAE,MAAM,UAAU,EAAE,CAAC;oBAC/B,SAAS,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBAClC,CAAC;qBAAM,IAAI,OAAO,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;oBAC1C,MAAM,SAAS,EAAE,CAAC;oBAClB,SAAS,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;oBAChC,MAAM,QAAQ,EAAE,CAAC;oBACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;qBAAM,CAAC;oBACN,MAAM,mBAAmB,EAAE,CAAC;oBAC5B,MAAM,OAAO,EAAE,CAAC;oBAChB,SAAS,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC1F,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,SAAS,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YACpE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,KAAK,IAAmB,EAAE;QACzC,MAAM,kBAAkB,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,kBAAkB,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,IAAI,OAAO,CAAO,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE;QACjD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC9B,MAAM,SAAS,EAAE,CAAC;QAClB,MAAM,QAAQ,EAAE,CAAC;QACjB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QAC/B,MAAM,SAAS,EAAE,CAAC;QAClB,MAAM,QAAQ,EAAE,CAAC;QACjB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IACH,MAAM,UAAU,EAAE,CAAC;IACnB,OAAO,MAAM,IAAI,OAAO,CAAS,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import { supervise } from "./session.js";
3
+ supervise(process.argv.slice(2))
4
+ .then((code) => { process.exitCode = code; })
5
+ .catch((error) => {
6
+ console.error(`agyx: ${error.message}`);
7
+ process.exitCode = 1;
8
+ });
9
+ //# sourceMappingURL=shim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shim.js","sourceRoot":"","sources":["../../src/shim.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KAC7B,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;KAC5C,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACf,OAAO,CAAC,KAAK,CAAC,SAAU,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IACnD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "agyx",
3
+ "version": "0.1.0",
4
+ "description": "Multi-account session supervisor for Google Antigravity CLI",
5
+ "type": "module",
6
+ "bin": {
7
+ "agyx": "dist/src/cli.js",
8
+ "agyx-agy": "dist/src/shim.js"
9
+ },
10
+ "files": [
11
+ "dist/src",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc -p tsconfig.json",
17
+ "clean": "rm -rf dist",
18
+ "prepack": "npm run clean && npm run build",
19
+ "test": "npm run clean && npm run build && node --test dist/test/*.test.js"
20
+ },
21
+ "keywords": [
22
+ "antigravity",
23
+ "gemini",
24
+ "cli",
25
+ "oauth",
26
+ "account-switcher"
27
+ ],
28
+ "author": "Dongwook Chan",
29
+ "license": "MIT",
30
+ "engines": {
31
+ "node": ">=20"
32
+ },
33
+ "os": [
34
+ "darwin"
35
+ ],
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/dongwook-chan/agyx.git"
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/dongwook-chan/agyx/issues"
42
+ },
43
+ "homepage": "https://github.com/dongwook-chan/agyx#readme",
44
+ "devDependencies": {
45
+ "@types/node": "^24.0.0",
46
+ "typescript": "^5.8.0"
47
+ }
48
+ }