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 +21 -0
- package/README.md +96 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +171 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.d.ts +23 -0
- package/dist/src/config.js +61 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/coordinator.d.ts +9 -0
- package/dist/src/coordinator.js +169 -0
- package/dist/src/coordinator.js.map +1 -0
- package/dist/src/install.d.ts +2 -0
- package/dist/src/install.js +32 -0
- package/dist/src/install.js.map +1 -0
- package/dist/src/keychain.d.ts +8 -0
- package/dist/src/keychain.js +43 -0
- package/dist/src/keychain.js.map +1 -0
- package/dist/src/processes.d.ts +18 -0
- package/dist/src/processes.js +140 -0
- package/dist/src/processes.js.map +1 -0
- package/dist/src/session.d.ts +15 -0
- package/dist/src/session.js +177 -0
- package/dist/src/session.js.map +1 -0
- package/dist/src/shim.d.ts +2 -0
- package/dist/src/shim.js +9 -0
- package/dist/src/shim.js.map +1 -0
- package/package.json +48 -0
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.
|
package/dist/src/cli.js
ADDED
|
@@ -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,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":"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"}
|
|
@@ -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":"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"}
|
package/dist/src/shim.js
ADDED
|
@@ -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
|
+
}
|