@getworkle/cli 0.2.13 → 0.3.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.
Files changed (3) hide show
  1. package/dist/cli.js +216 -1543
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +7 -24
package/dist/cli.js CHANGED
@@ -1209,8 +1209,8 @@ var require_command = __commonJS({
1209
1209
  "use strict";
1210
1210
  var EventEmitter = __require("events").EventEmitter;
1211
1211
  var childProcess = __require("child_process");
1212
- var path20 = __require("path");
1213
- var fs17 = __require("fs");
1212
+ var path11 = __require("path");
1213
+ var fs8 = __require("fs");
1214
1214
  var process2 = __require("process");
1215
1215
  var { Argument: Argument2, humanReadableArgName } = require_argument();
1216
1216
  var { CommanderError: CommanderError2 } = require_error();
@@ -2204,7 +2204,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2204
2204
  * @param {string} subcommandName
2205
2205
  */
2206
2206
  _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
2207
- if (fs17.existsSync(executableFile)) return;
2207
+ if (fs8.existsSync(executableFile)) return;
2208
2208
  const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
2209
2209
  const executableMissing = `'${executableFile}' does not exist
2210
2210
  - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
@@ -2222,11 +2222,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
2222
2222
  let launchWithNode = false;
2223
2223
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
2224
2224
  function findFile(baseDir, baseName) {
2225
- const localBin = path20.resolve(baseDir, baseName);
2226
- if (fs17.existsSync(localBin)) return localBin;
2227
- if (sourceExt.includes(path20.extname(baseName))) return void 0;
2225
+ const localBin = path11.resolve(baseDir, baseName);
2226
+ if (fs8.existsSync(localBin)) return localBin;
2227
+ if (sourceExt.includes(path11.extname(baseName))) return void 0;
2228
2228
  const foundExt = sourceExt.find(
2229
- (ext) => fs17.existsSync(`${localBin}${ext}`)
2229
+ (ext) => fs8.existsSync(`${localBin}${ext}`)
2230
2230
  );
2231
2231
  if (foundExt) return `${localBin}${foundExt}`;
2232
2232
  return void 0;
@@ -2238,21 +2238,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
2238
2238
  if (this._scriptPath) {
2239
2239
  let resolvedScriptPath;
2240
2240
  try {
2241
- resolvedScriptPath = fs17.realpathSync(this._scriptPath);
2241
+ resolvedScriptPath = fs8.realpathSync(this._scriptPath);
2242
2242
  } catch {
2243
2243
  resolvedScriptPath = this._scriptPath;
2244
2244
  }
2245
- executableDir = path20.resolve(
2246
- path20.dirname(resolvedScriptPath),
2245
+ executableDir = path11.resolve(
2246
+ path11.dirname(resolvedScriptPath),
2247
2247
  executableDir
2248
2248
  );
2249
2249
  }
2250
2250
  if (executableDir) {
2251
2251
  let localFile = findFile(executableDir, executableFile);
2252
2252
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
2253
- const legacyName = path20.basename(
2253
+ const legacyName = path11.basename(
2254
2254
  this._scriptPath,
2255
- path20.extname(this._scriptPath)
2255
+ path11.extname(this._scriptPath)
2256
2256
  );
2257
2257
  if (legacyName !== this._name) {
2258
2258
  localFile = findFile(
@@ -2263,7 +2263,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2263
2263
  }
2264
2264
  executableFile = localFile || executableFile;
2265
2265
  }
2266
- launchWithNode = sourceExt.includes(path20.extname(executableFile));
2266
+ launchWithNode = sourceExt.includes(path11.extname(executableFile));
2267
2267
  let proc;
2268
2268
  if (process2.platform !== "win32") {
2269
2269
  if (launchWithNode) {
@@ -3178,7 +3178,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3178
3178
  * @return {Command}
3179
3179
  */
3180
3180
  nameFromFilename(filename) {
3181
- this._name = path20.basename(filename, path20.extname(filename));
3181
+ this._name = path11.basename(filename, path11.extname(filename));
3182
3182
  return this;
3183
3183
  }
3184
3184
  /**
@@ -3192,9 +3192,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3192
3192
  * @param {string} [path]
3193
3193
  * @return {(string|null|Command)}
3194
3194
  */
3195
- executableDir(path21) {
3196
- if (path21 === void 0) return this._executableDir;
3197
- this._executableDir = path21;
3195
+ executableDir(path12) {
3196
+ if (path12 === void 0) return this._executableDir;
3197
+ this._executableDir = path12;
3198
3198
  return this;
3199
3199
  }
3200
3200
  /**
@@ -4285,7 +4285,7 @@ var require_background_scheduled_task = __commonJS({
4285
4285
  "../../node_modules/node-cron/src/background-scheduled-task/index.js"(exports, module) {
4286
4286
  "use strict";
4287
4287
  var EventEmitter = __require("events");
4288
- var path20 = __require("path");
4288
+ var path11 = __require("path");
4289
4289
  var { fork } = __require("child_process");
4290
4290
  var uuid3 = (init_esm_node(), __toCommonJS(esm_node_exports));
4291
4291
  var daemonPath = `${__dirname}/daemon.js`;
@@ -4320,7 +4320,7 @@ var require_background_scheduled_task = __commonJS({
4320
4320
  options.scheduled = true;
4321
4321
  this.forkProcess.send({
4322
4322
  type: "register",
4323
- path: path20.resolve(this.taskPath),
4323
+ path: path11.resolve(this.taskPath),
4324
4324
  cron: this.cronExpression,
4325
4325
  options
4326
4326
  });
@@ -6600,7 +6600,7 @@ var require_websocket = __commonJS({
6600
6600
  "use strict";
6601
6601
  var EventEmitter = __require("events");
6602
6602
  var https = __require("https");
6603
- var http3 = __require("http");
6603
+ var http2 = __require("http");
6604
6604
  var net = __require("net");
6605
6605
  var tls = __require("tls");
6606
6606
  var { randomBytes: randomBytes2, createHash: createHash2 } = __require("crypto");
@@ -7131,7 +7131,7 @@ var require_websocket = __commonJS({
7131
7131
  }
7132
7132
  const defaultPort = isSecure ? 443 : 80;
7133
7133
  const key = randomBytes2(16).toString("base64");
7134
- const request = isSecure ? https.request : http3.request;
7134
+ const request = isSecure ? https.request : http2.request;
7135
7135
  const protocolSet = /* @__PURE__ */ new Set();
7136
7136
  let perMessageDeflate;
7137
7137
  opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
@@ -7625,7 +7625,7 @@ var require_websocket_server = __commonJS({
7625
7625
  "../../node_modules/ws/lib/websocket-server.js"(exports, module) {
7626
7626
  "use strict";
7627
7627
  var EventEmitter = __require("events");
7628
- var http3 = __require("http");
7628
+ var http2 = __require("http");
7629
7629
  var { Duplex } = __require("stream");
7630
7630
  var { createHash: createHash2 } = __require("crypto");
7631
7631
  var extension = require_extension();
@@ -7696,8 +7696,8 @@ var require_websocket_server = __commonJS({
7696
7696
  );
7697
7697
  }
7698
7698
  if (options.port != null) {
7699
- this._server = http3.createServer((req, res) => {
7700
- const body = http3.STATUS_CODES[426];
7699
+ this._server = http2.createServer((req, res) => {
7700
+ const body = http2.STATUS_CODES[426];
7701
7701
  res.writeHead(426, {
7702
7702
  "Content-Length": body.length,
7703
7703
  "Content-Type": "text/plain"
@@ -7984,7 +7984,7 @@ var require_websocket_server = __commonJS({
7984
7984
  this.destroy();
7985
7985
  }
7986
7986
  function abortHandshake(socket, code, message, headers) {
7987
- message = message || http3.STATUS_CODES[code];
7987
+ message = message || http2.STATUS_CODES[code];
7988
7988
  headers = {
7989
7989
  Connection: "close",
7990
7990
  "Content-Type": "text/html",
@@ -7993,7 +7993,7 @@ var require_websocket_server = __commonJS({
7993
7993
  };
7994
7994
  socket.once("finish", socket.destroy);
7995
7995
  socket.end(
7996
- `HTTP/1.1 ${code} ${http3.STATUS_CODES[code]}\r
7996
+ `HTTP/1.1 ${code} ${http2.STATUS_CODES[code]}\r
7997
7997
  ` + Object.keys(headers).map((h) => `${h}: ${headers[h]}`).join("\r\n") + "\r\n\r\n" + message
7998
7998
  );
7999
7999
  }
@@ -8027,13 +8027,13 @@ var {
8027
8027
  } = import_index.default;
8028
8028
 
8029
8029
  // src/cli.ts
8030
- import { execSync as execSync2, spawnSync } from "child_process";
8030
+ import { execSync, spawnSync } from "child_process";
8031
8031
  import { createHash, randomBytes } from "crypto";
8032
- import { readFileSync } from "fs";
8033
- import fs16 from "fs/promises";
8034
- import http2 from "http";
8035
- import os18 from "os";
8036
- import path19 from "path";
8032
+ import { readFileSync as readFileSync2 } from "fs";
8033
+ import fs7 from "fs/promises";
8034
+ import http from "http";
8035
+ import os7 from "os";
8036
+ import path10 from "path";
8037
8037
 
8038
8038
  // src/agents/config-materializer.ts
8039
8039
  import fs2 from "fs/promises";
