dirac-lang 0.1.59 → 0.1.61
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/dist/agent-OXQZBLNQ.js +226 -0
- package/dist/chunk-AU3YU63U.js +208 -0
- package/dist/{chunk-NVKBCTEU.js → chunk-BMKPKK7M.js} +1 -1
- package/dist/{chunk-RDVNX3JG.js → chunk-ZAA6R2TC.js} +226 -12
- package/dist/cli.js +110 -4
- package/dist/cron-BQIWLGQY.js +15 -0
- package/dist/index.js +2 -2
- package/dist/{interpreter-QC6Z7Y6R.js → interpreter-NPXTWPHN.js} +1 -1
- package/dist/run-at-KDJYTEOD.js +15 -0
- package/dist/{schedule-2NDGR5S5.js → schedule-QZ5U3YBS.js} +1 -1
- package/dist/session-client-3VTC5MLO.js +177 -0
- package/dist/session-server-QZN2RMYD.js +14 -0
- package/dist/{shell-LPNBQPXC.js → shell-OFBL57OA.js} +190 -27
- package/dist/test-runner.js +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SessionServer,
|
|
3
|
+
getSocketPath,
|
|
4
|
+
isSessionRunning
|
|
5
|
+
} from "./chunk-AU3YU63U.js";
|
|
6
|
+
import "./chunk-ZAA6R2TC.js";
|
|
7
|
+
import "./chunk-HRHAMPOB.js";
|
|
8
|
+
import "./chunk-NKA6ZJDV.js";
|
|
9
|
+
import "./chunk-3UW6GWYQ.js";
|
|
10
|
+
|
|
11
|
+
// src/agent.ts
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import path from "path";
|
|
14
|
+
import os from "os";
|
|
15
|
+
import { spawn } from "child_process";
|
|
16
|
+
var AGENT_DIR = path.join(os.homedir(), ".dirac");
|
|
17
|
+
var PID_FILE = path.join(AGENT_DIR, "session.pid");
|
|
18
|
+
var LOG_FILE = path.join(AGENT_DIR, "agent.log");
|
|
19
|
+
var AgentCLI = class {
|
|
20
|
+
async start() {
|
|
21
|
+
if (isSessionRunning()) {
|
|
22
|
+
console.log("Agent is already running");
|
|
23
|
+
const pid = this.getRunningPid();
|
|
24
|
+
if (pid) {
|
|
25
|
+
console.log(`PID: ${pid}`);
|
|
26
|
+
console.log(`Socket: ${getSocketPath()}`);
|
|
27
|
+
console.log(`Logs: ${LOG_FILE}`);
|
|
28
|
+
}
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (!fs.existsSync(AGENT_DIR)) {
|
|
32
|
+
fs.mkdirSync(AGENT_DIR, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
console.log("Starting DIRAC agent...");
|
|
35
|
+
const logFd = fs.openSync(LOG_FILE, "a");
|
|
36
|
+
const child = spawn(
|
|
37
|
+
process.argv[0],
|
|
38
|
+
// node executable
|
|
39
|
+
[process.argv[1], "agent", "daemon"],
|
|
40
|
+
// dirac agent daemon
|
|
41
|
+
{
|
|
42
|
+
detached: true,
|
|
43
|
+
stdio: ["ignore", logFd, logFd],
|
|
44
|
+
// Redirect stdout/stderr to log file
|
|
45
|
+
cwd: process.cwd()
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
fs.closeSync(logFd);
|
|
49
|
+
child.unref();
|
|
50
|
+
let attempts = 0;
|
|
51
|
+
const maxAttempts = 10;
|
|
52
|
+
while (attempts < maxAttempts) {
|
|
53
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
54
|
+
if (isSessionRunning()) {
|
|
55
|
+
console.log("\u2713 Agent started successfully");
|
|
56
|
+
console.log(` PID: ${child.pid}`);
|
|
57
|
+
console.log(` Socket: ${getSocketPath()}`);
|
|
58
|
+
console.log(` Logs: ${LOG_FILE}`);
|
|
59
|
+
console.log("");
|
|
60
|
+
console.log("Connect with: dirac shell --agent");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
attempts++;
|
|
64
|
+
}
|
|
65
|
+
console.error("\u2717 Failed to start agent");
|
|
66
|
+
console.error("Check logs:", LOG_FILE);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
async stop() {
|
|
70
|
+
const pid = this.getRunningPid();
|
|
71
|
+
if (!pid) {
|
|
72
|
+
console.log("Agent is not running");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
console.log(`Stopping agent (PID: ${pid})...`);
|
|
76
|
+
try {
|
|
77
|
+
process.kill(pid, "SIGTERM");
|
|
78
|
+
let attempts = 0;
|
|
79
|
+
while (attempts < 10) {
|
|
80
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
81
|
+
try {
|
|
82
|
+
process.kill(pid, 0);
|
|
83
|
+
attempts++;
|
|
84
|
+
} catch {
|
|
85
|
+
console.log("\u2713 Agent stopped");
|
|
86
|
+
this.cleanup();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
console.log("Agent did not stop gracefully, forcing...");
|
|
91
|
+
process.kill(pid, "SIGKILL");
|
|
92
|
+
this.cleanup();
|
|
93
|
+
console.log("\u2713 Agent stopped (forced)");
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (error.code === "ESRCH") {
|
|
96
|
+
console.log("Agent was not running");
|
|
97
|
+
this.cleanup();
|
|
98
|
+
} else {
|
|
99
|
+
console.error("Error stopping agent:", error.message);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async status() {
|
|
105
|
+
const pid = this.getRunningPid();
|
|
106
|
+
if (!pid) {
|
|
107
|
+
console.log("Status: NOT RUNNING");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
process.kill(pid, 0);
|
|
112
|
+
console.log("Status: RUNNING");
|
|
113
|
+
console.log(`PID: ${pid}`);
|
|
114
|
+
console.log(`Socket: ${getSocketPath()}`);
|
|
115
|
+
console.log(`Logs: ${LOG_FILE}`);
|
|
116
|
+
if (fs.existsSync(PID_FILE)) {
|
|
117
|
+
const stats = fs.statSync(PID_FILE);
|
|
118
|
+
const uptime = Date.now() - stats.mtimeMs;
|
|
119
|
+
console.log(`Uptime: ${this.formatUptime(uptime)}`);
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (error.code === "ESRCH") {
|
|
123
|
+
console.log("Status: NOT RUNNING (stale PID file)");
|
|
124
|
+
this.cleanup();
|
|
125
|
+
} else {
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async restart() {
|
|
131
|
+
console.log("Restarting agent...");
|
|
132
|
+
await this.stop();
|
|
133
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
134
|
+
await this.start();
|
|
135
|
+
}
|
|
136
|
+
async logs(follow = false) {
|
|
137
|
+
if (!fs.existsSync(LOG_FILE)) {
|
|
138
|
+
console.log("No logs found");
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (follow) {
|
|
142
|
+
const { spawn: spawn2 } = await import("child_process");
|
|
143
|
+
const tail = spawn2("tail", ["-f", LOG_FILE], {
|
|
144
|
+
stdio: "inherit"
|
|
145
|
+
});
|
|
146
|
+
process.on("SIGINT", () => {
|
|
147
|
+
tail.kill();
|
|
148
|
+
process.exit(0);
|
|
149
|
+
});
|
|
150
|
+
} else {
|
|
151
|
+
const content = fs.readFileSync(LOG_FILE, "utf-8");
|
|
152
|
+
const lines = content.split("\n");
|
|
153
|
+
const lastLines = lines.slice(-50);
|
|
154
|
+
console.log(lastLines.join("\n"));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
getRunningPid() {
|
|
158
|
+
if (!fs.existsSync(PID_FILE)) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const pidStr = fs.readFileSync(PID_FILE, "utf-8").trim();
|
|
163
|
+
return parseInt(pidStr, 10);
|
|
164
|
+
} catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
cleanup() {
|
|
169
|
+
if (fs.existsSync(PID_FILE)) {
|
|
170
|
+
fs.unlinkSync(PID_FILE);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
formatUptime(ms) {
|
|
174
|
+
const seconds = Math.floor(ms / 1e3);
|
|
175
|
+
const minutes = Math.floor(seconds / 60);
|
|
176
|
+
const hours = Math.floor(minutes / 60);
|
|
177
|
+
const days = Math.floor(hours / 24);
|
|
178
|
+
if (days > 0) return `${days}d ${hours % 24}h`;
|
|
179
|
+
if (hours > 0) return `${hours}h ${minutes % 60}m`;
|
|
180
|
+
if (minutes > 0) return `${minutes}m`;
|
|
181
|
+
return `${seconds}s`;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
async function runAgentDaemon() {
|
|
185
|
+
console.log(`[${(/* @__PURE__ */ new Date()).toISOString()}] Starting DIRAC agent daemon`);
|
|
186
|
+
let config = {};
|
|
187
|
+
try {
|
|
188
|
+
const fs2 = await import("fs");
|
|
189
|
+
const path2 = await import("path");
|
|
190
|
+
const yaml = await import("js-yaml");
|
|
191
|
+
const configPath = path2.default.resolve(process.cwd(), "config.yml");
|
|
192
|
+
if (fs2.default.existsSync(configPath)) {
|
|
193
|
+
const configData = yaml.default.load(fs2.default.readFileSync(configPath, "utf-8"));
|
|
194
|
+
config = {
|
|
195
|
+
llmProvider: configData.llmProvider,
|
|
196
|
+
llmModel: configData.llmModel,
|
|
197
|
+
customLLMUrl: configData.customLLMUrl,
|
|
198
|
+
initScript: configData.initScript
|
|
199
|
+
};
|
|
200
|
+
console.log(`[${(/* @__PURE__ */ new Date()).toISOString()}] Loaded config: LLM=${config.llmProvider}/${config.llmModel}`);
|
|
201
|
+
}
|
|
202
|
+
} catch (err) {
|
|
203
|
+
console.log(`[${(/* @__PURE__ */ new Date()).toISOString()}] No config.yml found, using defaults`);
|
|
204
|
+
}
|
|
205
|
+
const server = new SessionServer(config);
|
|
206
|
+
try {
|
|
207
|
+
await server.start();
|
|
208
|
+
console.log(`[${(/* @__PURE__ */ new Date()).toISOString()}] Agent daemon started successfully`);
|
|
209
|
+
const shutdown = async () => {
|
|
210
|
+
console.log(`[${(/* @__PURE__ */ new Date()).toISOString()}] Shutting down agent daemon`);
|
|
211
|
+
await server.shutdown();
|
|
212
|
+
process.exit(0);
|
|
213
|
+
};
|
|
214
|
+
process.on("SIGTERM", shutdown);
|
|
215
|
+
process.on("SIGINT", shutdown);
|
|
216
|
+
await new Promise(() => {
|
|
217
|
+
});
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error(`[${(/* @__PURE__ */ new Date()).toISOString()}] Failed to start agent:`, error);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
export {
|
|
224
|
+
AgentCLI,
|
|
225
|
+
runAgentDaemon
|
|
226
|
+
};
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import {
|
|
2
|
+
integrate
|
|
3
|
+
} from "./chunk-ZAA6R2TC.js";
|
|
4
|
+
import {
|
|
5
|
+
DiracParser
|
|
6
|
+
} from "./chunk-HRHAMPOB.js";
|
|
7
|
+
import {
|
|
8
|
+
createSession
|
|
9
|
+
} from "./chunk-3UW6GWYQ.js";
|
|
10
|
+
|
|
11
|
+
// src/session-server.ts
|
|
12
|
+
import net from "net";
|
|
13
|
+
import fs from "fs";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import os from "os";
|
|
16
|
+
var SOCKET_DIR = path.join(os.homedir(), ".dirac");
|
|
17
|
+
var SOCKET_PATH = path.join(SOCKET_DIR, "session.sock");
|
|
18
|
+
var PID_PATH = path.join(SOCKET_DIR, "session.pid");
|
|
19
|
+
var SessionServer = class {
|
|
20
|
+
server;
|
|
21
|
+
session;
|
|
22
|
+
clients = /* @__PURE__ */ new Map();
|
|
23
|
+
clientIdCounter = 0;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.session = createSession(config || {});
|
|
26
|
+
this.server = net.createServer(this.handleConnection.bind(this));
|
|
27
|
+
}
|
|
28
|
+
async start() {
|
|
29
|
+
if (!fs.existsSync(SOCKET_DIR)) {
|
|
30
|
+
fs.mkdirSync(SOCKET_DIR, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
if (fs.existsSync(SOCKET_PATH)) {
|
|
33
|
+
fs.unlinkSync(SOCKET_PATH);
|
|
34
|
+
}
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
this.server.listen(SOCKET_PATH, () => {
|
|
37
|
+
console.log(`[session-server] Listening on ${SOCKET_PATH}`);
|
|
38
|
+
fs.writeFileSync(PID_PATH, process.pid.toString());
|
|
39
|
+
fs.chmodSync(SOCKET_PATH, 384);
|
|
40
|
+
resolve();
|
|
41
|
+
});
|
|
42
|
+
this.server.on("error", (error) => {
|
|
43
|
+
console.error("[session-server] Error:", error);
|
|
44
|
+
reject(error);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
handleConnection(socket) {
|
|
49
|
+
const clientId = `client-${++this.clientIdCounter}`;
|
|
50
|
+
const client = { id: clientId, socket };
|
|
51
|
+
this.clients.set(clientId, client);
|
|
52
|
+
console.log(`[session-server] Client connected: ${clientId}`);
|
|
53
|
+
let buffer = "";
|
|
54
|
+
socket.on("data", async (data) => {
|
|
55
|
+
buffer += data.toString();
|
|
56
|
+
const lines = buffer.split("\n");
|
|
57
|
+
buffer = lines.pop() || "";
|
|
58
|
+
for (const line of lines) {
|
|
59
|
+
if (!line.trim()) continue;
|
|
60
|
+
try {
|
|
61
|
+
const message = JSON.parse(line);
|
|
62
|
+
await this.handleMessage(client, message);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
this.sendError(client, `Invalid message: ${error}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
socket.on("end", () => {
|
|
69
|
+
console.log(`[session-server] Client disconnected: ${clientId}`);
|
|
70
|
+
this.clients.delete(clientId);
|
|
71
|
+
});
|
|
72
|
+
socket.on("error", (error) => {
|
|
73
|
+
console.error(`[session-server] Client error (${clientId}):`, error);
|
|
74
|
+
this.clients.delete(clientId);
|
|
75
|
+
});
|
|
76
|
+
this.sendResponse(client, {
|
|
77
|
+
type: "welcome",
|
|
78
|
+
sessionId: clientId,
|
|
79
|
+
message: "Connected to DIRAC session"
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async handleMessage(client, message) {
|
|
83
|
+
const { type, data } = message;
|
|
84
|
+
switch (type) {
|
|
85
|
+
case "execute":
|
|
86
|
+
await this.executeCommand(client, data.command);
|
|
87
|
+
break;
|
|
88
|
+
case "getVars":
|
|
89
|
+
this.sendResponse(client, {
|
|
90
|
+
type: "vars",
|
|
91
|
+
data: Object.keys(this.session.variables)
|
|
92
|
+
});
|
|
93
|
+
break;
|
|
94
|
+
case "getState":
|
|
95
|
+
this.sendResponse(client, {
|
|
96
|
+
type: "state",
|
|
97
|
+
data: {
|
|
98
|
+
variables: this.session.variables,
|
|
99
|
+
subroutines: this.session.subroutines,
|
|
100
|
+
varBoundary: this.session.varBoundary,
|
|
101
|
+
subBoundary: this.session.subBoundary
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
break;
|
|
105
|
+
case "shutdown":
|
|
106
|
+
this.sendResponse(client, {
|
|
107
|
+
type: "shutdown",
|
|
108
|
+
message: "Server shutting down"
|
|
109
|
+
});
|
|
110
|
+
await this.shutdown();
|
|
111
|
+
break;
|
|
112
|
+
default:
|
|
113
|
+
this.sendError(client, `Unknown message type: ${type}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async executeCommand(client, command) {
|
|
117
|
+
try {
|
|
118
|
+
this.session.output = [];
|
|
119
|
+
const parser = new DiracParser();
|
|
120
|
+
const ast = parser.parse(command);
|
|
121
|
+
await integrate(this.session, ast);
|
|
122
|
+
const output = this.session.output.join("");
|
|
123
|
+
this.sendResponse(client, {
|
|
124
|
+
type: "output",
|
|
125
|
+
data: output
|
|
126
|
+
});
|
|
127
|
+
} catch (error) {
|
|
128
|
+
this.sendError(client, error.message);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
sendResponse(client, response) {
|
|
132
|
+
try {
|
|
133
|
+
client.socket.write(JSON.stringify(response) + "\n");
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.error(`[session-server] Failed to send response:`, error);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
sendError(client, message) {
|
|
139
|
+
this.sendResponse(client, {
|
|
140
|
+
type: "error",
|
|
141
|
+
message
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
async shutdown() {
|
|
145
|
+
console.log("[session-server] Shutting down...");
|
|
146
|
+
for (const client of this.clients.values()) {
|
|
147
|
+
client.socket.end();
|
|
148
|
+
}
|
|
149
|
+
this.clients.clear();
|
|
150
|
+
return new Promise((resolve) => {
|
|
151
|
+
this.server.close(() => {
|
|
152
|
+
if (fs.existsSync(SOCKET_PATH)) {
|
|
153
|
+
fs.unlinkSync(SOCKET_PATH);
|
|
154
|
+
}
|
|
155
|
+
if (fs.existsSync(PID_PATH)) {
|
|
156
|
+
fs.unlinkSync(PID_PATH);
|
|
157
|
+
}
|
|
158
|
+
console.log("[session-server] Shutdown complete");
|
|
159
|
+
resolve();
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
function isSessionRunning() {
|
|
165
|
+
if (!fs.existsSync(PID_PATH)) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
const pid = parseInt(fs.readFileSync(PID_PATH, "utf-8").trim(), 10);
|
|
170
|
+
process.kill(pid, 0);
|
|
171
|
+
return true;
|
|
172
|
+
} catch (error) {
|
|
173
|
+
if (fs.existsSync(PID_PATH)) fs.unlinkSync(PID_PATH);
|
|
174
|
+
try {
|
|
175
|
+
if (fs.existsSync(SOCKET_PATH)) fs.unlinkSync(SOCKET_PATH);
|
|
176
|
+
} catch (e) {
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function getSocketPath() {
|
|
182
|
+
return SOCKET_PATH;
|
|
183
|
+
}
|
|
184
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
185
|
+
const server = new SessionServer();
|
|
186
|
+
server.start().then(() => {
|
|
187
|
+
console.log("[session-server] Server started successfully");
|
|
188
|
+
process.on("SIGINT", async () => {
|
|
189
|
+
console.log("\n[session-server] Received SIGINT, shutting down...");
|
|
190
|
+
await server.shutdown();
|
|
191
|
+
process.exit(0);
|
|
192
|
+
});
|
|
193
|
+
process.on("SIGTERM", async () => {
|
|
194
|
+
console.log("\n[session-server] Received SIGTERM, shutting down...");
|
|
195
|
+
await server.shutdown();
|
|
196
|
+
process.exit(0);
|
|
197
|
+
});
|
|
198
|
+
}).catch((error) => {
|
|
199
|
+
console.error("[session-server] Failed to start:", error);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export {
|
|
205
|
+
SessionServer,
|
|
206
|
+
isSessionRunning,
|
|
207
|
+
getSocketPath
|
|
208
|
+
};
|