@getworkle/cli 0.2.10 → 0.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1209,7 +1209,7 @@ var require_command = __commonJS({
1209
1209
  "use strict";
1210
1210
  var EventEmitter = __require("events").EventEmitter;
1211
1211
  var childProcess = __require("child_process");
1212
- var path19 = __require("path");
1212
+ var path20 = __require("path");
1213
1213
  var fs17 = __require("fs");
1214
1214
  var process2 = __require("process");
1215
1215
  var { Argument: Argument2, humanReadableArgName } = require_argument();
@@ -2222,9 +2222,9 @@ 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 = path19.resolve(baseDir, baseName);
2225
+ const localBin = path20.resolve(baseDir, baseName);
2226
2226
  if (fs17.existsSync(localBin)) return localBin;
2227
- if (sourceExt.includes(path19.extname(baseName))) return void 0;
2227
+ if (sourceExt.includes(path20.extname(baseName))) return void 0;
2228
2228
  const foundExt = sourceExt.find(
2229
2229
  (ext) => fs17.existsSync(`${localBin}${ext}`)
2230
2230
  );
@@ -2242,17 +2242,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
2242
2242
  } catch {
2243
2243
  resolvedScriptPath = this._scriptPath;
2244
2244
  }
2245
- executableDir = path19.resolve(
2246
- path19.dirname(resolvedScriptPath),
2245
+ executableDir = path20.resolve(
2246
+ path20.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 = path19.basename(
2253
+ const legacyName = path20.basename(
2254
2254
  this._scriptPath,
2255
- path19.extname(this._scriptPath)
2255
+ path20.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(path19.extname(executableFile));
2266
+ launchWithNode = sourceExt.includes(path20.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 = path19.basename(filename, path19.extname(filename));
3181
+ this._name = path20.basename(filename, path20.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(path20) {
3196
- if (path20 === void 0) return this._executableDir;
3197
- this._executableDir = path20;
3195
+ executableDir(path21) {
3196
+ if (path21 === void 0) return this._executableDir;
3197
+ this._executableDir = path21;
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 path19 = __require("path");
4288
+ var path20 = __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: path19.resolve(this.taskPath),
4323
+ path: path20.resolve(this.taskPath),
4324
4324
  cron: this.cronExpression,
4325
4325
  options
4326
4326
  });
@@ -8033,7 +8033,7 @@ import { readFileSync } from "fs";
8033
8033
  import fs16 from "fs/promises";
8034
8034
  import http2 from "http";
8035
8035
  import os18 from "os";
8036
- import path18 from "path";
8036
+ import path19 from "path";
8037
8037
 
8038
8038
  // src/agents/config-materializer.ts
8039
8039
  import fs2 from "fs/promises";
@@ -8106,12 +8106,37 @@ function getAgentDirPath(agentId) {
8106
8106
  const safeId = sanitizePathSegment(agentId, "agent");
8107
8107
  return path2.join(AGENTS_HOME, `id-${safeId}`);
8108
8108
  }
8109
+ function getSdkMemoryPath(agentId) {
8110
+ const agentDir = getAgentDirPath(agentId);
8111
+ const encoded = agentDir.replace(/[^a-zA-Z0-9]/g, "-");
8112
+ return path2.join(os2.homedir(), ".claude", "projects", encoded, "memory");
8113
+ }
8109
8114
  function sanitizeAgentAssetFilename(filename, fallback) {
8110
- return sanitizePathSegment(filename, fallback);
8115
+ const sanitized = sanitizePathSegment(filename, fallback);
8116
+ return sanitized.endsWith(".md") ? sanitized : `${sanitized}.md`;
8111
8117
  }
8112
8118
 
8113
8119
  // src/agents/config-materializer.ts
8114
8120
  var CACHE_FILE = path3.join(os3.homedir(), ".workle", "agent-cache.json");
8121
+ function buildSdkSettings(settings) {
8122
+ if (!settings) return {};
8123
+ const sdk = {};
8124
+ const perms = settings.permissions;
8125
+ if (perms && typeof perms === "object" && perms !== null) {
8126
+ const p = perms;
8127
+ const sdkPerms = {};
8128
+ if (Array.isArray(p.allow) && p.allow.length > 0) {
8129
+ sdkPerms.allow = p.allow;
8130
+ }
8131
+ if (Array.isArray(p.deny) && p.deny.length > 0) {
8132
+ sdkPerms.deny = p.deny;
8133
+ }
8134
+ if (Object.keys(sdkPerms).length > 0) {
8135
+ sdk.permissions = sdkPerms;
8136
+ }
8137
+ }
8138
+ return sdk;
8139
+ }
8115
8140
  var AgentConfigMaterializer = class {
8116
8141
  apiUrl;
8117
8142
  instanceId;
@@ -8215,10 +8240,26 @@ var AgentConfigMaterializer = class {
8215
8240
  "utf-8"
8216
8241
  );
8217
8242
  }
8218
- if (agent.settings) {
8243
+ if (agent.memory && agent.memory.length > 0) {
8244
+ const sdkMemoryDir = getSdkMemoryPath(agent.id);
8245
+ await fs2.mkdir(sdkMemoryDir, { recursive: true });
8246
+ for (const [index, mem] of agent.memory.entries()) {
8247
+ const filename = sanitizeAgentAssetFilename(
8248
+ mem.filename,
8249
+ `memory-${index + 1}.md`
8250
+ );
8251
+ await fs2.writeFile(
8252
+ path3.join(sdkMemoryDir, filename),
8253
+ mem.content,
8254
+ "utf-8"
8255
+ );
8256
+ }
8257
+ }
8258
+ const sdkSettings = buildSdkSettings(agent.settings);
8259
+ if (Object.keys(sdkSettings).length > 0) {
8219
8260
  await fs2.writeFile(
8220
8261
  settingsPath,
8221
- JSON.stringify(agent.settings, null, 2),
8262
+ JSON.stringify(sdkSettings, null, 2),
8222
8263
  "utf-8"
8223
8264
  );
8224
8265
  } else {
@@ -8257,14 +8298,20 @@ function resolveClaudeCodeExecutable() {
8257
8298
  return `${sdkDir}/cli.js`;
8258
8299
  }
8259
8300
  async function runAgent(opts) {
8260
- const { agentDir, prompt, sessionId, maxTurns, mcpServers, onMessage, abortController } = opts;
8301
+ const { agentDir, prompt, sessionId, maxTurns, permissionMode, model, allowedTools, mcpServers, onMessage, abortController } = opts;
8261
8302
  try {
8262
8303
  const stream = query({
8263
8304
  prompt,
8264
8305
  options: {
8265
8306
  pathToClaudeCodeExecutable: resolveClaudeCodeExecutable(),
8307
+ executable: process.execPath,
8308
+ // Full path to node — launchd doesn't have node in PATH
8266
8309
  cwd: agentDir,
8267
8310
  settingSources: ["project"],
8311
+ ...permissionMode ? { permissionMode } : {},
8312
+ ...permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {},
8313
+ ...model ? { model } : {},
8314
+ ...allowedTools && allowedTools.length > 0 ? { allowedTools } : {},
8268
8315
  ...sessionId ? { resume: sessionId } : {},
8269
8316
  ...typeof maxTurns === "number" ? { maxTurns } : {},
8270
8317
  ...mcpServers ? { mcpServers } : {},
@@ -9065,10 +9112,10 @@ function mergeDefs(...defs) {
9065
9112
  function cloneDef(schema) {
9066
9113
  return mergeDefs(schema._zod.def);
9067
9114
  }
9068
- function getElementAtPath(obj, path19) {
9069
- if (!path19)
9115
+ function getElementAtPath(obj, path20) {
9116
+ if (!path20)
9070
9117
  return obj;
9071
- return path19.reduce((acc, key) => acc?.[key], obj);
9118
+ return path20.reduce((acc, key) => acc?.[key], obj);
9072
9119
  }
9073
9120
  function promiseAllObject(promisesObj) {
9074
9121
  const keys = Object.keys(promisesObj);
@@ -9434,11 +9481,11 @@ function aborted(x, startIndex = 0) {
9434
9481
  }
9435
9482
  return false;
9436
9483
  }
9437
- function prefixIssues(path19, issues) {
9484
+ function prefixIssues(path20, issues) {
9438
9485
  return issues.map((iss) => {
9439
9486
  var _a2;
9440
9487
  (_a2 = iss).path ?? (_a2.path = []);
9441
- iss.path.unshift(path19);
9488
+ iss.path.unshift(path20);
9442
9489
  return iss;
9443
9490
  });
9444
9491
  }
@@ -9600,7 +9647,7 @@ function formatError(error46, mapper = (issue2) => issue2.message) {
9600
9647
  }
9601
9648
  function treeifyError(error46, mapper = (issue2) => issue2.message) {
9602
9649
  const result = { errors: [] };
9603
- const processError = (error47, path19 = []) => {
9650
+ const processError = (error47, path20 = []) => {
9604
9651
  var _a2, _b;
9605
9652
  for (const issue2 of error47.issues) {
9606
9653
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -9610,7 +9657,7 @@ function treeifyError(error46, mapper = (issue2) => issue2.message) {
9610
9657
  } else if (issue2.code === "invalid_element") {
9611
9658
  processError({ issues: issue2.issues }, issue2.path);
9612
9659
  } else {
9613
- const fullpath = [...path19, ...issue2.path];
9660
+ const fullpath = [...path20, ...issue2.path];
9614
9661
  if (fullpath.length === 0) {
9615
9662
  result.errors.push(mapper(issue2));
9616
9663
  continue;
@@ -9642,8 +9689,8 @@ function treeifyError(error46, mapper = (issue2) => issue2.message) {
9642
9689
  }
9643
9690
  function toDotPath(_path) {
9644
9691
  const segs = [];
9645
- const path19 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9646
- for (const seg of path19) {
9692
+ const path20 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9693
+ for (const seg of path20) {
9647
9694
  if (typeof seg === "number")
9648
9695
  segs.push(`[${seg}]`);
9649
9696
  else if (typeof seg === "symbol")
@@ -20979,23 +21026,23 @@ function date4(params) {
20979
21026
  config(en_default());
20980
21027
 
20981
21028
  // src/agents/mcp-server.ts
20982
- async function apiGet(apiUrl, path19, headers) {
20983
- const res = await fetch(`${apiUrl}${path19}`, {
21029
+ async function apiGet(apiUrl, path20, headers) {
21030
+ const res = await fetch(`${apiUrl}${path20}`, {
20984
21031
  headers: { ...headers, "Content-Type": "application/json" }
20985
21032
  });
20986
21033
  if (!res.ok) {
20987
- throw new Error(`API GET ${path19} failed: HTTP ${res.status}`);
21034
+ throw new Error(`API GET ${path20} failed: HTTP ${res.status}`);
20988
21035
  }
20989
21036
  return res.json();
20990
21037
  }
20991
- async function apiPost(apiUrl, path19, body, headers) {
20992
- const res = await fetch(`${apiUrl}${path19}`, {
21038
+ async function apiPost(apiUrl, path20, body, headers) {
21039
+ const res = await fetch(`${apiUrl}${path20}`, {
20993
21040
  method: "POST",
20994
21041
  headers: { ...headers, "Content-Type": "application/json" },
20995
21042
  body: JSON.stringify(body)
20996
21043
  });
20997
21044
  if (!res.ok) {
20998
- throw new Error(`API POST ${path19} failed: HTTP ${res.status}`);
21045
+ throw new Error(`API POST ${path20} failed: HTTP ${res.status}`);
20999
21046
  }
21000
21047
  return res.json();
21001
21048
  }
@@ -21121,6 +21168,7 @@ var AgentScheduler = class {
21121
21168
  // src/agents/service.ts
21122
21169
  import { randomUUID } from "crypto";
21123
21170
  import fs4 from "fs/promises";
21171
+ import path5 from "path";
21124
21172
 
21125
21173
  // ../../node_modules/ws/wrapper.mjs
21126
21174
  var import_stream = __toESM(require_stream(), 1);
@@ -21561,11 +21609,15 @@ var AgentService = class _AgentService {
21561
21609
  instanceId: this.instanceId,
21562
21610
  token: this.token
21563
21611
  });
21612
+ const { permissionMode, model, allowedTools } = extractSdkOptions(config2);
21564
21613
  const result = await runAgent({
21565
21614
  agentDir,
21566
21615
  prompt,
21567
21616
  sessionId: previousSessionId,
21568
21617
  maxTurns: typeof config2?.maxTurns === "number" ? config2.maxTurns : void 0,
21618
+ permissionMode,
21619
+ model,
21620
+ allowedTools,
21569
21621
  mcpServers: { workle: mcpServer },
21570
21622
  abortController,
21571
21623
  onMessage: (message) => {
@@ -21716,6 +21768,12 @@ var AgentService = class _AgentService {
21716
21768
  if (resumeSession && result.sessionId) {
21717
21769
  await saveSessionId(agentId, result.sessionId);
21718
21770
  }
21771
+ void this.pushMemoryFiles(agentId).catch((err) => {
21772
+ console.error(
21773
+ `[agents] Failed to push memory for ${agentId}:`,
21774
+ err instanceof Error ? err.message : err
21775
+ );
21776
+ });
21719
21777
  return result;
21720
21778
  })();
21721
21779
  this.activeRuns.set(agentId, runPromise);
@@ -21757,6 +21815,28 @@ var AgentService = class _AgentService {
21757
21815
  this.activeAborts.delete(runExecutionId);
21758
21816
  }
21759
21817
  }
21818
+ /**
21819
+ * Re-sync all agent configs from the cloud.
21820
+ * Called on relay reconnect to catch any config.updated events
21821
+ * that were missed while the relay was disconnected.
21822
+ */
21823
+ async resyncAllConfigs() {
21824
+ console.log("[agents] Re-syncing all agent configs...");
21825
+ const stubs = await this.materializer.listAgents();
21826
+ let synced = 0;
21827
+ for (const stub of stubs) {
21828
+ try {
21829
+ await this.syncAgentConfig(stub.id);
21830
+ synced++;
21831
+ } catch (err) {
21832
+ console.error(
21833
+ `[agents] Failed to re-sync agent ${stub.id}:`,
21834
+ err instanceof Error ? err.message : err
21835
+ );
21836
+ }
21837
+ }
21838
+ console.log(`[agents] Re-synced ${synced}/${stubs.length} agent config(s)`);
21839
+ }
21760
21840
  /**
21761
21841
  * Graceful shutdown.
21762
21842
  */
@@ -21786,6 +21866,7 @@ var AgentService = class _AgentService {
21786
21866
  }
21787
21867
  // ── Internal ────────────────────────────────────────────────────────────
21788
21868
  handleRelayMessage(msg) {
21869
+ console.log(`[agents] handleRelayMessage: type=${msg.type}`);
21789
21870
  if (msg.type === "agent.trigger") {
21790
21871
  const frame = msg;
21791
21872
  const { agentId, prompt, executionId, resumeSession } = frame.payload;
@@ -21808,6 +21889,39 @@ var AgentService = class _AgentService {
21808
21889
  }
21809
21890
  }
21810
21891
  }
21892
+ /**
21893
+ * Scan the SDK auto-memory directory and push files back to the cloud.
21894
+ * The SDK writes auto-memory to ~/.claude/projects/{encoded-cwd}/memory/.
21895
+ */
21896
+ async pushMemoryFiles(agentId) {
21897
+ const memoryDir = getSdkMemoryPath(agentId);
21898
+ let entries;
21899
+ try {
21900
+ entries = await fs4.readdir(memoryDir);
21901
+ } catch {
21902
+ return;
21903
+ }
21904
+ const mdFiles = entries.filter((f) => f.endsWith(".md"));
21905
+ if (mdFiles.length === 0) return;
21906
+ const files = [];
21907
+ for (const filename of mdFiles) {
21908
+ const content = await fs4.readFile(path5.join(memoryDir, filename), "utf-8");
21909
+ files.push({ filename, content });
21910
+ }
21911
+ const headers = createAuthHeaders(this.token);
21912
+ const res = await fetch(
21913
+ `${this.apiUrl}/api/claw/instances/${this.instanceId}/runtime/agents/${agentId}/push-memory`,
21914
+ {
21915
+ method: "POST",
21916
+ headers: { ...headers, "Content-Type": "application/json" },
21917
+ body: JSON.stringify({ files })
21918
+ }
21919
+ );
21920
+ if (!res.ok) {
21921
+ throw new Error(`Push memory failed: HTTP ${res.status}`);
21922
+ }
21923
+ console.log(`[agents] Pushed ${files.length} memory file(s) for agent ${agentId}`);
21924
+ }
21811
21925
  async resyncAgent(agentId) {
21812
21926
  try {
21813
21927
  await this.syncAgentConfig(agentId);
@@ -21859,6 +21973,37 @@ var AgentService = class _AgentService {
21859
21973
  this.updateSchedules(schedules);
21860
21974
  }
21861
21975
  };
21976
+ var VALID_PERMISSION_MODES = /* @__PURE__ */ new Set([
21977
+ "default",
21978
+ "acceptEdits",
21979
+ "bypassPermissions",
21980
+ "plan",
21981
+ "dontAsk"
21982
+ ]);
21983
+ function extractSdkOptions(config2) {
21984
+ const settings = config2?.settings;
21985
+ if (!settings || typeof settings !== "object") {
21986
+ return { permissionMode: void 0, model: void 0, allowedTools: void 0 };
21987
+ }
21988
+ const s = settings;
21989
+ let permissionMode;
21990
+ const perms = s.permissions;
21991
+ if (perms && typeof perms === "object" && perms !== null) {
21992
+ const defaultMode = perms.defaultMode;
21993
+ if (typeof defaultMode === "string" && VALID_PERMISSION_MODES.has(defaultMode)) {
21994
+ permissionMode = defaultMode;
21995
+ }
21996
+ }
21997
+ const model = typeof s.model === "string" && s.model.length > 0 ? s.model : void 0;
21998
+ let allowedTools;
21999
+ if (perms && typeof perms === "object" && perms !== null) {
22000
+ const allow = perms.allow;
22001
+ if (Array.isArray(allow) && allow.length > 0) {
22002
+ allowedTools = allow.filter((t) => typeof t === "string");
22003
+ }
22004
+ }
22005
+ return { permissionMode, model, allowedTools };
22006
+ }
21862
22007
  async function createAgentService() {
21863
22008
  const auth = await loadAuth();
21864
22009
  return new AgentService({
@@ -21873,10 +22018,10 @@ import { spawn } from "child_process";
21873
22018
  import fs5 from "fs/promises";
21874
22019
  import http from "http";
21875
22020
  import os5 from "os";
21876
- import path5 from "path";
21877
- var CLAW_HOME = path5.join(os5.homedir(), ".workle");
21878
- var LOG_FILE = path5.join(CLAW_HOME, "openclaw.log");
21879
- var PID_FILE = path5.join(CLAW_HOME, "openclaw.pid");
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");
21880
22025
  var OPENCLAW_PORT = 18789;
21881
22026
  var HEALTH_CHECK_TIMEOUT = 5e3;
21882
22027
  var ProcessManager = class {
@@ -21889,7 +22034,7 @@ var ProcessManager = class {
21889
22034
  * @param openclawBinary - Path to the openclaw binary (defaults to "openclaw" in PATH)
21890
22035
  * @param configPath - Path to openclaw.json config (defaults to ~/.workle/openclaw.json)
21891
22036
  */
21892
- async spawn(openclawBinary = "openclaw", configPath = path5.join(CLAW_HOME, "openclaw.json")) {
22037
+ async spawn(openclawBinary = "openclaw", configPath = path6.join(CLAW_HOME, "openclaw.json")) {
21893
22038
  if (this.process) {
21894
22039
  console.log("[claw] OpenClaw process already running");
21895
22040
  return;
@@ -22021,8 +22166,8 @@ var ProcessManager = class {
22021
22166
  import { execSync } from "child_process";
22022
22167
  import fs6 from "fs/promises";
22023
22168
  import os6 from "os";
22024
- import path6 from "path";
22025
- var WORKLE_HOME2 = path6.join(os6.homedir(), ".workle");
22169
+ import path7 from "path";
22170
+ var WORKLE_HOME2 = path7.join(os6.homedir(), ".workle");
22026
22171
  var MIN_NODE_MAJOR = 22;
22027
22172
  async function runDoctor() {
22028
22173
  const checks = [];
@@ -22105,7 +22250,7 @@ async function checkClawHome() {
22105
22250
  }
22106
22251
  }
22107
22252
  async function checkAuthFile() {
22108
- const authPath = path6.join(WORKLE_HOME2, "auth.json");
22253
+ const authPath = path7.join(WORKLE_HOME2, "auth.json");
22109
22254
  try {
22110
22255
  const raw = await fs6.readFile(authPath, "utf-8");
22111
22256
  const parsed = JSON.parse(raw);
@@ -22130,7 +22275,7 @@ async function checkAuthFile() {
22130
22275
  }
22131
22276
  }
22132
22277
  async function checkConfigFile() {
22133
- const configPath = path6.join(WORKLE_HOME2, "openclaw.json");
22278
+ const configPath = path7.join(WORKLE_HOME2, "openclaw.json");
22134
22279
  try {
22135
22280
  const raw = await fs6.readFile(configPath, "utf-8");
22136
22281
  const parsed = JSON.parse(raw);
@@ -22179,25 +22324,25 @@ async function checkGatewayReachable() {
22179
22324
  // src/lifecycle/install.ts
22180
22325
  import fs7 from "fs/promises";
22181
22326
  import os7 from "os";
22182
- import path7 from "path";
22183
- var WORKLE_HOME3 = path7.join(os7.homedir(), ".workle");
22184
- var LAUNCH_AGENTS_DIR = path7.join(os7.homedir(), "Library", "LaunchAgents");
22185
- var STAGED_CLI_PATH = path7.join(WORKLE_HOME3, "bin", "cli.js");
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");
22186
22331
  function escapeXml(value) {
22187
22332
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
22188
22333
  }
22189
22334
  async function setupClawDirectory() {
22190
22335
  const dirs = [
22191
22336
  WORKLE_HOME3,
22192
- path7.join(WORKLE_HOME3, "logs"),
22193
- path7.join(WORKLE_HOME3, "bin")
22337
+ path8.join(WORKLE_HOME3, "logs"),
22338
+ path8.join(WORKLE_HOME3, "bin")
22194
22339
  ];
22195
22340
  for (const dir of dirs) {
22196
22341
  await fs7.mkdir(dir, { recursive: true, mode: 448 });
22197
22342
  await fs7.chmod(dir, 448).catch(() => {
22198
22343
  });
22199
22344
  }
22200
- const gitignorePath = path7.join(WORKLE_HOME3, ".gitignore");
22345
+ const gitignorePath = path8.join(WORKLE_HOME3, ".gitignore");
22201
22346
  try {
22202
22347
  await fs7.access(gitignorePath);
22203
22348
  } catch {
@@ -22221,7 +22366,7 @@ async function stageCliForDaemon(currentCliPath) {
22221
22366
  }
22222
22367
  async function writeLaunchdPlist(serviceName = "com.workle.claw", executable = process.execPath, args = [STAGED_CLI_PATH, "start"]) {
22223
22368
  await fs7.mkdir(LAUNCH_AGENTS_DIR, { recursive: true });
22224
- const plistPath = path7.join(LAUNCH_AGENTS_DIR, `${serviceName}.plist`);
22369
+ const plistPath = path8.join(LAUNCH_AGENTS_DIR, `${serviceName}.plist`);
22225
22370
  const programArguments = [executable, ...args].map((arg) => ` <string>${escapeXml(arg)}</string>`).join("\n");
22226
22371
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
22227
22372
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -22245,10 +22390,10 @@ ${programArguments}
22245
22390
  </dict>
22246
22391
 
22247
22392
  <key>StandardOutPath</key>
22248
- <string>${path7.join(WORKLE_HOME3, "logs", "stdout.log")}</string>
22393
+ <string>${path8.join(WORKLE_HOME3, "logs", "stdout.log")}</string>
22249
22394
 
22250
22395
  <key>StandardErrorPath</key>
22251
- <string>${path7.join(WORKLE_HOME3, "logs", "stderr.log")}</string>
22396
+ <string>${path8.join(WORKLE_HOME3, "logs", "stderr.log")}</string>
22252
22397
 
22253
22398
  <key>WorkingDirectory</key>
22254
22399
  <string>${WORKLE_HOME3}</string>
@@ -22269,18 +22414,18 @@ ${programArguments}
22269
22414
  // src/sync/service.ts
22270
22415
  import fs15 from "fs/promises";
22271
22416
  import os17 from "os";
22272
- import path17 from "path";
22417
+ import path18 from "path";
22273
22418
 
22274
22419
  // src/legacy/openclaw/gateway.ts
22275
22420
  import os8 from "os";
22276
- import path8 from "path";
22277
- var CLAW_HOME2 = path8.join(os8.homedir(), ".workle");
22421
+ import path9 from "path";
22422
+ var CLAW_HOME2 = path9.join(os8.homedir(), ".workle");
22278
22423
  function generateGatewayConfig(_instance, agents) {
22279
22424
  const sorted = [...agents].sort((a, b) => a.sortOrder - b.sortOrder);
22280
22425
  const list = sorted.map((agent) => ({
22281
22426
  id: agent.id,
22282
22427
  default: !agent.isSubAgent,
22283
- workspace: path8.join(CLAW_HOME2, `workspace-${agent.agentKey}`),
22428
+ workspace: path9.join(CLAW_HOME2, `workspace-${agent.agentKey}`),
22284
22429
  model: agent.model,
22285
22430
  toolProfile: agent.toolProfile,
22286
22431
  promptMode: agent.promptMode
@@ -22293,8 +22438,8 @@ function generateGatewayConfig(_instance, agents) {
22293
22438
  // src/legacy/openclaw/soul.ts
22294
22439
  import fs8 from "fs/promises";
22295
22440
  import os9 from "os";
22296
- import path9 from "path";
22297
- var CLAW_HOME3 = path9.join(os9.homedir(), ".workle");
22441
+ import path10 from "path";
22442
+ var CLAW_HOME3 = path10.join(os9.homedir(), ".workle");
22298
22443
  var DEFAULT_SOUL_MD = `# Soul
22299
22444
 
22300
22445
  You are a Workle agent. Follow your assigned skills and operational instructions.
@@ -22306,17 +22451,17 @@ async function writeSoulMd(agentKey, content, rpcCall) {
22306
22451
  await rpcCall(agentKey, "SOUL.md", body);
22307
22452
  return;
22308
22453
  }
22309
- const workspaceDir = path9.join(CLAW_HOME3, `workspace-${agentKey}`);
22454
+ const workspaceDir = path10.join(CLAW_HOME3, `workspace-${agentKey}`);
22310
22455
  await fs8.mkdir(workspaceDir, { recursive: true });
22311
- const filePath = path9.join(workspaceDir, "SOUL.md");
22456
+ const filePath = path10.join(workspaceDir, "SOUL.md");
22312
22457
  await fs8.writeFile(filePath, body, "utf-8");
22313
22458
  }
22314
22459
 
22315
22460
  // src/legacy/openclaw/agents.ts
22316
22461
  import fs9 from "fs/promises";
22317
22462
  import os10 from "os";
22318
- import path10 from "path";
22319
- var CLAW_HOME4 = path10.join(os10.homedir(), ".workle");
22463
+ import path11 from "path";
22464
+ var CLAW_HOME4 = path11.join(os10.homedir(), ".workle");
22320
22465
  var DEFAULT_AGENTS_MD = `# Agents
22321
22466
 
22322
22467
  No additional agent configuration provided.
@@ -22327,17 +22472,17 @@ async function writeAgentsMd(agentKey, content, rpcCall) {
22327
22472
  await rpcCall(agentKey, "AGENTS.md", body);
22328
22473
  return;
22329
22474
  }
22330
- const workspaceDir = path10.join(CLAW_HOME4, `workspace-${agentKey}`);
22475
+ const workspaceDir = path11.join(CLAW_HOME4, `workspace-${agentKey}`);
22331
22476
  await fs9.mkdir(workspaceDir, { recursive: true });
22332
- const filePath = path10.join(workspaceDir, "AGENTS.md");
22477
+ const filePath = path11.join(workspaceDir, "AGENTS.md");
22333
22478
  await fs9.writeFile(filePath, body, "utf-8");
22334
22479
  }
22335
22480
 
22336
22481
  // src/config/identity.ts
22337
22482
  import fs10 from "fs/promises";
22338
22483
  import os11 from "os";
22339
- import path11 from "path";
22340
- var WORKLE_HOME4 = path11.join(os11.homedir(), ".workle");
22484
+ import path12 from "path";
22485
+ var WORKLE_HOME4 = path12.join(os11.homedir(), ".workle");
22341
22486
  var DEFAULT_IDENTITY_MD = `# Identity
22342
22487
 
22343
22488
  No identity configuration provided.
@@ -22348,17 +22493,17 @@ async function writeIdentityMd(agentKey, content, rpcCall) {
22348
22493
  await rpcCall(agentKey, "IDENTITY.md", body);
22349
22494
  return;
22350
22495
  }
22351
- const workspaceDir = path11.join(WORKLE_HOME4, `workspace-${agentKey}`);
22496
+ const workspaceDir = path12.join(WORKLE_HOME4, `workspace-${agentKey}`);
22352
22497
  await fs10.mkdir(workspaceDir, { recursive: true });
22353
- const filePath = path11.join(workspaceDir, "IDENTITY.md");
22498
+ const filePath = path12.join(workspaceDir, "IDENTITY.md");
22354
22499
  await fs10.writeFile(filePath, body, "utf-8");
22355
22500
  }
22356
22501
 
22357
22502
  // src/config/heartbeat.ts
22358
22503
  import fs11 from "fs/promises";
22359
22504
  import os12 from "os";
22360
- import path12 from "path";
22361
- var WORKLE_HOME5 = path12.join(os12.homedir(), ".workle");
22505
+ import path13 from "path";
22506
+ var WORKLE_HOME5 = path13.join(os12.homedir(), ".workle");
22362
22507
  var DEFAULT_HEARTBEAT_MD = `# Heartbeat
22363
22508
 
22364
22509
  No heartbeat configuration provided.
@@ -22369,34 +22514,34 @@ async function writeHeartbeatMd(agentKey, content, rpcCall) {
22369
22514
  await rpcCall(agentKey, "HEARTBEAT.md", body);
22370
22515
  return;
22371
22516
  }
22372
- const workspaceDir = path12.join(WORKLE_HOME5, `workspace-${agentKey}`);
22517
+ const workspaceDir = path13.join(WORKLE_HOME5, `workspace-${agentKey}`);
22373
22518
  await fs11.mkdir(workspaceDir, { recursive: true });
22374
- const filePath = path12.join(workspaceDir, "HEARTBEAT.md");
22519
+ const filePath = path13.join(workspaceDir, "HEARTBEAT.md");
22375
22520
  await fs11.writeFile(filePath, body, "utf-8");
22376
22521
  }
22377
22522
 
22378
22523
  // src/config/skills.ts
22379
22524
  import fs12 from "fs/promises";
22380
22525
  import os13 from "os";
22381
- import path13 from "path";
22382
- var WORKLE_HOME6 = path13.join(os13.homedir(), ".workle");
22526
+ import path14 from "path";
22527
+ var WORKLE_HOME6 = path14.join(os13.homedir(), ".workle");
22383
22528
 
22384
22529
  // src/legacy/openclaw/rpc.ts
22385
22530
  import crypto4 from "crypto";
22386
22531
  import fs13 from "fs";
22387
22532
  import os14 from "os";
22388
- import path14 from "path";
22533
+ import path15 from "path";
22389
22534
  var OPENCLAW_PORT2 = 18789;
22390
22535
  var OPENCLAW_URL = `ws://127.0.0.1:${OPENCLAW_PORT2}`;
22391
22536
  var RPC_TIMEOUT = 3e4;
22392
22537
  var MAX_RECONNECT_BACKOFF = 1e4;
22393
22538
  var CLAW_VERSION = "0.1.16";
22394
22539
  var OPENCLAW_CONFIG_PATHS = [
22395
- () => path14.join(os14.homedir(), ".openclaw", "openclaw.json"),
22396
- () => path14.join(os14.homedir(), ".config", "openclaw", "openclaw.json")
22540
+ () => path15.join(os14.homedir(), ".openclaw", "openclaw.json"),
22541
+ () => path15.join(os14.homedir(), ".config", "openclaw", "openclaw.json")
22397
22542
  ];
22398
- var CLAW_IDENTITY_DIR = path14.join(os14.homedir(), ".workle");
22399
- var CLAW_IDENTITY_FILE = path14.join(CLAW_IDENTITY_DIR, "device-identity.json");
22543
+ var CLAW_IDENTITY_DIR = path15.join(os14.homedir(), ".workle");
22544
+ var CLAW_IDENTITY_FILE = path15.join(CLAW_IDENTITY_DIR, "device-identity.json");
22400
22545
  var ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
22401
22546
  function base64UrlEncode(buf) {
22402
22547
  return buf.toString("base64").replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/g, "");
@@ -22905,17 +23050,17 @@ async function agentDiscovery(rpc, apiUrl, instanceId, token) {
22905
23050
 
22906
23051
  // src/sync/events.ts
22907
23052
  import os16 from "os";
22908
- import path16 from "path";
23053
+ import path17 from "path";
22909
23054
 
22910
23055
  // src/sync/queue.ts
22911
23056
  import fs14 from "fs/promises";
22912
23057
  import os15 from "os";
22913
- import path15 from "path";
23058
+ import path16 from "path";
22914
23059
  var MAX_FILE_SIZE = 5e8;
22915
23060
  var PersistentEventQueue = class {
22916
23061
  filePath;
22917
23062
  constructor(customPath) {
22918
- this.filePath = customPath ?? path15.join(os15.homedir(), ".workle", "pending-events.jsonl");
23063
+ this.filePath = customPath ?? path16.join(os15.homedir(), ".workle", "pending-events.jsonl");
22919
23064
  }
22920
23065
  /**
22921
23066
  * Append a single entry to the queue file.
@@ -22982,7 +23127,7 @@ var PersistentEventQueue = class {
22982
23127
  }
22983
23128
  // --- Internal ---
22984
23129
  async ensureDir() {
22985
- const dir = path15.dirname(this.filePath);
23130
+ const dir = path16.dirname(this.filePath);
22986
23131
  await fs14.mkdir(dir, { recursive: true });
22987
23132
  }
22988
23133
  /**
@@ -23010,7 +23155,7 @@ var PersistentEventQueue = class {
23010
23155
  };
23011
23156
 
23012
23157
  // src/sync/events.ts
23013
- var WORKLE_HOME7 = path16.join(os16.homedir(), ".workle");
23158
+ var WORKLE_HOME7 = path17.join(os16.homedir(), ".workle");
23014
23159
  var EVENT_TYPE_MAP = {
23015
23160
  "agent.run": "agent.started",
23016
23161
  "agent.run.complete": "agent.completed",
@@ -23051,7 +23196,7 @@ function getQueue(instanceId) {
23051
23196
  const existing = sharedQueues.get(queueKey);
23052
23197
  if (existing) return existing;
23053
23198
  const queue = new PersistentEventQueue(
23054
- path16.join(WORKLE_HOME7, `pending-events-${queueKey}.jsonl`)
23199
+ path17.join(WORKLE_HOME7, `pending-events-${queueKey}.jsonl`)
23055
23200
  );
23056
23201
  sharedQueues.set(queueKey, queue);
23057
23202
  return queue;
@@ -23114,7 +23259,7 @@ async function replayPendingEvents(apiUrl, token, instanceId) {
23114
23259
  }
23115
23260
 
23116
23261
  // src/sync/service.ts
23117
- var WORKLE_HOME8 = path17.join(os17.homedir(), ".workle");
23262
+ var WORKLE_HOME8 = path18.join(os17.homedir(), ".workle");
23118
23263
  function deriveRelayUrl2(apiUrl) {
23119
23264
  const url2 = new URL(apiUrl);
23120
23265
  url2.protocol = url2.protocol === "https:" ? "wss:" : "ws:";
@@ -23135,6 +23280,7 @@ var SyncService = class {
23135
23280
  unsubscribeRelayMessages = null;
23136
23281
  running = false;
23137
23282
  externalMessageHandler = null;
23283
+ reconnectHandler = null;
23138
23284
  /**
23139
23285
  * Register a handler for relay messages that SyncService doesn't handle
23140
23286
  * (e.g. agent.trigger, agent.cancel, agent.config.updated).
@@ -23143,6 +23289,14 @@ var SyncService = class {
23143
23289
  onRelayMessage(handler) {
23144
23290
  this.externalMessageHandler = handler;
23145
23291
  }
23292
+ /**
23293
+ * Register a handler called after relay reconnects.
23294
+ * Used by AgentService to re-sync all agent configs on reconnect,
23295
+ * catching any agent.config.updated events missed during disconnect.
23296
+ */
23297
+ onReconnect(handler) {
23298
+ this.reconnectHandler = handler;
23299
+ }
23146
23300
  /**
23147
23301
  * Send a message through the relay WebSocket connection.
23148
23302
  * Used by AgentService in embedded mode to send progress/result frames.
@@ -23231,6 +23385,13 @@ var SyncService = class {
23231
23385
  } catch (err) {
23232
23386
  console.error("[claw] Event replay on connect failed:", err);
23233
23387
  }
23388
+ if (this.reconnectHandler) {
23389
+ try {
23390
+ await this.reconnectHandler();
23391
+ } catch (err) {
23392
+ console.error("[claw] Agent config re-sync on reconnect failed:", err);
23393
+ }
23394
+ }
23234
23395
  })();
23235
23396
  }
23236
23397
  }
@@ -23246,6 +23407,7 @@ var SyncService = class {
23246
23407
  }
23247
23408
  this.unsubscribeRelayMessages = this.relayClient.onMessage((msg) => {
23248
23409
  if (msg.type !== "rpc.request") {
23410
+ console.log(`[claw] Relay message received: type=${msg.type}`, JSON.stringify(msg).slice(0, 200));
23249
23411
  if (this.externalMessageHandler) {
23250
23412
  this.externalMessageHandler(msg);
23251
23413
  }
@@ -23467,7 +23629,7 @@ var SyncService = class {
23467
23629
  }
23468
23630
  async writeConfigFiles(instance, agents) {
23469
23631
  const gatewayConfig = generateGatewayConfig(instance, agents);
23470
- const configPath = path17.join(WORKLE_HOME8, "openclaw.json");
23632
+ const configPath = path18.join(WORKLE_HOME8, "openclaw.json");
23471
23633
  await fs15.mkdir(WORKLE_HOME8, { recursive: true });
23472
23634
  await fs15.writeFile(configPath, JSON.stringify(gatewayConfig, null, 2), "utf-8");
23473
23635
  await Promise.all(
@@ -23482,9 +23644,9 @@ var SyncService = class {
23482
23644
  };
23483
23645
 
23484
23646
  // src/cli.ts
23485
- var WORKLE_HOME9 = path18.join(os18.homedir(), ".workle");
23486
- var AUTH_FILE2 = path18.join(WORKLE_HOME9, "auth.json");
23487
- var LAUNCH_AGENTS_DIR2 = path18.join(os18.homedir(), "Library", "LaunchAgents");
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");
23488
23650
  var PLIST_LABEL = "com.workle.claw";
23489
23651
  var color = {
23490
23652
  green: (s) => `\x1B[32m${s}\x1B[0m`,
@@ -23734,7 +23896,7 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23734
23896
  console.log("");
23735
23897
  console.log(` Service: ${color.dim(PLIST_LABEL)}`);
23736
23898
  console.log(` Plist: ${color.dim(plistPath)}`);
23737
- console.log(` Logs: ${color.dim(path18.join(WORKLE_HOME9, "logs/"))}`);
23899
+ console.log(` Logs: ${color.dim(path19.join(WORKLE_HOME9, "logs/"))}`);
23738
23900
  console.log("");
23739
23901
  console.log(
23740
23902
  `To stop: ${color.cyan("npx @getworkle/cli stop")}`
@@ -23779,7 +23941,12 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23779
23941
  await syncService.start();
23780
23942
  try {
23781
23943
  agentService = await createAgentService();
23782
- syncService.onRelayMessage((msg) => agentService.ingestRelayMessage(msg));
23944
+ syncService.onRelayMessage((msg) => agentService?.ingestRelayMessage(msg));
23945
+ syncService.onReconnect(async () => {
23946
+ if (agentService) {
23947
+ await agentService.resyncAllConfigs();
23948
+ }
23949
+ });
23783
23950
  await agentService.startEmbedded((msg) => syncService.sendRelayMessage(msg));
23784
23951
  } catch (err) {
23785
23952
  console.error(
@@ -23802,14 +23969,14 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23802
23969
  }
23803
23970
  });
23804
23971
  program2.command("stop").description("Stop the Workle Claw daemon").action(async () => {
23805
- const plistPath = path18.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
23972
+ const plistPath = path19.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
23806
23973
  try {
23807
23974
  execSync2(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
23808
23975
  console.log(color.green("\u2713 Daemon stopped"));
23809
23976
  } catch {
23810
23977
  console.log(color.dim("No launchd service loaded."));
23811
23978
  }
23812
- const pidFile = path18.join(WORKLE_HOME9, "openclaw.pid");
23979
+ const pidFile = path19.join(WORKLE_HOME9, "openclaw.pid");
23813
23980
  try {
23814
23981
  const pidStr = await fs16.readFile(pidFile, "utf-8");
23815
23982
  const pid = parseInt(pidStr.trim(), 10);
@@ -23854,7 +24021,7 @@ program2.command("status").description("Show connection state and instance info"
23854
24021
  } catch {
23855
24022
  console.log(` Gateway: ${color.yellow("unreachable")}`);
23856
24023
  }
23857
- const plistPath = path18.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
24024
+ const plistPath = path19.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
23858
24025
  try {
23859
24026
  await fs16.access(plistPath);
23860
24027
  try {
@@ -23881,8 +24048,8 @@ program2.command("logs").description("Tail the Workle Claw log files").option("-
23881
24048
  process.exit(1);
23882
24049
  }
23883
24050
  const logFiles = [
23884
- path18.join(WORKLE_HOME9, "openclaw.log"),
23885
- path18.join(WORKLE_HOME9, "logs", "stderr.log")
24051
+ path19.join(WORKLE_HOME9, "openclaw.log"),
24052
+ path19.join(WORKLE_HOME9, "logs", "stderr.log")
23886
24053
  ];
23887
24054
  const args = ["-n", String(lineCount)];
23888
24055
  if (opts.follow) args.push("-f");
@@ -24046,12 +24213,12 @@ agentCmd.command("logs [agentId]").description("Tail agent run logs").option("-n
24046
24213
  console.error(color.red("Error: --lines must be a positive integer."));
24047
24214
  process.exit(1);
24048
24215
  }
24049
- const logsDir = path18.join(WORKLE_HOME9, "agents");
24216
+ const logsDir = path19.join(WORKLE_HOME9, "agents");
24050
24217
  let logFile;
24051
24218
  if (agentId) {
24052
- logFile = path18.join(logsDir, agentId, "run.log");
24219
+ logFile = path19.join(logsDir, agentId, "run.log");
24053
24220
  } else {
24054
- logFile = path18.join(logsDir, "*", "run.log");
24221
+ logFile = path19.join(logsDir, "*", "run.log");
24055
24222
  }
24056
24223
  const args = ["-n", String(lineCount)];
24057
24224
  if (opts.follow) args.push("-f");