@@ -8151,7 +8151,7 @@ var AgentConfigMaterializer = class {
8151
8151
  */
8152
8152
  async listAgents() {
8153
8153
  const res = await fetch(
8154
- `${this.apiUrl}/api/claw/instances/${this.instanceId}/runtime/agents`,
8154
+ `${this.apiUrl}/api/local/instances/${this.instanceId}/runtime/agents`,
8155
8155
  { headers: { ...this.headers, "Content-Type": "application/json" } }
8156
8156
  );
8157
8157
  if (!res.ok) {
@@ -8165,7 +8165,7 @@ var AgentConfigMaterializer = class {
8165
8165
  */
8166
8166
  async pullAgent(agentId) {
8167
8167
  const res = await fetch(
8168
- `${this.apiUrl}/api/claw/instances/${this.instanceId}/runtime/agents/${agentId}/pull`,
8168
+ `${this.apiUrl}/api/local/instances/${this.instanceId}/runtime/agents/${agentId}/pull`,
8169
8169
  { headers: { ...this.headers, "Content-Type": "application/json" } }
8170
8170
  );
8171
8171
  if (!res.ok) {
@@ -8291,19 +8291,27 @@ var AgentConfigMaterializer = class {
8291
8291
 
8292
8292
  // src/agents/runner.ts
8293
8293
  import { query } from "@anthropic-ai/claude-agent-sdk";
8294
- function resolveClaudeCodeExecutable() {
8295
- const sdkUrl = import.meta.resolve("@anthropic-ai/claude-agent-sdk");
8296
- const sdkPath = new URL(sdkUrl).pathname;
8297
- const sdkDir = sdkPath.substring(0, sdkPath.lastIndexOf("/"));
8298
- return `${sdkDir}/cli.js`;
8294
+ import path4 from "path";
8295
+ import { fileURLToPath } from "url";
8296
+ async function resolveClaudeCodeExecutable() {
8297
+ let sdkEntryPath;
8298
+ try {
8299
+ sdkEntryPath = fileURLToPath(import.meta.resolve("@anthropic-ai/claude-agent-sdk"));
8300
+ } catch {
8301
+ const { createRequire } = await import("module");
8302
+ const localRequire = createRequire(import.meta.url);
8303
+ sdkEntryPath = localRequire.resolve("@anthropic-ai/claude-agent-sdk");
8304
+ }
8305
+ return path4.join(path4.dirname(sdkEntryPath), "cli.js");
8299
8306
  }
8300
8307
  async function runAgent(opts) {
8301
- const { agentDir, prompt, sessionId, maxTurns, permissionMode, model, allowedTools, mcpServers, onMessage, abortController } = opts;
8308
+ const { agentDir, prompt, sessionId, maxTurns, permissionMode, model, allowedTools, autoMemoryEnabled, mcpServers, onMessage, abortController } = opts;
8302
8309
  try {
8310
+ const pathToClaudeCodeExecutable = await resolveClaudeCodeExecutable();
8303
8311
  const stream = query({
8304
8312
  prompt,
8305
8313
  options: {
8306
- pathToClaudeCodeExecutable: resolveClaudeCodeExecutable(),
8314
+ pathToClaudeCodeExecutable,
8307
8315
  executable: process.execPath,
8308
8316
  // Full path to node — launchd doesn't have node in PATH
8309
8317
  cwd: agentDir,
@@ -8314,6 +8322,7 @@ async function runAgent(opts) {
8314
8322
  ...allowedTools && allowedTools.length > 0 ? { allowedTools } : {},
8315
8323
  ...sessionId ? { resume: sessionId } : {},
8316
8324
  ...typeof maxTurns === "number" ? { maxTurns } : {},
8325
+ ...typeof autoMemoryEnabled === "boolean" ? { autoMemoryEnabled } : {},
8317
8326
  ...mcpServers ? { mcpServers } : {},
8318
8327
  ...abortController ? { abortController } : {}
8319
8328
  }
@@ -9112,10 +9121,10 @@ function mergeDefs(...defs) {
9112
9121
  function cloneDef(schema) {
9113
9122
  return mergeDefs(schema._zod.def);
9114
9123
  }
9115
- function getElementAtPath(obj, path20) {
9116
- if (!path20)
9124
+ function getElementAtPath(obj, path11) {
9125
+ if (!path11)
9117
9126
  return obj;
9118
- return path20.reduce((acc, key) => acc?.[key], obj);
9127
+ return path11.reduce((acc, key) => acc?.[key], obj);
9119
9128
  }
9120
9129
  function promiseAllObject(promisesObj) {
9121
9130
  const keys = Object.keys(promisesObj);
@@ -9481,11 +9490,11 @@ function aborted(x, startIndex = 0) {
9481
9490
  }
9482
9491
  return false;
9483
9492
  }
9484
- function prefixIssues(path20, issues) {
9493
+ function prefixIssues(path11, issues) {
9485
9494
  return issues.map((iss) => {
9486
9495
  var _a2;
9487
9496
  (_a2 = iss).path ?? (_a2.path = []);
9488
- iss.path.unshift(path20);
9497
+ iss.path.unshift(path11);
9489
9498
  return iss;
9490
9499
  });
9491
9500
  }
@@ -9647,7 +9656,7 @@ function formatError(error46, mapper = (issue2) => issue2.message) {
9647
9656
  }
9648
9657
  function treeifyError(error46, mapper = (issue2) => issue2.message) {
9649
9658
  const result = { errors: [] };
9650
- const processError = (error47, path20 = []) => {
9659
+ const processError = (error47, path11 = []) => {
9651
9660
  var _a2, _b;
9652
9661
  for (const issue2 of error47.issues) {
9653
9662
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -9657,7 +9666,7 @@ function treeifyError(error46, mapper = (issue2) => issue2.message) {
9657
9666
  } else if (issue2.code === "invalid_element") {
9658
9667
  processError({ issues: issue2.issues }, issue2.path);
9659
9668
  } else {
9660
- const fullpath = [...path20, ...issue2.path];
9669
+ const fullpath = [...path11, ...issue2.path];
9661
9670
  if (fullpath.length === 0) {
9662
9671
  result.errors.push(mapper(issue2));
9663
9672
  continue;
@@ -9689,8 +9698,8 @@ function treeifyError(error46, mapper = (issue2) => issue2.message) {
9689
9698
  }
9690
9699
  function toDotPath(_path) {
9691
9700
  const segs = [];
9692
- const path20 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9693
- for (const seg of path20) {
9701
+ const path11 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9702
+ for (const seg of path11) {
9694
9703
  if (typeof seg === "number")
9695
9704
  segs.push(`[${seg}]`);
9696
9705
  else if (typeof seg === "symbol")
@@ -21026,23 +21035,23 @@ function date4(params) {
21026
21035
  config(en_default());
21027
21036
 
21028
21037
  // src/agents/mcp-server.ts
21029
- async function apiGet(apiUrl, path20, headers) {
21030
- const res = await fetch(`${apiUrl}${path20}`, {
21038
+ async function apiGet(apiUrl, path11, headers) {
21039
+ const res = await fetch(`${apiUrl}${path11}`, {
21031
21040
  headers: { ...headers, "Content-Type": "application/json" }
21032
21041
  });
21033
21042
  if (!res.ok) {
21034
- throw new Error(`API GET ${path20} failed: HTTP ${res.status}`);
21043
+ throw new Error(`API GET ${path11} failed: HTTP ${res.status}`);
21035
21044
  }
21036
21045
  return res.json();
21037
21046
  }
21038
- async function apiPost(apiUrl, path20, body, headers) {
21039
- const res = await fetch(`${apiUrl}${path20}`, {
21047
+ async function apiPost(apiUrl, path11, body, headers) {
21048
+ const res = await fetch(`${apiUrl}${path11}`, {
21040
21049
  method: "POST",
21041
21050
  headers: { ...headers, "Content-Type": "application/json" },
21042
21051
  body: JSON.stringify(body)
21043
21052
  });
21044
21053
  if (!res.ok) {
21045
- throw new Error(`API POST ${path20} failed: HTTP ${res.status}`);
21054
+ throw new Error(`API POST ${path11} failed: HTTP ${res.status}`);
21046
21055
  }
21047
21056
  return res.json();
21048
21057
  }
@@ -21063,7 +21072,7 @@ function createWorkleMcpServer(opts) {
21063
21072
  });
21064
21073
  const data = await apiGet(
21065
21074
  apiUrl,
21066
- `/api/claw/instances/${instanceId}/mcp/contacts?${params.toString()}`,
21075
+ `/api/local/instances/${instanceId}/mcp/contacts?${params.toString()}`,
21067
21076
  headers
21068
21077
  );
21069
21078
  return { content: [{ type: "text", text: JSON.stringify(data) }] };
@@ -21081,7 +21090,7 @@ function createWorkleMcpServer(opts) {
21081
21090
  async (input) => {
21082
21091
  const data = await apiPost(
21083
21092
  apiUrl,
21084
- `/api/claw/instances/${instanceId}/mcp/activity`,
21093
+ `/api/local/instances/${instanceId}/mcp/activity`,
21085
21094
  input,
21086
21095
  headers
21087
21096
  );
@@ -21102,7 +21111,7 @@ function createWorkleMcpServer(opts) {
21102
21111
  });
21103
21112
  const data = await apiGet(
21104
21113
  apiUrl,
21105
- `/api/claw/instances/${instanceId}/mcp/documents?${params.toString()}`,
21114
+ `/api/local/instances/${instanceId}/mcp/documents?${params.toString()}`,
21106
21115
  headers
21107
21116
  );
21108
21117
  return { content: [{ type: "text", text: JSON.stringify(data) }] };
@@ -21168,7 +21177,12 @@ var AgentScheduler = class {
21168
21177
  // src/agents/service.ts
21169
21178
  import { randomUUID } from "crypto";
21170
21179
  import fs4 from "fs/promises";
21180
+ import path7 from "path";
21181
+
21182
+ // src/sync/relay.ts
21183
+ import { readFileSync } from "fs";
21171
21184
  import path5 from "path";
21185
+ import { fileURLToPath as fileURLToPath2 } from "url";
21172
21186
 
21173
21187
  // ../../node_modules/ws/wrapper.mjs
21174
21188
  var import_stream = __toESM(require_stream(), 1);
@@ -21182,6 +21196,39 @@ var wrapper_default = import_websocket.default;
21182
21196
  var MAX_BACKOFF = 3e4;
21183
21197
  var INITIAL_BACKOFF = 1e3;
21184
21198
  var MAX_QUEUE_SIZE = 1e3;
21199
+ function readVersionFromJson(pathOrUrl) {
21200
+ try {
21201
+ const raw = readFileSync(pathOrUrl, "utf-8");
21202
+ const parsed = JSON.parse(raw);
21203
+ return typeof parsed.version === "string" ? parsed.version : void 0;
21204
+ } catch {
21205
+ return void 0;
21206
+ }
21207
+ }
21208
+ function readVersionFromNearestPackageJson(entryPath) {
21209
+ let currentDir = path5.dirname(entryPath);
21210
+ const rootDir = path5.parse(currentDir).root;
21211
+ while (true) {
21212
+ const version3 = readVersionFromJson(path5.join(currentDir, "package.json"));
21213
+ if (version3) {
21214
+ return version3;
21215
+ }
21216
+ if (currentDir === rootDir) {
21217
+ return void 0;
21218
+ }
21219
+ currentDir = path5.dirname(currentDir);
21220
+ }
21221
+ }
21222
+ var SYNC_VERSION = readVersionFromJson(new URL("../../package.json", import.meta.url));
21223
+ var AGENT_SDK_VERSION = (() => {
21224
+ try {
21225
+ return readVersionFromNearestPackageJson(
21226
+ fileURLToPath2(import.meta.resolve("@anthropic-ai/claude-agent-sdk"))
21227
+ );
21228
+ } catch {
21229
+ return void 0;
21230
+ }
21231
+ })();
21185
21232
  var RelayClient = class {
21186
21233
  constructor(relayUrl, instanceId, token, options) {
21187
21234
  this.relayUrl = relayUrl;
@@ -21250,7 +21297,7 @@ var RelayClient = class {
21250
21297
  doConnect() {
21251
21298
  return new Promise((resolve, reject) => {
21252
21299
  const url2 = `${this.relayUrl}/${this.instanceId}`;
21253
- console.log(`[claw] Connecting to relay: ${url2}`);
21300
+ console.log(`[local] Connecting to relay: ${url2}`);
21254
21301
  this.ws = new wrapper_default(url2, {
21255
21302
  headers: {
21256
21303
  Authorization: `Bearer ${this.token}`
@@ -21262,7 +21309,9 @@ var RelayClient = class {
21262
21309
  this.backoff = INITIAL_BACKOFF;
21263
21310
  const hello = {
21264
21311
  type: "hello",
21265
- instanceId: this.instanceId
21312
+ instanceId: this.instanceId,
21313
+ ...SYNC_VERSION ? { syncVersion: SYNC_VERSION } : {},
21314
+ ...AGENT_SDK_VERSION ? { agentSdkVersion: AGENT_SDK_VERSION } : {}
21266
21315
  };
21267
21316
  this.ws.send(JSON.stringify(hello));
21268
21317
  this.flushQueue();
@@ -21270,7 +21319,7 @@ var RelayClient = class {
21270
21319
  try {
21271
21320
  this.onConnectCallback();
21272
21321
  } catch (err) {
21273
- console.error("[claw] onConnect callback error:", err);
21322
+ console.error("[local] onConnect callback error:", err);
21274
21323
  }
21275
21324
  }
21276
21325
  if (!resolved) {
@@ -21286,7 +21335,7 @@ var RelayClient = class {
21286
21335
  try {
21287
21336
  handler(msg);
21288
21337
  } catch (err) {
21289
- console.error("[claw] Relay message handler error:", err);
21338
+ console.error("[local] Relay message handler error:", err);
21290
21339
  }
21291
21340
  }
21292
21341
  } catch {
@@ -21296,20 +21345,20 @@ var RelayClient = class {
21296
21345
  this.ws.on("close", (code, reason) => {
21297
21346
  if (closeHandled) return;
21298
21347
  closeHandled = true;
21299
- const reasonStr = reason ? Buffer.from(reason).toString("utf-8") : "";
21348
+ const reasonStr = typeof reason === "string" ? reason : reason instanceof Buffer ? reason.toString("utf-8") : "";
21300
21349
  console.log(
21301
- `[claw] Relay WebSocket closed: code=${code} reason="${reasonStr}"`
21350
+ `[local] Relay WebSocket closed: code=${code} reason="${reasonStr}"`
21302
21351
  );
21303
21352
  this._connected = false;
21304
21353
  this.cleanupWs();
21305
21354
  if (code === 4e3) {
21306
- console.log("[claw] Connection replaced \u2014 not reconnecting");
21355
+ console.log("[local] Connection replaced \u2014 not reconnecting");
21307
21356
  return;
21308
21357
  }
21309
21358
  this.scheduleReconnect();
21310
21359
  });
21311
21360
  this.ws.on("error", (err) => {
21312
- console.error("[claw] Relay WebSocket error:", err.message);
21361
+ console.error("[local] Relay WebSocket error:", err.message);
21313
21362
  this._connected = false;
21314
21363
  if (!resolved) {
21315
21364
  resolved = true;
@@ -21332,12 +21381,12 @@ var RelayClient = class {
21332
21381
  clearTimeout(this.reconnectTimer);
21333
21382
  }
21334
21383
  console.log(
21335
- `[claw] Relay disconnected. Reconnecting in ${this.backoff}ms...`
21384
+ `[local] Relay disconnected. Reconnecting in ${this.backoff}ms...`
21336
21385
  );
21337
21386
  this.reconnectTimer = setTimeout(() => {
21338
21387
  this.reconnectTimer = null;
21339
21388
  this.doConnect().catch((err) => {
21340
- console.error("[claw] Relay reconnect failed:", err);
21389
+ console.error("[local] Relay reconnect failed:", err);
21341
21390
  });
21342
21391
  }, this.backoff);
21343
21392
  const jitter = Math.random() * 0.3 * this.backoff;
@@ -21351,7 +21400,7 @@ var RelayClient = class {
21351
21400
  this.ws.send(JSON.stringify(msg));
21352
21401
  }
21353
21402
  if (queued.length > 0) {
21354
- console.log(`[claw] Flushed ${queued.length} queued messages to relay`);
21403
+ console.log(`[local] Flushed ${queued.length} queued messages to relay`);
21355
21404
  }
21356
21405
  }
21357
21406
  };
@@ -21359,8 +21408,8 @@ var RelayClient = class {
21359
21408
  // src/agents/sessions.ts
21360
21409
  import fs3 from "fs/promises";
21361
21410
  import os4 from "os";
21362
- import path4 from "path";
21363
- var SESSIONS_FILE = path4.join(
21411
+ import path6 from "path";
21412
+ var SESSIONS_FILE = path6.join(
21364
21413
  os4.homedir(),
21365
21414
  ".workle",
21366
21415
  "agent-sessions.json"
@@ -21382,7 +21431,7 @@ async function saveSessionId(agentId, sessionId) {
21382
21431
  } catch {
21383
21432
  }
21384
21433
  map2[agentId] = sessionId;
21385
- await fs3.mkdir(path4.dirname(SESSIONS_FILE), { recursive: true });
21434
+ await fs3.mkdir(path6.dirname(SESSIONS_FILE), { recursive: true });
21386
21435
  await fs3.writeFile(SESSIONS_FILE, JSON.stringify(map2, null, 2), "utf-8");
21387
21436
  }
21388
21437
 
@@ -21407,7 +21456,7 @@ function stringifyProgressValue(value) {
21407
21456
  function deriveRelayUrl(apiUrl) {
21408
21457
  const url2 = new URL(apiUrl);
21409
21458
  url2.protocol = url2.protocol === "https:" ? "wss:" : "ws:";
21410
- url2.pathname = "/api/claw/relay";
21459
+ url2.pathname = "/api/local/relay";
21411
21460
  if (url2.hostname !== "localhost") {
21412
21461
  url2.hostname = `relay.${url2.hostname}`;
21413
21462
  }
@@ -21609,7 +21658,7 @@ var AgentService = class _AgentService {
21609
21658
  instanceId: this.instanceId,
21610
21659
  token: this.token
21611
21660
  });
21612
- const { permissionMode, model, allowedTools } = extractSdkOptions(config2);
21661
+ const { permissionMode, model, allowedTools, autoMemoryEnabled } = extractSdkOptions(config2);
21613
21662
  const result = await runAgent({
21614
21663
  agentDir,
21615
21664
  prompt,
@@ -21618,6 +21667,7 @@ var AgentService = class _AgentService {
21618
21667
  permissionMode,
21619
21668
  model,
21620
21669
  allowedTools,
21670
+ autoMemoryEnabled,
21621
21671
  mcpServers: { workle: mcpServer },
21622
21672
  abortController,
21623
21673
  onMessage: (message) => {
@@ -21905,12 +21955,12 @@ var AgentService = class _AgentService {
21905
21955
  if (mdFiles.length === 0) return;
21906
21956
  const files = [];
21907
21957
  for (const filename of mdFiles) {
21908
- const content = await fs4.readFile(path5.join(memoryDir, filename), "utf-8");
21958
+ const content = await fs4.readFile(path7.join(memoryDir, filename), "utf-8");
21909
21959
  files.push({ filename, content });
21910
21960
  }
21911
21961
  const headers = createAuthHeaders(this.token);
21912
21962
  const res = await fetch(
21913
- `${this.apiUrl}/api/claw/instances/${this.instanceId}/runtime/agents/${agentId}/push-memory`,
21963
+ `${this.apiUrl}/api/local/instances/${this.instanceId}/runtime/agents/${agentId}/push-memory`,
21914
21964
  {
21915
21965
  method: "POST",
21916
21966
  headers: { ...headers, "Content-Type": "application/json" },
@@ -21983,7 +22033,7 @@ var VALID_PERMISSION_MODES = /* @__PURE__ */ new Set([
21983
22033
  function extractSdkOptions(config2) {
21984
22034
  const settings = config2?.settings;
21985
22035
  if (!settings || typeof settings !== "object") {
21986
- return { permissionMode: void 0, model: void 0, allowedTools: void 0 };
22036
+ return { permissionMode: void 0, model: void 0, allowedTools: void 0, autoMemoryEnabled: void 0 };
21987
22037
  }
21988
22038
  const s = settings;
21989
22039
  let permissionMode;
@@ -22002,7 +22052,8 @@ function extractSdkOptions(config2) {
22002
22052
  allowedTools = allow.filter((t) => typeof t === "string");
22003
22053
  }
22004
22054
  }
22005
- return { permissionMode, model, allowedTools };
22055
+ const autoMemoryEnabled = typeof s.autoMemoryEnabled === "boolean" ? s.autoMemoryEnabled : void 0;
22056
+ return { permissionMode, model, allowedTools, autoMemoryEnabled };
22006
22057
  }
22007
22058
  async function createAgentService() {
22008
22059
  const auth = await loadAuth();
@@ -22013,171 +22064,18 @@ async function createAgentService() {
22013
22064
  });
22014
22065
  }
22015
22066
 
22016
- // src/legacy/openclaw/process.ts
22017
- import { spawn } from "child_process";
22067
+ // src/lifecycle/doctor.ts
22018
22068
  import fs5 from "fs/promises";
22019
- import http from "http";
22020
22069
  import os5 from "os";
22021
- import path6 from "path";
22022
- var CLAW_HOME = path6.join(os5.homedir(), ".workle");
22023
- var LOG_FILE = path6.join(CLAW_HOME, "openclaw.log");
22024
- var PID_FILE = path6.join(CLAW_HOME, "openclaw.pid");
22025
- var OPENCLAW_PORT = 18789;
22026
- var HEALTH_CHECK_TIMEOUT = 5e3;
22027
- var ProcessManager = class {
22028
- process = null;
22029
- logHandle = null;
22030
- /**
22031
- * Spawn the OpenClaw gateway process.
22032
- * Pipes stdout/stderr to a log file and writes PID to disk.
22033
- *
22034
- * @param openclawBinary - Path to the openclaw binary (defaults to "openclaw" in PATH)
22035
- * @param configPath - Path to openclaw.json config (defaults to ~/.workle/openclaw.json)
22036
- */
22037
- async spawn(openclawBinary = "openclaw", configPath = path6.join(CLAW_HOME, "openclaw.json")) {
22038
- if (this.process) {
22039
- console.log("[claw] OpenClaw process already running");
22040
- return;
22041
- }
22042
- await fs5.mkdir(CLAW_HOME, { recursive: true });
22043
- this.logHandle = await fs5.open(LOG_FILE, "a");
22044
- const logFd = this.logHandle.fd;
22045
- this.process = spawn(openclawBinary, ["--config", configPath], {
22046
- stdio: ["ignore", logFd, logFd],
22047
- detached: false,
22048
- // eslint-disable-next-line no-restricted-properties -- CLI tool needs access to process.env
22049
- env: { ...process.env }
22050
- });
22051
- if (this.process.pid) {
22052
- await fs5.writeFile(PID_FILE, String(this.process.pid), "utf-8");
22053
- }
22054
- this.process.on("exit", (code, signal) => {
22055
- console.log(
22056
- `[claw] OpenClaw process exited (code=${code}, signal=${signal})`
22057
- );
22058
- this.process = null;
22059
- if (this.logHandle) {
22060
- void this.logHandle.close().catch(() => {
22061
- });
22062
- this.logHandle = null;
22063
- }
22064
- fs5.unlink(PID_FILE).catch(() => {
22065
- });
22066
- });
22067
- this.process.on("error", (err) => {
22068
- console.error("[claw] Failed to spawn OpenClaw:", err);
22069
- this.process = null;
22070
- });
22071
- console.log(`[claw] OpenClaw spawned (PID: ${this.process.pid})`);
22072
- await new Promise((resolve) => setTimeout(resolve, 500));
22073
- if (!this.process) {
22074
- throw new Error(
22075
- "OpenClaw process exited immediately. Check logs at " + LOG_FILE
22076
- );
22077
- }
22078
- }
22079
- /**
22080
- * Stop the OpenClaw gateway process.
22081
- */
22082
- async stop() {
22083
- if (!this.process) {
22084
- try {
22085
- const pidStr = await fs5.readFile(PID_FILE, "utf-8");
22086
- const pid = parseInt(pidStr.trim(), 10);
22087
- if (!isNaN(pid)) {
22088
- process.kill(pid, "SIGTERM");
22089
- await fs5.unlink(PID_FILE).catch(() => {
22090
- });
22091
- console.log(`[claw] Sent SIGTERM to OpenClaw (PID: ${pid})`);
22092
- return;
22093
- }
22094
- } catch {
22095
- }
22096
- console.log("[claw] No OpenClaw process to stop");
22097
- return;
22098
- }
22099
- this.process.kill("SIGTERM");
22100
- console.log("[claw] Sent SIGTERM to OpenClaw");
22101
- await new Promise((resolve) => {
22102
- const timer = setTimeout(() => {
22103
- if (this.process && !this.process.killed) {
22104
- this.process.kill("SIGKILL");
22105
- console.log("[claw] Force-killed OpenClaw (SIGKILL)");
22106
- }
22107
- resolve();
22108
- }, 5e3);
22109
- if (this.process) {
22110
- this.process.once("exit", () => {
22111
- clearTimeout(timer);
22112
- resolve();
22113
- });
22114
- } else {
22115
- clearTimeout(timer);
22116
- resolve();
22117
- }
22118
- });
22119
- this.process = null;
22120
- if (this.logHandle) {
22121
- await this.logHandle.close().catch(() => {
22122
- });
22123
- this.logHandle = null;
22124
- }
22125
- await fs5.unlink(PID_FILE).catch(() => {
22126
- });
22127
- }
22128
- /**
22129
- * Restart the OpenClaw gateway process.
22130
- */
22131
- async restart(openclawBinary, configPath) {
22132
- await this.stop();
22133
- await this.spawn(openclawBinary, configPath);
22134
- }
22135
- /**
22136
- * Check if the OpenClaw gateway is healthy by pinging the loopback port.
22137
- */
22138
- async isHealthy() {
22139
- return new Promise((resolve) => {
22140
- const req = http.request(
22141
- {
22142
- hostname: "127.0.0.1",
22143
- port: OPENCLAW_PORT,
22144
- path: "/",
22145
- method: "GET",
22146
- timeout: HEALTH_CHECK_TIMEOUT
22147
- },
22148
- (res) => {
22149
- res.resume();
22150
- resolve(true);
22151
- }
22152
- );
22153
- req.on("error", () => {
22154
- resolve(false);
22155
- });
22156
- req.on("timeout", () => {
22157
- req.destroy();
22158
- resolve(false);
22159
- });
22160
- req.end();
22161
- });
22162
- }
22163
- };
22164
-
22165
- // src/lifecycle/doctor.ts
22166
- import { execSync } from "child_process";
22167
- import fs6 from "fs/promises";
22168
- import os6 from "os";
22169
- import path7 from "path";
22170
- var WORKLE_HOME2 = path7.join(os6.homedir(), ".workle");
22070
+ import path8 from "path";
22071
+ var WORKLE_HOME2 = path8.join(os5.homedir(), ".workle");
22171
22072
  var MIN_NODE_MAJOR = 22;
22172
22073
  async function runDoctor() {
22173
22074
  const checks = [];
22174
22075
  checks.push(checkNodeVersion());
22175
- checks.push(checkOpenClawInstalled());
22176
- checks.push(await checkClawHome());
22076
+ checks.push(await checkLocalHome());
22177
22077
  checks.push(await checkAuthFile());
22178
- checks.push(await checkConfigFile());
22179
- checks.push(await checkGatewayReachable());
22180
- console.log("\n Workle Claw Doctor\n");
22078
+ console.log("\n Workle Local Doctor\n");
22181
22079
  for (const check2 of checks) {
22182
22080
  const icon = check2.status === "pass" ? "[OK]" : check2.status === "warn" ? "[WARN]" : "[FAIL]";
22183
22081
  console.log(` ${icon} ${check2.name}: ${check2.message}`);
@@ -22207,52 +22105,33 @@ function checkNodeVersion() {
22207
22105
  message: `${process.version} \u2014 Node >= ${MIN_NODE_MAJOR} is required`
22208
22106
  };
22209
22107
  }
22210
- function checkOpenClawInstalled() {
22211
- try {
22212
- const version3 = execSync("openclaw --version", {
22213
- encoding: "utf-8",
22214
- timeout: 5e3
22215
- }).trim();
22216
- return {
22217
- name: "OpenClaw binary",
22218
- status: "pass",
22219
- message: `Found: ${version3}`
22220
- };
22221
- } catch {
22222
- return {
22223
- name: "OpenClaw binary",
22224
- status: "fail",
22225
- message: "openclaw not found in PATH. Install from https://openclaw.dev"
22226
- };
22227
- }
22228
- }
22229
- async function checkClawHome() {
22108
+ async function checkLocalHome() {
22230
22109
  try {
22231
- const stat = await fs6.stat(WORKLE_HOME2);
22110
+ const stat = await fs5.stat(WORKLE_HOME2);
22232
22111
  if (stat.isDirectory()) {
22233
22112
  return {
22234
- name: "Claw home directory",
22113
+ name: "Home directory",
22235
22114
  status: "pass",
22236
22115
  message: WORKLE_HOME2
22237
22116
  };
22238
22117
  }
22239
22118
  return {
22240
- name: "Claw home directory",
22119
+ name: "Home directory",
22241
22120
  status: "fail",
22242
22121
  message: `${WORKLE_HOME2} exists but is not a directory`
22243
22122
  };
22244
22123
  } catch {
22245
22124
  return {
22246
- name: "Claw home directory",
22125
+ name: "Home directory",
22247
22126
  status: "fail",
22248
22127
  message: `${WORKLE_HOME2} does not exist. Run 'workle setup'`
22249
22128
  };
22250
22129
  }
22251
22130
  }
22252
22131
  async function checkAuthFile() {
22253
- const authPath = path7.join(WORKLE_HOME2, "auth.json");
22132
+ const authPath = path8.join(WORKLE_HOME2, "auth.json");
22254
22133
  try {
22255
- const raw = await fs6.readFile(authPath, "utf-8");
22134
+ const raw = await fs5.readFile(authPath, "utf-8");
22256
22135
  const parsed = JSON.parse(raw);
22257
22136
  if (parsed.instanceId && parsed.token && parsed.apiUrl) {
22258
22137
  return {
@@ -22274,99 +22153,53 @@ async function checkAuthFile() {
22274
22153
  };
22275
22154
  }
22276
22155
  }
22277
- async function checkConfigFile() {
22278
- const configPath = path7.join(WORKLE_HOME2, "openclaw.json");
22279
- try {
22280
- const raw = await fs6.readFile(configPath, "utf-8");
22281
- const parsed = JSON.parse(raw);
22282
- if (parsed.agents) {
22283
- return {
22284
- name: "Gateway config",
22285
- status: "pass",
22286
- message: configPath
22287
- };
22288
- }
22289
- return {
22290
- name: "Gateway config",
22291
- status: "warn",
22292
- message: "openclaw.json exists but has no agents section"
22293
- };
22294
- } catch {
22295
- return {
22296
- name: "Gateway config",
22297
- status: "warn",
22298
- message: `${configPath} not found. Will be created on first sync`
22299
- };
22300
- }
22301
- }
22302
- async function checkGatewayReachable() {
22303
- try {
22304
- const controller = new AbortController();
22305
- const timer = setTimeout(() => controller.abort(), 3e3);
22306
- const res = await fetch("http://127.0.0.1:18789/", {
22307
- signal: controller.signal
22308
- });
22309
- clearTimeout(timer);
22310
- return {
22311
- name: "OpenClaw gateway",
22312
- status: "pass",
22313
- message: `Reachable on :18789 (HTTP ${res.status})`
22314
- };
22315
- } catch {
22316
- return {
22317
- name: "OpenClaw gateway",
22318
- status: "warn",
22319
- message: "Not reachable on :18789. Start with 'workle start'"
22320
- };
22321
- }
22322
- }
22323
22156
 
22324
22157
  // src/lifecycle/install.ts
22325
- import fs7 from "fs/promises";
22326
- import os7 from "os";
22327
- import path8 from "path";
22328
- var WORKLE_HOME3 = path8.join(os7.homedir(), ".workle");
22329
- var LAUNCH_AGENTS_DIR = path8.join(os7.homedir(), "Library", "LaunchAgents");
22330
- var STAGED_CLI_PATH = path8.join(WORKLE_HOME3, "bin", "cli.js");
22158
+ import fs6 from "fs/promises";
22159
+ import os6 from "os";
22160
+ import path9 from "path";
22161
+ var WORKLE_HOME3 = path9.join(os6.homedir(), ".workle");
22162
+ var LAUNCH_AGENTS_DIR = path9.join(os6.homedir(), "Library", "LaunchAgents");
22163
+ var STAGED_CLI_PATH = path9.join(WORKLE_HOME3, "bin", "cli.js");
22331
22164
  function escapeXml(value) {
22332
22165
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
22333
22166
  }
22334
- async function setupClawDirectory() {
22167
+ async function setupLocalDirectory() {
22335
22168
  const dirs = [
22336
22169
  WORKLE_HOME3,
22337
- path8.join(WORKLE_HOME3, "logs"),
22338
- path8.join(WORKLE_HOME3, "bin")
22170
+ path9.join(WORKLE_HOME3, "logs"),
22171
+ path9.join(WORKLE_HOME3, "bin")
22339
22172
  ];
22340
22173
  for (const dir of dirs) {
22341
- await fs7.mkdir(dir, { recursive: true, mode: 448 });
22342
- await fs7.chmod(dir, 448).catch(() => {
22174
+ await fs6.mkdir(dir, { recursive: true, mode: 448 });
22175
+ await fs6.chmod(dir, 448).catch(() => {
22343
22176
  });
22344
22177
  }
22345
- const gitignorePath = path8.join(WORKLE_HOME3, ".gitignore");
22178
+ const gitignorePath = path9.join(WORKLE_HOME3, ".gitignore");
22346
22179
  try {
22347
- await fs7.access(gitignorePath);
22180
+ await fs6.access(gitignorePath);
22348
22181
  } catch {
22349
- await fs7.writeFile(gitignorePath, "*\n", "utf-8");
22182
+ await fs6.writeFile(gitignorePath, "*\n", "utf-8");
22350
22183
  }
22351
- console.log(`[claw] Directory structure created at ${WORKLE_HOME3}`);
22184
+ console.log(`[local] Directory structure created at ${WORKLE_HOME3}`);
22352
22185
  }
22353
22186
  async function stageCliForDaemon(currentCliPath) {
22354
22187
  if (!currentCliPath) {
22355
22188
  throw new Error("Cannot determine the current CLI path for daemon install.");
22356
22189
  }
22357
- await setupClawDirectory();
22190
+ await setupLocalDirectory();
22358
22191
  const isNpxCache = currentCliPath.includes("/_npx/") || currentCliPath.includes("\\_npx\\");
22359
22192
  if (!isNpxCache) {
22360
22193
  return currentCliPath;
22361
22194
  }
22362
- await fs7.copyFile(currentCliPath, STAGED_CLI_PATH);
22363
- await fs7.chmod(STAGED_CLI_PATH, 448).catch(() => {
22195
+ await fs6.copyFile(currentCliPath, STAGED_CLI_PATH);
22196
+ await fs6.chmod(STAGED_CLI_PATH, 448).catch(() => {
22364
22197
  });
22365
22198
  return STAGED_CLI_PATH;
22366
22199
  }
22367
- async function writeLaunchdPlist(serviceName = "com.workle.claw", executable = process.execPath, args = [STAGED_CLI_PATH, "start"]) {
22368
- await fs7.mkdir(LAUNCH_AGENTS_DIR, { recursive: true });
22369
- const plistPath = path8.join(LAUNCH_AGENTS_DIR, `${serviceName}.plist`);
22200
+ async function writeLaunchdPlist(serviceName = "com.workle.local", executable = process.execPath, args = [STAGED_CLI_PATH, "start"]) {
22201
+ await fs6.mkdir(LAUNCH_AGENTS_DIR, { recursive: true });
22202
+ const plistPath = path9.join(LAUNCH_AGENTS_DIR, `${serviceName}.plist`);
22370
22203
  const programArguments = [executable, ...args].map((arg) => ` <string>${escapeXml(arg)}</string>`).join("\n");
22371
22204
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
22372
22205
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -22390,10 +22223,10 @@ ${programArguments}
22390
22223
  </dict>
22391
22224
 
22392
22225
  <key>StandardOutPath</key>
22393
- <string>${path8.join(WORKLE_HOME3, "logs", "stdout.log")}</string>
22226
+ <string>${path9.join(WORKLE_HOME3, "logs", "stdout.log")}</string>
22394
22227
 
22395
22228
  <key>StandardErrorPath</key>
22396
- <string>${path8.join(WORKLE_HOME3, "logs", "stderr.log")}</string>
22229
+ <string>${path9.join(WORKLE_HOME3, "logs", "stderr.log")}</string>
22397
22230
 
22398
22231
  <key>WorkingDirectory</key>
22399
22232
  <string>${WORKLE_HOME3}</string>
@@ -22403,867 +22236,19 @@ ${programArguments}
22403
22236
  </dict>
22404
22237
  </plist>
22405
22238
  `;
22406
- await fs7.writeFile(plistPath, plist, "utf-8");
22407
- console.log(`[claw] Launchd plist written to ${plistPath}`);
22239
+ await fs6.writeFile(plistPath, plist, "utf-8");
22240
+ console.log(`[local] Launchd plist written to ${plistPath}`);
22408
22241
  console.log(
22409
- `[claw] To enable: launchctl load ${plistPath}`
22242
+ `[local] To enable: launchctl load ${plistPath}`
22410
22243
  );
22411
22244
  return plistPath;
22412
22245
  }
22413
22246
 
22414
22247
  // src/sync/service.ts
22415
- import fs15 from "fs/promises";
22416
- import os17 from "os";
22417
- import path18 from "path";
22418
-
22419
- // src/legacy/openclaw/gateway.ts
22420
- import os8 from "os";
22421
- import path9 from "path";
22422
- var CLAW_HOME2 = path9.join(os8.homedir(), ".workle");
22423
- function generateGatewayConfig(_instance, agents) {
22424
- const sorted = [...agents].sort((a, b) => a.sortOrder - b.sortOrder);
22425
- const list = sorted.map((agent) => ({
22426
- id: agent.id,
22427
- default: !agent.isSubAgent,
22428
- workspace: path9.join(CLAW_HOME2, `workspace-${agent.agentKey}`),
22429
- model: agent.model,
22430
- toolProfile: agent.toolProfile,
22431
- promptMode: agent.promptMode
22432
- }));
22433
- return {
22434
- agents: { list }
22435
- };
22436
- }
22437
-
22438
- // src/legacy/openclaw/soul.ts
22439
- import fs8 from "fs/promises";
22440
- import os9 from "os";
22441
- import path10 from "path";
22442
- var CLAW_HOME3 = path10.join(os9.homedir(), ".workle");
22443
- var DEFAULT_SOUL_MD = `# Soul
22444
-
22445
- You are a Workle agent. Follow your assigned skills and operational instructions.
22446
- Be helpful, accurate, and concise. Always use available tools before guessing.
22447
- `;
22448
- async function writeSoulMd(agentKey, content, rpcCall) {
22449
- const body = content?.trim() ? content : DEFAULT_SOUL_MD;
22450
- if (rpcCall) {
22451
- await rpcCall(agentKey, "SOUL.md", body);
22452
- return;
22453
- }
22454
- const workspaceDir = path10.join(CLAW_HOME3, `workspace-${agentKey}`);
22455
- await fs8.mkdir(workspaceDir, { recursive: true });
22456
- const filePath = path10.join(workspaceDir, "SOUL.md");
22457
- await fs8.writeFile(filePath, body, "utf-8");
22458
- }
22459
-
22460
- // src/legacy/openclaw/agents.ts
22461
- import fs9 from "fs/promises";
22462
- import os10 from "os";
22463
- import path11 from "path";
22464
- var CLAW_HOME4 = path11.join(os10.homedir(), ".workle");
22465
- var DEFAULT_AGENTS_MD = `# Agents
22466
-
22467
- No additional agent configuration provided.
22468
- `;
22469
- async function writeAgentsMd(agentKey, content, rpcCall) {
22470
- const body = content?.trim() ? content : DEFAULT_AGENTS_MD;
22471
- if (rpcCall) {
22472
- await rpcCall(agentKey, "AGENTS.md", body);
22473
- return;
22474
- }
22475
- const workspaceDir = path11.join(CLAW_HOME4, `workspace-${agentKey}`);
22476
- await fs9.mkdir(workspaceDir, { recursive: true });
22477
- const filePath = path11.join(workspaceDir, "AGENTS.md");
22478
- await fs9.writeFile(filePath, body, "utf-8");
22479
- }
22480
-
22481
- // src/config/identity.ts
22482
- import fs10 from "fs/promises";
22483
- import os11 from "os";
22484
- import path12 from "path";
22485
- var WORKLE_HOME4 = path12.join(os11.homedir(), ".workle");
22486
- var DEFAULT_IDENTITY_MD = `# Identity
22487
-
22488
- No identity configuration provided.
22489
- `;
22490
- async function writeIdentityMd(agentKey, content, rpcCall) {
22491
- const body = content?.trim() ? content : DEFAULT_IDENTITY_MD;
22492
- if (rpcCall) {
22493
- await rpcCall(agentKey, "IDENTITY.md", body);
22494
- return;
22495
- }
22496
- const workspaceDir = path12.join(WORKLE_HOME4, `workspace-${agentKey}`);
22497
- await fs10.mkdir(workspaceDir, { recursive: true });
22498
- const filePath = path12.join(workspaceDir, "IDENTITY.md");
22499
- await fs10.writeFile(filePath, body, "utf-8");
22500
- }
22501
-
22502
- // src/config/heartbeat.ts
22503
- import fs11 from "fs/promises";
22504
- import os12 from "os";
22505
- import path13 from "path";
22506
- var WORKLE_HOME5 = path13.join(os12.homedir(), ".workle");
22507
- var DEFAULT_HEARTBEAT_MD = `# Heartbeat
22508
-
22509
- No heartbeat configuration provided.
22510
- `;
22511
- async function writeHeartbeatMd(agentKey, content, rpcCall) {
22512
- const body = content?.trim() ? content : DEFAULT_HEARTBEAT_MD;
22513
- if (rpcCall) {
22514
- await rpcCall(agentKey, "HEARTBEAT.md", body);
22515
- return;
22516
- }
22517
- const workspaceDir = path13.join(WORKLE_HOME5, `workspace-${agentKey}`);
22518
- await fs11.mkdir(workspaceDir, { recursive: true });
22519
- const filePath = path13.join(workspaceDir, "HEARTBEAT.md");
22520
- await fs11.writeFile(filePath, body, "utf-8");
22521
- }
22522
-
22523
- // src/config/skills.ts
22524
- import fs12 from "fs/promises";
22525
- import os13 from "os";
22526
- import path14 from "path";
22527
- var WORKLE_HOME6 = path14.join(os13.homedir(), ".workle");
22528
-
22529
- // src/legacy/openclaw/rpc.ts
22530
- import crypto4 from "crypto";
22531
- import fs13 from "fs";
22532
- import os14 from "os";
22533
- import path15 from "path";
22534
- var OPENCLAW_PORT2 = 18789;
22535
- var OPENCLAW_URL = `ws://127.0.0.1:${OPENCLAW_PORT2}`;
22536
- var RPC_TIMEOUT = 3e4;
22537
- var MAX_RECONNECT_BACKOFF = 1e4;
22538
- var CLAW_VERSION = "0.1.16";
22539
- var OPENCLAW_CONFIG_PATHS = [
22540
- () => path15.join(os14.homedir(), ".openclaw", "openclaw.json"),
22541
- () => path15.join(os14.homedir(), ".config", "openclaw", "openclaw.json")
22542
- ];
22543
- var CLAW_IDENTITY_DIR = path15.join(os14.homedir(), ".workle");
22544
- var CLAW_IDENTITY_FILE = path15.join(CLAW_IDENTITY_DIR, "device-identity.json");
22545
- var ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
22546
- function base64UrlEncode(buf) {
22547
- return buf.toString("base64").replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/g, "");
22548
- }
22549
- function derivePublicKeyRaw(publicKeyPem) {
22550
- const key = crypto4.createPublicKey(publicKeyPem);
22551
- const spki = key.export({ type: "spki", format: "der" });
22552
- if (spki.length === ED25519_SPKI_PREFIX.length + 32 && spki.subarray(0, ED25519_SPKI_PREFIX.length).equals(ED25519_SPKI_PREFIX)) {
22553
- return spki.subarray(ED25519_SPKI_PREFIX.length);
22554
- }
22555
- return spki;
22556
- }
22557
- function fingerprintPublicKey(publicKeyPem) {
22558
- const raw = derivePublicKeyRaw(publicKeyPem);
22559
- return crypto4.createHash("sha256").update(raw).digest("hex");
22560
- }
22561
- function loadOrCreateDeviceIdentity() {
22562
- try {
22563
- if (fs13.existsSync(CLAW_IDENTITY_FILE)) {
22564
- const raw = fs13.readFileSync(CLAW_IDENTITY_FILE, "utf8");
22565
- const parsed = JSON.parse(raw);
22566
- if (parsed?.version === 1 && typeof parsed.deviceId === "string" && typeof parsed.publicKeyPem === "string" && typeof parsed.privateKeyPem === "string") {
22567
- const derivedId = fingerprintPublicKey(parsed.publicKeyPem);
22568
- const deviceId2 = derivedId === parsed.deviceId ? parsed.deviceId : derivedId;
22569
- console.log(`[claw] Loaded device identity: ${deviceId2.slice(0, 12)}...`);
22570
- return {
22571
- deviceId: deviceId2,
22572
- publicKeyPem: parsed.publicKeyPem,
22573
- privateKeyPem: parsed.privateKeyPem
22574
- };
22575
- }
22576
- }
22577
- } catch {
22578
- }
22579
- const { publicKey, privateKey } = crypto4.generateKeyPairSync("ed25519");
22580
- const publicKeyPem = publicKey.export({ type: "spki", format: "pem" }).toString();
22581
- const privateKeyPem = privateKey.export({ type: "pkcs8", format: "pem" }).toString();
22582
- const deviceId = fingerprintPublicKey(publicKeyPem);
22583
- fs13.mkdirSync(CLAW_IDENTITY_DIR, { recursive: true });
22584
- const stored = {
22585
- version: 1,
22586
- deviceId,
22587
- publicKeyPem,
22588
- privateKeyPem,
22589
- createdAtMs: Date.now()
22590
- };
22591
- fs13.writeFileSync(CLAW_IDENTITY_FILE, `${JSON.stringify(stored, null, 2)}
22592
- `, { mode: 384 });
22593
- try {
22594
- fs13.chmodSync(CLAW_IDENTITY_FILE, 384);
22595
- } catch {
22596
- }
22597
- console.log(`[claw] Generated new device identity: ${deviceId.slice(0, 12)}...`);
22598
- return { deviceId, publicKeyPem, privateKeyPem };
22599
- }
22600
- function buildDeviceAuthPayload(params) {
22601
- return [
22602
- "v2",
22603
- params.deviceId,
22604
- params.clientId,
22605
- params.clientMode,
22606
- params.role,
22607
- params.scopes.join(","),
22608
- String(params.signedAtMs),
22609
- params.token,
22610
- params.nonce
22611
- ].join("|");
22612
- }
22613
- function signPayload(privateKeyPem, payload) {
22614
- const key = crypto4.createPrivateKey(privateKeyPem);
22615
- const sig = crypto4.sign(null, Buffer.from(payload, "utf8"), key);
22616
- return base64UrlEncode(sig);
22617
- }
22618
- function readGatewayAuth() {
22619
- const envToken = process.env.OPENCLAW_GATEWAY_TOKEN?.trim() || process.env.CLAWDBOT_GATEWAY_TOKEN?.trim();
22620
- if (envToken) {
22621
- console.log("[claw] Using gateway token from environment variable");
22622
- return { token: envToken };
22623
- }
22624
- const envPassword = process.env.OPENCLAW_GATEWAY_PASSWORD?.trim() || process.env.CLAWDBOT_GATEWAY_PASSWORD?.trim();
22625
- if (envPassword) {
22626
- console.log("[claw] Using gateway password from environment variable");
22627
- return { password: envPassword };
22628
- }
22629
- for (const getPath of OPENCLAW_CONFIG_PATHS) {
22630
- try {
22631
- const configPath = getPath();
22632
- const raw = fs13.readFileSync(configPath, "utf-8");
22633
- const config2 = JSON.parse(raw);
22634
- const token = config2.gateway?.auth?.token?.trim();
22635
- const password = config2.gateway?.auth?.password?.trim();
22636
- if (token || password) {
22637
- console.log(
22638
- `[claw] Using gateway ${token ? "token" : "password"} from ${configPath}`
22639
- );
22640
- return { token: token || void 0, password: password || void 0 };
22641
- }
22642
- } catch {
22643
- }
22644
- }
22645
- console.warn(
22646
- "[claw] \u26A0 No gateway auth found! Set OPENCLAW_GATEWAY_TOKEN or configure gateway.auth.token in ~/.openclaw/openclaw.json"
22647
- );
22648
- return void 0;
22649
- }
22650
- var OpenClawRpcClient = class {
22651
- ws = null;
22652
- pendingCalls = /* @__PURE__ */ new Map();
22653
- eventHandlers = [];
22654
- callCounter = 0;
22655
- _connected = false;
22656
- /** True after the connect handshake completes (hello-ok received) */
22657
- _handshakeComplete = false;
22658
- shouldReconnect = false;
22659
- reconnectTimer = null;
22660
- reconnectBackoff = 1e3;
22661
- get connected() {
22662
- return this._connected && this._handshakeComplete;
22663
- }
22664
- /**
22665
- * Connect to the OpenClaw gateway WebSocket and complete the handshake.
22666
- */
22667
- async connect() {
22668
- if (this.ws && this._connected && this._handshakeComplete) return;
22669
- this.shouldReconnect = true;
22670
- return this.doConnect();
22671
- }
22672
- doConnect() {
22673
- return new Promise((resolve, reject) => {
22674
- let resolved = false;
22675
- this._handshakeComplete = false;
22676
- let challengeNonce;
22677
- this.ws = new wrapper_default(OPENCLAW_URL);
22678
- this.ws.on("open", () => {
22679
- console.log("[claw] OpenClaw RPC WebSocket opened");
22680
- this._connected = true;
22681
- this.reconnectBackoff = 1e3;
22682
- });
22683
- this.ws.on("message", (data) => {
22684
- try {
22685
- const text = typeof data === "string" ? data : Buffer.from(data).toString("utf-8");
22686
- const frame = JSON.parse(text);
22687
- if (frame.type === "res") {
22688
- if (!this._handshakeComplete && frame.ok) {
22689
- this._handshakeComplete = true;
22690
- console.log("[claw] OpenClaw handshake complete");
22691
- if (!resolved) {
22692
- resolved = true;
22693
- resolve();
22694
- }
22695
- return;
22696
- }
22697
- if (!this._handshakeComplete && !frame.ok) {
22698
- const errMsg = frame.error?.message ?? "handshake rejected";
22699
- console.error(`[claw] OpenClaw handshake failed: ${errMsg}`);
22700
- if (!resolved) {
22701
- resolved = true;
22702
- reject(new Error(`Gateway handshake failed: ${errMsg}`));
22703
- }
22704
- return;
22705
- }
22706
- this.handleResponse(frame);
22707
- } else if (frame.type === "event") {
22708
- if (frame.event === "connect.challenge" && !this._handshakeComplete) {
22709
- const payload = frame.payload;
22710
- challengeNonce = payload?.nonce;
22711
- console.log("[claw] Received connect.challenge, sending handshake...");
22712
- this.sendConnectHandshake(challengeNonce);
22713
- return;
22714
- }
22715
- this.handleEvent(frame);
22716
- }
22717
- } catch {
22718
- }
22719
- });
22720
- this.ws.on("close", (code, reason) => {
22721
- const reasonStr = reason ? Buffer.from(reason).toString("utf-8") : "";
22722
- console.log(
22723
- `[claw] OpenClaw RPC WebSocket closed: code=${code} reason="${reasonStr}"`
22724
- );
22725
- this._connected = false;
22726
- this._handshakeComplete = false;
22727
- this.rejectAllPending(new Error("WebSocket connection closed"));
22728
- if (!resolved) {
22729
- resolved = true;
22730
- reject(new Error(`Gateway closed during handshake: ${reasonStr}`));
22731
- }
22732
- this.scheduleReconnect();
22733
- });
22734
- this.ws.on("error", (err) => {
22735
- this._connected = false;
22736
- this._handshakeComplete = false;
22737
- if (!resolved) {
22738
- resolved = true;
22739
- reject(err);
22740
- }
22741
- });
22742
- });
22743
- }
22744
- /**
22745
- * Send the connect handshake required by the OpenClaw gateway protocol.
22746
- *
22747
- * Flow:
22748
- * 1. Gateway sends connect.challenge with { nonce, ts }
22749
- * 2. Client builds device identity + signs the nonce
22750
- * 3. Client sends connect request with device, auth, role, and scopes
22751
- * 4. Gateway auto-approves pairing for loopback connections (silent)
22752
- * 5. Gateway responds with hello-ok including granted scopes
22753
- *
22754
- * CRITICAL: The gateway strips ALL self-declared scopes from connections
22755
- * that lack a signed device identity, even if the auth token is valid.
22756
- * The device identity is what binds scopes to a connection.
22757
- */
22758
- sendConnectHandshake(challengeNonce) {
22759
- const gatewayAuth = readGatewayAuth();
22760
- const identity = loadOrCreateDeviceIdentity();
22761
- const role = "operator";
22762
- const scopes = ["operator.admin"];
22763
- const signedAtMs = Date.now();
22764
- const authToken = gatewayAuth?.token ?? "";
22765
- const payload = buildDeviceAuthPayload({
22766
- deviceId: identity.deviceId,
22767
- clientId: "gateway-client",
22768
- clientMode: "backend",
22769
- role,
22770
- scopes,
22771
- signedAtMs,
22772
- token: authToken,
22773
- nonce: challengeNonce ?? ""
22774
- });
22775
- const signature = signPayload(identity.privateKeyPem, payload);
22776
- const publicKeyBase64Url = base64UrlEncode(derivePublicKeyRaw(identity.publicKeyPem));
22777
- const connectFrame = {
22778
- type: "req",
22779
- id: `rpc_connect_${Date.now()}`,
22780
- method: "connect",
22781
- params: {
22782
- minProtocol: 3,
22783
- maxProtocol: 3,
22784
- client: {
22785
- id: "gateway-client",
22786
- displayName: "Workle Claw",
22787
- version: CLAW_VERSION,
22788
- platform: "node",
22789
- mode: "backend"
22790
- },
22791
- role,
22792
- scopes,
22793
- device: {
22794
- id: identity.deviceId,
22795
- publicKey: publicKeyBase64Url,
22796
- signature,
22797
- signedAt: signedAtMs,
22798
- nonce: challengeNonce ?? void 0
22799
- },
22800
- ...gatewayAuth ? { auth: gatewayAuth } : {}
22801
- }
22802
- };
22803
- const authKind = gatewayAuth?.token ? "token" : gatewayAuth?.password ? "password" : "none";
22804
- console.log(
22805
- `[claw] Sending connect handshake (auth=${authKind}, device=${identity.deviceId.slice(0, 12)}..., scopes=operator.admin)`
22806
- );
22807
- this.ws.send(JSON.stringify(connectFrame));
22808
- }
22809
- scheduleReconnect() {
22810
- if (!this.shouldReconnect) return;
22811
- if (this.reconnectTimer) return;
22812
- this.reconnectTimer = setTimeout(() => {
22813
- this.reconnectTimer = null;
22814
- this.doConnect().catch(() => {
22815
- });
22816
- }, this.reconnectBackoff);
22817
- this.reconnectBackoff = Math.min(
22818
- this.reconnectBackoff * 2,
22819
- MAX_RECONNECT_BACKOFF
22820
- );
22821
- }
22822
- /**
22823
- * Disconnect from the OpenClaw gateway.
22824
- */
22825
- disconnect() {
22826
- this.shouldReconnect = false;
22827
- if (this.reconnectTimer) {
22828
- clearTimeout(this.reconnectTimer);
22829
- this.reconnectTimer = null;
22830
- }
22831
- if (this.ws) {
22832
- this.ws.close();
22833
- this.ws = null;
22834
- this._connected = false;
22835
- this._handshakeComplete = false;
22836
- this.rejectAllPending(new Error("Client disconnected"));
22837
- }
22838
- }
22839
- /**
22840
- * Get the current gateway configuration.
22841
- */
22842
- async configGet() {
22843
- return this.call("config.get", {});
22844
- }
22845
- /**
22846
- * Patch the gateway configuration.
22847
- */
22848
- async configPatch(patch, baseHash) {
22849
- return this.call("config.patch", { patch, baseHash });
22850
- }
22851
- /**
22852
- * List all agents known to the gateway.
22853
- */
22854
- async agentsList() {
22855
- return this.call("agents.list", {});
22856
- }
22857
- /**
22858
- * Send a chat message to an agent.
22859
- */
22860
- async chatSend(message, agentId) {
22861
- return this.call("chat.send", { message, agentId });
22862
- }
22863
- /**
22864
- * Get chat history for an agent.
22865
- */
22866
- async chatHistory(agentId) {
22867
- return this.call("chat.history", { agentId });
22868
- }
22869
- /**
22870
- * Get a file from an agent's workspace.
22871
- */
22872
- async agentFilesGet(agentId, name) {
22873
- return this.call("agents.files.get", { agentId, name });
22874
- }
22875
- /**
22876
- * Set (write) a file in an agent's workspace.
22877
- */
22878
- async agentFilesSet(agentId, name, content) {
22879
- return this.call("agents.files.set", { agentId, name, content });
22880
- }
22881
- /**
22882
- * Create a new agent.
22883
- */
22884
- async agentsCreate(name, workspace) {
22885
- return this.call("agents.create", { name, workspace });
22886
- }
22887
- /**
22888
- * Update an existing agent.
22889
- */
22890
- async agentsUpdate(agentId, patch) {
22891
- return this.call("agents.update", { agentId, ...patch });
22892
- }
22893
- /**
22894
- * Delete an agent.
22895
- */
22896
- async agentsDelete(agentId) {
22897
- return this.call("agents.delete", { agentId });
22898
- }
22899
- /**
22900
- * List cron jobs.
22901
- */
22902
- async cronList(params) {
22903
- return this.call("cron.list", params ?? {});
22904
- }
22905
- /**
22906
- * Add a cron job.
22907
- */
22908
- async cronAdd(params) {
22909
- return this.call("cron.add", params);
22910
- }
22911
- /**
22912
- * Update a cron job.
22913
- */
22914
- async cronUpdate(id, patch) {
22915
- return this.call("cron.update", { id, ...patch });
22916
- }
22917
- /**
22918
- * Remove a cron job.
22919
- */
22920
- async cronRemove(id) {
22921
- return this.call("cron.remove", { id });
22922
- }
22923
- /**
22924
- * Run a cron job immediately.
22925
- */
22926
- async cronRun(id, mode) {
22927
- return this.call("cron.run", { id, ...mode ? { mode } : {} });
22928
- }
22929
- /**
22930
- * Get skills status for an agent (or all agents).
22931
- */
22932
- async skillsStatus(agentId) {
22933
- return this.call("skills.status", agentId ? { agentId } : {});
22934
- }
22935
- /**
22936
- * Update skills configuration.
22937
- */
22938
- async skillsUpdate(params) {
22939
- return this.call("skills.update", params);
22940
- }
22941
- /**
22942
- * Get the tool catalog for an agent (or all agents).
22943
- */
22944
- async toolsCatalog(agentId) {
22945
- return this.call("tools.catalog", agentId ? { agentId } : {});
22946
- }
22947
- /**
22948
- * List available models.
22949
- */
22950
- async modelsList() {
22951
- return this.call("models.list", {});
22952
- }
22953
- /**
22954
- * Subscribe to OpenClaw events. The handler receives all events.
22955
- */
22956
- subscribeEvents(handler) {
22957
- this.eventHandlers.push(handler);
22958
- return () => {
22959
- this.eventHandlers = this.eventHandlers.filter((h) => h !== handler);
22960
- };
22961
- }
22962
- // --- Internal ---
22963
- async call(method, params) {
22964
- if (!this.ws || !this._connected || !this._handshakeComplete) {
22965
- throw new Error("Not connected to OpenClaw gateway");
22966
- }
22967
- const id = `rpc_${++this.callCounter}_${Date.now()}`;
22968
- return new Promise((resolve, reject) => {
22969
- const timer = setTimeout(() => {
22970
- this.pendingCalls.delete(id);
22971
- reject(new Error(`RPC call ${method} timed out after ${RPC_TIMEOUT}ms`));
22972
- }, RPC_TIMEOUT);
22973
- this.pendingCalls.set(id, { resolve, reject, timer });
22974
- const frame = { type: "req", id, method, params };
22975
- this.ws.send(JSON.stringify(frame));
22976
- });
22977
- }
22978
- handleResponse(frame) {
22979
- const pending = this.pendingCalls.get(frame.id);
22980
- if (!pending) return;
22981
- clearTimeout(pending.timer);
22982
- this.pendingCalls.delete(frame.id);
22983
- if (!frame.ok || frame.error) {
22984
- pending.reject(
22985
- new Error(
22986
- `RPC error ${frame.error?.code ?? "unknown"}: ${frame.error?.message ?? "Unknown error"}`
22987
- )
22988
- );
22989
- } else {
22990
- pending.resolve(frame.payload);
22991
- }
22992
- }
22993
- handleEvent(frame) {
22994
- const event = {
22995
- type: "event",
22996
- name: frame.event,
22997
- data: frame.payload ?? {}
22998
- };
22999
- for (const handler of this.eventHandlers) {
23000
- try {
23001
- handler(event);
23002
- } catch (err) {
23003
- console.error("[claw] Event handler error:", err);
23004
- }
23005
- }
23006
- }
23007
- rejectAllPending(error46) {
23008
- for (const [id, pending] of this.pendingCalls) {
23009
- clearTimeout(pending.timer);
23010
- pending.reject(error46);
23011
- this.pendingCalls.delete(id);
23012
- }
23013
- }
23014
- };
23015
-
23016
- // src/sync/discovery.ts
23017
- async function agentDiscovery(rpc, apiUrl, instanceId, token) {
23018
- const result = await rpc.agentsList();
23019
- console.log(
23020
- `[claw] agents.list returned ${result.agents?.length ?? 0} agents (default=${result.defaultId})`
23021
- );
23022
- const agents = (result.agents ?? []).map((agent) => ({
23023
- name: agent.id,
23024
- // OpenClaw agent id IS the agent key/name
23025
- isDefault: agent.id === result.defaultId
23026
- }));
23027
- const res = await fetch(
23028
- `${apiUrl}/api/claw/instances/${instanceId}/sync-agents`,
23029
- {
23030
- method: "POST",
23031
- headers: {
23032
- "Content-Type": "application/json",
23033
- Authorization: `Bearer ${token}`
23034
- },
23035
- body: JSON.stringify({ agents })
23036
- }
23037
- );
23038
- if (!res.ok) {
23039
- const body = await res.text().catch(() => "");
23040
- throw new Error(
23041
- `Agent discovery sync failed: ${res.status} ${res.statusText} \u2014 ${body}`
23042
- );
23043
- }
23044
- const syncResult = await res.json();
23045
- console.log(
23046
- `[claw] Agent discovery: ${syncResult.created} created, ${syncResult.deleted} deleted`
23047
- );
23048
- return syncResult;
23049
- }
23050
-
23051
- // src/sync/events.ts
23052
- import os16 from "os";
23053
- import path17 from "path";
23054
-
23055
- // src/sync/queue.ts
23056
- import fs14 from "fs/promises";
23057
- import os15 from "os";
23058
- import path16 from "path";
23059
- var MAX_FILE_SIZE = 5e8;
23060
- var PersistentEventQueue = class {
23061
- filePath;
23062
- constructor(customPath) {
23063
- this.filePath = customPath ?? path16.join(os15.homedir(), ".workle", "pending-events.jsonl");
23064
- }
23065
- /**
23066
- * Append a single entry to the queue file.
23067
- */
23068
- async append(entry) {
23069
- await this.ensureDir();
23070
- const currentSize = await this.size();
23071
- if (currentSize > MAX_FILE_SIZE) {
23072
- await this.evictOldestHalf();
23073
- }
23074
- const line = JSON.stringify(entry) + "\n";
23075
- await fs14.appendFile(this.filePath, line, "utf-8");
23076
- }
23077
- /**
23078
- * Read and return all entries in chronological order.
23079
- */
23080
- async replay() {
23081
- let raw;
23082
- try {
23083
- raw = await fs14.readFile(this.filePath, "utf-8");
23084
- } catch {
23085
- return [];
23086
- }
23087
- const lines = raw.split("\n").filter((l) => l.trim().length > 0);
23088
- const entries = [];
23089
- for (const line of lines) {
23090
- try {
23091
- entries.push(JSON.parse(line));
23092
- } catch {
23093
- }
23094
- }
23095
- return entries;
23096
- }
23097
- /**
23098
- * Remove the first `upToIndex` entries from the file (0-based exclusive).
23099
- * E.g., truncate(3) removes entries at index 0, 1, 2.
23100
- */
23101
- async truncate(upToIndex) {
23102
- if (upToIndex <= 0) return;
23103
- let raw;
23104
- try {
23105
- raw = await fs14.readFile(this.filePath, "utf-8");
23106
- } catch {
23107
- return;
23108
- }
23109
- const lines = raw.split("\n").filter((l) => l.trim().length > 0);
23110
- const remaining = lines.slice(upToIndex);
23111
- if (remaining.length === 0) {
23112
- await fs14.writeFile(this.filePath, "", "utf-8");
23113
- } else {
23114
- await fs14.writeFile(this.filePath, remaining.join("\n") + "\n", "utf-8");
23115
- }
23116
- }
23117
- /**
23118
- * Return the current file size in bytes, or 0 if the file does not exist.
23119
- */
23120
- async size() {
23121
- try {
23122
- const stats = await fs14.stat(this.filePath);
23123
- return stats.size;
23124
- } catch {
23125
- return 0;
23126
- }
23127
- }
23128
- // --- Internal ---
23129
- async ensureDir() {
23130
- const dir = path16.dirname(this.filePath);
23131
- await fs14.mkdir(dir, { recursive: true });
23132
- }
23133
- /**
23134
- * Evict the oldest half of entries when the file exceeds the size cap.
23135
- */
23136
- async evictOldestHalf() {
23137
- let raw;
23138
- try {
23139
- raw = await fs14.readFile(this.filePath, "utf-8");
23140
- } catch {
23141
- return;
23142
- }
23143
- const lines = raw.split("\n").filter((l) => l.trim().length > 0);
23144
- const halfIndex = Math.ceil(lines.length / 2);
23145
- const remaining = lines.slice(halfIndex);
23146
- if (remaining.length === 0) {
23147
- await fs14.writeFile(this.filePath, "", "utf-8");
23148
- } else {
23149
- await fs14.writeFile(this.filePath, remaining.join("\n") + "\n", "utf-8");
23150
- }
23151
- console.log(
23152
- `[claw] Queue size exceeded ${MAX_FILE_SIZE} bytes. Evicted ${halfIndex} oldest entries.`
23153
- );
23154
- }
23155
- };
23156
-
23157
- // src/sync/events.ts
23158
- var WORKLE_HOME7 = path17.join(os16.homedir(), ".workle");
23159
- var EVENT_TYPE_MAP = {
23160
- "agent.run": "agent.started",
23161
- "agent.run.complete": "agent.completed",
23162
- tool: "tool.executed",
23163
- "tool.error": "tool.errored",
23164
- turn: "agent.turn",
23165
- "turn.complete": "agent.turn.complete",
23166
- "session.start": "session.lifecycle",
23167
- "session.end": "session.lifecycle",
23168
- "session.pause": "session.lifecycle",
23169
- "session.resume": "session.lifecycle",
23170
- "config.changed": "config.synced",
23171
- "config.reload": "config.synced"
23172
- };
23173
- function mapOpenClawEvent(event, instanceId) {
23174
- const eventType = EVENT_TYPE_MAP[event.name];
23175
- if (!eventType) return null;
23176
- const agentId = typeof event.data.agentId === "string" ? event.data.agentId : void 0;
23177
- const summary = typeof event.data.summary === "string" ? event.data.summary : void 0;
23178
- return {
23179
- eventType,
23180
- subjectType: agentId ? "claw.agent" : "claw.instance",
23181
- subjectId: agentId ?? instanceId,
23182
- summary,
23183
- actorType: "device",
23184
- actorId: `claw_${instanceId}`,
23185
- metadata: {
23186
- ...event.data,
23187
- clawInstanceId: instanceId,
23188
- sourceEvent: event.name,
23189
- occurredAt: (/* @__PURE__ */ new Date()).toISOString()
23190
- }
23191
- };
23192
- }
23193
- var sharedQueues = /* @__PURE__ */ new Map();
23194
- function getQueue(instanceId) {
23195
- const queueKey = instanceId.replace(/[^a-zA-Z0-9_-]/g, "_");
23196
- const existing = sharedQueues.get(queueKey);
23197
- if (existing) return existing;
23198
- const queue = new PersistentEventQueue(
23199
- path17.join(WORKLE_HOME7, `pending-events-${queueKey}.jsonl`)
23200
- );
23201
- sharedQueues.set(queueKey, queue);
23202
- return queue;
23203
- }
23204
- async function deliverPayload(endpoint, token, payload) {
23205
- try {
23206
- const res = await fetch(endpoint, {
23207
- method: "POST",
23208
- headers: {
23209
- "Content-Type": "application/json",
23210
- Authorization: `Bearer ${token}`
23211
- },
23212
- body: JSON.stringify(payload)
23213
- });
23214
- return res.ok || res.status === 400;
23215
- } catch {
23216
- return false;
23217
- }
23218
- }
23219
- function createEventForwarder(apiUrl, token, instanceId) {
23220
- const endpoint = `${apiUrl}/api/claw/instances/${instanceId}/activity`;
23221
- const queue = getQueue(instanceId);
23222
- return (event) => {
23223
- const payload = mapOpenClawEvent(event, instanceId);
23224
- if (!payload) return;
23225
- const entry = {
23226
- ts: (/* @__PURE__ */ new Date()).toISOString(),
23227
- event: event.name,
23228
- payload,
23229
- instanceId
23230
- };
23231
- void (async () => {
23232
- const success2 = await deliverPayload(endpoint, token, payload);
23233
- if (!success2) {
23234
- await queue.append(entry);
23235
- }
23236
- })();
23237
- };
23238
- }
23239
- async function replayPendingEvents(apiUrl, token, instanceId) {
23240
- const endpoint = `${apiUrl}/api/claw/instances/${instanceId}/activity`;
23241
- const queue = getQueue(instanceId);
23242
- const entries = await queue.replay();
23243
- if (entries.length === 0) return;
23244
- console.log(`[claw] Replaying ${entries.length} pending events...`);
23245
- let deliveredCount = 0;
23246
- for (const entry of entries) {
23247
- const payload = entry.payload;
23248
- const success2 = await deliverPayload(endpoint, token, payload);
23249
- if (success2) {
23250
- deliveredCount++;
23251
- } else {
23252
- break;
23253
- }
23254
- }
23255
- if (deliveredCount > 0) {
23256
- await queue.truncate(deliveredCount);
23257
- console.log(`[claw] Replayed ${deliveredCount}/${entries.length} events`);
23258
- }
23259
- }
23260
-
23261
- // src/sync/service.ts
23262
- var WORKLE_HOME8 = path18.join(os17.homedir(), ".workle");
23263
22248
  function deriveRelayUrl2(apiUrl) {
23264
22249
  const url2 = new URL(apiUrl);
23265
22250
  url2.protocol = url2.protocol === "https:" ? "wss:" : "ws:";
23266
- url2.pathname = "/api/claw/relay";
22251
+ url2.pathname = "/api/local/relay";
23267
22252
  if (url2.hostname !== "localhost") {
23268
22253
  url2.hostname = `relay.${url2.hostname}`;
23269
22254
  }
@@ -23274,9 +22259,7 @@ var SyncService = class {
23274
22259
  this.options = options;
23275
22260
  }
23276
22261
  auth = null;
23277
- rpcClient = null;
23278
22262
  relayClient = null;
23279
- unsubscribeEvents = null;
23280
22263
  unsubscribeRelayMessages = null;
23281
22264
  running = false;
23282
22265
  externalMessageHandler = null;
@@ -23312,30 +22295,14 @@ var SyncService = class {
23312
22295
  */
23313
22296
  async start() {
23314
22297
  if (this.running) {
23315
- console.log("[claw] SyncService already running");
22298
+ console.log("[local] SyncService already running");
23316
22299
  return;
23317
22300
  }
23318
- console.log("[claw] Starting SyncService...");
22301
+ console.log("[local] Starting SyncService...");
23319
22302
  this.auth = await loadAuth();
23320
22303
  console.log(
23321
- `[claw] Authenticated as instance ${this.auth.instanceId}`
22304
+ `[local] Authenticated as instance ${this.auth.instanceId}`
23322
22305
  );
23323
- const { instance, agents } = await this.fetchCloudData();
23324
- console.log(
23325
- `[claw] Fetched ${agents.length} agents for instance "${instance.name}"`
23326
- );
23327
- await this.writeConfigFiles(instance, agents);
23328
- console.log("[claw] Config files written to disk");
23329
- this.rpcClient = new OpenClawRpcClient();
23330
- try {
23331
- await this.rpcClient.connect();
23332
- console.log("[claw] Connected to OpenClaw gateway");
23333
- } catch (err) {
23334
- console.warn(
23335
- "[claw] Could not connect to OpenClaw gateway (is it running?):",
23336
- err
23337
- );
23338
- }
23339
22306
  if (!this.options.localOnly) {
23340
22307
  const relayUrl = this.options.relayUrl ?? deriveRelayUrl2(this.auth.apiUrl);
23341
22308
  this.relayClient = new RelayClient(
@@ -23345,51 +22312,11 @@ var SyncService = class {
23345
22312
  {
23346
22313
  onConnect: () => {
23347
22314
  void (async () => {
23348
- const MAX_RETRIES = 3;
23349
- const RETRY_DELAY_MS = 2e3;
23350
- for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
23351
- try {
23352
- if (!this.auth) break;
23353
- if (!this.rpcClient?.connected) {
23354
- console.log(
23355
- `[claw] RPC client not connected, waiting ${RETRY_DELAY_MS}ms (attempt ${attempt}/${MAX_RETRIES})`
23356
- );
23357
- await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
23358
- if (!this.rpcClient?.connected) continue;
23359
- }
23360
- await agentDiscovery(
23361
- this.rpcClient,
23362
- this.auth.apiUrl,
23363
- this.auth.instanceId,
23364
- this.auth.token
23365
- );
23366
- break;
23367
- } catch (err) {
23368
- console.error(
23369
- `[claw] Agent discovery failed (attempt ${attempt}/${MAX_RETRIES}):`,
23370
- err instanceof Error ? err.message : err
23371
- );
23372
- if (attempt < MAX_RETRIES) {
23373
- await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
23374
- }
23375
- }
23376
- }
23377
- try {
23378
- if (this.auth) {
23379
- await replayPendingEvents(
23380
- this.auth.apiUrl,
23381
- this.auth.token,
23382
- this.auth.instanceId
23383
- );
23384
- }
23385
- } catch (err) {
23386
- console.error("[claw] Event replay on connect failed:", err);
23387
- }
23388
22315
  if (this.reconnectHandler) {
23389
22316
  try {
23390
22317
  await this.reconnectHandler();
23391
22318
  } catch (err) {
23392
- console.error("[claw] Agent config re-sync on reconnect failed:", err);
22319
+ console.error("[local] Agent config re-sync on reconnect failed:", err);
23393
22320
  }
23394
22321
  }
23395
22322
  })();
@@ -23398,200 +22325,29 @@ var SyncService = class {
23398
22325
  );
23399
22326
  try {
23400
22327
  await this.relayClient.connect();
23401
- console.log("[claw] Connected to relay server");
22328
+ console.log("[local] Connected to relay server");
23402
22329
  } catch (err) {
23403
22330
  console.warn(
23404
- "[claw] Could not connect to relay (will retry):",
22331
+ "[local] Could not connect to relay (will retry):",
23405
22332
  err
23406
22333
  );
23407
22334
  }
23408
22335
  this.unsubscribeRelayMessages = this.relayClient.onMessage((msg) => {
23409
- if (msg.type !== "rpc.request") {
23410
- console.log(`[claw] Relay message received: type=${msg.type}`, JSON.stringify(msg).slice(0, 200));
23411
- if (this.externalMessageHandler) {
23412
- this.externalMessageHandler(msg);
23413
- }
23414
- return;
22336
+ console.log(`[local] Relay message received: type=${msg.type}`, JSON.stringify(msg).slice(0, 200));
22337
+ if (this.externalMessageHandler) {
22338
+ this.externalMessageHandler(msg);
23415
22339
  }
23416
- const rpcId = typeof msg.id === "string" ? msg.id : null;
23417
- const method = typeof msg.method === "string" ? msg.method : null;
23418
- const params = msg.params && typeof msg.params === "object" ? msg.params : {};
23419
- if (!rpcId || !method) return;
23420
- void (async () => {
23421
- try {
23422
- if (!this.rpcClient?.connected) {
23423
- throw new Error("OpenClaw gateway is not connected");
23424
- }
23425
- let result;
23426
- switch (method) {
23427
- case "config.get":
23428
- result = await this.rpcClient.configGet();
23429
- break;
23430
- case "agents.list":
23431
- result = await this.rpcClient.agentsList();
23432
- break;
23433
- case "chat.send": {
23434
- const message = typeof params.message === "string" ? params.message : "";
23435
- const agentId = typeof params.agentId === "string" ? params.agentId : typeof params.agentKey === "string" ? params.agentKey : "main";
23436
- if (!message.trim()) {
23437
- throw new Error("Missing chat message");
23438
- }
23439
- result = await this.rpcClient.chatSend(message, agentId);
23440
- break;
23441
- }
23442
- case "chat.abort":
23443
- result = { ok: true };
23444
- break;
23445
- case "config.patch": {
23446
- const patch = params.patch && typeof params.patch === "object" ? params.patch : {};
23447
- const baseHash = typeof params.baseHash === "string" ? params.baseHash : "";
23448
- if (!baseHash) {
23449
- throw new Error("Missing config baseHash");
23450
- }
23451
- result = await this.rpcClient.configPatch(patch, baseHash);
23452
- break;
23453
- }
23454
- case "config.push":
23455
- result = { accepted: true };
23456
- break;
23457
- case "agents.files.get": {
23458
- const agentId = typeof params.agentId === "string" ? params.agentId : "";
23459
- const name = typeof params.name === "string" ? params.name : "";
23460
- if (!agentId || !name) {
23461
- throw new Error("Missing agentId or name");
23462
- }
23463
- result = await this.rpcClient.agentFilesGet(agentId, name);
23464
- break;
23465
- }
23466
- case "agents.files.set": {
23467
- const agentId = typeof params.agentId === "string" ? params.agentId : "";
23468
- const name = typeof params.name === "string" ? params.name : "";
23469
- const content = typeof params.content === "string" ? params.content : "";
23470
- if (!agentId || !name) {
23471
- throw new Error("Missing agentId or name");
23472
- }
23473
- result = await this.rpcClient.agentFilesSet(
23474
- agentId,
23475
- name,
23476
- content
23477
- );
23478
- break;
23479
- }
23480
- case "agents.create": {
23481
- const name = typeof params.name === "string" ? params.name : "";
23482
- const workspace = typeof params.workspace === "string" ? params.workspace : "";
23483
- if (!name || !workspace) {
23484
- throw new Error("Missing name or workspace");
23485
- }
23486
- result = await this.rpcClient.agentsCreate(name, workspace);
23487
- break;
23488
- }
23489
- case "agents.update": {
23490
- const agentId = typeof params.agentId === "string" ? params.agentId : "";
23491
- if (!agentId) {
23492
- throw new Error("Missing agentId");
23493
- }
23494
- const { agentId: _, ...patch } = params;
23495
- result = await this.rpcClient.agentsUpdate(agentId, patch);
23496
- break;
23497
- }
23498
- case "agents.delete": {
23499
- const agentId = typeof params.agentId === "string" ? params.agentId : "";
23500
- if (!agentId) {
23501
- throw new Error("Missing agentId");
23502
- }
23503
- result = await this.rpcClient.agentsDelete(agentId);
23504
- break;
23505
- }
23506
- case "cron.list":
23507
- result = await this.rpcClient.cronList(params);
23508
- break;
23509
- case "cron.add":
23510
- result = await this.rpcClient.cronAdd(params);
23511
- break;
23512
- case "cron.update": {
23513
- const id = typeof params.id === "string" ? params.id : "";
23514
- if (!id) {
23515
- throw new Error("Missing cron id");
23516
- }
23517
- const { id: _cronId, ...cronPatch } = params;
23518
- result = await this.rpcClient.cronUpdate(id, cronPatch);
23519
- break;
23520
- }
23521
- case "cron.remove": {
23522
- const id = typeof params.id === "string" ? params.id : "";
23523
- if (!id) {
23524
- throw new Error("Missing cron id");
23525
- }
23526
- result = await this.rpcClient.cronRemove(id);
23527
- break;
23528
- }
23529
- case "cron.run": {
23530
- const id = typeof params.id === "string" ? params.id : "";
23531
- if (!id) {
23532
- throw new Error("Missing cron id");
23533
- }
23534
- const mode = typeof params.mode === "string" ? params.mode : void 0;
23535
- result = await this.rpcClient.cronRun(id, mode);
23536
- break;
23537
- }
23538
- case "skills.status": {
23539
- const agentId = typeof params.agentId === "string" ? params.agentId : void 0;
23540
- result = await this.rpcClient.skillsStatus(agentId);
23541
- break;
23542
- }
23543
- case "skills.update":
23544
- result = await this.rpcClient.skillsUpdate(params);
23545
- break;
23546
- case "tools.catalog": {
23547
- const agentId = typeof params.agentId === "string" ? params.agentId : void 0;
23548
- result = await this.rpcClient.toolsCatalog(agentId);
23549
- break;
23550
- }
23551
- case "models.list":
23552
- result = await this.rpcClient.modelsList();
23553
- break;
23554
- default:
23555
- throw new Error(`Unsupported RPC method: ${method}`);
23556
- }
23557
- this.relayClient?.send({
23558
- type: "rpc.response",
23559
- id: rpcId,
23560
- result
23561
- });
23562
- } catch (err) {
23563
- this.relayClient?.send({
23564
- type: "rpc.response",
23565
- id: rpcId,
23566
- error: {
23567
- code: "rpc_error",
23568
- message: err instanceof Error ? err.message : String(err)
23569
- }
23570
- });
23571
- }
23572
- })();
23573
22340
  });
23574
22341
  }
23575
- const forwarder = createEventForwarder(
23576
- this.auth.apiUrl,
23577
- this.auth.token,
23578
- this.auth.instanceId
23579
- );
23580
- this.unsubscribeEvents = this.rpcClient.subscribeEvents(forwarder);
23581
- console.log("[claw] Event forwarding registered");
23582
22342
  this.running = true;
23583
- console.log("[claw] SyncService started");
22343
+ console.log("[local] SyncService started");
23584
22344
  }
23585
22345
  /**
23586
22346
  * Gracefully stop the sync service.
23587
22347
  */
23588
22348
  stop() {
23589
22349
  if (!this.running) return;
23590
- console.log("[claw] Stopping SyncService...");
23591
- if (this.unsubscribeEvents) {
23592
- this.unsubscribeEvents();
23593
- this.unsubscribeEvents = null;
23594
- }
22350
+ console.log("[local] Stopping SyncService...");
23595
22351
  if (this.unsubscribeRelayMessages) {
23596
22352
  this.unsubscribeRelayMessages();
23597
22353
  this.unsubscribeRelayMessages = null;
@@ -23600,54 +22356,16 @@ var SyncService = class {
23600
22356
  this.relayClient.disconnect();
23601
22357
  this.relayClient = null;
23602
22358
  }
23603
- if (this.rpcClient) {
23604
- this.rpcClient.disconnect();
23605
- this.rpcClient = null;
23606
- }
23607
22359
  this.running = false;
23608
- console.log("[claw] SyncService stopped");
23609
- }
23610
- // --- Internal ---
23611
- async fetchCloudData() {
23612
- if (!this.auth) throw new Error("Not authenticated");
23613
- const res = await fetch(
23614
- `${this.auth.apiUrl}/api/claw/instances/${this.auth.instanceId}/sync`,
23615
- {
23616
- headers: {
23617
- Authorization: `Bearer ${this.auth.token}`,
23618
- "Content-Type": "application/json"
23619
- }
23620
- }
23621
- );
23622
- if (!res.ok) {
23623
- throw new Error(
23624
- `Failed to fetch cloud data: ${res.status} ${res.statusText}`
23625
- );
23626
- }
23627
- const data = await res.json();
23628
- return data;
23629
- }
23630
- async writeConfigFiles(instance, agents) {
23631
- const gatewayConfig = generateGatewayConfig(instance, agents);
23632
- const configPath = path18.join(WORKLE_HOME8, "openclaw.json");
23633
- await fs15.mkdir(WORKLE_HOME8, { recursive: true });
23634
- await fs15.writeFile(configPath, JSON.stringify(gatewayConfig, null, 2), "utf-8");
23635
- await Promise.all(
23636
- agents.map(async (agent) => {
23637
- await writeSoulMd(agent.agentKey, agent.soulMd);
23638
- await writeAgentsMd(agent.agentKey, agent.agentsMd);
23639
- await writeIdentityMd(agent.agentKey, agent.identityMd);
23640
- await writeHeartbeatMd(agent.agentKey, agent.heartbeatMd);
23641
- })
23642
- );
22360
+ console.log("[local] SyncService stopped");
23643
22361
  }
23644
22362
  };
23645
22363
 
23646
22364
  // src/cli.ts
23647
- var WORKLE_HOME9 = path19.join(os18.homedir(), ".workle");
23648
- var AUTH_FILE2 = path19.join(WORKLE_HOME9, "auth.json");
23649
- var LAUNCH_AGENTS_DIR2 = path19.join(os18.homedir(), "Library", "LaunchAgents");
23650
- var PLIST_LABEL = "com.workle.claw";
22365
+ var WORKLE_HOME4 = path10.join(os7.homedir(), ".workle");
22366
+ var AUTH_FILE2 = path10.join(WORKLE_HOME4, "auth.json");
22367
+ var LAUNCH_AGENTS_DIR2 = path10.join(os7.homedir(), "Library", "LaunchAgents");
22368
+ var PLIST_LABEL = "com.workle.local";
23651
22369
  var color = {
23652
22370
  green: (s) => `\x1B[32m${s}\x1B[0m`,
23653
22371
  red: (s) => `\x1B[31m${s}\x1B[0m`,
@@ -23659,7 +22377,7 @@ var color = {
23659
22377
  function readPkgVersion() {
23660
22378
  try {
23661
22379
  const pkgPath = new URL("../package.json", import.meta.url);
23662
- const raw = readFileSync(pkgPath, "utf-8");
22380
+ const raw = readFileSync2(pkgPath, "utf-8");
23663
22381
  return JSON.parse(raw).version;
23664
22382
  } catch {
23665
22383
  return "0.0.0";
@@ -23684,16 +22402,16 @@ function pairingErrorMessage(status, fallback) {
23684
22402
  return fallback;
23685
22403
  }
23686
22404
  async function saveAuth(data) {
23687
- await setupClawDirectory();
22405
+ await setupLocalDirectory();
23688
22406
  const authData = {
23689
22407
  instanceId: data.instanceId,
23690
22408
  token: data.token,
23691
22409
  apiUrl: data.apiUrl
23692
22410
  };
23693
- await fs16.writeFile(AUTH_FILE2, JSON.stringify(authData, null, 2), {
22411
+ await fs7.writeFile(AUTH_FILE2, JSON.stringify(authData, null, 2), {
23694
22412
  mode: 384
23695
22413
  });
23696
- await fs16.chmod(AUTH_FILE2, 384).catch(() => {
22414
+ await fs7.chmod(AUTH_FILE2, 384).catch(() => {
23697
22415
  });
23698
22416
  console.log("");
23699
22417
  console.log(color.green("\u2713 Paired successfully!"));
@@ -23710,7 +22428,7 @@ async function saveAuth(data) {
23710
22428
  console.log(` ${color.cyan("npx @getworkle/cli doctor")} Run health checks`);
23711
22429
  }
23712
22430
  async function exchangeBrowserCode(code, codeVerifier, apiUrl) {
23713
- const res = await fetch(`${apiUrl}/api/claw/pair/exchange`, {
22431
+ const res = await fetch(`${apiUrl}/api/local/pair/exchange`, {
23714
22432
  method: "POST",
23715
22433
  headers: { "Content-Type": "application/json" },
23716
22434
  body: JSON.stringify({ code, codeVerifier })
@@ -23728,7 +22446,7 @@ function browserAuth(apiUrl) {
23728
22446
  const codeVerifier = createPairingCodeVerifier();
23729
22447
  const codeChallenge = createPairingCodeChallenge(codeVerifier);
23730
22448
  let settled = false;
23731
- const server = http2.createServer((req, res) => {
22449
+ const server = http.createServer((req, res) => {
23732
22450
  void (async () => {
23733
22451
  const url2 = new URL(req.url ?? "/", "http://127.0.0.1");
23734
22452
  if (url2.pathname !== "/callback") {
@@ -23758,7 +22476,7 @@ function browserAuth(apiUrl) {
23758
22476
  res.end(
23759
22477
  [
23760
22478
  "<!DOCTYPE html>",
23761
- "<html><head><title>Workle Claw</title>",
22479
+ "<html><head><title>Workle Local</title>",
23762
22480
  "<style>body{font-family:system-ui;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;background:#fafafa;color:#111}",
23763
22481
  ".card{text-align:center;padding:3rem;border-radius:12px;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.1)}",
23764
22482
  "h1{font-size:1.5rem;margin:0 0 .5rem}p{color:#666;margin:0}</style></head>",
@@ -23775,7 +22493,7 @@ function browserAuth(apiUrl) {
23775
22493
  res.end(
23776
22494
  [
23777
22495
  "<!DOCTYPE html>",
23778
- "<html><head><title>Workle Claw</title>",
22496
+ "<html><head><title>Workle Local</title>",
23779
22497
  "<style>body{font-family:system-ui;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;background:#fafafa;color:#111}",
23780
22498
  ".card{text-align:center;padding:3rem;border-radius:12px;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.1)}",
23781
22499
  "h1{font-size:1.5rem;margin:0 0 .5rem}p{color:#666;margin:0 0 1rem}</style></head>",
@@ -23807,12 +22525,12 @@ function browserAuth(apiUrl) {
23807
22525
  return;
23808
22526
  }
23809
22527
  const port = addr.port;
23810
- const pairUrl = `${apiUrl}/claw/pair?port=${port}&state=${encodeURIComponent(callbackState)}&codeChallenge=${encodeURIComponent(codeChallenge)}`;
22528
+ const pairUrl = `${apiUrl}/local/pair?port=${port}&state=${encodeURIComponent(callbackState)}&codeChallenge=${encodeURIComponent(codeChallenge)}`;
23811
22529
  console.log(color.dim("Opening browser to authenticate..."));
23812
22530
  console.log(color.dim(` ${pairUrl}
23813
22531
  `));
23814
22532
  try {
23815
- execSync2(`open "${pairUrl}"`, { stdio: "ignore" });
22533
+ execSync(`open "${pairUrl}"`, { stdio: "ignore" });
23816
22534
  } catch {
23817
22535
  console.log(color.yellow("Could not open browser automatically."));
23818
22536
  console.log("Open this URL in your browser:\n");
@@ -23841,7 +22559,7 @@ function browserAuth(apiUrl) {
23841
22559
  }
23842
22560
  async function tokenAuth(setupToken, apiUrl) {
23843
22561
  console.log(color.dim("Activating with Workle..."));
23844
- const res = await fetch(`${apiUrl}/api/claw/activate`, {
22562
+ const res = await fetch(`${apiUrl}/api/local/activate`, {
23845
22563
  method: "POST",
23846
22564
  headers: { "Content-Type": "application/json" },
23847
22565
  body: JSON.stringify({ setupToken })
@@ -23882,7 +22600,7 @@ program2.command("setup").alias("pair").description("Pair this Mac with a Workle
23882
22600
  process.exit(1);
23883
22601
  }
23884
22602
  });
23885
- program2.command("start").description("Start the Workle Claw sync service").option("-d, --daemon", "Run as a background daemon via launchd").action(async (opts) => {
22603
+ program2.command("start").description("Start the Workle Local sync service").option("-d, --daemon", "Run as a background daemon via launchd").action(async (opts) => {
23886
22604
  if (opts.daemon) {
23887
22605
  console.log(color.dim("Installing launchd service..."));
23888
22606
  const stagedCliPath = await stageCliForDaemon(process.argv[1] ?? "");
@@ -23891,12 +22609,12 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23891
22609
  "start"
23892
22610
  ]);
23893
22611
  try {
23894
- execSync2(`launchctl load -w "${plistPath}"`, { stdio: "inherit" });
22612
+ execSync(`launchctl load -w "${plistPath}"`, { stdio: "inherit" });
23895
22613
  console.log(color.green("\u2713 Daemon started"));
23896
22614
  console.log("");
23897
22615
  console.log(` Service: ${color.dim(PLIST_LABEL)}`);
23898
22616
  console.log(` Plist: ${color.dim(plistPath)}`);
23899
- console.log(` Logs: ${color.dim(path19.join(WORKLE_HOME9, "logs/"))}`);
22617
+ console.log(` Logs: ${color.dim(path10.join(WORKLE_HOME4, "logs/"))}`);
23900
22618
  console.log("");
23901
22619
  console.log(
23902
22620
  `To stop: ${color.cyan("npx @getworkle/cli stop")}`
@@ -23908,36 +22626,19 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23908
22626
  }
23909
22627
  return;
23910
22628
  }
23911
- console.log(color.bold("Workle Claw"));
22629
+ console.log(color.bold("Workle Local"));
23912
22630
  console.log(color.dim("Starting sync service... (Ctrl+C to stop)\n"));
23913
- const processManager = new ProcessManager();
23914
22631
  const syncService = new SyncService();
23915
22632
  let agentService = null;
23916
- let weSpawnedGateway = false;
23917
22633
  const shutdown = () => {
23918
22634
  console.log("\n" + color.dim("Shutting down..."));
23919
22635
  agentService?.stop();
23920
22636
  syncService.stop();
23921
- if (weSpawnedGateway) {
23922
- void processManager.stop().then(() => {
23923
- process.exit(0);
23924
- });
23925
- } else {
23926
- process.exit(0);
23927
- }
22637
+ process.exit(0);
23928
22638
  };
23929
22639
  process.on("SIGINT", shutdown);
23930
22640
  process.on("SIGTERM", shutdown);
23931
22641
  try {
23932
- const alreadyRunning = await processManager.isHealthy();
23933
- if (alreadyRunning) {
23934
- console.log(
23935
- color.dim("OpenClaw gateway already running on :18789 \u2014 skipping spawn")
23936
- );
23937
- } else {
23938
- await processManager.spawn();
23939
- weSpawnedGateway = true;
23940
- }
23941
22642
  await syncService.start();
23942
22643
  try {
23943
22644
  agentService = await createAgentService();
@@ -23962,41 +22663,26 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23962
22663
  )
23963
22664
  );
23964
22665
  syncService.stop();
23965
- if (weSpawnedGateway) {
23966
- await processManager.stop();
23967
- }
23968
22666
  process.exit(1);
23969
22667
  }
23970
22668
  });
23971
- program2.command("stop").description("Stop the Workle Claw daemon").action(async () => {
23972
- const plistPath = path19.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
22669
+ program2.command("stop").description("Stop the Workle Local daemon").action(async () => {
22670
+ const plistPath = path10.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
23973
22671
  try {
23974
- execSync2(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
22672
+ execSync(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
23975
22673
  console.log(color.green("\u2713 Daemon stopped"));
23976
22674
  } catch {
23977
22675
  console.log(color.dim("No launchd service loaded."));
23978
22676
  }
23979
- const pidFile = path19.join(WORKLE_HOME9, "openclaw.pid");
23980
- try {
23981
- const pidStr = await fs16.readFile(pidFile, "utf-8");
23982
- const pid = parseInt(pidStr.trim(), 10);
23983
- if (!isNaN(pid)) {
23984
- process.kill(pid, "SIGTERM");
23985
- await fs16.unlink(pidFile).catch(() => {
23986
- });
23987
- console.log(color.dim(`Sent SIGTERM to OpenClaw (PID: ${pid})`));
23988
- }
23989
- } catch {
23990
- }
23991
22677
  });
23992
- program2.command("doctor").description("Run health checks for the Workle Claw environment").action(async () => {
22678
+ program2.command("doctor").description("Run health checks for the Workle Local environment").action(async () => {
23993
22679
  const checks = await runDoctor();
23994
22680
  const failures = checks.filter((c) => c.status === "fail");
23995
22681
  process.exit(failures.length > 0 ? 1 : 0);
23996
22682
  });
23997
22683
  program2.command("status").description("Show connection state and instance info").action(async () => {
23998
22684
  console.log("");
23999
- console.log(color.bold(" Workle Claw Status"));
22685
+ console.log(color.bold(" Workle Local Status"));
24000
22686
  console.log("");
24001
22687
  try {
24002
22688
  const auth = await loadAuth();
@@ -24008,24 +22694,11 @@ program2.command("status").description("Show connection state and instance info"
24008
22694
  console.log("");
24009
22695
  return;
24010
22696
  }
22697
+ const plistPath = path10.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
24011
22698
  try {
24012
- const controller = new AbortController();
24013
- const timer = setTimeout(() => controller.abort(), 3e3);
24014
- const res = await fetch("http://127.0.0.1:18789/", {
24015
- signal: controller.signal
24016
- });
24017
- clearTimeout(timer);
24018
- console.log(
24019
- ` Gateway: ${color.green("reachable")} (HTTP ${res.status})`
24020
- );
24021
- } catch {
24022
- console.log(` Gateway: ${color.yellow("unreachable")}`);
24023
- }
24024
- const plistPath = path19.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
24025
- try {
24026
- await fs16.access(plistPath);
22699
+ await fs7.access(plistPath);
24027
22700
  try {
24028
- const output = execSync2(`launchctl list ${PLIST_LABEL} 2>&1`, {
22701
+ const output = execSync(`launchctl list ${PLIST_LABEL} 2>&1`, {
24029
22702
  encoding: "utf-8"
24030
22703
  });
24031
22704
  if (output.includes(PLIST_LABEL)) {
@@ -24041,15 +22714,15 @@ program2.command("status").description("Show connection state and instance info"
24041
22714
  }
24042
22715
  console.log("");
24043
22716
  });
24044
- program2.command("logs").description("Tail the Workle Claw log files").option("-n, --lines <count>", "Number of lines to show", "50").option("-f, --follow", "Follow log output").action((opts) => {
22717
+ program2.command("logs").description("Tail the Workle Local log files").option("-n, --lines <count>", "Number of lines to show", "50").option("-f, --follow", "Follow log output").action((opts) => {
24045
22718
  const lineCount = parseInt(opts.lines, 10);
24046
22719
  if (!Number.isFinite(lineCount) || lineCount < 1) {
24047
22720
  console.error(color.red("Error: --lines must be a positive integer."));
24048
22721
  process.exit(1);
24049
22722
  }
24050
22723
  const logFiles = [
24051
- path19.join(WORKLE_HOME9, "openclaw.log"),
24052
- path19.join(WORKLE_HOME9, "logs", "stderr.log")
22724
+ path10.join(WORKLE_HOME4, "logs", "stdout.log"),
22725
+ path10.join(WORKLE_HOME4, "logs", "stderr.log")
24053
22726
  ];
24054
22727
  const args = ["-n", String(lineCount)];
24055
22728
  if (opts.follow) args.push("-f");
@@ -24057,7 +22730,7 @@ program2.command("logs").description("Tail the Workle Claw log files").option("-
24057
22730
  const result = spawnSync("tail", args, { stdio: "inherit" });
24058
22731
  if (result.error && !opts.follow) {
24059
22732
  console.error(color.red(`Failed to read logs: ${result.error.message}`));
24060
- console.error(`Expected log files at: ${WORKLE_HOME9}/logs/`);
22733
+ console.error(`Expected log files at: ${WORKLE_HOME4}/logs/`);
24061
22734
  }
24062
22735
  });
24063
22736
  var agentCmd = program2.command("agent").description("Manage and run Workle AI agents locally");
@@ -24213,12 +22886,12 @@ agentCmd.command("logs [agentId]").description("Tail agent run logs").option("-n
24213
22886
  console.error(color.red("Error: --lines must be a positive integer."));
24214
22887
  process.exit(1);
24215
22888
  }
24216
- const logsDir = path19.join(WORKLE_HOME9, "agents");
22889
+ const logsDir = path10.join(WORKLE_HOME4, "agents");
24217
22890
  let logFile;
24218
22891
  if (agentId) {
24219
- logFile = path19.join(logsDir, agentId, "run.log");
22892
+ logFile = path10.join(logsDir, agentId, "run.log");
24220
22893
  } else {
24221
- logFile = path19.join(logsDir, "*", "run.log");
22894
+ logFile = path10.join(logsDir, "*", "run.log");
24222
22895
  }
24223
22896
  const args = ["-n", String(lineCount)];
24224
22897
  if (opts.follow) args.push("-f");