agent-gear 1.0.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.
Files changed (65) hide show
  1. package/AGENTS.md +67 -0
  2. package/dist/acp/bridge.d.ts +56 -0
  3. package/dist/acp/bridge.d.ts.map +1 -0
  4. package/dist/acp/bridge.js +295 -0
  5. package/dist/acp/bridge.js.map +1 -0
  6. package/dist/acp/detector.d.ts +13 -0
  7. package/dist/acp/detector.d.ts.map +1 -0
  8. package/dist/acp/detector.js +29 -0
  9. package/dist/acp/detector.js.map +1 -0
  10. package/dist/acp/spawner.d.ts +24 -0
  11. package/dist/acp/spawner.d.ts.map +1 -0
  12. package/dist/acp/spawner.js +82 -0
  13. package/dist/acp/spawner.js.map +1 -0
  14. package/dist/acp/sync-bridge.d.ts +21 -0
  15. package/dist/acp/sync-bridge.d.ts.map +1 -0
  16. package/dist/acp/sync-bridge.js +75 -0
  17. package/dist/acp/sync-bridge.js.map +1 -0
  18. package/dist/config.d.ts +22 -0
  19. package/dist/config.d.ts.map +1 -0
  20. package/dist/config.js +63 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/daemon.d.ts +5 -0
  23. package/dist/daemon.d.ts.map +1 -0
  24. package/dist/daemon.js +32 -0
  25. package/dist/daemon.js.map +1 -0
  26. package/dist/git-handler.d.ts +17 -0
  27. package/dist/git-handler.d.ts.map +1 -0
  28. package/dist/git-handler.js +60 -0
  29. package/dist/git-handler.js.map +1 -0
  30. package/dist/git-handler.test.d.ts +2 -0
  31. package/dist/git-handler.test.d.ts.map +1 -0
  32. package/dist/git-handler.test.js +127 -0
  33. package/dist/git-handler.test.js.map +1 -0
  34. package/dist/heartbeat.d.ts +6 -0
  35. package/dist/heartbeat.d.ts.map +1 -0
  36. package/dist/heartbeat.js +16 -0
  37. package/dist/heartbeat.js.map +1 -0
  38. package/dist/index.d.ts +3 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +52 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/socketio-client.d.ts +6 -0
  43. package/dist/socketio-client.d.ts.map +1 -0
  44. package/dist/socketio-client.js +385 -0
  45. package/dist/socketio-client.js.map +1 -0
  46. package/package.json +34 -0
  47. package/src/acp/bridge.ts +327 -0
  48. package/src/acp/detector.ts +40 -0
  49. package/src/acp/spawner.ts +94 -0
  50. package/src/acp/sync-bridge.ts +111 -0
  51. package/src/config.ts +75 -0
  52. package/src/daemon.ts +33 -0
  53. package/src/git-handler.test.ts +153 -0
  54. package/src/git-handler.ts +75 -0
  55. package/src/heartbeat.ts +18 -0
  56. package/src/index.ts +60 -0
  57. package/src/socketio-client.ts +497 -0
  58. package/tests/acp-bridge.test.ts +473 -0
  59. package/tests/acp-detector.test.ts +70 -0
  60. package/tests/acp-spawner.test.ts +149 -0
  61. package/tests/acp-sync-bridge.test.ts +263 -0
  62. package/tests/config.test.ts +166 -0
  63. package/tests/socketio-client.test.ts +196 -0
  64. package/tsconfig.json +21 -0
  65. package/vitest.config.ts +14 -0
