@openclaw-cloud/agent-controller 1.0.0-beta.2 → 1.0.0-beta.20

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 (131) hide show
  1. package/bin/agent-controller.js +11 -2
  2. package/dist/api.d.ts +4 -0
  3. package/dist/api.js +10 -2
  4. package/dist/api.js.map +1 -1
  5. package/dist/commands/bootstrap.js +9 -34
  6. package/dist/commands/bootstrap.js.map +1 -1
  7. package/dist/commands/channel-server.d.ts +17 -0
  8. package/dist/commands/channel-server.js +71 -0
  9. package/dist/commands/channel-server.js.map +1 -0
  10. package/dist/commands/heartbeat-cli.js +5 -4
  11. package/dist/commands/heartbeat-cli.js.map +1 -1
  12. package/dist/commands/install-deps.js +18 -8
  13. package/dist/commands/install-deps.js.map +1 -1
  14. package/dist/commands/install.js +8 -8
  15. package/dist/commands/install.js.map +1 -1
  16. package/dist/commands/self-update.js +2 -1
  17. package/dist/commands/self-update.js.map +1 -1
  18. package/dist/config-file.js +20 -4
  19. package/dist/config-file.js.map +1 -1
  20. package/dist/config.d.ts +39 -0
  21. package/dist/config.js +101 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/connection.d.ts +2 -0
  24. package/dist/connection.js +38 -7
  25. package/dist/connection.js.map +1 -1
  26. package/dist/debug.js +2 -1
  27. package/dist/debug.js.map +1 -1
  28. package/dist/handlers/backup.js +4 -1
  29. package/dist/handlers/backup.js.map +1 -1
  30. package/dist/handlers/board-handler.d.ts +4 -0
  31. package/dist/handlers/board-handler.js +127 -100
  32. package/dist/handlers/board-handler.js.map +1 -1
  33. package/dist/handlers/chat.d.ts +17 -0
  34. package/dist/handlers/chat.js +187 -6
  35. package/dist/handlers/chat.js.map +1 -1
  36. package/dist/handlers/deploy.js +16 -29
  37. package/dist/handlers/deploy.js.map +1 -1
  38. package/dist/handlers/diagnostics.js +12 -0
  39. package/dist/handlers/diagnostics.js.map +1 -1
  40. package/dist/handlers/knowledge-sync.js +21 -1
  41. package/dist/handlers/knowledge-sync.js.map +1 -1
  42. package/dist/handlers/memory.d.ts +13 -0
  43. package/dist/handlers/memory.js +128 -0
  44. package/dist/handlers/memory.js.map +1 -0
  45. package/dist/handlers/onboarding.js +18 -2
  46. package/dist/handlers/onboarding.js.map +1 -1
  47. package/dist/handlers/package-install.js +44 -12
  48. package/dist/handlers/package-install.js.map +1 -1
  49. package/dist/handlers/pair.js +14 -1
  50. package/dist/handlers/pair.js.map +1 -1
  51. package/dist/handlers/restart.js +3 -1
  52. package/dist/handlers/restart.js.map +1 -1
  53. package/dist/handlers/self-update.js +3 -1
  54. package/dist/handlers/self-update.js.map +1 -1
  55. package/dist/handlers/stop.js +7 -0
  56. package/dist/handlers/stop.js.map +1 -1
  57. package/dist/handlers/telegram-webhook.js +23 -0
  58. package/dist/handlers/telegram-webhook.js.map +1 -1
  59. package/dist/handlers/update-config.js +8 -2
  60. package/dist/handlers/update-config.js.map +1 -1
  61. package/dist/heartbeat.d.ts +7 -0
  62. package/dist/heartbeat.js +15 -65
  63. package/dist/heartbeat.js.map +1 -1
  64. package/dist/index.d.ts +1 -1
  65. package/dist/index.js +140 -29
  66. package/dist/index.js.map +1 -1
  67. package/dist/mcp-client.js.map +1 -1
  68. package/dist/memory-mcp-server.d.ts +8 -0
  69. package/dist/memory-mcp-server.js +291 -0
  70. package/dist/memory-mcp-server.js.map +1 -0
  71. package/dist/platform/linux.js +7 -3
  72. package/dist/platform/linux.js.map +1 -1
  73. package/dist/platform/macos.js +4 -2
  74. package/dist/platform/macos.js.map +1 -1
  75. package/dist/platform/windows.js +4 -2
  76. package/dist/platform/windows.js.map +1 -1
  77. package/dist/providers/claude-code/channel-server.d.ts +60 -0
  78. package/dist/providers/claude-code/channel-server.js +155 -0
  79. package/dist/providers/claude-code/channel-server.js.map +1 -0
  80. package/dist/providers/claude-code/index.d.ts +68 -0
  81. package/dist/providers/claude-code/index.js +276 -0
  82. package/dist/providers/claude-code/index.js.map +1 -0
  83. package/dist/providers/claude-code/login-flow.d.ts +26 -0
  84. package/dist/providers/claude-code/login-flow.js +129 -0
  85. package/dist/providers/claude-code/login-flow.js.map +1 -0
  86. package/dist/providers/claude-code/settings-writer.d.ts +29 -0
  87. package/dist/providers/claude-code/settings-writer.js +95 -0
  88. package/dist/providers/claude-code/settings-writer.js.map +1 -0
  89. package/dist/providers/claude-code/socket-bridge.d.ts +88 -0
  90. package/dist/providers/claude-code/socket-bridge.js +302 -0
  91. package/dist/providers/claude-code/socket-bridge.js.map +1 -0
  92. package/dist/providers/claude-code/spawn-claude.d.ts +44 -0
  93. package/dist/providers/claude-code/spawn-claude.js +108 -0
  94. package/dist/providers/claude-code/spawn-claude.js.map +1 -0
  95. package/dist/providers/index.d.ts +4 -2
  96. package/dist/providers/index.js +12 -0
  97. package/dist/providers/index.js.map +1 -1
  98. package/dist/providers/mock/index.js.map +1 -1
  99. package/dist/providers/openclaw/device-identity.js +2 -2
  100. package/dist/providers/openclaw/device-identity.js.map +1 -1
  101. package/dist/providers/openclaw/gateway-adapter.js +19 -8
  102. package/dist/providers/openclaw/gateway-adapter.js.map +1 -1
  103. package/dist/providers/openclaw/gateway-client.js +9 -3
  104. package/dist/providers/openclaw/gateway-client.js.map +1 -1
  105. package/dist/providers/openclaw/index.js +14 -3
  106. package/dist/providers/openclaw/index.js.map +1 -1
  107. package/dist/types.d.ts +1 -1
  108. package/dist/utils/agent-controller-bin.d.ts +8 -0
  109. package/dist/utils/agent-controller-bin.js +58 -0
  110. package/dist/utils/agent-controller-bin.js.map +1 -0
  111. package/dist/utils/apply-config.d.ts +28 -0
  112. package/dist/utils/apply-config.js +234 -4
  113. package/dist/utils/apply-config.js.map +1 -1
  114. package/dist/utils/claude-env.js +11 -5
  115. package/dist/utils/claude-env.js.map +1 -1
  116. package/dist/utils/config-merge-paths.d.ts +21 -0
  117. package/dist/utils/config-merge-paths.js +27 -0
  118. package/dist/utils/config-merge-paths.js.map +1 -0
  119. package/dist/utils/env.js +2 -1
  120. package/dist/utils/env.js.map +1 -1
  121. package/dist/utils/knowledge-graph.d.ts +66 -0
  122. package/dist/utils/knowledge-graph.js +163 -0
  123. package/dist/utils/knowledge-graph.js.map +1 -0
  124. package/dist/utils/release-channel.js +2 -4
  125. package/dist/utils/release-channel.js.map +1 -1
  126. package/dist/utils/write-workspace-files.d.ts +15 -0
  127. package/dist/utils/write-workspace-files.js +48 -0
  128. package/dist/utils/write-workspace-files.js.map +1 -0
  129. package/dist/workspace.js +4 -5
  130. package/dist/workspace.js.map +1 -1
  131. package/package.json +24 -3
