@getworkle/cli 0.2.12 → 0.3.0

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 +209 -1539
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +8 -22
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
8308
  const { agentDir, prompt, sessionId, maxTurns, permissionMode, model, allowedTools, 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,
@@ -9112,10 +9120,10 @@ function mergeDefs(...defs) {
9112
9120
  function cloneDef(schema) {
9113
9121
  return mergeDefs(schema._zod.def);
9114
9122
  }
9115
- function getElementAtPath(obj, path20) {
9116
- if (!path20)
9123
+ function getElementAtPath(obj, path11) {
9124
+ if (!path11)
9117
9125
  return obj;
9118
- return path20.reduce((acc, key) => acc?.[key], obj);
9126
+ return path11.reduce((acc, key) => acc?.[key], obj);
9119
9127
  }
9120
9128
  function promiseAllObject(promisesObj) {
9121
9129
  const keys = Object.keys(promisesObj);
@@ -9481,11 +9489,11 @@ function aborted(x, startIndex = 0) {
9481
9489
  }
9482
9490
  return false;
9483
9491
  }
9484
- function prefixIssues(path20, issues) {
9492
+ function prefixIssues(path11, issues) {
9485
9493
  return issues.map((iss) => {
9486
9494
  var _a2;
9487
9495
  (_a2 = iss).path ?? (_a2.path = []);
9488
- iss.path.unshift(path20);
9496
+ iss.path.unshift(path11);
9489
9497
  return iss;
9490
9498
  });
9491
9499
  }
@@ -9647,7 +9655,7 @@ function formatError(error46, mapper = (issue2) => issue2.message) {
9647
9655
  }
9648
9656
  function treeifyError(error46, mapper = (issue2) => issue2.message) {
9649
9657
  const result = { errors: [] };
9650
- const processError = (error47, path20 = []) => {
9658
+ const processError = (error47, path11 = []) => {
9651
9659
  var _a2, _b;
9652
9660
  for (const issue2 of error47.issues) {
9653
9661
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -9657,7 +9665,7 @@ function treeifyError(error46, mapper = (issue2) => issue2.message) {
9657
9665
  } else if (issue2.code === "invalid_element") {
9658
9666
  processError({ issues: issue2.issues }, issue2.path);
9659
9667
  } else {
9660
- const fullpath = [...path20, ...issue2.path];
9668
+ const fullpath = [...path11, ...issue2.path];
9661
9669
  if (fullpath.length === 0) {
9662
9670
  result.errors.push(mapper(issue2));
9663
9671
  continue;
@@ -9689,8 +9697,8 @@ function treeifyError(error46, mapper = (issue2) => issue2.message) {
9689
9697
  }
9690
9698
  function toDotPath(_path) {
9691
9699
  const segs = [];
9692
- const path20 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9693
- for (const seg of path20) {
9700
+ const path11 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9701
+ for (const seg of path11) {
9694
9702
  if (typeof seg === "number")
9695
9703
  segs.push(`[${seg}]`);
9696
9704
  else if (typeof seg === "symbol")
@@ -21026,23 +21034,23 @@ function date4(params) {
21026
21034
  config(en_default());
21027
21035
 
21028
21036
  // src/agents/mcp-server.ts
21029
- async function apiGet(apiUrl, path20, headers) {
21030
- const res = await fetch(`${apiUrl}${path20}`, {
21037
+ async function apiGet(apiUrl, path11, headers) {
21038
+ const res = await fetch(`${apiUrl}${path11}`, {
21031
21039
  headers: { ...headers, "Content-Type": "application/json" }
21032
21040
  });
21033
21041
  if (!res.ok) {
21034
- throw new Error(`API GET ${path20} failed: HTTP ${res.status}`);
21042
+ throw new Error(`API GET ${path11} failed: HTTP ${res.status}`);
21035
21043
  }
21036
21044
  return res.json();
21037
21045
  }
21038
- async function apiPost(apiUrl, path20, body, headers) {
21039
- const res = await fetch(`${apiUrl}${path20}`, {
21046
+ async function apiPost(apiUrl, path11, body, headers) {
21047
+ const res = await fetch(`${apiUrl}${path11}`, {
21040
21048
  method: "POST",
21041
21049
  headers: { ...headers, "Content-Type": "application/json" },
21042
21050
  body: JSON.stringify(body)
21043
21051
  });
21044
21052
  if (!res.ok) {
21045
- throw new Error(`API POST ${path20} failed: HTTP ${res.status}`);
21053
+ throw new Error(`API POST ${path11} failed: HTTP ${res.status}`);
21046
21054
  }
21047
21055
  return res.json();
21048
21056
  }
@@ -21063,7 +21071,7 @@ function createWorkleMcpServer(opts) {
21063
21071
  });
21064
21072
  const data = await apiGet(
21065
21073
  apiUrl,
21066
- `/api/claw/instances/${instanceId}/mcp/contacts?${params.toString()}`,
21074
+ `/api/local/instances/${instanceId}/mcp/contacts?${params.toString()}`,
21067
21075
  headers
21068
21076
  );
21069
21077
  return { content: [{ type: "text", text: JSON.stringify(data) }] };
@@ -21081,7 +21089,7 @@ function createWorkleMcpServer(opts) {
21081
21089
  async (input) => {
21082
21090
  const data = await apiPost(
21083
21091
  apiUrl,
21084
- `/api/claw/instances/${instanceId}/mcp/activity`,
21092
+ `/api/local/instances/${instanceId}/mcp/activity`,
21085
21093
  input,
21086
21094
  headers
21087
21095
  );
@@ -21102,7 +21110,7 @@ function createWorkleMcpServer(opts) {
21102
21110
  });
21103
21111
  const data = await apiGet(
21104
21112
  apiUrl,
21105
- `/api/claw/instances/${instanceId}/mcp/documents?${params.toString()}`,
21113
+ `/api/local/instances/${instanceId}/mcp/documents?${params.toString()}`,
21106
21114
  headers
21107
21115
  );
21108
21116
  return { content: [{ type: "text", text: JSON.stringify(data) }] };
@@ -21168,7 +21176,12 @@ var AgentScheduler = class {
21168
21176
  // src/agents/service.ts
21169
21177
  import { randomUUID } from "crypto";
21170
21178
  import fs4 from "fs/promises";
21179
+ import path7 from "path";
21180
+
21181
+ // src/sync/relay.ts
21182
+ import { readFileSync } from "fs";
21171
21183
  import path5 from "path";
21184
+ import { fileURLToPath as fileURLToPath2 } from "url";
21172
21185
 
21173
21186
  // ../../node_modules/ws/wrapper.mjs
21174
21187
  var import_stream = __toESM(require_stream(), 1);
@@ -21182,6 +21195,39 @@ var wrapper_default = import_websocket.default;
21182
21195
  var MAX_BACKOFF = 3e4;
21183
21196
  var INITIAL_BACKOFF = 1e3;
21184
21197
  var MAX_QUEUE_SIZE = 1e3;
21198
+ function readVersionFromJson(pathOrUrl) {
21199
+ try {
21200
+ const raw = readFileSync(pathOrUrl, "utf-8");
21201
+ const parsed = JSON.parse(raw);
21202
+ return typeof parsed.version === "string" ? parsed.version : void 0;
21203
+ } catch {
21204
+ return void 0;
21205
+ }
21206
+ }
21207
+ function readVersionFromNearestPackageJson(entryPath) {
21208
+ let currentDir = path5.dirname(entryPath);
21209
+ const rootDir = path5.parse(currentDir).root;
21210
+ while (true) {
21211
+ const version3 = readVersionFromJson(path5.join(currentDir, "package.json"));
21212
+ if (version3) {
21213
+ return version3;
21214
+ }
21215
+ if (currentDir === rootDir) {
21216
+ return void 0;
21217
+ }
21218
+ currentDir = path5.dirname(currentDir);
21219
+ }
21220
+ }
21221
+ var SYNC_VERSION = readVersionFromJson(new URL("../../package.json", import.meta.url));
21222
+ var AGENT_SDK_VERSION = (() => {
21223
+ try {
21224
+ return readVersionFromNearestPackageJson(
21225
+ fileURLToPath2(import.meta.resolve("@anthropic-ai/claude-agent-sdk"))
21226
+ );
21227
+ } catch {
21228
+ return void 0;
21229
+ }
21230
+ })();
21185
21231
  var RelayClient = class {
21186
21232
  constructor(relayUrl, instanceId, token, options) {
21187
21233
  this.relayUrl = relayUrl;
@@ -21250,7 +21296,7 @@ var RelayClient = class {
21250
21296
  doConnect() {
21251
21297
  return new Promise((resolve, reject) => {
21252
21298
  const url2 = `${this.relayUrl}/${this.instanceId}`;
21253
- console.log(`[claw] Connecting to relay: ${url2}`);
21299
+ console.log(`[local] Connecting to relay: ${url2}`);
21254
21300
  this.ws = new wrapper_default(url2, {
21255
21301
  headers: {
21256
21302
  Authorization: `Bearer ${this.token}`
@@ -21262,7 +21308,9 @@ var RelayClient = class {
21262
21308
  this.backoff = INITIAL_BACKOFF;
21263
21309
  const hello = {
21264
21310
  type: "hello",
21265
- instanceId: this.instanceId
21311
+ instanceId: this.instanceId,
21312
+ ...SYNC_VERSION ? { syncVersion: SYNC_VERSION } : {},
21313
+ ...AGENT_SDK_VERSION ? { agentSdkVersion: AGENT_SDK_VERSION } : {}
21266
21314
  };
21267
21315
  this.ws.send(JSON.stringify(hello));
21268
21316
  this.flushQueue();
@@ -21270,7 +21318,7 @@ var RelayClient = class {
21270
21318
  try {
21271
21319
  this.onConnectCallback();
21272
21320
  } catch (err) {
21273
- console.error("[claw] onConnect callback error:", err);
21321
+ console.error("[local] onConnect callback error:", err);
21274
21322
  }
21275
21323
  }
21276
21324
  if (!resolved) {
@@ -21286,7 +21334,7 @@ var RelayClient = class {
21286
21334
  try {
21287
21335
  handler(msg);
21288
21336
  } catch (err) {
21289
- console.error("[claw] Relay message handler error:", err);
21337
+ console.error("[local] Relay message handler error:", err);
21290
21338
  }
21291
21339
  }
21292
21340
  } catch {
@@ -21296,20 +21344,20 @@ var RelayClient = class {
21296
21344
  this.ws.on("close", (code, reason) => {
21297
21345
  if (closeHandled) return;
21298
21346
  closeHandled = true;
21299
- const reasonStr = reason ? Buffer.from(reason).toString("utf-8") : "";
21347
+ const reasonStr = typeof reason === "string" ? reason : reason instanceof Buffer ? reason.toString("utf-8") : "";
21300
21348
  console.log(
21301
- `[claw] Relay WebSocket closed: code=${code} reason="${reasonStr}"`
21349
+ `[local] Relay WebSocket closed: code=${code} reason="${reasonStr}"`
21302
21350
  );
21303
21351
  this._connected = false;
21304
21352
  this.cleanupWs();
21305
21353
  if (code === 4e3) {
21306
- console.log("[claw] Connection replaced \u2014 not reconnecting");
21354
+ console.log("[local] Connection replaced \u2014 not reconnecting");
21307
21355
  return;
21308
21356
  }
21309
21357
  this.scheduleReconnect();
21310
21358
  });
21311
21359
  this.ws.on("error", (err) => {
21312
- console.error("[claw] Relay WebSocket error:", err.message);
21360
+ console.error("[local] Relay WebSocket error:", err.message);
21313
21361
  this._connected = false;
21314
21362
  if (!resolved) {
21315
21363
  resolved = true;
@@ -21332,12 +21380,12 @@ var RelayClient = class {
21332
21380
  clearTimeout(this.reconnectTimer);
21333
21381
  }
21334
21382
  console.log(
21335
- `[claw] Relay disconnected. Reconnecting in ${this.backoff}ms...`
21383
+ `[local] Relay disconnected. Reconnecting in ${this.backoff}ms...`
21336
21384
  );
21337
21385
  this.reconnectTimer = setTimeout(() => {
21338
21386
  this.reconnectTimer = null;
21339
21387
  this.doConnect().catch((err) => {
21340
- console.error("[claw] Relay reconnect failed:", err);
21388
+ console.error("[local] Relay reconnect failed:", err);
21341
21389
  });
21342
21390
  }, this.backoff);
21343
21391
  const jitter = Math.random() * 0.3 * this.backoff;
@@ -21351,7 +21399,7 @@ var RelayClient = class {
21351
21399
  this.ws.send(JSON.stringify(msg));
21352
21400
  }
21353
21401
  if (queued.length > 0) {
21354
- console.log(`[claw] Flushed ${queued.length} queued messages to relay`);
21402
+ console.log(`[local] Flushed ${queued.length} queued messages to relay`);
21355
21403
  }
21356
21404
  }
21357
21405
  };
@@ -21359,8 +21407,8 @@ var RelayClient = class {
21359
21407
  // src/agents/sessions.ts
21360
21408
  import fs3 from "fs/promises";
21361
21409
  import os4 from "os";
21362
- import path4 from "path";
21363
- var SESSIONS_FILE = path4.join(
21410
+ import path6 from "path";
21411
+ var SESSIONS_FILE = path6.join(
21364
21412
  os4.homedir(),
21365
21413
  ".workle",
21366
21414
  "agent-sessions.json"
@@ -21382,7 +21430,7 @@ async function saveSessionId(agentId, sessionId) {
21382
21430
  } catch {
21383
21431
  }
21384
21432
  map2[agentId] = sessionId;
21385
- await fs3.mkdir(path4.dirname(SESSIONS_FILE), { recursive: true });
21433
+ await fs3.mkdir(path6.dirname(SESSIONS_FILE), { recursive: true });
21386
21434
  await fs3.writeFile(SESSIONS_FILE, JSON.stringify(map2, null, 2), "utf-8");
21387
21435
  }
21388
21436
 
@@ -21407,7 +21455,7 @@ function stringifyProgressValue(value) {
21407
21455
  function deriveRelayUrl(apiUrl) {
21408
21456
  const url2 = new URL(apiUrl);
21409
21457
  url2.protocol = url2.protocol === "https:" ? "wss:" : "ws:";
21410
- url2.pathname = "/api/claw/relay";
21458
+ url2.pathname = "/api/local/relay";
21411
21459
  if (url2.hostname !== "localhost") {
21412
21460
  url2.hostname = `relay.${url2.hostname}`;
21413
21461
  }
@@ -21905,12 +21953,12 @@ var AgentService = class _AgentService {
21905
21953
  if (mdFiles.length === 0) return;
21906
21954
  const files = [];
21907
21955
  for (const filename of mdFiles) {
21908
- const content = await fs4.readFile(path5.join(memoryDir, filename), "utf-8");
21956
+ const content = await fs4.readFile(path7.join(memoryDir, filename), "utf-8");
21909
21957
  files.push({ filename, content });
21910
21958
  }
21911
21959
  const headers = createAuthHeaders(this.token);
21912
21960
  const res = await fetch(
21913
- `${this.apiUrl}/api/claw/instances/${this.instanceId}/runtime/agents/${agentId}/push-memory`,
21961
+ `${this.apiUrl}/api/local/instances/${this.instanceId}/runtime/agents/${agentId}/push-memory`,
21914
21962
  {
21915
21963
  method: "POST",
21916
21964
  headers: { ...headers, "Content-Type": "application/json" },
@@ -22013,171 +22061,18 @@ async function createAgentService() {
22013
22061
  });
22014
22062
  }
22015
22063
 
22016
- // src/legacy/openclaw/process.ts
22017
- import { spawn } from "child_process";
22064
+ // src/lifecycle/doctor.ts
22018
22065
  import fs5 from "fs/promises";
22019
- import http from "http";
22020
22066
  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");
22067
+ import path8 from "path";
22068
+ var WORKLE_HOME2 = path8.join(os5.homedir(), ".workle");
22171
22069
  var MIN_NODE_MAJOR = 22;
22172
22070
  async function runDoctor() {
22173
22071
  const checks = [];
22174
22072
  checks.push(checkNodeVersion());
22175
- checks.push(checkOpenClawInstalled());
22176
- checks.push(await checkClawHome());
22073
+ checks.push(await checkLocalHome());
22177
22074
  checks.push(await checkAuthFile());
22178
- checks.push(await checkConfigFile());
22179
- checks.push(await checkGatewayReachable());
22180
- console.log("\n Workle Claw Doctor\n");
22075
+ console.log("\n Workle Local Doctor\n");
22181
22076
  for (const check2 of checks) {
22182
22077
  const icon = check2.status === "pass" ? "[OK]" : check2.status === "warn" ? "[WARN]" : "[FAIL]";
22183
22078
  console.log(` ${icon} ${check2.name}: ${check2.message}`);
@@ -22207,52 +22102,33 @@ function checkNodeVersion() {
22207
22102
  message: `${process.version} \u2014 Node >= ${MIN_NODE_MAJOR} is required`
22208
22103
  };
22209
22104
  }
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() {
22105
+ async function checkLocalHome() {
22230
22106
  try {
22231
- const stat = await fs6.stat(WORKLE_HOME2);
22107
+ const stat = await fs5.stat(WORKLE_HOME2);
22232
22108
  if (stat.isDirectory()) {
22233
22109
  return {
22234
- name: "Claw home directory",
22110
+ name: "Home directory",
22235
22111
  status: "pass",
22236
22112
  message: WORKLE_HOME2
22237
22113
  };
22238
22114
  }
22239
22115
  return {
22240
- name: "Claw home directory",
22116
+ name: "Home directory",
22241
22117
  status: "fail",
22242
22118
  message: `${WORKLE_HOME2} exists but is not a directory`
22243
22119
  };
22244
22120
  } catch {
22245
22121
  return {
22246
- name: "Claw home directory",
22122
+ name: "Home directory",
22247
22123
  status: "fail",
22248
22124
  message: `${WORKLE_HOME2} does not exist. Run 'workle setup'`
22249
22125
  };
22250
22126
  }
22251
22127
  }
22252
22128
  async function checkAuthFile() {
22253
- const authPath = path7.join(WORKLE_HOME2, "auth.json");
22129
+ const authPath = path8.join(WORKLE_HOME2, "auth.json");
22254
22130
  try {
22255
- const raw = await fs6.readFile(authPath, "utf-8");
22131
+ const raw = await fs5.readFile(authPath, "utf-8");
22256
22132
  const parsed = JSON.parse(raw);
22257
22133
  if (parsed.instanceId && parsed.token && parsed.apiUrl) {
22258
22134
  return {
@@ -22274,99 +22150,53 @@ async function checkAuthFile() {
22274
22150
  };
22275
22151
  }
22276
22152
  }
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
22153
 
22324
22154
  // 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");
22155
+ import fs6 from "fs/promises";
22156
+ import os6 from "os";
22157
+ import path9 from "path";
22158
+ var WORKLE_HOME3 = path9.join(os6.homedir(), ".workle");
22159
+ var LAUNCH_AGENTS_DIR = path9.join(os6.homedir(), "Library", "LaunchAgents");
22160
+ var STAGED_CLI_PATH = path9.join(WORKLE_HOME3, "bin", "cli.js");
22331
22161
  function escapeXml(value) {
22332
22162
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
22333
22163
  }
22334
- async function setupClawDirectory() {
22164
+ async function setupLocalDirectory() {
22335
22165
  const dirs = [
22336
22166
  WORKLE_HOME3,
22337
- path8.join(WORKLE_HOME3, "logs"),
22338
- path8.join(WORKLE_HOME3, "bin")
22167
+ path9.join(WORKLE_HOME3, "logs"),
22168
+ path9.join(WORKLE_HOME3, "bin")
22339
22169
  ];
22340
22170
  for (const dir of dirs) {
22341
- await fs7.mkdir(dir, { recursive: true, mode: 448 });
22342
- await fs7.chmod(dir, 448).catch(() => {
22171
+ await fs6.mkdir(dir, { recursive: true, mode: 448 });
22172
+ await fs6.chmod(dir, 448).catch(() => {
22343
22173
  });
22344
22174
  }
22345
- const gitignorePath = path8.join(WORKLE_HOME3, ".gitignore");
22175
+ const gitignorePath = path9.join(WORKLE_HOME3, ".gitignore");
22346
22176
  try {
22347
- await fs7.access(gitignorePath);
22177
+ await fs6.access(gitignorePath);
22348
22178
  } catch {
22349
- await fs7.writeFile(gitignorePath, "*\n", "utf-8");
22179
+ await fs6.writeFile(gitignorePath, "*\n", "utf-8");
22350
22180
  }
22351
- console.log(`[claw] Directory structure created at ${WORKLE_HOME3}`);
22181
+ console.log(`[local] Directory structure created at ${WORKLE_HOME3}`);
22352
22182
  }
22353
22183
  async function stageCliForDaemon(currentCliPath) {
22354
22184
  if (!currentCliPath) {
22355
22185
  throw new Error("Cannot determine the current CLI path for daemon install.");
22356
22186
  }
22357
- await setupClawDirectory();
22187
+ await setupLocalDirectory();
22358
22188
  const isNpxCache = currentCliPath.includes("/_npx/") || currentCliPath.includes("\\_npx\\");
22359
22189
  if (!isNpxCache) {
22360
22190
  return currentCliPath;
22361
22191
  }
22362
- await fs7.copyFile(currentCliPath, STAGED_CLI_PATH);
22363
- await fs7.chmod(STAGED_CLI_PATH, 448).catch(() => {
22192
+ await fs6.copyFile(currentCliPath, STAGED_CLI_PATH);
22193
+ await fs6.chmod(STAGED_CLI_PATH, 448).catch(() => {
22364
22194
  });
22365
22195
  return STAGED_CLI_PATH;
22366
22196
  }
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`);
22197
+ async function writeLaunchdPlist(serviceName = "com.workle.local", executable = process.execPath, args = [STAGED_CLI_PATH, "start"]) {
22198
+ await fs6.mkdir(LAUNCH_AGENTS_DIR, { recursive: true });
22199
+ const plistPath = path9.join(LAUNCH_AGENTS_DIR, `${serviceName}.plist`);
22370
22200
  const programArguments = [executable, ...args].map((arg) => ` <string>${escapeXml(arg)}</string>`).join("\n");
22371
22201
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
22372
22202
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -22390,10 +22220,10 @@ ${programArguments}
22390
22220
  </dict>
22391
22221
 
22392
22222
  <key>StandardOutPath</key>
22393
- <string>${path8.join(WORKLE_HOME3, "logs", "stdout.log")}</string>
22223
+ <string>${path9.join(WORKLE_HOME3, "logs", "stdout.log")}</string>
22394
22224
 
22395
22225
  <key>StandardErrorPath</key>
22396
- <string>${path8.join(WORKLE_HOME3, "logs", "stderr.log")}</string>
22226
+ <string>${path9.join(WORKLE_HOME3, "logs", "stderr.log")}</string>
22397
22227
 
22398
22228
  <key>WorkingDirectory</key>
22399
22229
  <string>${WORKLE_HOME3}</string>
@@ -22403,867 +22233,19 @@ ${programArguments}
22403
22233
  </dict>
22404
22234
  </plist>
22405
22235
  `;
22406
- await fs7.writeFile(plistPath, plist, "utf-8");
22407
- console.log(`[claw] Launchd plist written to ${plistPath}`);
22236
+ await fs6.writeFile(plistPath, plist, "utf-8");
22237
+ console.log(`[local] Launchd plist written to ${plistPath}`);
22408
22238
  console.log(
22409
- `[claw] To enable: launchctl load ${plistPath}`
22239
+ `[local] To enable: launchctl load ${plistPath}`
22410
22240
  );
22411
22241
  return plistPath;
22412
22242
  }
22413
22243
 
22414
22244
  // 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
22245
  function deriveRelayUrl2(apiUrl) {
23264
22246
  const url2 = new URL(apiUrl);
23265
22247
  url2.protocol = url2.protocol === "https:" ? "wss:" : "ws:";
23266
- url2.pathname = "/api/claw/relay";
22248
+ url2.pathname = "/api/local/relay";
23267
22249
  if (url2.hostname !== "localhost") {
23268
22250
  url2.hostname = `relay.${url2.hostname}`;
23269
22251
  }
@@ -23274,9 +22256,7 @@ var SyncService = class {
23274
22256
  this.options = options;
23275
22257
  }
23276
22258
  auth = null;
23277
- rpcClient = null;
23278
22259
  relayClient = null;
23279
- unsubscribeEvents = null;
23280
22260
  unsubscribeRelayMessages = null;
23281
22261
  running = false;
23282
22262
  externalMessageHandler = null;
@@ -23312,30 +22292,14 @@ var SyncService = class {
23312
22292
  */
23313
22293
  async start() {
23314
22294
  if (this.running) {
23315
- console.log("[claw] SyncService already running");
22295
+ console.log("[local] SyncService already running");
23316
22296
  return;
23317
22297
  }
23318
- console.log("[claw] Starting SyncService...");
22298
+ console.log("[local] Starting SyncService...");
23319
22299
  this.auth = await loadAuth();
23320
22300
  console.log(
23321
- `[claw] Authenticated as instance ${this.auth.instanceId}`
22301
+ `[local] Authenticated as instance ${this.auth.instanceId}`
23322
22302
  );
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
22303
  if (!this.options.localOnly) {
23340
22304
  const relayUrl = this.options.relayUrl ?? deriveRelayUrl2(this.auth.apiUrl);
23341
22305
  this.relayClient = new RelayClient(
@@ -23345,51 +22309,11 @@ var SyncService = class {
23345
22309
  {
23346
22310
  onConnect: () => {
23347
22311
  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
22312
  if (this.reconnectHandler) {
23389
22313
  try {
23390
22314
  await this.reconnectHandler();
23391
22315
  } catch (err) {
23392
- console.error("[claw] Agent config re-sync on reconnect failed:", err);
22316
+ console.error("[local] Agent config re-sync on reconnect failed:", err);
23393
22317
  }
23394
22318
  }
23395
22319
  })();
@@ -23398,200 +22322,29 @@ var SyncService = class {
23398
22322
  );
23399
22323
  try {
23400
22324
  await this.relayClient.connect();
23401
- console.log("[claw] Connected to relay server");
22325
+ console.log("[local] Connected to relay server");
23402
22326
  } catch (err) {
23403
22327
  console.warn(
23404
- "[claw] Could not connect to relay (will retry):",
22328
+ "[local] Could not connect to relay (will retry):",
23405
22329
  err
23406
22330
  );
23407
22331
  }
23408
22332
  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;
22333
+ console.log(`[local] Relay message received: type=${msg.type}`, JSON.stringify(msg).slice(0, 200));
22334
+ if (this.externalMessageHandler) {
22335
+ this.externalMessageHandler(msg);
23415
22336
  }
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
22337
  });
23574
22338
  }
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
22339
  this.running = true;
23583
- console.log("[claw] SyncService started");
22340
+ console.log("[local] SyncService started");
23584
22341
  }
23585
22342
  /**
23586
22343
  * Gracefully stop the sync service.
23587
22344
  */
23588
22345
  stop() {
23589
22346
  if (!this.running) return;
23590
- console.log("[claw] Stopping SyncService...");
23591
- if (this.unsubscribeEvents) {
23592
- this.unsubscribeEvents();
23593
- this.unsubscribeEvents = null;
23594
- }
22347
+ console.log("[local] Stopping SyncService...");
23595
22348
  if (this.unsubscribeRelayMessages) {
23596
22349
  this.unsubscribeRelayMessages();
23597
22350
  this.unsubscribeRelayMessages = null;
@@ -23600,54 +22353,16 @@ var SyncService = class {
23600
22353
  this.relayClient.disconnect();
23601
22354
  this.relayClient = null;
23602
22355
  }
23603
- if (this.rpcClient) {
23604
- this.rpcClient.disconnect();
23605
- this.rpcClient = null;
23606
- }
23607
22356
  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
- );
22357
+ console.log("[local] SyncService stopped");
23643
22358
  }
23644
22359
  };
23645
22360
 
23646
22361
  // 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";
22362
+ var WORKLE_HOME4 = path10.join(os7.homedir(), ".workle");
22363
+ var AUTH_FILE2 = path10.join(WORKLE_HOME4, "auth.json");
22364
+ var LAUNCH_AGENTS_DIR2 = path10.join(os7.homedir(), "Library", "LaunchAgents");
22365
+ var PLIST_LABEL = "com.workle.local";
23651
22366
  var color = {
23652
22367
  green: (s) => `\x1B[32m${s}\x1B[0m`,
23653
22368
  red: (s) => `\x1B[31m${s}\x1B[0m`,
@@ -23659,7 +22374,7 @@ var color = {
23659
22374
  function readPkgVersion() {
23660
22375
  try {
23661
22376
  const pkgPath = new URL("../package.json", import.meta.url);
23662
- const raw = readFileSync(pkgPath, "utf-8");
22377
+ const raw = readFileSync2(pkgPath, "utf-8");
23663
22378
  return JSON.parse(raw).version;
23664
22379
  } catch {
23665
22380
  return "0.0.0";
@@ -23684,16 +22399,16 @@ function pairingErrorMessage(status, fallback) {
23684
22399
  return fallback;
23685
22400
  }
23686
22401
  async function saveAuth(data) {
23687
- await setupClawDirectory();
22402
+ await setupLocalDirectory();
23688
22403
  const authData = {
23689
22404
  instanceId: data.instanceId,
23690
22405
  token: data.token,
23691
22406
  apiUrl: data.apiUrl
23692
22407
  };
23693
- await fs16.writeFile(AUTH_FILE2, JSON.stringify(authData, null, 2), {
22408
+ await fs7.writeFile(AUTH_FILE2, JSON.stringify(authData, null, 2), {
23694
22409
  mode: 384
23695
22410
  });
23696
- await fs16.chmod(AUTH_FILE2, 384).catch(() => {
22411
+ await fs7.chmod(AUTH_FILE2, 384).catch(() => {
23697
22412
  });
23698
22413
  console.log("");
23699
22414
  console.log(color.green("\u2713 Paired successfully!"));
@@ -23710,7 +22425,7 @@ async function saveAuth(data) {
23710
22425
  console.log(` ${color.cyan("npx @getworkle/cli doctor")} Run health checks`);
23711
22426
  }
23712
22427
  async function exchangeBrowserCode(code, codeVerifier, apiUrl) {
23713
- const res = await fetch(`${apiUrl}/api/claw/pair/exchange`, {
22428
+ const res = await fetch(`${apiUrl}/api/local/pair/exchange`, {
23714
22429
  method: "POST",
23715
22430
  headers: { "Content-Type": "application/json" },
23716
22431
  body: JSON.stringify({ code, codeVerifier })
@@ -23728,7 +22443,7 @@ function browserAuth(apiUrl) {
23728
22443
  const codeVerifier = createPairingCodeVerifier();
23729
22444
  const codeChallenge = createPairingCodeChallenge(codeVerifier);
23730
22445
  let settled = false;
23731
- const server = http2.createServer((req, res) => {
22446
+ const server = http.createServer((req, res) => {
23732
22447
  void (async () => {
23733
22448
  const url2 = new URL(req.url ?? "/", "http://127.0.0.1");
23734
22449
  if (url2.pathname !== "/callback") {
@@ -23758,7 +22473,7 @@ function browserAuth(apiUrl) {
23758
22473
  res.end(
23759
22474
  [
23760
22475
  "<!DOCTYPE html>",
23761
- "<html><head><title>Workle Claw</title>",
22476
+ "<html><head><title>Workle Local</title>",
23762
22477
  "<style>body{font-family:system-ui;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;background:#fafafa;color:#111}",
23763
22478
  ".card{text-align:center;padding:3rem;border-radius:12px;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.1)}",
23764
22479
  "h1{font-size:1.5rem;margin:0 0 .5rem}p{color:#666;margin:0}</style></head>",
@@ -23775,7 +22490,7 @@ function browserAuth(apiUrl) {
23775
22490
  res.end(
23776
22491
  [
23777
22492
  "<!DOCTYPE html>",
23778
- "<html><head><title>Workle Claw</title>",
22493
+ "<html><head><title>Workle Local</title>",
23779
22494
  "<style>body{font-family:system-ui;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;background:#fafafa;color:#111}",
23780
22495
  ".card{text-align:center;padding:3rem;border-radius:12px;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.1)}",
23781
22496
  "h1{font-size:1.5rem;margin:0 0 .5rem}p{color:#666;margin:0 0 1rem}</style></head>",
@@ -23807,12 +22522,12 @@ function browserAuth(apiUrl) {
23807
22522
  return;
23808
22523
  }
23809
22524
  const port = addr.port;
23810
- const pairUrl = `${apiUrl}/claw/pair?port=${port}&state=${encodeURIComponent(callbackState)}&codeChallenge=${encodeURIComponent(codeChallenge)}`;
22525
+ const pairUrl = `${apiUrl}/local/pair?port=${port}&state=${encodeURIComponent(callbackState)}&codeChallenge=${encodeURIComponent(codeChallenge)}`;
23811
22526
  console.log(color.dim("Opening browser to authenticate..."));
23812
22527
  console.log(color.dim(` ${pairUrl}
23813
22528
  `));
23814
22529
  try {
23815
- execSync2(`open "${pairUrl}"`, { stdio: "ignore" });
22530
+ execSync(`open "${pairUrl}"`, { stdio: "ignore" });
23816
22531
  } catch {
23817
22532
  console.log(color.yellow("Could not open browser automatically."));
23818
22533
  console.log("Open this URL in your browser:\n");
@@ -23841,7 +22556,7 @@ function browserAuth(apiUrl) {
23841
22556
  }
23842
22557
  async function tokenAuth(setupToken, apiUrl) {
23843
22558
  console.log(color.dim("Activating with Workle..."));
23844
- const res = await fetch(`${apiUrl}/api/claw/activate`, {
22559
+ const res = await fetch(`${apiUrl}/api/local/activate`, {
23845
22560
  method: "POST",
23846
22561
  headers: { "Content-Type": "application/json" },
23847
22562
  body: JSON.stringify({ setupToken })
@@ -23882,7 +22597,7 @@ program2.command("setup").alias("pair").description("Pair this Mac with a Workle
23882
22597
  process.exit(1);
23883
22598
  }
23884
22599
  });
23885
- program2.command("start").description("Start the Workle Claw sync service").option("-d, --daemon", "Run as a background daemon via launchd").action(async (opts) => {
22600
+ program2.command("start").description("Start the Workle Local sync service").option("-d, --daemon", "Run as a background daemon via launchd").action(async (opts) => {
23886
22601
  if (opts.daemon) {
23887
22602
  console.log(color.dim("Installing launchd service..."));
23888
22603
  const stagedCliPath = await stageCliForDaemon(process.argv[1] ?? "");
@@ -23891,12 +22606,12 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23891
22606
  "start"
23892
22607
  ]);
23893
22608
  try {
23894
- execSync2(`launchctl load -w "${plistPath}"`, { stdio: "inherit" });
22609
+ execSync(`launchctl load -w "${plistPath}"`, { stdio: "inherit" });
23895
22610
  console.log(color.green("\u2713 Daemon started"));
23896
22611
  console.log("");
23897
22612
  console.log(` Service: ${color.dim(PLIST_LABEL)}`);
23898
22613
  console.log(` Plist: ${color.dim(plistPath)}`);
23899
- console.log(` Logs: ${color.dim(path19.join(WORKLE_HOME9, "logs/"))}`);
22614
+ console.log(` Logs: ${color.dim(path10.join(WORKLE_HOME4, "logs/"))}`);
23900
22615
  console.log("");
23901
22616
  console.log(
23902
22617
  `To stop: ${color.cyan("npx @getworkle/cli stop")}`
@@ -23908,36 +22623,19 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23908
22623
  }
23909
22624
  return;
23910
22625
  }
23911
- console.log(color.bold("Workle Claw"));
22626
+ console.log(color.bold("Workle Local"));
23912
22627
  console.log(color.dim("Starting sync service... (Ctrl+C to stop)\n"));
23913
- const processManager = new ProcessManager();
23914
22628
  const syncService = new SyncService();
23915
22629
  let agentService = null;
23916
- let weSpawnedGateway = false;
23917
22630
  const shutdown = () => {
23918
22631
  console.log("\n" + color.dim("Shutting down..."));
23919
22632
  agentService?.stop();
23920
22633
  syncService.stop();
23921
- if (weSpawnedGateway) {
23922
- void processManager.stop().then(() => {
23923
- process.exit(0);
23924
- });
23925
- } else {
23926
- process.exit(0);
23927
- }
22634
+ process.exit(0);
23928
22635
  };
23929
22636
  process.on("SIGINT", shutdown);
23930
22637
  process.on("SIGTERM", shutdown);
23931
22638
  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
22639
  await syncService.start();
23942
22640
  try {
23943
22641
  agentService = await createAgentService();
@@ -23962,41 +22660,26 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23962
22660
  )
23963
22661
  );
23964
22662
  syncService.stop();
23965
- if (weSpawnedGateway) {
23966
- await processManager.stop();
23967
- }
23968
22663
  process.exit(1);
23969
22664
  }
23970
22665
  });
23971
- program2.command("stop").description("Stop the Workle Claw daemon").action(async () => {
23972
- const plistPath = path19.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
22666
+ program2.command("stop").description("Stop the Workle Local daemon").action(async () => {
22667
+ const plistPath = path10.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
23973
22668
  try {
23974
- execSync2(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
22669
+ execSync(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
23975
22670
  console.log(color.green("\u2713 Daemon stopped"));
23976
22671
  } catch {
23977
22672
  console.log(color.dim("No launchd service loaded."));
23978
22673
  }
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
22674
  });
23992
- program2.command("doctor").description("Run health checks for the Workle Claw environment").action(async () => {
22675
+ program2.command("doctor").description("Run health checks for the Workle Local environment").action(async () => {
23993
22676
  const checks = await runDoctor();
23994
22677
  const failures = checks.filter((c) => c.status === "fail");
23995
22678
  process.exit(failures.length > 0 ? 1 : 0);
23996
22679
  });
23997
22680
  program2.command("status").description("Show connection state and instance info").action(async () => {
23998
22681
  console.log("");
23999
- console.log(color.bold(" Workle Claw Status"));
22682
+ console.log(color.bold(" Workle Local Status"));
24000
22683
  console.log("");
24001
22684
  try {
24002
22685
  const auth = await loadAuth();
@@ -24008,24 +22691,11 @@ program2.command("status").description("Show connection state and instance info"
24008
22691
  console.log("");
24009
22692
  return;
24010
22693
  }
22694
+ const plistPath = path10.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
24011
22695
  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);
22696
+ await fs7.access(plistPath);
24027
22697
  try {
24028
- const output = execSync2(`launchctl list ${PLIST_LABEL} 2>&1`, {
22698
+ const output = execSync(`launchctl list ${PLIST_LABEL} 2>&1`, {
24029
22699
  encoding: "utf-8"
24030
22700
  });
24031
22701
  if (output.includes(PLIST_LABEL)) {
@@ -24041,15 +22711,15 @@ program2.command("status").description("Show connection state and instance info"
24041
22711
  }
24042
22712
  console.log("");
24043
22713
  });
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) => {
22714
+ 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
22715
  const lineCount = parseInt(opts.lines, 10);
24046
22716
  if (!Number.isFinite(lineCount) || lineCount < 1) {
24047
22717
  console.error(color.red("Error: --lines must be a positive integer."));
24048
22718
  process.exit(1);
24049
22719
  }
24050
22720
  const logFiles = [
24051
- path19.join(WORKLE_HOME9, "openclaw.log"),
24052
- path19.join(WORKLE_HOME9, "logs", "stderr.log")
22721
+ path10.join(WORKLE_HOME4, "logs", "stdout.log"),
22722
+ path10.join(WORKLE_HOME4, "logs", "stderr.log")
24053
22723
  ];
24054
22724
  const args = ["-n", String(lineCount)];
24055
22725
  if (opts.follow) args.push("-f");
@@ -24057,7 +22727,7 @@ program2.command("logs").description("Tail the Workle Claw log files").option("-
24057
22727
  const result = spawnSync("tail", args, { stdio: "inherit" });
24058
22728
  if (result.error && !opts.follow) {
24059
22729
  console.error(color.red(`Failed to read logs: ${result.error.message}`));
24060
- console.error(`Expected log files at: ${WORKLE_HOME9}/logs/`);
22730
+ console.error(`Expected log files at: ${WORKLE_HOME4}/logs/`);
24061
22731
  }
24062
22732
  });
24063
22733
  var agentCmd = program2.command("agent").description("Manage and run Workle AI agents locally");
@@ -24213,12 +22883,12 @@ agentCmd.command("logs [agentId]").description("Tail agent run logs").option("-n
24213
22883
  console.error(color.red("Error: --lines must be a positive integer."));
24214
22884
  process.exit(1);
24215
22885
  }
24216
- const logsDir = path19.join(WORKLE_HOME9, "agents");
22886
+ const logsDir = path10.join(WORKLE_HOME4, "agents");
24217
22887
  let logFile;
24218
22888
  if (agentId) {
24219
- logFile = path19.join(logsDir, agentId, "run.log");
22889
+ logFile = path10.join(logsDir, agentId, "run.log");
24220
22890
  } else {
24221
- logFile = path19.join(logsDir, "*", "run.log");
22891
+ logFile = path10.join(logsDir, "*", "run.log");
24222
22892
  }
24223
22893
  const args = ["-n", String(lineCount)];
24224
22894
  if (opts.follow) args.push("-f");