@@ -0,0 +1,75 @@
1
+ import * as acp from '@agentclientprotocol/sdk';
2
+ import { AcpSpawner } from './spawner.js';
3
+ const ACP_PROTOCOL_VERSION = 1;
4
+ const CONNECT_TIMEOUT_MS = 30_000;
5
+ const LOAD_SESSION_TIMEOUT_MS = 120_000;
6
+ async function withTimeout(promise, ms, message) {
7
+ let timer;
8
+ const timerPromise = new Promise((_, reject) => {
9
+ timer = setTimeout(() => reject(new Error(message)), ms);
10
+ });
11
+ try {
12
+ return await Promise.race([promise, timerPromise]);
13
+ }
14
+ finally {
15
+ clearTimeout(timer);
16
+ }
17
+ }
18
+ export class AcpSyncBridge {
19
+ spawner;
20
+ connection = null;
21
+ updates = [];
22
+ constructor(options, spawner) {
23
+ this.spawner = spawner ?? new AcpSpawner({
24
+ sessionId: `sync_${Date.now()}`,
25
+ cwd: options.cwd,
26
+ });
27
+ }
28
+ async connect(timeoutMs = CONNECT_TIMEOUT_MS) {
29
+ this.spawner.start();
30
+ const stream = acp.ndJsonStream(this.spawner.stdin, this.spawner.stdout);
31
+ this.connection = new acp.ClientSideConnection(() => this, stream);
32
+ const exitPromise = this.spawner.closed.then(() => {
33
+ throw new Error('ACP process exited unexpectedly');
34
+ });
35
+ exitPromise.catch(() => { });
36
+ const initPromise = this.connection.initialize({
37
+ protocolVersion: ACP_PROTOCOL_VERSION,
38
+ clientCapabilities: {},
39
+ clientInfo: { name: 'agent-gear', version: '1.0.0' },
40
+ });
41
+ await withTimeout(Promise.race([initPromise, exitPromise]), timeoutMs, `ACP connect timed out after ${timeoutMs}ms`);
42
+ }
43
+ async listSessions(cwd) {
44
+ return this.connection.listSessions({ cwd });
45
+ }
46
+ async loadSession(sessionId, cwd, timeoutMs = LOAD_SESSION_TIMEOUT_MS) {
47
+ this.updates = [];
48
+ const exitPromise = this.spawner.closed.then(() => {
49
+ throw new Error('ACP process exited unexpectedly');
50
+ });
51
+ exitPromise.catch(() => { });
52
+ const config = await withTimeout(Promise.race([
53
+ this.connection.loadSession({
54
+ cwd,
55
+ sessionId,
56
+ mcpServers: [],
57
+ }),
58
+ exitPromise,
59
+ ]), timeoutMs, `ACP load-session timed out after ${timeoutMs}ms`);
60
+ return { config, updates: [...this.updates] };
61
+ }
62
+ async disconnect(sessionId) {
63
+ if (sessionId) {
64
+ await this.connection?.closeSession({ sessionId }).catch(() => { });
65
+ }
66
+ this.spawner.stop();
67
+ }
68
+ async sessionUpdate(params) {
69
+ this.updates.push(params);
70
+ }
71
+ async requestPermission() {
72
+ return { outcome: { outcome: 'cancelled' } };
73
+ }
74
+ }
75
+ //# sourceMappingURL=sync-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-bridge.js","sourceRoot":"","sources":["../../src/acp/sync-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface ConfigData {
2
+ key?: {
3
+ value: string;
4
+ };
5
+ server?: {
6
+ endpoint: string;
7
+ };
8
+ controller?: {
9
+ name: string;
10
+ };
11
+ }
12
+ export declare function readConfig(): ConfigData;
13
+ export declare function writeConfig(data: ConfigData): void;
14
+ export declare function clearConfigKey(): void;
15
+ export declare function getKeyFromConfig(): string | undefined;
16
+ export declare function getEndpointFromConfig(): string | undefined;
17
+ export declare function getControllerNameFromConfig(): string | undefined;
18
+ export declare function saveKeyToConfig(key: string): void;
19
+ export declare function saveEndpointToConfig(endpoint: string): void;
20
+ export declare function resolveKey(cliKey?: string): string | undefined;
21
+ export declare function resolveEndpoint(cliEndpoint?: string): string | undefined;
22
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxB,MAAM,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/B;AAED,wBAAgB,UAAU,IAAI,UAAU,CAMvC;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAKlD;AAED,wBAAgB,cAAc,IAAI,IAAI,CAIrC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAGrD;AAED,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,SAAS,CAG1D;AAED,wBAAgB,2BAA2B,IAAI,MAAM,GAAG,SAAS,CAGhE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAIjD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAI3D;AAED,wBAAgB,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK9D;AAED,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKxE"}
package/dist/config.js ADDED
@@ -0,0 +1,63 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { homedir } from 'os';
4
+ import { parse, stringify } from 'smol-toml';
5
+ const CONFIG_DIR = join(homedir(), '.zag');
6
+ const CONFIG_FILE = join(CONFIG_DIR, 'config.toml');
7
+ export function readConfig() {
8
+ if (!existsSync(CONFIG_FILE)) {
9
+ return {};
10
+ }
11
+ const content = readFileSync(CONFIG_FILE, 'utf-8');
12
+ return parse(content);
13
+ }
14
+ export function writeConfig(data) {
15
+ if (!existsSync(CONFIG_DIR)) {
16
+ mkdirSync(CONFIG_DIR, { recursive: true });
17
+ }
18
+ writeFileSync(CONFIG_FILE, stringify(data), 'utf-8');
19
+ }
20
+ export function clearConfigKey() {
21
+ const config = readConfig();
22
+ delete config.key;
23
+ writeConfig(config);
24
+ }
25
+ export function getKeyFromConfig() {
26
+ const config = readConfig();
27
+ return config.key?.value;
28
+ }
29
+ export function getEndpointFromConfig() {
30
+ const config = readConfig();
31
+ return config.server?.endpoint;
32
+ }
33
+ export function getControllerNameFromConfig() {
34
+ const config = readConfig();
35
+ return config.controller?.name;
36
+ }
37
+ export function saveKeyToConfig(key) {
38
+ const config = readConfig();
39
+ config.key = { value: key };
40
+ writeConfig(config);
41
+ }
42
+ export function saveEndpointToConfig(endpoint) {
43
+ const config = readConfig();
44
+ config.server = { endpoint };
45
+ writeConfig(config);
46
+ }
47
+ export function resolveKey(cliKey) {
48
+ if (cliKey)
49
+ return cliKey;
50
+ const envKey = process.env.ZAG_CONTROLLER_KEY;
51
+ if (envKey)
52
+ return envKey;
53
+ return getKeyFromConfig();
54
+ }
55
+ export function resolveEndpoint(cliEndpoint) {
56
+ if (cliEndpoint)
57
+ return cliEndpoint;
58
+ const envEndpoint = process.env.ZAG_SERVER_ENDPOINT;
59
+ if (envEndpoint)
60
+ return envEndpoint;
61
+ return getEndpointFromConfig();
62
+ }
63
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;AAC3C,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAQpD,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACnD,OAAO,KAAK,CAAC,OAAO,CAAe,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAgB;IAC1C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,aAAa,CAAC,WAAW,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,GAAG,CAAC;IAClB,WAAW,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAC5B,WAAW,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAgB;IACnD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,CAAC,MAAM,GAAG,EAAE,QAAQ,EAAE,CAAC;IAC7B,WAAW,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAe;IACxC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC9C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,OAAO,gBAAgB,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,WAAoB;IAClD,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IACpC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACpD,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IACpC,OAAO,qBAAqB,EAAE,CAAC;AACjC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function writePid(): void;
2
+ export declare function readPid(): number | null;
3
+ export declare function removePid(): void;
4
+ export declare function isRunning(): boolean;
5
+ //# sourceMappingURL=daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAMA,wBAAgB,QAAQ,IAAI,IAAI,CAE/B;AAED,wBAAgB,OAAO,IAAI,MAAM,GAAG,IAAI,CAKvC;AAED,wBAAgB,SAAS,IAAI,IAAI,CAIhC;AAED,wBAAgB,SAAS,IAAI,OAAO,CASnC"}
package/dist/daemon.js ADDED
@@ -0,0 +1,32 @@
1
+ import { writeFileSync, existsSync, readFileSync, unlinkSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { tmpdir } from 'os';
4
+ const PID_FILE = join(tmpdir(), 'agent-gear.pid');
5
+ export function writePid() {
6
+ writeFileSync(PID_FILE, process.pid.toString(), 'utf-8');
7
+ }
8
+ export function readPid() {
9
+ if (!existsSync(PID_FILE))
10
+ return null;
11
+ const content = readFileSync(PID_FILE, 'utf-8').trim();
12
+ const pid = parseInt(content, 10);
13
+ return isNaN(pid) ? null : pid;
14
+ }
15
+ export function removePid() {
16
+ if (existsSync(PID_FILE)) {
17
+ unlinkSync(PID_FILE);
18
+ }
19
+ }
20
+ export function isRunning() {
21
+ const pid = readPid();
22
+ if (!pid)
23
+ return false;
24
+ try {
25
+ process.kill(pid, 0);
26
+ return true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAE5B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAElD,MAAM,UAAU,QAAQ;IACtB,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACvD,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAClC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ export interface GitCheckResult {
2
+ isGitRepo: boolean;
3
+ currentBranch?: string;
4
+ branches?: string[];
5
+ defaultBranch?: string;
6
+ error?: string;
7
+ }
8
+ export interface GitInitResult {
9
+ success: boolean;
10
+ error?: string;
11
+ }
12
+ export declare class GitHandler {
13
+ check(path: string): Promise<GitCheckResult>;
14
+ init(path: string): Promise<GitInitResult>;
15
+ }
16
+ export declare const gitHandler: GitHandler;
17
+ //# sourceMappingURL=git-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-handler.d.ts","sourceRoot":"","sources":["../src/git-handler.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,UAAU;IACf,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAyC5C,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;CAYjD;AAED,eAAO,MAAM,UAAU,YAAmB,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { exec } from 'child_process';
2
+ import { promisify } from 'util';
3
+ const execAsync = promisify(exec);
4
+ export class GitHandler {
5
+ async check(path) {
6
+ try {
7
+ const { stdout: gitDir } = await execAsync('git rev-parse --git-dir', { cwd: path });
8
+ if (!gitDir.trim()) {
9
+ return { isGitRepo: false };
10
+ }
11
+ }
12
+ catch {
13
+ return { isGitRepo: false };
14
+ }
15
+ try {
16
+ const { stdout: currentBranch } = await execAsync('git rev-parse --abbrev-ref HEAD', { cwd: path });
17
+ const { stdout: branchesOutput } = await execAsync('git branch --format="%(refname:short)"', { cwd: path });
18
+ const branches = branchesOutput.trim().split('\n').filter(Boolean);
19
+ const current = currentBranch.trim();
20
+ let defaultBranch;
21
+ if (branches.includes('main')) {
22
+ defaultBranch = 'main';
23
+ }
24
+ else if (branches.includes('master')) {
25
+ defaultBranch = 'master';
26
+ }
27
+ else {
28
+ const sorted = [...branches].sort();
29
+ defaultBranch = sorted[0] || current;
30
+ }
31
+ return {
32
+ isGitRepo: true,
33
+ currentBranch: current,
34
+ branches,
35
+ defaultBranch,
36
+ };
37
+ }
38
+ catch (err) {
39
+ return {
40
+ isGitRepo: true,
41
+ error: err instanceof Error ? err.message : 'Unknown error',
42
+ };
43
+ }
44
+ }
45
+ async init(path) {
46
+ try {
47
+ await execAsync('git init', { cwd: path });
48
+ await execAsync('git branch -m main', { cwd: path });
49
+ return { success: true };
50
+ }
51
+ catch (err) {
52
+ return {
53
+ success: false,
54
+ error: err instanceof Error ? err.message : 'Unknown error',
55
+ };
56
+ }
57
+ }
58
+ }
59
+ export const gitHandler = new GitHandler();
60
+ //# sourceMappingURL=git-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-handler.js","sourceRoot":"","sources":["../src/git-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAelC,MAAM,OAAO,UAAU;IACrB,KAAK,CAAC,KAAK,CAAC,IAAY;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,yBAAyB,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YACrF,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;gBACnB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;YAC9B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAC9B,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,SAAS,CAAC,iCAAiC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YACpG,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,SAAS,CAAC,wCAAwC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YAE5G,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACnE,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC;YAErC,IAAI,aAAqB,CAAC;YAC1B,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9B,aAAa,GAAG,MAAM,CAAC;YACzB,CAAC;iBAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACvC,aAAa,GAAG,QAAQ,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;gBACpC,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;YACvC,CAAC;YAED,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,aAAa,EAAE,OAAO;gBACtB,QAAQ;gBACR,aAAa;aACd,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;aAC5D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY;QACrB,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,UAAU,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3C,MAAM,SAAS,CAAC,oBAAoB,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YACrD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;aAC5D,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=git-handler.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-handler.test.d.ts","sourceRoot":"","sources":["../src/git-handler.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,127 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { exec } from 'child_process';
3
+ vi.mock('child_process', () => ({
4
+ exec: vi.fn(),
5
+ }));
6
+ import { GitHandler } from './git-handler.js';
7
+ function mockExecResolved(stdout) {
8
+ return vi.mocked(exec).mockImplementation(((_cmd, _opts, cb) => {
9
+ if (typeof cb === 'function') {
10
+ cb(null, { stdout });
11
+ }
12
+ }));
13
+ }
14
+ function mockExecRejected(errorMsg) {
15
+ return vi.mocked(exec).mockImplementation(((_cmd, _opts, cb) => {
16
+ if (typeof cb === 'function') {
17
+ cb(new Error(errorMsg), null);
18
+ }
19
+ }));
20
+ }
21
+ describe('GitHandler', () => {
22
+ let handler;
23
+ beforeEach(() => {
24
+ vi.clearAllMocks();
25
+ handler = new GitHandler();
26
+ });
27
+ describe('check', () => {
28
+ it('should detect a valid git repo with branches', async () => {
29
+ let callCount = 0;
30
+ vi.mocked(exec).mockImplementation(((_cmd, _opts, cb) => {
31
+ callCount++;
32
+ const outputs = {
33
+ 1: '.git\n',
34
+ 2: 'main\n',
35
+ 3: 'main\ndevelop\nfeature-x\n',
36
+ };
37
+ if (typeof cb === 'function') {
38
+ cb(null, { stdout: outputs[callCount] || '' });
39
+ }
40
+ }));
41
+ const result = await handler.check('/fake/path');
42
+ expect(result.isGitRepo).toBe(true);
43
+ expect(result.currentBranch).toBe('main');
44
+ expect(result.branches).toEqual(['main', 'develop', 'feature-x']);
45
+ expect(result.defaultBranch).toBe('main');
46
+ });
47
+ it('should detect master as default if main does not exist', async () => {
48
+ let callCount = 0;
49
+ vi.mocked(exec).mockImplementation(((_cmd, _opts, cb) => {
50
+ callCount++;
51
+ const outputs = {
52
+ 1: '.git\n',
53
+ 2: 'master\n',
54
+ 3: 'develop\nmaster\n',
55
+ };
56
+ if (typeof cb === 'function') {
57
+ cb(null, { stdout: outputs[callCount] || '' });
58
+ }
59
+ }));
60
+ const result = await handler.check('/fake/path');
61
+ expect(result.isGitRepo).toBe(true);
62
+ expect(result.defaultBranch).toBe('master');
63
+ });
64
+ it('should sort alphabetically if neither main nor master exists', async () => {
65
+ let callCount = 0;
66
+ vi.mocked(exec).mockImplementation(((_cmd, _opts, cb) => {
67
+ callCount++;
68
+ const outputs = {
69
+ 1: '.git\n',
70
+ 2: 'feature-x\n',
71
+ 3: 'develop\nfeature-x\n',
72
+ };
73
+ if (typeof cb === 'function') {
74
+ cb(null, { stdout: outputs[callCount] || '' });
75
+ }
76
+ }));
77
+ const result = await handler.check('/fake/path');
78
+ expect(result.isGitRepo).toBe(true);
79
+ expect(result.defaultBranch).toBe('develop');
80
+ });
81
+ it('should return isGitRepo=false when not a git repo', async () => {
82
+ mockExecRejected('fatal: not a git repository');
83
+ const result = await handler.check('/fake/path');
84
+ expect(result.isGitRepo).toBe(false);
85
+ expect(result.currentBranch).toBeUndefined();
86
+ expect(result.branches).toBeUndefined();
87
+ });
88
+ it('should handle git-dir check returning empty string', async () => {
89
+ mockExecResolved('');
90
+ const result = await handler.check('/fake/path');
91
+ expect(result.isGitRepo).toBe(false);
92
+ });
93
+ it('should return error when branch listing fails on a valid repo', async () => {
94
+ vi.mocked(exec).mockImplementationOnce(((_cmd, _opts, cb) => {
95
+ if (typeof cb === 'function')
96
+ cb(null, { stdout: '.git\n' });
97
+ }));
98
+ vi.mocked(exec).mockImplementation(((_cmd, _opts, cb) => {
99
+ if (typeof cb === 'function')
100
+ cb(new Error('git command failed'), null);
101
+ }));
102
+ const result = await handler.check('/fake/path');
103
+ expect(result.isGitRepo).toBe(true);
104
+ expect(result.error).toBe('git command failed');
105
+ });
106
+ });
107
+ describe('init', () => {
108
+ it('should initialize git repo and rename branch to main', async () => {
109
+ vi.mocked(exec).mockImplementation(((_cmd, _opts, cb) => {
110
+ if (typeof cb === 'function')
111
+ cb(null, { stdout: '' });
112
+ }));
113
+ const result = await handler.init('/fake/path');
114
+ expect(result.success).toBe(true);
115
+ expect(exec).toHaveBeenCalledTimes(2);
116
+ expect(vi.mocked(exec).mock.calls[0][0]).toBe('git init');
117
+ expect(vi.mocked(exec).mock.calls[1][0]).toBe('git branch -m main');
118
+ });
119
+ it('should handle git init failure', async () => {
120
+ mockExecRejected('permission denied');
121
+ const result = await handler.init('/fake/path');
122
+ expect(result.success).toBe(false);
123
+ expect(result.error).toBe('permission denied');
124
+ });
125
+ });
126
+ });
127
+ //# sourceMappingURL=git-handler.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-handler.test.js","sourceRoot":"","sources":["../src/git-handler.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare class Heartbeat {
2
+ private intervalId;
3
+ start(sendFn: () => void): void;
4
+ stop(): void;
5
+ }
6
+ //# sourceMappingURL=heartbeat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../src/heartbeat.ts"],"names":[],"mappings":"AAEA,qBAAa,SAAS;IACpB,OAAO,CAAC,UAAU,CAA+C;IAEjE,KAAK,CAAC,MAAM,EAAE,MAAM,IAAI,GAAG,IAAI;IAM/B,IAAI,IAAI,IAAI;CAMb"}
@@ -0,0 +1,16 @@
1
+ const HEARTBEAT_INTERVAL_MS = 30_000;
2
+ export class Heartbeat {
3
+ intervalId = null;
4
+ start(sendFn) {
5
+ this.intervalId = setInterval(() => {
6
+ sendFn();
7
+ }, HEARTBEAT_INTERVAL_MS);
8
+ }
9
+ stop() {
10
+ if (this.intervalId) {
11
+ clearInterval(this.intervalId);
12
+ this.intervalId = null;
13
+ }
14
+ }
15
+ }
16
+ //# sourceMappingURL=heartbeat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../src/heartbeat.ts"],"names":[],"mappings":"AAAA,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAErC,MAAM,OAAO,SAAS;IACZ,UAAU,GAA0C,IAAI,CAAC;IAEjE,KAAK,CAAC,MAAkB;QACtB,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;YACjC,MAAM,EAAE,CAAC;QACX,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAC5B,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { hostname } from 'os';
4
+ import { resolveKey, resolveEndpoint, saveKeyToConfig, saveEndpointToConfig } from './config.js';
5
+ import { connectToServer, unregister } from './socketio-client.js';
6
+ import { writePid, removePid, isRunning } from './daemon.js';
7
+ const program = new Command();
8
+ program
9
+ .name('agent-gear')
10
+ .description('Agent Controller - manages connection to controller-api')
11
+ .version('1.0.0')
12
+ .option('-k, --key <key>', 'Controller key')
13
+ .option('-s, --server <endpoint>', 'Server endpoint URL')
14
+ .option('-n, --name <name>', 'Controller name')
15
+ .action(async (options) => {
16
+ if (isRunning()) {
17
+ console.error('Controller is already running. Stop it first or remove the PID file.');
18
+ process.exit(1);
19
+ }
20
+ const key = resolveKey(options.key);
21
+ if (!key) {
22
+ console.error('No key provided. Use --key, ZAG_CONTROLLER_KEY env, or configure in ~/.zag/config.toml');
23
+ process.exit(1);
24
+ }
25
+ const endpoint = resolveEndpoint(options.server);
26
+ if (!endpoint) {
27
+ console.error('No server endpoint provided. Use --server, ZAG_SERVER_ENDPOINT env, or configure in ~/.zag/config.toml');
28
+ process.exit(1);
29
+ }
30
+ if (options.key)
31
+ saveKeyToConfig(options.key);
32
+ if (options.server)
33
+ saveEndpointToConfig(options.server);
34
+ writePid();
35
+ const socket = connectToServer(endpoint, key, {
36
+ serverName: options.name || hostname(),
37
+ });
38
+ const shutdown = () => {
39
+ console.log('Shutting down...');
40
+ unregister(socket);
41
+ socket.disconnect();
42
+ removePid();
43
+ process.exit(0);
44
+ };
45
+ process.on('SIGINT', shutdown);
46
+ process.on('SIGTERM', shutdown);
47
+ process.on('exit', () => {
48
+ removePid();
49
+ });
50
+ });
51
+ program.parse();
52
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACjG,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,yDAAyD,CAAC;KACtE,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,iBAAiB,EAAE,gBAAgB,CAAC;KAC3C,MAAM,CAAC,yBAAyB,EAAE,qBAAqB,CAAC;KACxD,MAAM,CAAC,mBAAmB,EAAE,iBAAiB,CAAC;KAC9C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,SAAS,EAAE,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,sEAAsE,CAAC,CAAC;QACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,CAAC,KAAK,CAAC,wFAAwF,CAAC,CAAC;QACxG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,wGAAwG,CAAC,CAAC;QACxH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,CAAC,GAAG;QAAE,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,OAAO,CAAC,MAAM;QAAE,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzD,QAAQ,EAAE,CAAC;IAEX,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,EAAE,GAAG,EAAE;QAC5C,UAAU,EAAE,OAAO,CAAC,IAAI,IAAI,QAAQ,EAAE;KACvC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAChC,UAAU,CAAC,MAAM,CAAC,CAAC;QACnB,MAAM,CAAC,UAAU,EAAE,CAAC;QACpB,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;QACtB,SAAS,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { type Socket } from 'socket.io-client';
2
+ export declare function connectToServer(endpoint: string, key: string, options?: {
3
+ serverName?: string;
4
+ }): Socket;
5
+ export declare function unregister(socket: Socket): void;
6
+ //# sourceMappingURL=socketio-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socketio-client.d.ts","sourceRoot":"","sources":["../src/socketio-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAoG3E,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,MAAM,CAoYR;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAE/C"}