@@ -0,0 +1,88 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { ChannelReply, ChannelMessageMeta, ChannelReplyMeta } from './channel-server.js';
3
+ /**
4
+ * Unix-domain-socket bridge between the main agent-controller process and the
5
+ * channel-server worker that holds Claude Code's stdio MCP channel.
6
+ *
7
+ * Protocol: newline-delimited JSON. Ops:
8
+ * { op: "hello", pid } — worker → main
9
+ * { op: "reply", content, meta } — worker → main (Claude reply tool)
10
+ * { op: "edit", content, meta } — worker → main (Claude edit_message tool)
11
+ * { op: "push", content, meta } — main → worker (inbound chat msg)
12
+ *
13
+ * Liberal parsing: malformed lines are logged + dropped (never crash the link).
14
+ */
15
+ export declare const DEFAULT_SOCKET_PATH: string;
16
+ export type SocketOp = {
17
+ op: 'hello';
18
+ pid: number;
19
+ } | {
20
+ op: 'reply';
21
+ content: string;
22
+ meta: ChannelReplyMeta;
23
+ } | {
24
+ op: 'edit';
25
+ content: string;
26
+ meta: ChannelReplyMeta;
27
+ } | {
28
+ op: 'push';
29
+ content: string;
30
+ meta: ChannelMessageMeta;
31
+ };
32
+ export interface ChannelBridgeServerEvents {
33
+ connect: [pid: number | null];
34
+ reply: [content: string, meta: ChannelReplyMeta, tool: 'reply' | 'edit_message'];
35
+ close: [];
36
+ error: [err: Error];
37
+ }
38
+ /**
39
+ * Server side — lives in the main agent-controller process.
40
+ *
41
+ * Accepts exactly one worker connection (extras are rejected + closed). Emits
42
+ * reply/edit ops; callers invoke `push(content, meta)` to emit an inbound
43
+ * chat message to the worker.
44
+ */
45
+ export declare class ChannelBridgeServer extends EventEmitter {
46
+ private readonly opts;
47
+ private server;
48
+ private active;
49
+ private buf;
50
+ constructor(opts?: {
51
+ socketPath?: string;
52
+ });
53
+ get socketPath(): string;
54
+ listen(): Promise<void>;
55
+ private handleConnection;
56
+ private ingest;
57
+ private dispatch;
58
+ /** Push an inbound chat message to the worker (→ Claude MCP notification). */
59
+ push(content: string, meta: ChannelMessageMeta): void;
60
+ private write;
61
+ close(): Promise<void>;
62
+ isConnected(): boolean;
63
+ }
64
+ /**
65
+ * Client side — lives in the channel-server worker subprocess.
66
+ *
67
+ * Connects to the bridge socket with retry/backoff (up to 30s). Parses
68
+ * incoming `push` ops and forwards outgoing `reply`/`edit` ops.
69
+ */
70
+ export declare class ChannelBridgeClient extends EventEmitter {
71
+ private readonly opts;
72
+ private sock;
73
+ private buf;
74
+ private closed;
75
+ constructor(opts?: {
76
+ socketPath?: string;
77
+ maxWaitMs?: number;
78
+ });
79
+ get socketPath(): string;
80
+ connect(): Promise<void>;
81
+ private connectOnce;
82
+ sendHello(pid: number): void;
83
+ sendReply(content: string, meta: ChannelReplyMeta, tool: 'reply' | 'edit_message'): void;
84
+ private ingest;
85
+ private write;
86
+ close(): void;
87
+ }
88
+ export type { ChannelReply, ChannelMessageMeta, ChannelReplyMeta };
@@ -0,0 +1,302 @@
1
+ import net from 'node:net';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+ import { EventEmitter } from 'node:events';
6
+ import { logCollector } from '../../connection.js';
7
+ import { toErrorMessage } from '../../utils/response.js';
8
+ /**
9
+ * Unix-domain-socket bridge between the main agent-controller process and the
10
+ * channel-server worker that holds Claude Code's stdio MCP channel.
11
+ *
12
+ * Protocol: newline-delimited JSON. Ops:
13
+ * { op: "hello", pid } — worker → main
14
+ * { op: "reply", content, meta } — worker → main (Claude reply tool)
15
+ * { op: "edit", content, meta } — worker → main (Claude edit_message tool)
16
+ * { op: "push", content, meta } — main → worker (inbound chat msg)
17
+ *
18
+ * Liberal parsing: malformed lines are logged + dropped (never crash the link).
19
+ */
20
+ export const DEFAULT_SOCKET_PATH = path.join(os.homedir(), '.openclaw', 'claude-channel.sock');
21
+ /**
22
+ * Server side — lives in the main agent-controller process.
23
+ *
24
+ * Accepts exactly one worker connection (extras are rejected + closed). Emits
25
+ * reply/edit ops; callers invoke `push(content, meta)` to emit an inbound
26
+ * chat message to the worker.
27
+ */
28
+ export class ChannelBridgeServer extends EventEmitter {
29
+ opts;
30
+ server = null;
31
+ active = null;
32
+ buf = '';
33
+ constructor(opts = {}) {
34
+ super();
35
+ this.opts = opts;
36
+ // Default no-op 'error' listener so re-emitting a server error never turns
37
+ // into an unhandled-exception process crash if no external listener is
38
+ // registered. External callers can still attach their own listener.
39
+ this.on('error', () => {
40
+ /* no-op */
41
+ });
42
+ }
43
+ get socketPath() {
44
+ return this.opts.socketPath ?? DEFAULT_SOCKET_PATH;
45
+ }
46
+ async listen() {
47
+ const p = this.socketPath;
48
+ await fs.promises.mkdir(path.dirname(p), { recursive: true });
49
+ // Best-effort: remove stale socket file from a previous crash.
50
+ try {
51
+ await fs.promises.unlink(p);
52
+ }
53
+ catch {
54
+ /* not present */
55
+ }
56
+ return new Promise((resolve, reject) => {
57
+ const srv = net.createServer((sock) => this.handleConnection(sock));
58
+ // One-shot rejector so listen() failures surface to the awaiter; detach
59
+ // after successful bind so it doesn't leak into runtime errors.
60
+ const onListenError = (err) => {
61
+ srv.removeListener('error', onRuntimeError);
62
+ reject(err);
63
+ };
64
+ const onRuntimeError = (err) => {
65
+ logCollector?.push('channel_bridge_error', 'error', `bridge server error: ${err.message}`);
66
+ this.emit('error', err);
67
+ };
68
+ srv.once('error', onListenError);
69
+ srv.on('error', onRuntimeError);
70
+ srv.listen(p, () => {
71
+ srv.removeListener('error', onListenError);
72
+ this.server = srv;
73
+ logCollector?.push('channel_bridge_listening', 'info', `channel bridge on ${p}`);
74
+ resolve();
75
+ });
76
+ });
77
+ }
78
+ handleConnection(sock) {
79
+ if (this.active) {
80
+ // Reject extras — we expect exactly one worker.
81
+ logCollector?.push('channel_bridge_reject_extra', 'warn', 'extra worker connection rejected — one worker already active');
82
+ try {
83
+ sock.end();
84
+ }
85
+ catch {
86
+ /* ignore */
87
+ }
88
+ return;
89
+ }
90
+ this.active = sock;
91
+ sock.setEncoding('utf8');
92
+ sock.on('data', (chunk) => this.ingest(String(chunk)));
93
+ sock.on('close', () => {
94
+ this.active = null;
95
+ this.buf = '';
96
+ logCollector?.push('channel_bridge_closed', 'info', 'worker connection closed');
97
+ this.emit('close');
98
+ });
99
+ sock.on('error', (err) => {
100
+ logCollector?.push('channel_bridge_sock_error', 'warn', `worker socket error: ${err.message}`);
101
+ });
102
+ }
103
+ ingest(chunk) {
104
+ this.buf += chunk;
105
+ let idx;
106
+ while ((idx = this.buf.indexOf('\n')) >= 0) {
107
+ const line = this.buf.slice(0, idx).trim();
108
+ this.buf = this.buf.slice(idx + 1);
109
+ if (!line)
110
+ continue;
111
+ let msg = null;
112
+ try {
113
+ msg = JSON.parse(line);
114
+ }
115
+ catch {
116
+ logCollector?.push('channel_bridge_bad_line', 'warn', 'dropped malformed bridge line');
117
+ continue;
118
+ }
119
+ this.dispatch(msg);
120
+ }
121
+ }
122
+ dispatch(msg) {
123
+ if (!msg || typeof msg !== 'object' || !msg.op)
124
+ return;
125
+ switch (msg.op) {
126
+ case 'hello': {
127
+ const pid = typeof msg.pid === 'number' ? msg.pid : null;
128
+ logCollector?.push('channel_bridge_hello', 'info', `worker hello pid=${pid ?? 'unknown'}`);
129
+ this.emit('connect', pid);
130
+ break;
131
+ }
132
+ case 'reply': {
133
+ const m = msg;
134
+ const content = typeof m.content === 'string' ? m.content : '';
135
+ const meta = (m.meta ?? {});
136
+ this.emit('reply', content, meta, 'reply');
137
+ break;
138
+ }
139
+ case 'edit': {
140
+ const m = msg;
141
+ const content = typeof m.content === 'string' ? m.content : '';
142
+ const meta = (m.meta ?? {});
143
+ this.emit('reply', content, meta, 'edit_message');
144
+ break;
145
+ }
146
+ default:
147
+ logCollector?.push('channel_bridge_unknown_op', 'warn', `unknown op: ${String(msg.op)}`);
148
+ }
149
+ }
150
+ /** Push an inbound chat message to the worker (→ Claude MCP notification). */
151
+ push(content, meta) {
152
+ this.write({ op: 'push', content, meta });
153
+ }
154
+ write(op) {
155
+ if (!this.active) {
156
+ logCollector?.push('channel_bridge_no_worker', 'warn', `dropped op ${op.op} — no worker`);
157
+ return;
158
+ }
159
+ try {
160
+ this.active.write(JSON.stringify(op) + '\n');
161
+ }
162
+ catch (err) {
163
+ logCollector?.push('channel_bridge_write_error', 'warn', `write ${op.op} failed: ${toErrorMessage(err)}`);
164
+ }
165
+ }
166
+ async close() {
167
+ try {
168
+ this.active?.end();
169
+ }
170
+ catch {
171
+ /* ignore */
172
+ }
173
+ this.active = null;
174
+ if (!this.server)
175
+ return;
176
+ const srv = this.server;
177
+ this.server = null;
178
+ await new Promise((resolve) => srv.close(() => resolve()));
179
+ try {
180
+ await fs.promises.unlink(this.socketPath);
181
+ }
182
+ catch {
183
+ /* ignore */
184
+ }
185
+ }
186
+ isConnected() {
187
+ return !!this.active;
188
+ }
189
+ }
190
+ /**
191
+ * Client side — lives in the channel-server worker subprocess.
192
+ *
193
+ * Connects to the bridge socket with retry/backoff (up to 30s). Parses
194
+ * incoming `push` ops and forwards outgoing `reply`/`edit` ops.
195
+ */
196
+ export class ChannelBridgeClient extends EventEmitter {
197
+ opts;
198
+ sock = null;
199
+ buf = '';
200
+ closed = false;
201
+ constructor(opts = {}) {
202
+ super();
203
+ this.opts = opts;
204
+ }
205
+ get socketPath() {
206
+ return this.opts.socketPath ?? DEFAULT_SOCKET_PATH;
207
+ }
208
+ async connect() {
209
+ const maxWait = this.opts.maxWaitMs ?? 30_000;
210
+ const started = Date.now();
211
+ let attempt = 0;
212
+ // Retry with capped exponential backoff while the main process comes up.
213
+ while (true) {
214
+ try {
215
+ await this.connectOnce();
216
+ return;
217
+ }
218
+ catch (err) {
219
+ if (Date.now() - started > maxWait) {
220
+ throw err instanceof Error ? err : new Error(String(err));
221
+ }
222
+ attempt += 1;
223
+ const delay = Math.min(2000, 100 * 2 ** Math.min(attempt, 6));
224
+ await new Promise((r) => setTimeout(r, delay));
225
+ }
226
+ }
227
+ }
228
+ connectOnce() {
229
+ return new Promise((resolve, reject) => {
230
+ const s = net.createConnection({ path: this.socketPath });
231
+ const onError = (err) => {
232
+ s.removeAllListeners();
233
+ reject(err);
234
+ };
235
+ s.once('error', onError);
236
+ s.once('connect', () => {
237
+ s.removeListener('error', onError);
238
+ s.setEncoding('utf8');
239
+ this.sock = s;
240
+ s.on('data', (chunk) => this.ingest(String(chunk)));
241
+ s.on('close', () => {
242
+ this.sock = null;
243
+ this.buf = '';
244
+ if (!this.closed)
245
+ this.emit('close');
246
+ });
247
+ s.on('error', (err) => this.emit('error', err));
248
+ resolve();
249
+ });
250
+ });
251
+ }
252
+ sendHello(pid) {
253
+ this.write({ op: 'hello', pid });
254
+ }
255
+ sendReply(content, meta, tool) {
256
+ this.write({ op: tool === 'edit_message' ? 'edit' : 'reply', content, meta });
257
+ }
258
+ ingest(chunk) {
259
+ this.buf += chunk;
260
+ let idx;
261
+ while ((idx = this.buf.indexOf('\n')) >= 0) {
262
+ const line = this.buf.slice(0, idx).trim();
263
+ this.buf = this.buf.slice(idx + 1);
264
+ if (!line)
265
+ continue;
266
+ let msg = null;
267
+ try {
268
+ msg = JSON.parse(line);
269
+ }
270
+ catch {
271
+ continue;
272
+ }
273
+ if (msg && msg.op === 'push') {
274
+ const m = msg;
275
+ const content = typeof m.content === 'string' ? m.content : '';
276
+ const meta = (m.meta ?? {});
277
+ this.emit('push', content, meta);
278
+ }
279
+ }
280
+ }
281
+ write(op) {
282
+ if (!this.sock)
283
+ return;
284
+ try {
285
+ this.sock.write(JSON.stringify(op) + '\n');
286
+ }
287
+ catch {
288
+ /* ignore — socket will emit close/error */
289
+ }
290
+ }
291
+ close() {
292
+ this.closed = true;
293
+ try {
294
+ this.sock?.end();
295
+ }
296
+ catch {
297
+ /* ignore */
298
+ }
299
+ this.sock = null;
300
+ }
301
+ }
302
+ //# sourceMappingURL=socket-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket-bridge.js","sourceRoot":"","sources":["../../../src/providers/claude-code/socket-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { spawn, type ChildProcess } from 'node:child_process';
2
+ import { EventEmitter } from 'node:events';
3
+ export interface SpawnClaudeDeps {
4
+ /** Working directory for the claude process (workspace). */
5
+ workspaceDir: string;
6
+ /** Channels plugin flag argument (defaults to `plugin:agent-controller`). */
7
+ channelsFlag?: string;
8
+ /** Extra CLI flags to append. */
9
+ extraArgs?: string[];
10
+ /** Environment variables to merge on top of process.env. */
11
+ env?: Record<string, string | undefined>;
12
+ /** Allow `--dangerously-load-development-channels` (default true). */
13
+ danglyDev?: boolean;
14
+ /** Override spawn (tests). */
15
+ spawnFn?: typeof spawn;
16
+ /** Max retries on crash (default 5). */
17
+ maxRetries?: number;
18
+ }
19
+ /**
20
+ * Supervise a `claude` subprocess. Emits:
21
+ * - `stderr` (Buffer)
22
+ * - `stdout` (Buffer)
23
+ * - `spawn` (ChildProcess)
24
+ * - `exit` (code|null, signal|null)
25
+ * - `gaveup` — too many crashes, no more restarts.
26
+ *
27
+ * Restart on crash with capped exponential backoff.
28
+ */
29
+ export declare class ClaudeProcess extends EventEmitter {
30
+ private readonly deps;
31
+ private child;
32
+ private retries;
33
+ private shuttingDown;
34
+ private lastSpawnAt;
35
+ constructor(deps: SpawnClaudeDeps);
36
+ start(): void;
37
+ private spawnOnce;
38
+ private buildArgs;
39
+ /** Send SIGINT to interrupt the current turn. */
40
+ interrupt(): void;
41
+ stop(): void;
42
+ isRunning(): boolean;
43
+ getChild(): ChildProcess | null;
44
+ }
@@ -0,0 +1,108 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { EventEmitter } from 'node:events';
3
+ import { logCollector } from '../../connection.js';
4
+ /**
5
+ * Supervise a `claude` subprocess. Emits:
6
+ * - `stderr` (Buffer)
7
+ * - `stdout` (Buffer)
8
+ * - `spawn` (ChildProcess)
9
+ * - `exit` (code|null, signal|null)
10
+ * - `gaveup` — too many crashes, no more restarts.
11
+ *
12
+ * Restart on crash with capped exponential backoff.
13
+ */
14
+ export class ClaudeProcess extends EventEmitter {
15
+ deps;
16
+ child = null;
17
+ retries = 0;
18
+ shuttingDown = false;
19
+ lastSpawnAt = 0;
20
+ constructor(deps) {
21
+ super();
22
+ this.deps = deps;
23
+ }
24
+ start() {
25
+ if (this.child)
26
+ return;
27
+ this.shuttingDown = false;
28
+ this.spawnOnce();
29
+ }
30
+ spawnOnce() {
31
+ const spawnFn = this.deps.spawnFn ?? spawn;
32
+ const args = this.buildArgs();
33
+ this.lastSpawnAt = Date.now();
34
+ const child = spawnFn('claude', args, {
35
+ cwd: this.deps.workspaceDir,
36
+ env: { ...process.env, ...(this.deps.env ?? {}) },
37
+ stdio: ['pipe', 'pipe', 'pipe'],
38
+ });
39
+ this.child = child;
40
+ child.stdout?.on('data', (data) => this.emit('stdout', data));
41
+ child.stderr?.on('data', (data) => {
42
+ this.emit('stderr', data);
43
+ logCollector?.push('claude_stderr', 'debug', data.toString().slice(0, 500));
44
+ });
45
+ child.on('error', (err) => {
46
+ logCollector?.push('claude_spawn_error', 'error', err.message);
47
+ this.emit('error', err);
48
+ });
49
+ child.on('exit', (code, signal) => {
50
+ this.emit('exit', code, signal);
51
+ this.child = null;
52
+ if (this.shuttingDown)
53
+ return;
54
+ // Reset retries on a healthy long run
55
+ if (Date.now() - this.lastSpawnAt > 60_000)
56
+ this.retries = 0;
57
+ const maxRetries = this.deps.maxRetries ?? 5;
58
+ // Semantics: maxRetries is the number of RESTART attempts allowed.
59
+ // Increment first, then check — so maxRetries=5 yields exactly 5 restarts
60
+ // (retry counts 1..5) before giving up on the 6th crash.
61
+ this.retries += 1;
62
+ if (this.retries > maxRetries) {
63
+ logCollector?.push('claude_giveup', 'error', `claude crashed too many times (${this.retries - 1}/${maxRetries}), giving up`);
64
+ this.emit('gaveup');
65
+ return;
66
+ }
67
+ const backoff = Math.min(30_000, 500 * 2 ** (this.retries - 1));
68
+ logCollector?.push('claude_restart_scheduled', 'warn', `claude exited code=${code ?? 'null'} sig=${signal ?? 'null'}; retry ${this.retries}/${maxRetries} in ${backoff}ms`);
69
+ setTimeout(() => {
70
+ if (!this.shuttingDown)
71
+ this.spawnOnce();
72
+ }, backoff).unref();
73
+ });
74
+ this.emit('spawn', child);
75
+ logCollector?.push('claude_spawned', 'info', `claude spawned (pid=${child.pid})`);
76
+ }
77
+ buildArgs() {
78
+ const args = ['--channels', this.deps.channelsFlag ?? 'plugin:agent-controller'];
79
+ if (this.deps.danglyDev !== false)
80
+ args.push('--dangerously-load-development-channels');
81
+ if (this.deps.extraArgs)
82
+ args.push(...this.deps.extraArgs);
83
+ return args;
84
+ }
85
+ /** Send SIGINT to interrupt the current turn. */
86
+ interrupt() {
87
+ this.child?.kill('SIGINT');
88
+ }
89
+ stop() {
90
+ this.shuttingDown = true;
91
+ if (this.child) {
92
+ try {
93
+ this.child.kill('SIGTERM');
94
+ }
95
+ catch {
96
+ /* ignore */
97
+ }
98
+ }
99
+ this.child = null;
100
+ }
101
+ isRunning() {
102
+ return !!this.child && this.child.exitCode === null;
103
+ }
104
+ getChild() {
105
+ return this.child;
106
+ }
107
+ }
108
+ //# sourceMappingURL=spawn-claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn-claude.js","sourceRoot":"","sources":["../../../src/providers/claude-code/spawn-claude.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAmBnD;;;;;;;;;GASG;AACH,MAAM,OAAO,aAAc,SAAQ,YAAY;IAMhB;IALrB,KAAK,GAAwB,IAAI,CAAC;IAClC,OAAO,GAAG,CAAC,CAAC;IACZ,YAAY,GAAG,KAAK,CAAC;IACrB,WAAW,GAAG,CAAC,CAAC;IAExB,YAA6B,IAAqB;QAChD,KAAK,EAAE,CAAC;QADmB,SAAI,GAAJ,IAAI,CAAiB;IAElD,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAEO,SAAS;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE;YACpC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY;YAC3B,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,EAAuB;YACtE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QAEnB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9D,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAChC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC1B,YAAY,EAAE,IAAI,CAAC,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC9E,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,YAAY,EAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;YAC/D,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;YAChC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,IAAI,IAAI,CAAC,YAAY;gBAAE,OAAO;YAC9B,sCAAsC;YACtC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,GAAG,MAAM;gBAAE,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;YAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;YAC7C,mEAAmE;YACnE,0EAA0E;YAC1E,yDAAyD;YACzD,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;YAClB,IAAI,IAAI,CAAC,OAAO,GAAG,UAAU,EAAE,CAAC;gBAC9B,YAAY,EAAE,IAAI,CAChB,eAAe,EACf,OAAO,EACP,kCAAkC,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,UAAU,cAAc,CAC/E,CAAC;gBACF,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACpB,OAAO;YACT,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;YAChE,YAAY,EAAE,IAAI,CAChB,0BAA0B,EAC1B,MAAM,EACN,sBAAsB,IAAI,IAAI,MAAM,QAAQ,MAAM,IAAI,MAAM,WAAW,IAAI,CAAC,OAAO,IAAI,UAAU,OAAO,OAAO,IAAI,CACpH,CAAC;YACF,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,CAAC,IAAI,CAAC,YAAY;oBAAE,IAAI,CAAC,SAAS,EAAE,CAAC;YAC3C,CAAC,EAAE,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC1B,YAAY,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,EAAE,uBAAuB,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;IACpF,CAAC;IAEO,SAAS;QACf,MAAM,IAAI,GAAa,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,yBAAyB,CAAC,CAAC;QAC3F,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,KAAK,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;QACxF,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,iDAAiD;IACjD,SAAS;QACP,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI;QACF,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC;gBACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;QACH,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,SAAS;QACP,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC;IACtD,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF"}
@@ -1,11 +1,13 @@
1
1
  import type { IAgentProvider } from './types.js';
