@agentrix/cli 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -0
- package/bin/agentrix.mjs +35 -0
- package/dist/index.cjs +16774 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +16754 -0
- package/dist/lib.cjs +19 -0
- package/dist/lib.d.cts +76 -0
- package/dist/lib.d.mts +76 -0
- package/dist/lib.mjs +11 -0
- package/dist/logger-CVOTByt5.cjs +497 -0
- package/dist/logger-f691UxTg.mjs +487 -0
- package/package.json +125 -0
- package/scripts/unpack-tools.cjs +163 -0
- package/tools/archives/difftastic-LICENSE +21 -0
- package/tools/archives/difftastic-arm64-darwin.tar.gz +0 -0
- package/tools/archives/difftastic-arm64-linux.tar.gz +0 -0
- package/tools/archives/difftastic-x64-darwin.tar.gz +0 -0
- package/tools/archives/difftastic-x64-linux.tar.gz +0 -0
- package/tools/archives/difftastic-x64-win32.tar.gz +0 -0
- package/tools/archives/ripgrep-LICENSE +3 -0
- package/tools/archives/ripgrep-arm64-darwin.tar.gz +0 -0
- package/tools/archives/ripgrep-arm64-linux.tar.gz +0 -0
- package/tools/archives/ripgrep-x64-darwin.tar.gz +0 -0
- package/tools/archives/ripgrep-x64-linux.tar.gz +0 -0
- package/tools/archives/ripgrep-x64-win32.tar.gz +0 -0
- package/tools/licenses/difftastic-LICENSE +21 -0
- package/tools/licenses/ripgrep-LICENSE +3 -0
- package/tools/unpacked/difft +0 -0
- package/tools/unpacked/rg +0 -0
- package/tools/unpacked/ripgrep.node +0 -0
package/dist/lib.cjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var logger = require('./logger-CVOTByt5.cjs');
|
|
4
|
+
require('winston');
|
|
5
|
+
require('chalk');
|
|
6
|
+
require('node:os');
|
|
7
|
+
require('node:crypto');
|
|
8
|
+
require('node:fs');
|
|
9
|
+
require('node:fs/promises');
|
|
10
|
+
require('node:path');
|
|
11
|
+
require('@agentrix/shared');
|
|
12
|
+
require('path');
|
|
13
|
+
require('url');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
exports.Machine = logger.Machine;
|
|
18
|
+
exports.logger = logger.logger;
|
|
19
|
+
exports.machine = logger.machine;
|
package/dist/lib.d.cts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import winston from 'winston';
|
|
2
|
+
import { FileHandle } from 'node:fs/promises';
|
|
3
|
+
import { AgentContext, CreateTaskEventData, ResumeTaskEventData } from '@agentrix/shared';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Winston-based logging system for agentrix CLI
|
|
7
|
+
*
|
|
8
|
+
* Design decisions:
|
|
9
|
+
* - Use Winston for robust logging with file rotation
|
|
10
|
+
* - Three logging modes:
|
|
11
|
+
* 1. console-only: CLI commands (no file logging)
|
|
12
|
+
* 2. daemon: Single daemon.log with rotation (10MB x 10 files)
|
|
13
|
+
* 3. worker: Per-task logs task-{taskId}.log with rotation (5MB x 3 files)
|
|
14
|
+
* - File output location: ~/.agentrix/logs/
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
declare let logger: winston.Logger;
|
|
18
|
+
|
|
19
|
+
interface DaemonState {
|
|
20
|
+
pid: number;
|
|
21
|
+
port: number;
|
|
22
|
+
startTime: string;
|
|
23
|
+
cliVersion: string;
|
|
24
|
+
logPath: string;
|
|
25
|
+
}
|
|
26
|
+
type Credentials = {
|
|
27
|
+
secret?: string;
|
|
28
|
+
token: string;
|
|
29
|
+
machineId: string;
|
|
30
|
+
};
|
|
31
|
+
type MachineStatePaths = {
|
|
32
|
+
rootDir: string;
|
|
33
|
+
logsDir: string;
|
|
34
|
+
settingsFile: string;
|
|
35
|
+
credentialsFile: string;
|
|
36
|
+
daemonStateFile: string;
|
|
37
|
+
daemonLockFile: string;
|
|
38
|
+
};
|
|
39
|
+
declare class Machine implements AgentContext {
|
|
40
|
+
readonly serverUrl: string;
|
|
41
|
+
readonly webappUrl: string;
|
|
42
|
+
readonly isDaemonProcess: boolean;
|
|
43
|
+
readonly agentrixHomeDir: string;
|
|
44
|
+
readonly agentrixWorkspaceHomeDir: string;
|
|
45
|
+
readonly agentrixAgentsHomeDir: string;
|
|
46
|
+
readonly currentCliVersion: string;
|
|
47
|
+
readonly disableCaffeinate: boolean;
|
|
48
|
+
readonly statePaths: MachineStatePaths;
|
|
49
|
+
secretKey?: Uint8Array<ArrayBufferLike>;
|
|
50
|
+
constructor();
|
|
51
|
+
generateMachineId(): string;
|
|
52
|
+
metadata(): any;
|
|
53
|
+
getStatePaths(): MachineStatePaths;
|
|
54
|
+
readCredentials(): Promise<Credentials | null>;
|
|
55
|
+
writeCredentials(credentials: Credentials): Promise<void>;
|
|
56
|
+
clearCredentials(): Promise<void>;
|
|
57
|
+
readDaemonState(): Promise<DaemonState | null>;
|
|
58
|
+
writeDaemonState(state: DaemonState): void;
|
|
59
|
+
clearDaemonState(): Promise<void>;
|
|
60
|
+
acquireDaemonLock(maxAttempts?: number, delayIncrementMs?: number): Promise<FileHandle | null>;
|
|
61
|
+
releaseDaemonLock(lockHandle: FileHandle): Promise<void>;
|
|
62
|
+
ensureDir(target: string): string;
|
|
63
|
+
resolveProjectDir(cwd: string | undefined, userId: string, taskId: string): string;
|
|
64
|
+
resolveDataDir(userId: string, taskId: string): string;
|
|
65
|
+
resolveAttachmentsDir(userId: string, taskId: string): string;
|
|
66
|
+
resolveAgentDir(agentId: string): string;
|
|
67
|
+
getInitialCommitHashPath(userId: string, taskId: string): string;
|
|
68
|
+
readInitialCommitHash(userId: string, taskId: string): Promise<string | null>;
|
|
69
|
+
writeInitialCommitHash(userId: string, taskId: string, hash: string): Promise<void>;
|
|
70
|
+
writeTaskInput(data: CreateTaskEventData | ResumeTaskEventData): void;
|
|
71
|
+
readTaskInput(userId: string, taskId: string): (CreateTaskEventData | ResumeTaskEventData);
|
|
72
|
+
getSecretKey(): Promise<Uint8Array<ArrayBufferLike> | undefined>;
|
|
73
|
+
}
|
|
74
|
+
declare const machine: Machine;
|
|
75
|
+
|
|
76
|
+
export { Machine, logger, machine };
|
package/dist/lib.d.mts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import winston from 'winston';
|
|
2
|
+
import { FileHandle } from 'node:fs/promises';
|
|
3
|
+
import { AgentContext, CreateTaskEventData, ResumeTaskEventData } from '@agentrix/shared';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Winston-based logging system for agentrix CLI
|
|
7
|
+
*
|
|
8
|
+
* Design decisions:
|
|
9
|
+
* - Use Winston for robust logging with file rotation
|
|
10
|
+
* - Three logging modes:
|
|
11
|
+
* 1. console-only: CLI commands (no file logging)
|
|
12
|
+
* 2. daemon: Single daemon.log with rotation (10MB x 10 files)
|
|
13
|
+
* 3. worker: Per-task logs task-{taskId}.log with rotation (5MB x 3 files)
|
|
14
|
+
* - File output location: ~/.agentrix/logs/
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
declare let logger: winston.Logger;
|
|
18
|
+
|
|
19
|
+
interface DaemonState {
|
|
20
|
+
pid: number;
|
|
21
|
+
port: number;
|
|
22
|
+
startTime: string;
|
|
23
|
+
cliVersion: string;
|
|
24
|
+
logPath: string;
|
|
25
|
+
}
|
|
26
|
+
type Credentials = {
|
|
27
|
+
secret?: string;
|
|
28
|
+
token: string;
|
|
29
|
+
machineId: string;
|
|
30
|
+
};
|
|
31
|
+
type MachineStatePaths = {
|
|
32
|
+
rootDir: string;
|
|
33
|
+
logsDir: string;
|
|
34
|
+
settingsFile: string;
|
|
35
|
+
credentialsFile: string;
|
|
36
|
+
daemonStateFile: string;
|
|
37
|
+
daemonLockFile: string;
|
|
38
|
+
};
|
|
39
|
+
declare class Machine implements AgentContext {
|
|
40
|
+
readonly serverUrl: string;
|
|
41
|
+
readonly webappUrl: string;
|
|
42
|
+
readonly isDaemonProcess: boolean;
|
|
43
|
+
readonly agentrixHomeDir: string;
|
|
44
|
+
readonly agentrixWorkspaceHomeDir: string;
|
|
45
|
+
readonly agentrixAgentsHomeDir: string;
|
|
46
|
+
readonly currentCliVersion: string;
|
|
47
|
+
readonly disableCaffeinate: boolean;
|
|
48
|
+
readonly statePaths: MachineStatePaths;
|
|
49
|
+
secretKey?: Uint8Array<ArrayBufferLike>;
|
|
50
|
+
constructor();
|
|
51
|
+
generateMachineId(): string;
|
|
52
|
+
metadata(): any;
|
|
53
|
+
getStatePaths(): MachineStatePaths;
|
|
54
|
+
readCredentials(): Promise<Credentials | null>;
|
|
55
|
+
writeCredentials(credentials: Credentials): Promise<void>;
|
|
56
|
+
clearCredentials(): Promise<void>;
|
|
57
|
+
readDaemonState(): Promise<DaemonState | null>;
|
|
58
|
+
writeDaemonState(state: DaemonState): void;
|
|
59
|
+
clearDaemonState(): Promise<void>;
|
|
60
|
+
acquireDaemonLock(maxAttempts?: number, delayIncrementMs?: number): Promise<FileHandle | null>;
|
|
61
|
+
releaseDaemonLock(lockHandle: FileHandle): Promise<void>;
|
|
62
|
+
ensureDir(target: string): string;
|
|
63
|
+
resolveProjectDir(cwd: string | undefined, userId: string, taskId: string): string;
|
|
64
|
+
resolveDataDir(userId: string, taskId: string): string;
|
|
65
|
+
resolveAttachmentsDir(userId: string, taskId: string): string;
|
|
66
|
+
resolveAgentDir(agentId: string): string;
|
|
67
|
+
getInitialCommitHashPath(userId: string, taskId: string): string;
|
|
68
|
+
readInitialCommitHash(userId: string, taskId: string): Promise<string | null>;
|
|
69
|
+
writeInitialCommitHash(userId: string, taskId: string, hash: string): Promise<void>;
|
|
70
|
+
writeTaskInput(data: CreateTaskEventData | ResumeTaskEventData): void;
|
|
71
|
+
readTaskInput(userId: string, taskId: string): (CreateTaskEventData | ResumeTaskEventData);
|
|
72
|
+
getSecretKey(): Promise<Uint8Array<ArrayBufferLike> | undefined>;
|
|
73
|
+
}
|
|
74
|
+
declare const machine: Machine;
|
|
75
|
+
|
|
76
|
+
export { Machine, logger, machine };
|
package/dist/lib.mjs
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { M as Machine, l as logger, m as machine } from './logger-f691UxTg.mjs';
|
|
2
|
+
import 'winston';
|
|
3
|
+
import 'chalk';
|
|
4
|
+
import 'node:os';
|
|
5
|
+
import 'node:crypto';
|
|
6
|
+
import 'node:fs';
|
|
7
|
+
import 'node:fs/promises';
|
|
8
|
+
import 'node:path';
|
|
9
|
+
import '@agentrix/shared';
|
|
10
|
+
import 'path';
|
|
11
|
+
import 'url';
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var winston = require('winston');
|
|
4
|
+
var chalk = require('chalk');
|
|
5
|
+
var os = require('node:os');
|
|
6
|
+
var node_crypto = require('node:crypto');
|
|
7
|
+
var fs = require('node:fs');
|
|
8
|
+
var promises = require('node:fs/promises');
|
|
9
|
+
var path = require('node:path');
|
|
10
|
+
var shared = require('@agentrix/shared');
|
|
11
|
+
var require$$1 = require('path');
|
|
12
|
+
var url = require('url');
|
|
13
|
+
|
|
14
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
15
|
+
var name = "@agentrix/cli";
|
|
16
|
+
var version = "0.0.2";
|
|
17
|
+
var description = "Mobile and Web client for Claude Code and Codex";
|
|
18
|
+
var author = "agentrix.xmz.ai";
|
|
19
|
+
var type = "module";
|
|
20
|
+
var homepage = "https://github.com/xmz-ai/agentrix-cli";
|
|
21
|
+
var bugs = "https://github.com/xmz-ai/agentrix-cli/issues";
|
|
22
|
+
var repository = "xmz-ai/agentrix-cli";
|
|
23
|
+
var bin = {
|
|
24
|
+
agentrix: "./bin/agentrix.mjs"
|
|
25
|
+
};
|
|
26
|
+
var main = "./dist/index.cjs";
|
|
27
|
+
var module$1 = "./dist/index.mjs";
|
|
28
|
+
var types = "./dist/index.d.cts";
|
|
29
|
+
var exports$1 = {
|
|
30
|
+
".": {
|
|
31
|
+
require: {
|
|
32
|
+
types: "./dist/index.d.cts",
|
|
33
|
+
"default": "./dist/index.cjs"
|
|
34
|
+
},
|
|
35
|
+
"import": {
|
|
36
|
+
types: "./dist/index.d.mts",
|
|
37
|
+
"default": "./dist/index.mjs"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"./lib": {
|
|
41
|
+
require: {
|
|
42
|
+
types: "./dist/lib.d.cts",
|
|
43
|
+
"default": "./dist/lib.cjs"
|
|
44
|
+
},
|
|
45
|
+
"import": {
|
|
46
|
+
types: "./dist/lib.d.mts",
|
|
47
|
+
"default": "./dist/lib.mjs"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var files = [
|
|
52
|
+
"dist",
|
|
53
|
+
"bin",
|
|
54
|
+
"scripts",
|
|
55
|
+
"tools",
|
|
56
|
+
"package.json"
|
|
57
|
+
];
|
|
58
|
+
var scripts = {
|
|
59
|
+
"why do we need to build before running tests / dev?": "We need the binary to be built so we run daemon commands which directly run the binary",
|
|
60
|
+
typecheck: "tsc --noEmit --skipLibCheck 2>&1 | (grep -v 'node_modules/effect' | grep -v 'Symbol.dispose' || true)",
|
|
61
|
+
build: "shx rm -rf dist && npx tsc --noEmit --skipLibCheck 2>&1 | (grep -v 'node_modules/effect' | grep -v 'Symbol.dispose' || true) && pkgroll",
|
|
62
|
+
prod: "node --env-file=.env ./bin/agentrix.mjs",
|
|
63
|
+
test: "yarn build && tsx --env-file .env.integration-test node_modules/.bin/vitest run",
|
|
64
|
+
dev: "yarn build && tsx --env-file .env.dev src/index.ts",
|
|
65
|
+
prepublishOnly: "yarn build && yarn test",
|
|
66
|
+
release: "release-it",
|
|
67
|
+
postinstall: "node scripts/unpack-tools.cjs",
|
|
68
|
+
lint: "eslint 'src/**/*.{js,ts}' --fix"
|
|
69
|
+
};
|
|
70
|
+
var pkgroll = {
|
|
71
|
+
minify: true,
|
|
72
|
+
sourcemap: false
|
|
73
|
+
};
|
|
74
|
+
var dependencies = {
|
|
75
|
+
"@agentrix/shared": "*",
|
|
76
|
+
"@anthropic-ai/claude-agent-sdk": "^0.1.30",
|
|
77
|
+
"@anthropic-ai/claude-code": "2.0.14",
|
|
78
|
+
"@anthropic-ai/sdk": "0.65.0",
|
|
79
|
+
"@modelcontextprotocol/sdk": "^1.15.1",
|
|
80
|
+
"@openai/codex-sdk": "^0.58.0",
|
|
81
|
+
"@stablelib/base64": "^2.0.1",
|
|
82
|
+
"@stablelib/hex": "^2.0.1",
|
|
83
|
+
"@types/cross-spawn": "^6.0.6",
|
|
84
|
+
"@types/http-proxy": "^1.17.16",
|
|
85
|
+
"@types/ps-list": "^6.2.1",
|
|
86
|
+
"@types/qrcode-terminal": "^0.12.2",
|
|
87
|
+
"@types/react": "^19.1.9",
|
|
88
|
+
"@types/tmp": "^0.2.6",
|
|
89
|
+
"@types/yargs": "^17.0.33",
|
|
90
|
+
axios: "^1.10.0",
|
|
91
|
+
chalk: "^5.4.1",
|
|
92
|
+
"cross-spawn": "^7.0.6",
|
|
93
|
+
"expo-server-sdk": "^3.15.0",
|
|
94
|
+
fastify: "^5.5.0",
|
|
95
|
+
"fastify-type-provider-zod": "4.0.2",
|
|
96
|
+
"http-proxy": "^1.18.1",
|
|
97
|
+
"http-proxy-middleware": "^3.0.5",
|
|
98
|
+
ink: "^6.1.0",
|
|
99
|
+
open: "^10.2.0",
|
|
100
|
+
"ps-list": "^8.1.1",
|
|
101
|
+
"qrcode-terminal": "^0.12.0",
|
|
102
|
+
react: "^19.1.1",
|
|
103
|
+
"simple-git": "^3.30.0",
|
|
104
|
+
"socket.io-client": "^4.8.1",
|
|
105
|
+
tar: "^7.4.3",
|
|
106
|
+
tmp: "^0.2.5",
|
|
107
|
+
tweetnacl: "^1.0.3",
|
|
108
|
+
winston: "^3.18.3",
|
|
109
|
+
"winston-daily-rotate-file": "^5.0.0",
|
|
110
|
+
yargs: "^17.7.2",
|
|
111
|
+
zod: "^3.23.8"
|
|
112
|
+
};
|
|
113
|
+
var devDependencies = {
|
|
114
|
+
"@eslint/compat": "^1",
|
|
115
|
+
"@types/mime-types": "^3.0.1",
|
|
116
|
+
"@types/node": ">=20",
|
|
117
|
+
"cross-env": "^10.0.0",
|
|
118
|
+
dotenv: "^16.6.1",
|
|
119
|
+
eslint: "^9",
|
|
120
|
+
"eslint-config-prettier": "^10",
|
|
121
|
+
pkgroll: "^2.14.2",
|
|
122
|
+
"release-it": "^19.0.4",
|
|
123
|
+
shx: "^0.3.3",
|
|
124
|
+
"ts-node": "^10",
|
|
125
|
+
tsx: "^4.20.3",
|
|
126
|
+
typescript: "^5",
|
|
127
|
+
vitest: "^3.2.4"
|
|
128
|
+
};
|
|
129
|
+
var resolutions = {
|
|
130
|
+
"whatwg-url": "14.2.0",
|
|
131
|
+
"parse-path": "7.0.3",
|
|
132
|
+
"@types/parse-path": "7.0.3"
|
|
133
|
+
};
|
|
134
|
+
var publishConfig = {
|
|
135
|
+
registry: "https://registry.npmjs.org"
|
|
136
|
+
};
|
|
137
|
+
var packageManager = "yarn@1.22.22";
|
|
138
|
+
var packageJson = {
|
|
139
|
+
name: name,
|
|
140
|
+
version: version,
|
|
141
|
+
description: description,
|
|
142
|
+
author: author,
|
|
143
|
+
type: type,
|
|
144
|
+
homepage: homepage,
|
|
145
|
+
bugs: bugs,
|
|
146
|
+
repository: repository,
|
|
147
|
+
bin: bin,
|
|
148
|
+
main: main,
|
|
149
|
+
module: module$1,
|
|
150
|
+
types: types,
|
|
151
|
+
exports: exports$1,
|
|
152
|
+
files: files,
|
|
153
|
+
scripts: scripts,
|
|
154
|
+
pkgroll: pkgroll,
|
|
155
|
+
dependencies: dependencies,
|
|
156
|
+
devDependencies: devDependencies,
|
|
157
|
+
resolutions: resolutions,
|
|
158
|
+
publishConfig: publishConfig,
|
|
159
|
+
packageManager: packageManager
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const __dirname$1 = require$$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('logger-CVOTByt5.cjs', document.baseURI).href))));
|
|
163
|
+
function projectPath() {
|
|
164
|
+
const path = require$$1.resolve(__dirname$1, "..");
|
|
165
|
+
return path;
|
|
166
|
+
}
|
|
167
|
+
class Machine {
|
|
168
|
+
serverUrl;
|
|
169
|
+
webappUrl;
|
|
170
|
+
isDaemonProcess;
|
|
171
|
+
agentrixHomeDir;
|
|
172
|
+
agentrixWorkspaceHomeDir;
|
|
173
|
+
agentrixAgentsHomeDir;
|
|
174
|
+
currentCliVersion;
|
|
175
|
+
disableCaffeinate;
|
|
176
|
+
statePaths;
|
|
177
|
+
secretKey;
|
|
178
|
+
constructor() {
|
|
179
|
+
const args = process.argv.slice(2);
|
|
180
|
+
this.isDaemonProcess = args[0] === "daemon";
|
|
181
|
+
this.serverUrl = process.env.AGENTRIX_SERVER_URL || "https://agentrix.xmz.ai";
|
|
182
|
+
this.webappUrl = process.env.AGENTRIX_WEBAPP_URL || "https://agentrix.xmz.ai";
|
|
183
|
+
this.agentrixHomeDir = process.env.AGENTRIX_HOME_DIR ? process.env.AGENTRIX_HOME_DIR.replace(/^~/, os.homedir()) : path.join(os.homedir(), ".agentrix");
|
|
184
|
+
this.agentrixWorkspaceHomeDir = process.env.AGENTRIX_WORKSPACE_HOME_DIR ? process.env.AGENTRIX_WORKSPACE_HOME_DIR.replace(/^~/, os.homedir()) : path.join(this.agentrixHomeDir, "workspaces");
|
|
185
|
+
this.agentrixAgentsHomeDir = process.env.AGENTRIX_AGENTS_HOME_DIR ? process.env.AGENTRIX_AGENTS_HOME_DIR.replace(/^~/, os.homedir()) : path.join(this.agentrixHomeDir, "agents");
|
|
186
|
+
this.disableCaffeinate = ["true", "1", "yes"].includes(
|
|
187
|
+
(process.env.AGENTRIX_DISABLE_CAFFEINATE ?? "").toLowerCase()
|
|
188
|
+
);
|
|
189
|
+
this.currentCliVersion = packageJson.version;
|
|
190
|
+
this.ensureDir(this.agentrixHomeDir);
|
|
191
|
+
this.ensureDir(this.agentrixWorkspaceHomeDir);
|
|
192
|
+
this.ensureDir(this.agentrixAgentsHomeDir);
|
|
193
|
+
this.statePaths = {
|
|
194
|
+
rootDir: this.agentrixHomeDir,
|
|
195
|
+
logsDir: this.ensureDir(path.join(this.agentrixHomeDir, "logs")),
|
|
196
|
+
settingsFile: path.join(this.agentrixHomeDir, "settings.json"),
|
|
197
|
+
credentialsFile: path.join(this.agentrixHomeDir, "credentials.json"),
|
|
198
|
+
daemonStateFile: path.join(this.agentrixHomeDir, "daemon.state.json"),
|
|
199
|
+
daemonLockFile: path.join(this.agentrixHomeDir, "daemon.state.json.lock")
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
generateMachineId() {
|
|
203
|
+
return `machine-${node_crypto.randomUUID()}`;
|
|
204
|
+
}
|
|
205
|
+
metadata() {
|
|
206
|
+
return {
|
|
207
|
+
host: os.hostname(),
|
|
208
|
+
platform: os.platform(),
|
|
209
|
+
cliVersion: this.currentCliVersion,
|
|
210
|
+
homeDir: os.homedir(),
|
|
211
|
+
agentrixHomeDir: this.agentrixHomeDir,
|
|
212
|
+
agentrixWorkspaceHomeDir: this.agentrixWorkspaceHomeDir
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
getStatePaths() {
|
|
216
|
+
return this.statePaths;
|
|
217
|
+
}
|
|
218
|
+
async readCredentials() {
|
|
219
|
+
const paths = this.getStatePaths();
|
|
220
|
+
if (!fs.existsSync(paths.credentialsFile)) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
const content = await promises.readFile(paths.credentialsFile, "utf8");
|
|
225
|
+
const parsed = JSON.parse(content);
|
|
226
|
+
return {
|
|
227
|
+
secret: parsed.secret,
|
|
228
|
+
token: parsed.token,
|
|
229
|
+
machineId: parsed.machineId
|
|
230
|
+
};
|
|
231
|
+
} catch {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
async writeCredentials(credentials) {
|
|
236
|
+
const paths = this.getStatePaths();
|
|
237
|
+
await promises.writeFile(
|
|
238
|
+
paths.credentialsFile,
|
|
239
|
+
JSON.stringify(credentials, null, 2)
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
async clearCredentials() {
|
|
243
|
+
const paths = this.getStatePaths();
|
|
244
|
+
if (fs.existsSync(paths.credentialsFile)) {
|
|
245
|
+
await promises.unlink(paths.credentialsFile);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async readDaemonState() {
|
|
249
|
+
const paths = this.getStatePaths();
|
|
250
|
+
try {
|
|
251
|
+
if (!fs.existsSync(paths.daemonStateFile)) {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
const content = await promises.readFile(paths.daemonStateFile, "utf-8");
|
|
255
|
+
return JSON.parse(content);
|
|
256
|
+
} catch (error) {
|
|
257
|
+
console.error(`[PERSISTENCE] Daemon state file corrupted: ${paths.daemonStateFile}`, error);
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
writeDaemonState(state) {
|
|
262
|
+
const paths = this.getStatePaths();
|
|
263
|
+
fs.writeFileSync(paths.daemonStateFile, JSON.stringify(state, null, 2), "utf-8");
|
|
264
|
+
}
|
|
265
|
+
async clearDaemonState() {
|
|
266
|
+
const paths = this.getStatePaths();
|
|
267
|
+
if (fs.existsSync(paths.daemonStateFile)) {
|
|
268
|
+
await promises.unlink(paths.daemonStateFile);
|
|
269
|
+
}
|
|
270
|
+
if (fs.existsSync(paths.daemonLockFile)) {
|
|
271
|
+
try {
|
|
272
|
+
await promises.unlink(paths.daemonLockFile);
|
|
273
|
+
} catch {
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
async acquireDaemonLock(maxAttempts = 5, delayIncrementMs = 200) {
|
|
278
|
+
const paths = this.getStatePaths();
|
|
279
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
280
|
+
try {
|
|
281
|
+
const handle = await promises.open(
|
|
282
|
+
paths.daemonLockFile,
|
|
283
|
+
fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY
|
|
284
|
+
);
|
|
285
|
+
await handle.writeFile(String(process.pid));
|
|
286
|
+
return handle;
|
|
287
|
+
} catch (error) {
|
|
288
|
+
if (error.code === "EEXIST") {
|
|
289
|
+
try {
|
|
290
|
+
const lockPid = fs.readFileSync(paths.daemonLockFile, "utf-8").trim();
|
|
291
|
+
if (lockPid && !Number.isNaN(Number(lockPid))) {
|
|
292
|
+
try {
|
|
293
|
+
process.kill(Number(lockPid), 0);
|
|
294
|
+
} catch {
|
|
295
|
+
fs.unlinkSync(paths.daemonLockFile);
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (attempt === maxAttempts) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
const delayMs = attempt * delayIncrementMs;
|
|
306
|
+
await new Promise((resolve2) => setTimeout(resolve2, delayMs));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
async releaseDaemonLock(lockHandle) {
|
|
312
|
+
const paths = this.getStatePaths();
|
|
313
|
+
try {
|
|
314
|
+
await lockHandle.close();
|
|
315
|
+
} catch {
|
|
316
|
+
}
|
|
317
|
+
try {
|
|
318
|
+
if (fs.existsSync(paths.daemonLockFile)) {
|
|
319
|
+
fs.unlinkSync(paths.daemonLockFile);
|
|
320
|
+
}
|
|
321
|
+
} catch {
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
ensureDir(target) {
|
|
325
|
+
if (!fs.existsSync(target)) {
|
|
326
|
+
fs.mkdirSync(target, { recursive: true });
|
|
327
|
+
}
|
|
328
|
+
return target;
|
|
329
|
+
}
|
|
330
|
+
resolveProjectDir(cwd, userId, taskId) {
|
|
331
|
+
if (cwd) {
|
|
332
|
+
return this.ensureDir(cwd.replace(/^~/, os.homedir()));
|
|
333
|
+
}
|
|
334
|
+
const workspaceDir = path.join(this.agentrixWorkspaceHomeDir, "users", userId, taskId, "project");
|
|
335
|
+
return this.ensureDir(workspaceDir);
|
|
336
|
+
}
|
|
337
|
+
resolveDataDir(userId, taskId) {
|
|
338
|
+
const dataDir = path.join(this.agentrixWorkspaceHomeDir, "users", userId, taskId, "data");
|
|
339
|
+
return this.ensureDir(dataDir);
|
|
340
|
+
}
|
|
341
|
+
resolveAttachmentsDir(userId, taskId) {
|
|
342
|
+
const attachmentsDir = path.join(this.resolveDataDir(userId, taskId), "attachments");
|
|
343
|
+
return this.ensureDir(attachmentsDir);
|
|
344
|
+
}
|
|
345
|
+
resolveAgentDir(agentId) {
|
|
346
|
+
return path.join(this.agentrixAgentsHomeDir, agentId);
|
|
347
|
+
}
|
|
348
|
+
getInitialCommitHashPath(userId, taskId) {
|
|
349
|
+
return path.join(this.resolveDataDir(userId, taskId), "initial-commit-hash.txt");
|
|
350
|
+
}
|
|
351
|
+
async readInitialCommitHash(userId, taskId) {
|
|
352
|
+
const path = this.getInitialCommitHashPath(userId, taskId);
|
|
353
|
+
if (!fs.existsSync(path)) {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
const content = await promises.readFile(path, "utf-8");
|
|
358
|
+
return content.trim();
|
|
359
|
+
} catch {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
async writeInitialCommitHash(userId, taskId, hash) {
|
|
364
|
+
const path = this.getInitialCommitHashPath(userId, taskId);
|
|
365
|
+
await promises.writeFile(path, hash);
|
|
366
|
+
}
|
|
367
|
+
writeTaskInput(data) {
|
|
368
|
+
const path$1 = this.resolveDataDir(data.userId, data.taskId);
|
|
369
|
+
const inputFile = path.join(path$1, "input.json");
|
|
370
|
+
fs.writeFileSync(inputFile, JSON.stringify(data, null, 2));
|
|
371
|
+
}
|
|
372
|
+
readTaskInput(userId, taskId) {
|
|
373
|
+
const path$1 = this.resolveDataDir(userId, taskId);
|
|
374
|
+
const inputFile = path.join(path$1, "input.json");
|
|
375
|
+
if (!fs.existsSync(inputFile)) {
|
|
376
|
+
throw new Error(`Task input file does not exist: ${inputFile}`);
|
|
377
|
+
}
|
|
378
|
+
const content = fs.readFileSync(inputFile, "utf-8");
|
|
379
|
+
return JSON.parse(content);
|
|
380
|
+
}
|
|
381
|
+
async getSecretKey() {
|
|
382
|
+
if (this.secretKey) {
|
|
383
|
+
return this.secretKey;
|
|
384
|
+
}
|
|
385
|
+
const credentials = await this.readCredentials();
|
|
386
|
+
if (credentials && credentials.secret) {
|
|
387
|
+
const keyPair = await shared.createKeyPair(credentials.secret);
|
|
388
|
+
this.secretKey = keyPair.secretKey;
|
|
389
|
+
}
|
|
390
|
+
return this.secretKey;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
const machine = new Machine();
|
|
394
|
+
shared.setAgentContext(machine);
|
|
395
|
+
|
|
396
|
+
const consoleFormat = winston.format.printf(({ level, message, timestamp, ...meta }) => {
|
|
397
|
+
const timeStr = new Date(timestamp).toLocaleTimeString("en-US", {
|
|
398
|
+
hour12: false,
|
|
399
|
+
hour: "2-digit",
|
|
400
|
+
minute: "2-digit",
|
|
401
|
+
second: "2-digit",
|
|
402
|
+
fractionalSecondDigits: 3
|
|
403
|
+
});
|
|
404
|
+
let coloredLevel = level;
|
|
405
|
+
switch (level) {
|
|
406
|
+
case "error":
|
|
407
|
+
coloredLevel = chalk.red(level.toUpperCase());
|
|
408
|
+
break;
|
|
409
|
+
case "warn":
|
|
410
|
+
coloredLevel = chalk.yellow(level.toUpperCase());
|
|
411
|
+
break;
|
|
412
|
+
case "info":
|
|
413
|
+
coloredLevel = chalk.blue(level.toUpperCase());
|
|
414
|
+
break;
|
|
415
|
+
case "debug":
|
|
416
|
+
coloredLevel = chalk.gray(level.toUpperCase());
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
const metaStr = Object.keys(meta).length > 0 ? " " + JSON.stringify(meta) : "";
|
|
420
|
+
return `[${timeStr}] ${coloredLevel}: ${message}${metaStr}`;
|
|
421
|
+
});
|
|
422
|
+
const fileFormat = winston.format.printf(({ level, message, timestamp, ...meta }) => {
|
|
423
|
+
const metaStr = Object.keys(meta).length > 0 ? " " + JSON.stringify(meta) : "";
|
|
424
|
+
return `[${timestamp}] ${level.toUpperCase()}: ${message}${metaStr}`;
|
|
425
|
+
});
|
|
426
|
+
function createLogger(context) {
|
|
427
|
+
const logsDir = machine.getStatePaths().logsDir;
|
|
428
|
+
const level = process.env.DEBUG ? "debug" : "info";
|
|
429
|
+
if (context.type === "console-only") {
|
|
430
|
+
return winston.createLogger({
|
|
431
|
+
level,
|
|
432
|
+
format: winston.format.combine(
|
|
433
|
+
winston.format.timestamp(),
|
|
434
|
+
consoleFormat
|
|
435
|
+
),
|
|
436
|
+
transports: [
|
|
437
|
+
new winston.transports.Console()
|
|
438
|
+
]
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
const filename = context.type === "daemon" ? "daemon.log" : `task-${context.taskId}.log`;
|
|
442
|
+
const maxsize = 100 * 1024 * 1024;
|
|
443
|
+
const maxFiles = context.type === "daemon" ? 3 : 1;
|
|
444
|
+
const transports = [
|
|
445
|
+
new winston.transports.File({
|
|
446
|
+
filename,
|
|
447
|
+
dirname: logsDir,
|
|
448
|
+
zippedArchive: true,
|
|
449
|
+
maxsize,
|
|
450
|
+
maxFiles,
|
|
451
|
+
tailable: true,
|
|
452
|
+
format: winston.format.combine(
|
|
453
|
+
winston.format.timestamp(),
|
|
454
|
+
fileFormat
|
|
455
|
+
)
|
|
456
|
+
})
|
|
457
|
+
];
|
|
458
|
+
if (process.env.DEBUG) {
|
|
459
|
+
transports.push(
|
|
460
|
+
new winston.transports.Console({
|
|
461
|
+
format: winston.format.combine(
|
|
462
|
+
winston.format.timestamp(),
|
|
463
|
+
consoleFormat
|
|
464
|
+
)
|
|
465
|
+
})
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
return winston.createLogger({
|
|
469
|
+
level,
|
|
470
|
+
transports
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
let logger = createLogger({ type: "console-only" });
|
|
474
|
+
function getLogPath(context) {
|
|
475
|
+
const logsDir = machine.getStatePaths().logsDir;
|
|
476
|
+
if (context.type === "console-only") {
|
|
477
|
+
return "";
|
|
478
|
+
}
|
|
479
|
+
const filename = context.type === "daemon" ? "daemon.log" : `task-${context.taskId}.log`;
|
|
480
|
+
return path.join(logsDir, filename);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
var logger$1 = /*#__PURE__*/Object.freeze({
|
|
484
|
+
__proto__: null,
|
|
485
|
+
createLogger: createLogger,
|
|
486
|
+
getLogPath: getLogPath,
|
|
487
|
+
logger: logger
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
exports.Machine = Machine;
|
|
491
|
+
exports.createLogger = createLogger;
|
|
492
|
+
exports.getLogPath = getLogPath;
|
|
493
|
+
exports.logger = logger;
|
|
494
|
+
exports.logger$1 = logger$1;
|
|
495
|
+
exports.machine = machine;
|
|
496
|
+
exports.packageJson = packageJson;
|
|
497
|
+
exports.projectPath = projectPath;
|