@sofer_agent/cli 0.7.0 → 0.7.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AA6BA,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAKhD;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAoIjD"}
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AA2CA,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAKhD;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAuLjD"}
package/dist/daemon.js CHANGED
@@ -1,74 +1,106 @@
1
1
  import { createServer } from "node:http";
2
- import { readFileSync, writeFileSync, unlinkSync, existsSync } from "node:fs";
2
+ import { chmodSync, existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
- import { agentPaths, decryptWithKey, loadConfig, readSecret, SoferAgent, } from "@sofer_agent/core";
4
+ import { agentPaths, decryptWithKey, loadConfig, readSecret, shortAgentId, SoferAgent, } from "@sofer_agent/core";
5
5
  import { TelegramListener } from "@sofer_agent/plugin-telegram";
6
6
  import { loadSecrets } from "./env.js";
7
- const PID_FILE = join(agentPaths.root, "daemon.pid");
8
- function writePid(pid) {
9
- writeFileSync(PID_FILE, String(pid), "utf8");
10
- }
11
- function readPid() {
7
+ const LOCK_FILE = join(agentPaths.root, "daemon.lock");
8
+ const SOCK_PATH = join(agentPaths.root, "daemon.sock");
9
+ // ── Process lock ──────────────────────────────────────────────────────────
10
+ function acquireLock() {
12
11
  try {
13
- return Number(readFileSync(PID_FILE, "utf8").trim());
12
+ if (existsSync(LOCK_FILE)) {
13
+ const pid = Number(readFileSync(LOCK_FILE, "utf8").trim());
14
+ try {
15
+ process.kill(pid, 0);
16
+ return false;
17
+ }
18
+ catch { /* stale */ }
19
+ }
20
+ writeFileSync(LOCK_FILE, String(process.pid), "utf8");
21
+ return true;
14
22
  }
15
23
  catch {
16
- return null;
24
+ return false;
17
25
  }
18
26
  }
27
+ function releaseLock() {
28
+ try {
29
+ if (existsSync(LOCK_FILE))
30
+ unlinkSync(LOCK_FILE);
31
+ }
32
+ catch { /* */ }
33
+ }
34
+ let state = "bootstrapping";
35
+ // ── Main ──────────────────────────────────────────────────────────────────
19
36
  export async function daemonStop() {
20
- const pid = readPid();
21
- if (!pid) {
37
+ if (!existsSync(LOCK_FILE)) {
22
38
  console.log("No daemon running.");
23
39
  return;
24
40
  }
41
+ const pid = Number(readFileSync(LOCK_FILE, "utf8").trim());
25
42
  try {
26
43
  process.kill(pid, "SIGTERM");
27
- console.log(`Sent stop signal to PID ${pid}.`);
44
+ console.log(`Sent stop to PID ${pid}.`);
28
45
  }
29
46
  catch {
30
- console.log("Daemon not running (stale PID).");
31
- unlinkSync(PID_FILE);
47
+ console.log("Stale lock. Cleaning up.");
48
+ releaseLock();
32
49
  }
33
50
  }
34
51
  export async function daemonStart() {
52
+ if (!acquireLock()) {
53
+ console.error("Daemon already running (lock exists). Use `sofer daemon stop` first.");
54
+ process.exit(1);
55
+ }
35
56
  const secrets = loadSecrets();
36
57
  if (!secrets.suiSecretKey || !secrets.anthropicApiKey) {
37
58
  console.error("Missing secrets. Run `sofer init` first.");
38
59
  process.exit(1);
39
60
  }
61
+ console.log("[daemon] bootstrapping…");
40
62
  const config = loadConfig();
41
- const agent = await SoferAgent.create(config, {
42
- suiSecretKey: secrets.suiSecretKey,
43
- anthropicApiKey: secrets.anthropicApiKey,
44
- });
63
+ let agent;
64
+ try {
65
+ agent = await SoferAgent.create(config, {
66
+ suiSecretKey: secrets.suiSecretKey,
67
+ anthropicApiKey: secrets.anthropicApiKey,
68
+ });
69
+ }
70
+ catch (e) {
71
+ console.error("[daemon] failed to create agent:", e.message);
72
+ releaseLock();
73
+ process.exit(1);
74
+ }
45
75
  // SSE clients
46
76
  let sseId = 0;
47
77
  const sseClients = new Set();
48
78
  function broadcast(event, data) {
79
+ const payload = JSON.stringify(data);
49
80
  for (const c of sseClients) {
50
- c.res.write(`event: ${event}\ndata: ${data}\n\n`);
81
+ c.res.write(`event: ${event}\ndata: ${payload}\n\n`);
51
82
  }
52
83
  }
53
- // HTTP server
84
+ // ── HTTP server ────────────────────────────────────────────────────────
54
85
  const server = createServer(async (req, res) => {
55
86
  res.setHeader("Access-Control-Allow-Origin", "*");
56
87
  if (req.method === "OPTIONS") {
57
88
  res.writeHead(204).end();
58
89
  return;
59
90
  }
91
+ const url = req.url ?? "/";
60
92
  // GET /healthz
61
- if (req.url === "/healthz" || req.url === "/") {
93
+ if (req.method === "GET" && url === "/healthz") {
62
94
  res.writeHead(200, { "content-type": "application/json" });
63
- res.end(JSON.stringify({ status: "ok", agent: agent.address.slice(0, 10), network: config.network }));
95
+ res.end(JSON.stringify({ status: state, agent: agent.address.slice(0, 10), network: config.network }));
64
96
  return;
65
97
  }
66
98
  // GET /events (SSE)
67
- if (req.url === "/events") {
99
+ if (req.method === "GET" && url === "/events") {
68
100
  res.writeHead(200, {
69
101
  "content-type": "text/event-stream",
70
102
  "cache-control": "no-cache",
71
- "connection": "keep-alive",
103
+ connection: "keep-alive",
72
104
  });
73
105
  const client = { id: ++sseId, res };
74
106
  sseClients.add(client);
@@ -77,7 +109,7 @@ export async function daemonStart() {
77
109
  return;
78
110
  }
79
111
  // POST /chat
80
- if (req.method === "POST" && req.url === "/chat") {
112
+ if (req.method === "POST" && url === "/chat") {
81
113
  const body = await readBody(req);
82
114
  try {
83
115
  const { message } = JSON.parse(body);
@@ -85,23 +117,38 @@ export async function daemonStart() {
85
117
  res.writeHead(400).end("missing message");
86
118
  return;
87
119
  }
88
- broadcast("thinking", JSON.stringify({ status: "thinking" }));
120
+ broadcast("thinking", { status: "thinking" });
89
121
  const { text } = await agent.chat(message);
90
- broadcast("response", JSON.stringify({ text }));
91
- broadcast("idle", JSON.stringify({ status: "idle" }));
122
+ broadcast("response", { text });
123
+ broadcast("idle", { status: "idle" });
92
124
  res.writeHead(200, { "content-type": "application/json" });
93
125
  res.end(JSON.stringify({ text }));
94
126
  }
95
127
  catch (e) {
96
- broadcast("error", JSON.stringify({ error: e.message }));
128
+ broadcast("error", { error: e.message });
129
+ res.writeHead(500).end(e.message);
130
+ }
131
+ return;
132
+ }
133
+ // POST /sync — force memory flush
134
+ if (req.method === "POST" && url === "/sync") {
135
+ broadcast("sync", { status: "syncing" });
136
+ // Memory is already persisted via JSONL; trigger a fresh agent state read
137
+ try {
138
+ const bal = await agent.getBalance();
139
+ broadcast("sync", { status: "done", balance: (Number(bal) / 1e9).toFixed(4) });
140
+ res.writeHead(200).end("synced");
141
+ }
142
+ catch (e) {
97
143
  res.writeHead(500).end(e.message);
98
144
  }
99
145
  return;
100
146
  }
101
147
  // GET /status
102
- if (req.url === "/status") {
148
+ if (req.method === "GET" && url === "/status") {
103
149
  res.writeHead(200, { "content-type": "application/json" });
104
150
  res.end(JSON.stringify({
151
+ state,
105
152
  agent: agent.address,
106
153
  name: agent.name,
107
154
  network: config.network,
@@ -112,7 +159,7 @@ export async function daemonStart() {
112
159
  }
113
160
  res.writeHead(404).end("not found");
114
161
  });
115
- // Telegram listener
162
+ // ── Telegram ───────────────────────────────────────────────────────────
116
163
  const tgPath = `${agentPaths.root}/telegram.enc`;
117
164
  const tgEnc = readSecret(tgPath);
118
165
  let tgListener = null;
@@ -127,33 +174,53 @@ export async function daemonStart() {
127
174
  agentName: agent.name.toLowerCase(),
128
175
  });
129
176
  tgListener.onDispatch(async (input) => {
130
- broadcast("tg-message", JSON.stringify({ from: input.displayName, text: input.text.slice(0, 100) }));
177
+ broadcast("tg-message", { from: input.displayName, text: input.text.slice(0, 200) });
131
178
  const { text } = await agent.chat(input.text);
132
- broadcast("tg-response", JSON.stringify({ text: text.slice(0, 100) }));
179
+ broadcast("tg-response", { text: text.slice(0, 200) });
133
180
  return text;
134
181
  });
135
182
  }
136
183
  }
137
184
  catch { /* skip */ }
138
185
  }
186
+ // ── Bind ───────────────────────────────────────────────────────────────
139
187
  const PORT = Number(process.env.SOFER_DAEMON_PORT ?? 4242);
140
- server.listen(PORT, () => {
141
- writePid(process.pid);
142
- console.log(`[daemon] sofer running on http://localhost:${PORT}`);
143
- console.log(`[daemon] agent: ${agent.address.slice(0, 10)}… network: ${config.network}`);
144
- if (tgListener) {
145
- console.log("[daemon] telegram: starting bot…");
146
- tgListener.start().catch((e) => console.error("[daemon] telegram failed:", e.message));
147
- }
148
- });
149
- // Graceful shutdown
188
+ // Try Unix socket first, fall back to TCP
189
+ try {
190
+ if (existsSync(SOCK_PATH))
191
+ unlinkSync(SOCK_PATH);
192
+ server.listen(SOCK_PATH, () => {
193
+ chmodSync(SOCK_PATH, 0o600);
194
+ state = "ready";
195
+ console.log(`[daemon] ready — unix socket ${SOCK_PATH}`);
196
+ console.log(`[daemon] agent: ${agent.address.slice(0, 10)}… network: ${config.network}`);
197
+ if (tgListener) {
198
+ console.log("[daemon] telegram: starting bot…");
199
+ tgListener.start().catch((e) => console.error("[daemon] telegram:", e.message));
200
+ }
201
+ });
202
+ }
203
+ catch {
204
+ server.listen(PORT, () => {
205
+ state = "ready";
206
+ console.log(`[daemon] ready — tcp port ${PORT} (SOFER_DAEMON_PORT)`);
207
+ console.log(`[daemon] agent: ${agent.address.slice(0, 10)}… network: ${config.network}`);
208
+ if (tgListener) {
209
+ tgListener.start().catch((e) => console.error("[daemon] telegram:", e.message));
210
+ }
211
+ });
212
+ }
213
+ // ── Shutdown ───────────────────────────────────────────────────────────
150
214
  const shutdown = async () => {
215
+ state = "shutting_down";
151
216
  console.log("\n[daemon] shutting down…");
152
217
  if (tgListener)
153
- await tgListener.stop();
218
+ await tgListener.stop().catch(() => { });
154
219
  server.close();
220
+ releaseLock();
155
221
  try {
156
- unlinkSync(PID_FILE);
222
+ if (existsSync(SOCK_PATH))
223
+ unlinkSync(SOCK_PATH);
157
224
  }
158
225
  catch { /* */ }
159
226
  process.exit(0);
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAC;AACpF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,UAAU,EACV,cAAc,EACd,UAAU,EACV,UAAU,EACV,YAAY,EACZ,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AACvD,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AAIvD,6EAA6E;AAE7E,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC3D,IAAI,CAAC;gBAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAAC,OAAO,KAAK,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC;QACnE,CAAC;QACD,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,KAAK,CAAC;IAAC,CAAC;AAC3B,CAAC;AAED,SAAS,WAAW;IAClB,IAAI,CAAC;QAAC,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;AAC3E,CAAC;AAKD,IAAI,KAAK,GAAgB,eAAe,CAAC;AAEzC,6EAA6E;AAE7E,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAC1E,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC;QAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,GAAG,CAAC,CAAC;IAAC,CAAC;IAC9E,MAAM,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;QAAC,WAAW,EAAE,CAAC;IAAC,CAAC;AACnE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,sEAAsE,CAAC,CAAC;QACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;QACtD,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,KAAiB,CAAC;IACtB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE;YACtC,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,eAAe,EAAE,OAAO,CAAC,eAAe;SACzC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAG,CAAW,CAAC,OAAO,CAAC,CAAC;QACxE,WAAW,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,cAAc;IACd,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,UAAU,GAAG,IAAI,GAAG,EAAa,CAAC;IAExC,SAAS,SAAS,CAAC,KAAa,EAAE,IAA6B;QAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrC,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3B,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,WAAW,OAAO,MAAM,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,0EAA0E;IAE1E,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,GAAoB,EAAE,GAAmB,EAAE,EAAE;QAC9E,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;QAClD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QAEnE,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC;QAE3B,eAAe;QACf,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;YAC/C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACvG,OAAO;QACT,CAAC;QAED,oBAAoB;QACpB,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC9C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;gBACjB,cAAc,EAAE,mBAAmB;gBACnC,eAAe,EAAE,UAAU;gBAC3B,UAAU,EAAE,YAAY;aACzB,CAAC,CAAC;YACH,MAAM,MAAM,GAAc,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;YAC/C,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACvB,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;YACvF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YACjD,OAAO;QACT,CAAC;QAED,aAAa;QACb,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YAC7C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACrC,IAAI,CAAC,OAAO,EAAE,CAAC;oBAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;oBAAC,OAAO;gBAAC,CAAC;gBACpE,SAAS,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;gBAC9C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC3C,SAAS,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBAChC,SAAS,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;gBACtC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACpC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,SAAS,CAAC,OAAO,EAAE,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAE,CAAW,CAAC,OAAO,CAAC,CAAC;YAC/C,CAAC;YACD,OAAO;QACT,CAAC;QAED,kCAAkC;QAClC,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YAC7C,SAAS,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;YACzC,0EAA0E;YAC1E,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC;gBACrC,SAAS,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC/E,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACnC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAE,CAAW,CAAC,OAAO,CAAC,CAAC;YAC/C,CAAC;YACD,OAAO;QACT,CAAC;QAED,cAAc;QACd,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC9C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;gBACrB,KAAK;gBACL,KAAK,EAAE,KAAK,CAAC,OAAO;gBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM;gBAC1B,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;aACrC,CAAC,CAAC,CAAC;YACJ,OAAO;QACT,CAAC;QAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,0EAA0E;IAE1E,MAAM,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,eAAe,CAAC;IACjD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,UAAU,GAA4B,IAAI,CAAC;IAC/C,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,cAAc,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YACxD,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmD,CAAC;gBACnF,UAAU,GAAG,IAAI,gBAAgB,CAAC;oBAChC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;oBAC3B,cAAc,EAAE,QAAQ,CAAC,cAAc;oBACvC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;gBACH,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;oBACpC,SAAS,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;oBACrF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC9C,SAAS,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;oBACvD,OAAO,IAAI,CAAC;gBACd,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;IACxB,CAAC;IAED,0EAA0E;IAE1E,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,IAAI,CAAC,CAAC;IAE3D,0CAA0C;IAC1C,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,UAAU,CAAC,SAAS,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE;YAC5B,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YAC5B,KAAK,GAAG,OAAO,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,gCAAgC,SAAS,EAAE,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YAC1F,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;gBAChD,UAAU,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;YAClF,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;YACvB,KAAK,GAAG,OAAO,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,6BAA6B,IAAI,sBAAsB,CAAC,CAAC;YACrE,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YAC1F,IAAI,UAAU,EAAE,CAAC;gBACf,UAAU,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;YAClF,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,0EAA0E;IAE1E,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,KAAK,GAAG,eAAe,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,IAAI,UAAU;YAAE,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,WAAW,EAAE,CAAC;QACd,IAAI,CAAC;YAAC,IAAI,UAAU,CAAC,SAAS,CAAC;gBAAE,UAAU,CAAC,SAAS,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;QACzE,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;AAClC,CAAC;AAED,SAAS,QAAQ,CAAC,GAAoB;IACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sofer_agent/cli",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sofer": "./bin/sofer"
package/src/daemon.ts CHANGED
@@ -1,81 +1,111 @@
1
1
  import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
2
- import { readFileSync, writeFileSync, unlinkSync, existsSync } from "node:fs";
2
+ import { chmodSync, existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import {
5
- type SoferConfig,
6
5
  agentPaths,
7
6
  decryptWithKey,
8
7
  loadConfig,
9
8
  readSecret,
9
+ shortAgentId,
10
10
  SoferAgent,
11
11
  } from "@sofer_agent/core";
12
12
  import { TelegramListener } from "@sofer_agent/plugin-telegram";
13
13
  import { loadSecrets } from "./env.js";
14
14
 
15
- const PID_FILE = join(agentPaths.root, "daemon.pid");
15
+ const LOCK_FILE = join(agentPaths.root, "daemon.lock");
16
+ const SOCK_PATH = join(agentPaths.root, "daemon.sock");
16
17
 
17
- interface SSEClient {
18
- id: number;
19
- res: ServerResponse;
20
- }
18
+ interface SSEClient { id: number; res: ServerResponse; }
19
+
20
+ // ── Process lock ──────────────────────────────────────────────────────────
21
21
 
22
- function writePid(pid: number): void {
23
- writeFileSync(PID_FILE, String(pid), "utf8");
22
+ function acquireLock(): boolean {
23
+ try {
24
+ if (existsSync(LOCK_FILE)) {
25
+ const pid = Number(readFileSync(LOCK_FILE, "utf8").trim());
26
+ try { process.kill(pid, 0); return false; } catch { /* stale */ }
27
+ }
28
+ writeFileSync(LOCK_FILE, String(process.pid), "utf8");
29
+ return true;
30
+ } catch { return false; }
24
31
  }
25
32
 
26
- function readPid(): number | null {
27
- try { return Number(readFileSync(PID_FILE, "utf8").trim()); } catch { return null; }
33
+ function releaseLock(): void {
34
+ try { if (existsSync(LOCK_FILE)) unlinkSync(LOCK_FILE); } catch { /* */ }
28
35
  }
29
36
 
37
+ // ── State machine ─────────────────────────────────────────────────────────
38
+
39
+ type DaemonState = "bootstrapping" | "ready" | "shutting_down";
40
+ let state: DaemonState = "bootstrapping";
41
+
42
+ // ── Main ──────────────────────────────────────────────────────────────────
43
+
30
44
  export async function daemonStop(): Promise<void> {
31
- const pid = readPid();
32
- if (!pid) { console.log("No daemon running."); return; }
33
- try { process.kill(pid, "SIGTERM"); console.log(`Sent stop signal to PID ${pid}.`); }
34
- catch { console.log("Daemon not running (stale PID)."); unlinkSync(PID_FILE); }
45
+ if (!existsSync(LOCK_FILE)) { console.log("No daemon running."); return; }
46
+ const pid = Number(readFileSync(LOCK_FILE, "utf8").trim());
47
+ try { process.kill(pid, "SIGTERM"); console.log(`Sent stop to PID ${pid}.`); }
48
+ catch { console.log("Stale lock. Cleaning up."); releaseLock(); }
35
49
  }
36
50
 
37
51
  export async function daemonStart(): Promise<void> {
52
+ if (!acquireLock()) {
53
+ console.error("Daemon already running (lock exists). Use `sofer daemon stop` first.");
54
+ process.exit(1);
55
+ }
56
+
38
57
  const secrets = loadSecrets();
39
58
  if (!secrets.suiSecretKey || !secrets.anthropicApiKey) {
40
59
  console.error("Missing secrets. Run `sofer init` first.");
41
60
  process.exit(1);
42
61
  }
43
62
 
63
+ console.log("[daemon] bootstrapping…");
44
64
  const config = loadConfig();
45
- const agent = await SoferAgent.create(config, {
46
- suiSecretKey: secrets.suiSecretKey,
47
- anthropicApiKey: secrets.anthropicApiKey,
48
- });
65
+ let agent: SoferAgent;
66
+ try {
67
+ agent = await SoferAgent.create(config, {
68
+ suiSecretKey: secrets.suiSecretKey,
69
+ anthropicApiKey: secrets.anthropicApiKey,
70
+ });
71
+ } catch (e) {
72
+ console.error("[daemon] failed to create agent:", (e as Error).message);
73
+ releaseLock();
74
+ process.exit(1);
75
+ }
49
76
 
50
77
  // SSE clients
51
78
  let sseId = 0;
52
79
  const sseClients = new Set<SSEClient>();
53
80
 
54
- function broadcast(event: string, data: string): void {
81
+ function broadcast(event: string, data: Record<string, unknown>): void {
82
+ const payload = JSON.stringify(data);
55
83
  for (const c of sseClients) {
56
- c.res.write(`event: ${event}\ndata: ${data}\n\n`);
84
+ c.res.write(`event: ${event}\ndata: ${payload}\n\n`);
57
85
  }
58
86
  }
59
87
 
60
- // HTTP server
88
+ // ── HTTP server ────────────────────────────────────────────────────────
89
+
61
90
  const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {
62
91
  res.setHeader("Access-Control-Allow-Origin", "*");
63
-
64
92
  if (req.method === "OPTIONS") { res.writeHead(204).end(); return; }
65
93
 
94
+ const url = req.url ?? "/";
95
+
66
96
  // GET /healthz
67
- if (req.url === "/healthz" || req.url === "/") {
97
+ if (req.method === "GET" && url === "/healthz") {
68
98
  res.writeHead(200, { "content-type": "application/json" });
69
- res.end(JSON.stringify({ status: "ok", agent: agent.address.slice(0, 10), network: config.network }));
99
+ res.end(JSON.stringify({ status: state, agent: agent.address.slice(0, 10), network: config.network }));
70
100
  return;
71
101
  }
72
102
 
73
103
  // GET /events (SSE)
74
- if (req.url === "/events") {
104
+ if (req.method === "GET" && url === "/events") {
75
105
  res.writeHead(200, {
76
106
  "content-type": "text/event-stream",
77
107
  "cache-control": "no-cache",
78
- "connection": "keep-alive",
108
+ connection: "keep-alive",
79
109
  });
80
110
  const client: SSEClient = { id: ++sseId, res };
81
111
  sseClients.add(client);
@@ -85,30 +115,43 @@ export async function daemonStart(): Promise<void> {
85
115
  }
86
116
 
87
117
  // POST /chat
88
- if (req.method === "POST" && req.url === "/chat") {
118
+ if (req.method === "POST" && url === "/chat") {
89
119
  const body = await readBody(req);
90
120
  try {
91
121
  const { message } = JSON.parse(body);
92
122
  if (!message) { res.writeHead(400).end("missing message"); return; }
93
-
94
- broadcast("thinking", JSON.stringify({ status: "thinking" }));
123
+ broadcast("thinking", { status: "thinking" });
95
124
  const { text } = await agent.chat(message);
96
- broadcast("response", JSON.stringify({ text }));
97
- broadcast("idle", JSON.stringify({ status: "idle" }));
98
-
125
+ broadcast("response", { text });
126
+ broadcast("idle", { status: "idle" });
99
127
  res.writeHead(200, { "content-type": "application/json" });
100
128
  res.end(JSON.stringify({ text }));
101
129
  } catch (e) {
102
- broadcast("error", JSON.stringify({ error: (e as Error).message }));
130
+ broadcast("error", { error: (e as Error).message });
131
+ res.writeHead(500).end((e as Error).message);
132
+ }
133
+ return;
134
+ }
135
+
136
+ // POST /sync — force memory flush
137
+ if (req.method === "POST" && url === "/sync") {
138
+ broadcast("sync", { status: "syncing" });
139
+ // Memory is already persisted via JSONL; trigger a fresh agent state read
140
+ try {
141
+ const bal = await agent.getBalance();
142
+ broadcast("sync", { status: "done", balance: (Number(bal) / 1e9).toFixed(4) });
143
+ res.writeHead(200).end("synced");
144
+ } catch (e) {
103
145
  res.writeHead(500).end((e as Error).message);
104
146
  }
105
147
  return;
106
148
  }
107
149
 
108
150
  // GET /status
109
- if (req.url === "/status") {
151
+ if (req.method === "GET" && url === "/status") {
110
152
  res.writeHead(200, { "content-type": "application/json" });
111
153
  res.end(JSON.stringify({
154
+ state,
112
155
  agent: agent.address,
113
156
  name: agent.name,
114
157
  network: config.network,
@@ -121,7 +164,8 @@ export async function daemonStart(): Promise<void> {
121
164
  res.writeHead(404).end("not found");
122
165
  });
123
166
 
124
- // Telegram listener
167
+ // ── Telegram ───────────────────────────────────────────────────────────
168
+
125
169
  const tgPath = `${agentPaths.root}/telegram.enc`;
126
170
  const tgEnc = readSecret(tgPath);
127
171
  let tgListener: TelegramListener | null = null;
@@ -136,34 +180,55 @@ export async function daemonStart(): Promise<void> {
136
180
  agentName: agent.name.toLowerCase(),
137
181
  });
138
182
  tgListener.onDispatch(async (input) => {
139
- broadcast("tg-message", JSON.stringify({ from: input.displayName, text: input.text.slice(0, 100) }));
183
+ broadcast("tg-message", { from: input.displayName, text: input.text.slice(0, 200) });
140
184
  const { text } = await agent.chat(input.text);
141
- broadcast("tg-response", JSON.stringify({ text: text.slice(0, 100) }));
185
+ broadcast("tg-response", { text: text.slice(0, 200) });
142
186
  return text;
143
187
  });
144
188
  }
145
189
  } catch { /* skip */ }
146
190
  }
147
191
 
192
+ // ── Bind ───────────────────────────────────────────────────────────────
193
+
148
194
  const PORT = Number(process.env.SOFER_DAEMON_PORT ?? 4242);
149
- server.listen(PORT, () => {
150
- writePid(process.pid);
151
- console.log(`[daemon] sofer running on http://localhost:${PORT}`);
152
- console.log(`[daemon] agent: ${agent.address.slice(0, 10)}… network: ${config.network}`);
153
- if (tgListener) {
154
- console.log("[daemon] telegram: starting bot…");
155
- tgListener.start().catch((e) => console.error("[daemon] telegram failed:", e.message));
156
- }
157
- });
158
195
 
159
- // Graceful shutdown
196
+ // Try Unix socket first, fall back to TCP
197
+ try {
198
+ if (existsSync(SOCK_PATH)) unlinkSync(SOCK_PATH);
199
+ server.listen(SOCK_PATH, () => {
200
+ chmodSync(SOCK_PATH, 0o600);
201
+ state = "ready";
202
+ console.log(`[daemon] ready — unix socket ${SOCK_PATH}`);
203
+ console.log(`[daemon] agent: ${agent.address.slice(0, 10)}… network: ${config.network}`);
204
+ if (tgListener) {
205
+ console.log("[daemon] telegram: starting bot…");
206
+ tgListener.start().catch((e) => console.error("[daemon] telegram:", e.message));
207
+ }
208
+ });
209
+ } catch {
210
+ server.listen(PORT, () => {
211
+ state = "ready";
212
+ console.log(`[daemon] ready — tcp port ${PORT} (SOFER_DAEMON_PORT)`);
213
+ console.log(`[daemon] agent: ${agent.address.slice(0, 10)}… network: ${config.network}`);
214
+ if (tgListener) {
215
+ tgListener.start().catch((e) => console.error("[daemon] telegram:", e.message));
216
+ }
217
+ });
218
+ }
219
+
220
+ // ── Shutdown ───────────────────────────────────────────────────────────
221
+
160
222
  const shutdown = async () => {
223
+ state = "shutting_down";
161
224
  console.log("\n[daemon] shutting down…");
162
- if (tgListener) await tgListener.stop();
225
+ if (tgListener) await tgListener.stop().catch(() => {});
163
226
  server.close();
164
- try { unlinkSync(PID_FILE); } catch { /* */ }
227
+ releaseLock();
228
+ try { if (existsSync(SOCK_PATH)) unlinkSync(SOCK_PATH); } catch { /* */ }
165
229
  process.exit(0);
166
230
  };
231
+
167
232
  process.on("SIGINT", shutdown);
168
233
  process.on("SIGTERM", shutdown);
169
234
  }