2
2
  export type { IAgentProvider, AgentHealthStatus, SendMessageParams } from './types.js';
3
- export type { ChatSession, ChatMessage, ChatAttachment, ChatContentBlock, IChatProvider } from './chat-types.js';
3
+ export type { ChatSession, ChatMessage, ChatAttachment, ChatContentBlock, IChatProvider, } from './chat-types.js';
4
4
  export { OpenclawProvider } from './openclaw/index.js';
5
5
  export { MockProvider } from './mock/index.js';
6
6
  export type { MockAction } from './mock/index.js';
7
+ export { ClaudeCodeProvider } from './claude-code/index.js';
8
+ export type { ClaudeCodeProviderConfig } from './claude-code/index.js';
7
9
  export declare function configureProvider(provider: IAgentProvider): void;
8
10
  export declare function getProvider(): IAgentProvider | null;
9
11
  /** For testing only — reset the global provider */
10
12
  export declare function resetProvider(): void;
11
- export declare function createProvider(type: string, config: Record<string, string>): IAgentProvider;
13
+ export declare function createProvider(type: string, config: Record<string, string | undefined>): IAgentProvider;
@@ -1,7 +1,9 @@
1
1
  import { OpenclawProvider } from './openclaw/index.js';
2
2
  import { MockProvider } from './mock/index.js';
3
+ import { ClaudeCodeProvider } from './claude-code/index.js';
3
4
  export { OpenclawProvider } from './openclaw/index.js';
4
5
  export { MockProvider } from './mock/index.js';
6
+ export { ClaudeCodeProvider } from './claude-code/index.js';
5
7
  let _provider = null;
6
8
  export function configureProvider(provider) {
7
9
  _provider = provider;
@@ -19,6 +21,16 @@ export function createProvider(type, config) {
19
21
  return new OpenclawProvider(config.wsUrl ?? 'ws://localhost:18789', config.wsToken ?? '');
20
22
  case 'mock':
21
23
  return new MockProvider();
24
+ case 'claude-code':
25
+ return new ClaudeCodeProvider({
26
+ workspaceDir: config.workspaceDir ?? '/home/ubuntu/.claude/workspace',
27
+ anthropicApiKey: config.anthropicApiKey,
28
+ anthropicAuthToken: config.anthropicAuthToken,
29
+ claudeCodeOauthToken: config.claudeCodeOauthToken,
30
+ backendUrl: config.backendUrl,
31
+ agentToken: config.agentToken,
32
+ claudeMdContent: config.claudeMdContent,
33
+ });
22
34
  default:
23
35
  throw new Error(`Unknown provider type: ${type}`);
24
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAI/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,IAAI,SAAS,GAA0B,IAAI,CAAC;AAE5C,MAAM,UAAU,iBAAiB,CAAC,QAAwB;IACxD,SAAS,GAAG,QAAQ,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,aAAa;IAC3B,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,MAA8B;IACzE,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,UAAU;YACb,OAAO,IAAI,gBAAgB,CACzB,MAAM,CAAC,KAAK,IAAI,sBAAsB,EACtC,MAAM,CAAC,OAAO,IAAI,EAAE,CACrB,CAAC;QACJ,KAAK,MAAM;YACT,OAAO,IAAI,YAAY,EAAE,CAAC;QAC5B;YACE,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAU5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAG5D,IAAI,SAAS,GAA0B,IAAI,CAAC;AAE5C,MAAM,UAAU,iBAAiB,CAAC,QAAwB;IACxD,SAAS,GAAG,QAAQ,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,aAAa;IAC3B,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,MAA0C;IAE1C,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,UAAU;YACb,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,KAAK,IAAI,sBAAsB,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QAC5F,KAAK,MAAM;YACT,OAAO,IAAI,YAAY,EAAE,CAAC;QAC5B,KAAK,aAAa;YAChB,OAAO,IAAI,kBAAkB,CAAC;gBAC5B,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,gCAAgC;gBACrE,eAAe,EAAE,MAAM,CAAC,eAAe;gBACvC,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;gBAC7C,oBAAoB,EAAE,MAAM,CAAC,oBAAoB;gBACjD,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,eAAe,EAAE,MAAM,CAAC,eAAe;aACxC,CAAC,CAAC;QACL;YACE,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/mock/index.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,MAAM,OAAO,YAAY;IACd,IAAI,GAAG,MAAM,CAAC;IACf,UAAU,GAAG,KAAK,CAAC;IAE3B,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IACzB,CAAC;IAED,UAAU;QACR,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC1B,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,MAAyB;QACzC,MAAM,YAAY,GAAG,gCAAgC,CAAC;QACtD,MAAM,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,WAAmB,EAAE,MAAe;QACnD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,WAAmB,EAAE,MAAe;QAC9C,QAAQ;IACV,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,OAAO;QACX,QAAQ;IACV,CAAC;CAEF"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/mock/index.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,MAAM,OAAO,YAAY;IACd,IAAI,GAAG,MAAM,CAAC;IACf,UAAU,GAAG,KAAK,CAAC;IAE3B,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IACzB,CAAC;IAED,UAAU;QACR,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC1B,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,MAAyB;QACzC,MAAM,YAAY,GAAG,gCAAgC,CAAC;QACtD,MAAM,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,WAAmB,EAAE,MAAe;QACnD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,WAAmB,EAAE,MAAe;QAC9C,QAAQ;IACV,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,OAAO;QACX,QAAQ;IACV,CAAC;CACF"}
@@ -1,7 +1,7 @@
1
1
  import crypto from 'node:crypto';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
- import os from 'node:os';
4
+ import { config } from '../../config.js';
5
5
  const ED25519_SPKI_PREFIX = Buffer.from('302a300506032b6570032100', 'hex');
6
6
  function base64UrlEncode(buf) {
7
7
  return buf.toString('base64').replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/g, '');
@@ -43,7 +43,7 @@ export function buildDeviceAuthPayloadV3(params) {
43
43
  ].join('|');
44
44
  }
45
45
  function getIdentityPath() {
46
- const stateDir = process.env.OPENCLAW_STATE_DIR?.trim() || path.join(os.homedir(), '.openclaw');
46
+ const stateDir = config.stateDir;
47
47
  return path.join(stateDir, 'identity', 'device.json');
48
48
  }
49
49
  export function loadOrCreateDeviceIdentity() {