@getworkle/cli 0.2.11 → 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,7 +8298,7 @@ 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,
@@ -8267,6 +8308,10 @@ async function runAgent(opts) {
8267
8308
  // Full path to node — launchd doesn't have node in PATH
8268
8309
  cwd: agentDir,
8269
8310
  settingSources: ["project"],
8311
+ ...permissionMode ? { permissionMode } : {},
8312
+ ...permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {},
8313
+ ...model ? { model } : {},
8314
+ ...allowedTools && allowedTools.length > 0 ? { allowedTools } : {},
8270
8315
  ...sessionId ? { resume: sessionId } : {},
8271
8316
  ...typeof maxTurns === "number" ? { maxTurns } : {},
8272
8317
  ...mcpServers ? { mcpServers } : {},
@@ -9067,10 +9112,10 @@ function mergeDefs(...defs) {
9067
9112
  function cloneDef(schema) {
9068
9113
  return mergeDefs(schema._zod.def);
9069
9114
  }
9070
- function getElementAtPath(obj, path19) {
9071
- if (!path19)
9115
+ function getElementAtPath(obj, path20) {
9116
+ if (!path20)
9072
9117
  return obj;
9073
- return path19.reduce((acc, key) => acc?.[key], obj);
9118
+ return path20.reduce((acc, key) => acc?.[key], obj);
9074
9119
  }
9075
9120
  function promiseAllObject(promisesObj) {
9076
9121
  const keys = Object.keys(promisesObj);
@@ -9436,11 +9481,11 @@ function aborted(x, startIndex = 0) {
9436
9481
  }
9437
9482
  return false;
9438
9483
  }
9439
- function prefixIssues(path19, issues) {
9484
+ function prefixIssues(path20, issues) {
9440
9485
  return issues.map((iss) => {
9441
9486
  var _a2;
9442
9487
  (_a2 = iss).path ?? (_a2.path = []);
9443
- iss.path.unshift(path19);
9488
+ iss.path.unshift(path20);
9444
9489
  return iss;
9445
9490
  });
9446
9491
  }
@@ -9602,7 +9647,7 @@ function formatError(error46, mapper = (issue2) => issue2.message) {
9602
9647
  }
9603
9648
  function treeifyError(error46, mapper = (issue2) => issue2.message) {
9604
9649
  const result = { errors: [] };
9605
- const processError = (error47, path19 = []) => {
9650
+ const processError = (error47, path20 = []) => {
9606
9651
  var _a2, _b;
9607
9652
  for (const issue2 of error47.issues) {
9608
9653
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -9612,7 +9657,7 @@ function treeifyError(error46, mapper = (issue2) => issue2.message) {
9612
9657
  } else if (issue2.code === "invalid_element") {
9613
9658
  processError({ issues: issue2.issues }, issue2.path);
9614
9659
  } else {
9615
- const fullpath = [...path19, ...issue2.path];
9660
+ const fullpath = [...path20, ...issue2.path];
9616
9661
  if (fullpath.length === 0) {
9617
9662
  result.errors.push(mapper(issue2));
9618
9663
  continue;
@@ -9644,8 +9689,8 @@ function treeifyError(error46, mapper = (issue2) => issue2.message) {
9644
9689
  }
9645
9690
  function toDotPath(_path) {
9646
9691
  const segs = [];
9647
- const path19 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9648
- for (const seg of path19) {
9692
+ const path20 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
9693
+ for (const seg of path20) {
9649
9694
  if (typeof seg === "number")
9650
9695
  segs.push(`[${seg}]`);
9651
9696
  else if (typeof seg === "symbol")
@@ -20981,23 +21026,23 @@ function date4(params) {
20981
21026
  config(en_default());
20982
21027
 
20983
21028
  // src/agents/mcp-server.ts
20984
- async function apiGet(apiUrl, path19, headers) {
20985
- const res = await fetch(`${apiUrl}${path19}`, {
21029
+ async function apiGet(apiUrl, path20, headers) {
21030
+ const res = await fetch(`${apiUrl}${path20}`, {
20986
21031
  headers: { ...headers, "Content-Type": "application/json" }
20987
21032
  });
20988
21033
  if (!res.ok) {
20989
- throw new Error(`API GET ${path19} failed: HTTP ${res.status}`);
21034
+ throw new Error(`API GET ${path20} failed: HTTP ${res.status}`);
20990
21035
  }
20991
21036
  return res.json();
20992
21037
  }
20993
- async function apiPost(apiUrl, path19, body, headers) {
20994
- const res = await fetch(`${apiUrl}${path19}`, {
21038
+ async function apiPost(apiUrl, path20, body, headers) {
21039
+ const res = await fetch(`${apiUrl}${path20}`, {
20995
21040
  method: "POST",
20996
21041
  headers: { ...headers, "Content-Type": "application/json" },
20997
21042
  body: JSON.stringify(body)
20998
21043
  });
20999
21044
  if (!res.ok) {
21000
- throw new Error(`API POST ${path19} failed: HTTP ${res.status}`);
21045
+ throw new Error(`API POST ${path20} failed: HTTP ${res.status}`);
21001
21046
  }
21002
21047
  return res.json();
21003
21048
  }
@@ -21123,6 +21168,7 @@ var AgentScheduler = class {
21123
21168
  // src/agents/service.ts
21124
21169
  import { randomUUID } from "crypto";
21125
21170
  import fs4 from "fs/promises";
21171
+ import path5 from "path";
21126
21172
 
21127
21173
  // ../../node_modules/ws/wrapper.mjs
21128
21174
  var import_stream = __toESM(require_stream(), 1);
@@ -21563,11 +21609,15 @@ var AgentService = class _AgentService {
21563
21609
  instanceId: this.instanceId,
21564
21610
  token: this.token
21565
21611
  });
21612
+ const { permissionMode, model, allowedTools } = extractSdkOptions(config2);
21566
21613
  const result = await runAgent({
21567
21614
  agentDir,
21568
21615
  prompt,
21569
21616
  sessionId: previousSessionId,
21570
21617
  maxTurns: typeof config2?.maxTurns === "number" ? config2.maxTurns : void 0,
21618
+ permissionMode,
21619
+ model,
21620
+ allowedTools,
21571
21621
  mcpServers: { workle: mcpServer },
21572
21622
  abortController,
21573
21623
  onMessage: (message) => {
@@ -21718,6 +21768,12 @@ var AgentService = class _AgentService {
21718
21768
  if (resumeSession && result.sessionId) {
21719
21769
  await saveSessionId(agentId, result.sessionId);
21720
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
+ });
21721
21777
  return result;
21722
21778
  })();
21723
21779
  this.activeRuns.set(agentId, runPromise);
@@ -21759,6 +21815,28 @@ var AgentService = class _AgentService {
21759
21815
  this.activeAborts.delete(runExecutionId);
21760
21816
  }
21761
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
+ }
21762
21840
  /**
21763
21841
  * Graceful shutdown.
21764
21842
  */
@@ -21788,6 +21866,7 @@ var AgentService = class _AgentService {
21788
21866
  }
21789
21867
  // ── Internal ────────────────────────────────────────────────────────────
21790
21868
  handleRelayMessage(msg) {
21869
+ console.log(`[agents] handleRelayMessage: type=${msg.type}`);
21791
21870
  if (msg.type === "agent.trigger") {
21792
21871
  const frame = msg;
21793
21872
  const { agentId, prompt, executionId, resumeSession } = frame.payload;
@@ -21810,6 +21889,39 @@ var AgentService = class _AgentService {
21810
21889
  }
21811
21890
  }
21812
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
+ }
21813
21925
  async resyncAgent(agentId) {
21814
21926
  try {
21815
21927
  await this.syncAgentConfig(agentId);
@@ -21861,6 +21973,37 @@ var AgentService = class _AgentService {
21861
21973
  this.updateSchedules(schedules);
21862
21974
  }
21863
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
+ }
21864
22007
  async function createAgentService() {
21865
22008
  const auth = await loadAuth();
21866
22009
  return new AgentService({
@@ -21875,10 +22018,10 @@ import { spawn } from "child_process";
21875
22018
  import fs5 from "fs/promises";
21876
22019
  import http from "http";
21877
22020
  import os5 from "os";
21878
- import path5 from "path";
21879
- var CLAW_HOME = path5.join(os5.homedir(), ".workle");
21880
- var LOG_FILE = path5.join(CLAW_HOME, "openclaw.log");
21881
- 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");
21882
22025
  var OPENCLAW_PORT = 18789;
21883
22026
  var HEALTH_CHECK_TIMEOUT = 5e3;
21884
22027
  var ProcessManager = class {
@@ -21891,7 +22034,7 @@ var ProcessManager = class {
21891
22034
  * @param openclawBinary - Path to the openclaw binary (defaults to "openclaw" in PATH)
21892
22035
  * @param configPath - Path to openclaw.json config (defaults to ~/.workle/openclaw.json)
21893
22036
  */
21894
- async spawn(openclawBinary = "openclaw", configPath = path5.join(CLAW_HOME, "openclaw.json")) {
22037
+ async spawn(openclawBinary = "openclaw", configPath = path6.join(CLAW_HOME, "openclaw.json")) {
21895
22038
  if (this.process) {
21896
22039
  console.log("[claw] OpenClaw process already running");
21897
22040
  return;
@@ -22023,8 +22166,8 @@ var ProcessManager = class {
22023
22166
  import { execSync } from "child_process";
22024
22167
  import fs6 from "fs/promises";
22025
22168
  import os6 from "os";
22026
- import path6 from "path";
22027
- var WORKLE_HOME2 = path6.join(os6.homedir(), ".workle");
22169
+ import path7 from "path";
22170
+ var WORKLE_HOME2 = path7.join(os6.homedir(), ".workle");
22028
22171
  var MIN_NODE_MAJOR = 22;
22029
22172
  async function runDoctor() {
22030
22173
  const checks = [];
@@ -22107,7 +22250,7 @@ async function checkClawHome() {
22107
22250
  }
22108
22251
  }
22109
22252
  async function checkAuthFile() {
22110
- const authPath = path6.join(WORKLE_HOME2, "auth.json");
22253
+ const authPath = path7.join(WORKLE_HOME2, "auth.json");
22111
22254
  try {
22112
22255
  const raw = await fs6.readFile(authPath, "utf-8");
22113
22256
  const parsed = JSON.parse(raw);
@@ -22132,7 +22275,7 @@ async function checkAuthFile() {
22132
22275
  }
22133
22276
  }
22134
22277
  async function checkConfigFile() {
22135
- const configPath = path6.join(WORKLE_HOME2, "openclaw.json");
22278
+ const configPath = path7.join(WORKLE_HOME2, "openclaw.json");
22136
22279
  try {
22137
22280
  const raw = await fs6.readFile(configPath, "utf-8");
22138
22281
  const parsed = JSON.parse(raw);
@@ -22181,25 +22324,25 @@ async function checkGatewayReachable() {
22181
22324
  // src/lifecycle/install.ts
22182
22325
  import fs7 from "fs/promises";
22183
22326
  import os7 from "os";
22184
- import path7 from "path";
22185
- var WORKLE_HOME3 = path7.join(os7.homedir(), ".workle");
22186
- var LAUNCH_AGENTS_DIR = path7.join(os7.homedir(), "Library", "LaunchAgents");
22187
- 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");
22188
22331
  function escapeXml(value) {
22189
22332
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
22190
22333
  }
22191
22334
  async function setupClawDirectory() {
22192
22335
  const dirs = [
22193
22336
  WORKLE_HOME3,
22194
- path7.join(WORKLE_HOME3, "logs"),
22195
- path7.join(WORKLE_HOME3, "bin")
22337
+ path8.join(WORKLE_HOME3, "logs"),
22338
+ path8.join(WORKLE_HOME3, "bin")
22196
22339
  ];
22197
22340
  for (const dir of dirs) {
22198
22341
  await fs7.mkdir(dir, { recursive: true, mode: 448 });
22199
22342
  await fs7.chmod(dir, 448).catch(() => {
22200
22343
  });
22201
22344
  }
22202
- const gitignorePath = path7.join(WORKLE_HOME3, ".gitignore");
22345
+ const gitignorePath = path8.join(WORKLE_HOME3, ".gitignore");
22203
22346
  try {
22204
22347
  await fs7.access(gitignorePath);
22205
22348
  } catch {
@@ -22223,7 +22366,7 @@ async function stageCliForDaemon(currentCliPath) {
22223
22366
  }
22224
22367
  async function writeLaunchdPlist(serviceName = "com.workle.claw", executable = process.execPath, args = [STAGED_CLI_PATH, "start"]) {
22225
22368
  await fs7.mkdir(LAUNCH_AGENTS_DIR, { recursive: true });
22226
- const plistPath = path7.join(LAUNCH_AGENTS_DIR, `${serviceName}.plist`);
22369
+ const plistPath = path8.join(LAUNCH_AGENTS_DIR, `${serviceName}.plist`);
22227
22370
  const programArguments = [executable, ...args].map((arg) => ` <string>${escapeXml(arg)}</string>`).join("\n");
22228
22371
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
22229
22372
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -22247,10 +22390,10 @@ ${programArguments}
22247
22390
  </dict>
22248
22391
 
22249
22392
  <key>StandardOutPath</key>
22250
- <string>${path7.join(WORKLE_HOME3, "logs", "stdout.log")}</string>
22393
+ <string>${path8.join(WORKLE_HOME3, "logs", "stdout.log")}</string>
22251
22394
 
22252
22395
  <key>StandardErrorPath</key>
22253
- <string>${path7.join(WORKLE_HOME3, "logs", "stderr.log")}</string>
22396
+ <string>${path8.join(WORKLE_HOME3, "logs", "stderr.log")}</string>
22254
22397
 
22255
22398
  <key>WorkingDirectory</key>
22256
22399
  <string>${WORKLE_HOME3}</string>
@@ -22271,18 +22414,18 @@ ${programArguments}
22271
22414
  // src/sync/service.ts
22272
22415
  import fs15 from "fs/promises";
22273
22416
  import os17 from "os";
22274
- import path17 from "path";
22417
+ import path18 from "path";
22275
22418
 
22276
22419
  // src/legacy/openclaw/gateway.ts
22277
22420
  import os8 from "os";
22278
- import path8 from "path";
22279
- var CLAW_HOME2 = path8.join(os8.homedir(), ".workle");
22421
+ import path9 from "path";
22422
+ var CLAW_HOME2 = path9.join(os8.homedir(), ".workle");
22280
22423
  function generateGatewayConfig(_instance, agents) {
22281
22424
  const sorted = [...agents].sort((a, b) => a.sortOrder - b.sortOrder);
22282
22425
  const list = sorted.map((agent) => ({
22283
22426
  id: agent.id,
22284
22427
  default: !agent.isSubAgent,
22285
- workspace: path8.join(CLAW_HOME2, `workspace-${agent.agentKey}`),
22428
+ workspace: path9.join(CLAW_HOME2, `workspace-${agent.agentKey}`),
22286
22429
  model: agent.model,
22287
22430
  toolProfile: agent.toolProfile,
22288
22431
  promptMode: agent.promptMode
@@ -22295,8 +22438,8 @@ function generateGatewayConfig(_instance, agents) {
22295
22438
  // src/legacy/openclaw/soul.ts
22296
22439
  import fs8 from "fs/promises";
22297
22440
  import os9 from "os";
22298
- import path9 from "path";
22299
- var CLAW_HOME3 = path9.join(os9.homedir(), ".workle");
22441
+ import path10 from "path";
22442
+ var CLAW_HOME3 = path10.join(os9.homedir(), ".workle");
22300
22443
  var DEFAULT_SOUL_MD = `# Soul
22301
22444
 
22302
22445
  You are a Workle agent. Follow your assigned skills and operational instructions.
@@ -22308,17 +22451,17 @@ async function writeSoulMd(agentKey, content, rpcCall) {
22308
22451
  await rpcCall(agentKey, "SOUL.md", body);
22309
22452
  return;
22310
22453
  }
22311
- const workspaceDir = path9.join(CLAW_HOME3, `workspace-${agentKey}`);
22454
+ const workspaceDir = path10.join(CLAW_HOME3, `workspace-${agentKey}`);
22312
22455
  await fs8.mkdir(workspaceDir, { recursive: true });
22313
- const filePath = path9.join(workspaceDir, "SOUL.md");
22456
+ const filePath = path10.join(workspaceDir, "SOUL.md");
22314
22457
  await fs8.writeFile(filePath, body, "utf-8");
22315
22458
  }
22316
22459
 
22317
22460
  // src/legacy/openclaw/agents.ts
22318
22461
  import fs9 from "fs/promises";
22319
22462
  import os10 from "os";
22320
- import path10 from "path";
22321
- var CLAW_HOME4 = path10.join(os10.homedir(), ".workle");
22463
+ import path11 from "path";
22464
+ var CLAW_HOME4 = path11.join(os10.homedir(), ".workle");
22322
22465
  var DEFAULT_AGENTS_MD = `# Agents
22323
22466
 
22324
22467
  No additional agent configuration provided.
@@ -22329,17 +22472,17 @@ async function writeAgentsMd(agentKey, content, rpcCall) {
22329
22472
  await rpcCall(agentKey, "AGENTS.md", body);
22330
22473
  return;
22331
22474
  }
22332
- const workspaceDir = path10.join(CLAW_HOME4, `workspace-${agentKey}`);
22475
+ const workspaceDir = path11.join(CLAW_HOME4, `workspace-${agentKey}`);
22333
22476
  await fs9.mkdir(workspaceDir, { recursive: true });
22334
- const filePath = path10.join(workspaceDir, "AGENTS.md");
22477
+ const filePath = path11.join(workspaceDir, "AGENTS.md");
22335
22478
  await fs9.writeFile(filePath, body, "utf-8");
22336
22479
  }
22337
22480
 
22338
22481
  // src/config/identity.ts
22339
22482
  import fs10 from "fs/promises";
22340
22483
  import os11 from "os";
22341
- import path11 from "path";
22342
- var WORKLE_HOME4 = path11.join(os11.homedir(), ".workle");
22484
+ import path12 from "path";
22485
+ var WORKLE_HOME4 = path12.join(os11.homedir(), ".workle");
22343
22486
  var DEFAULT_IDENTITY_MD = `# Identity
22344
22487
 
22345
22488
  No identity configuration provided.
@@ -22350,17 +22493,17 @@ async function writeIdentityMd(agentKey, content, rpcCall) {
22350
22493
  await rpcCall(agentKey, "IDENTITY.md", body);
22351
22494
  return;
22352
22495
  }
22353
- const workspaceDir = path11.join(WORKLE_HOME4, `workspace-${agentKey}`);
22496
+ const workspaceDir = path12.join(WORKLE_HOME4, `workspace-${agentKey}`);
22354
22497
  await fs10.mkdir(workspaceDir, { recursive: true });
22355
- const filePath = path11.join(workspaceDir, "IDENTITY.md");
22498
+ const filePath = path12.join(workspaceDir, "IDENTITY.md");
22356
22499
  await fs10.writeFile(filePath, body, "utf-8");
22357
22500
  }
22358
22501
 
22359
22502
  // src/config/heartbeat.ts
22360
22503
  import fs11 from "fs/promises";
22361
22504
  import os12 from "os";
22362
- import path12 from "path";
22363
- var WORKLE_HOME5 = path12.join(os12.homedir(), ".workle");
22505
+ import path13 from "path";
22506
+ var WORKLE_HOME5 = path13.join(os12.homedir(), ".workle");
22364
22507
  var DEFAULT_HEARTBEAT_MD = `# Heartbeat
22365
22508
 
22366
22509
  No heartbeat configuration provided.
@@ -22371,34 +22514,34 @@ async function writeHeartbeatMd(agentKey, content, rpcCall) {
22371
22514
  await rpcCall(agentKey, "HEARTBEAT.md", body);
22372
22515
  return;
22373
22516
  }
22374
- const workspaceDir = path12.join(WORKLE_HOME5, `workspace-${agentKey}`);
22517
+ const workspaceDir = path13.join(WORKLE_HOME5, `workspace-${agentKey}`);
22375
22518
  await fs11.mkdir(workspaceDir, { recursive: true });
22376
- const filePath = path12.join(workspaceDir, "HEARTBEAT.md");
22519
+ const filePath = path13.join(workspaceDir, "HEARTBEAT.md");
22377
22520
  await fs11.writeFile(filePath, body, "utf-8");
22378
22521
  }
22379
22522
 
22380
22523
  // src/config/skills.ts
22381
22524
  import fs12 from "fs/promises";
22382
22525
  import os13 from "os";
22383
- import path13 from "path";
22384
- var WORKLE_HOME6 = path13.join(os13.homedir(), ".workle");
22526
+ import path14 from "path";
22527
+ var WORKLE_HOME6 = path14.join(os13.homedir(), ".workle");
22385
22528
 
22386
22529
  // src/legacy/openclaw/rpc.ts
22387
22530
  import crypto4 from "crypto";
22388
22531
  import fs13 from "fs";
22389
22532
  import os14 from "os";
22390
- import path14 from "path";
22533
+ import path15 from "path";
22391
22534
  var OPENCLAW_PORT2 = 18789;
22392
22535
  var OPENCLAW_URL = `ws://127.0.0.1:${OPENCLAW_PORT2}`;
22393
22536
  var RPC_TIMEOUT = 3e4;
22394
22537
  var MAX_RECONNECT_BACKOFF = 1e4;
22395
22538
  var CLAW_VERSION = "0.1.16";
22396
22539
  var OPENCLAW_CONFIG_PATHS = [
22397
- () => path14.join(os14.homedir(), ".openclaw", "openclaw.json"),
22398
- () => 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")
22399
22542
  ];
22400
- var CLAW_IDENTITY_DIR = path14.join(os14.homedir(), ".workle");
22401
- 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");
22402
22545
  var ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
22403
22546
  function base64UrlEncode(buf) {
22404
22547
  return buf.toString("base64").replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/g, "");
@@ -22907,17 +23050,17 @@ async function agentDiscovery(rpc, apiUrl, instanceId, token) {
22907
23050
 
22908
23051
  // src/sync/events.ts
22909
23052
  import os16 from "os";
22910
- import path16 from "path";
23053
+ import path17 from "path";
22911
23054
 
22912
23055
  // src/sync/queue.ts
22913
23056
  import fs14 from "fs/promises";
22914
23057
  import os15 from "os";
22915
- import path15 from "path";
23058
+ import path16 from "path";
22916
23059
  var MAX_FILE_SIZE = 5e8;
22917
23060
  var PersistentEventQueue = class {
22918
23061
  filePath;
22919
23062
  constructor(customPath) {
22920
- this.filePath = customPath ?? path15.join(os15.homedir(), ".workle", "pending-events.jsonl");
23063
+ this.filePath = customPath ?? path16.join(os15.homedir(), ".workle", "pending-events.jsonl");
22921
23064
  }
22922
23065
  /**
22923
23066
  * Append a single entry to the queue file.
@@ -22984,7 +23127,7 @@ var PersistentEventQueue = class {
22984
23127
  }
22985
23128
  // --- Internal ---
22986
23129
  async ensureDir() {
22987
- const dir = path15.dirname(this.filePath);
23130
+ const dir = path16.dirname(this.filePath);
22988
23131
  await fs14.mkdir(dir, { recursive: true });
22989
23132
  }
22990
23133
  /**
@@ -23012,7 +23155,7 @@ var PersistentEventQueue = class {
23012
23155
  };
23013
23156
 
23014
23157
  // src/sync/events.ts
23015
- var WORKLE_HOME7 = path16.join(os16.homedir(), ".workle");
23158
+ var WORKLE_HOME7 = path17.join(os16.homedir(), ".workle");
23016
23159
  var EVENT_TYPE_MAP = {
23017
23160
  "agent.run": "agent.started",
23018
23161
  "agent.run.complete": "agent.completed",
@@ -23053,7 +23196,7 @@ function getQueue(instanceId) {
23053
23196
  const existing = sharedQueues.get(queueKey);
23054
23197
  if (existing) return existing;
23055
23198
  const queue = new PersistentEventQueue(
23056
- path16.join(WORKLE_HOME7, `pending-events-${queueKey}.jsonl`)
23199
+ path17.join(WORKLE_HOME7, `pending-events-${queueKey}.jsonl`)
23057
23200
  );
23058
23201
  sharedQueues.set(queueKey, queue);
23059
23202
  return queue;
@@ -23116,7 +23259,7 @@ async function replayPendingEvents(apiUrl, token, instanceId) {
23116
23259
  }
23117
23260
 
23118
23261
  // src/sync/service.ts
23119
- var WORKLE_HOME8 = path17.join(os17.homedir(), ".workle");
23262
+ var WORKLE_HOME8 = path18.join(os17.homedir(), ".workle");
23120
23263
  function deriveRelayUrl2(apiUrl) {
23121
23264
  const url2 = new URL(apiUrl);
23122
23265
  url2.protocol = url2.protocol === "https:" ? "wss:" : "ws:";
@@ -23137,6 +23280,7 @@ var SyncService = class {
23137
23280
  unsubscribeRelayMessages = null;
23138
23281
  running = false;
23139
23282
  externalMessageHandler = null;
23283
+ reconnectHandler = null;
23140
23284
  /**
23141
23285
  * Register a handler for relay messages that SyncService doesn't handle
23142
23286
  * (e.g. agent.trigger, agent.cancel, agent.config.updated).
@@ -23145,6 +23289,14 @@ var SyncService = class {
23145
23289
  onRelayMessage(handler) {
23146
23290
  this.externalMessageHandler = handler;
23147
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
+ }
23148
23300
  /**
23149
23301
  * Send a message through the relay WebSocket connection.
23150
23302
  * Used by AgentService in embedded mode to send progress/result frames.
@@ -23233,6 +23385,13 @@ var SyncService = class {
23233
23385
  } catch (err) {
23234
23386
  console.error("[claw] Event replay on connect failed:", err);
23235
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
+ }
23236
23395
  })();
23237
23396
  }
23238
23397
  }
@@ -23248,6 +23407,7 @@ var SyncService = class {
23248
23407
  }
23249
23408
  this.unsubscribeRelayMessages = this.relayClient.onMessage((msg) => {
23250
23409
  if (msg.type !== "rpc.request") {
23410
+ console.log(`[claw] Relay message received: type=${msg.type}`, JSON.stringify(msg).slice(0, 200));
23251
23411
  if (this.externalMessageHandler) {
23252
23412
  this.externalMessageHandler(msg);
23253
23413
  }
@@ -23469,7 +23629,7 @@ var SyncService = class {
23469
23629
  }
23470
23630
  async writeConfigFiles(instance, agents) {
23471
23631
  const gatewayConfig = generateGatewayConfig(instance, agents);
23472
- const configPath = path17.join(WORKLE_HOME8, "openclaw.json");
23632
+ const configPath = path18.join(WORKLE_HOME8, "openclaw.json");
23473
23633
  await fs15.mkdir(WORKLE_HOME8, { recursive: true });
23474
23634
  await fs15.writeFile(configPath, JSON.stringify(gatewayConfig, null, 2), "utf-8");
23475
23635
  await Promise.all(
@@ -23484,9 +23644,9 @@ var SyncService = class {
23484
23644
  };
23485
23645
 
23486
23646
  // src/cli.ts
23487
- var WORKLE_HOME9 = path18.join(os18.homedir(), ".workle");
23488
- var AUTH_FILE2 = path18.join(WORKLE_HOME9, "auth.json");
23489
- 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");
23490
23650
  var PLIST_LABEL = "com.workle.claw";
23491
23651
  var color = {
23492
23652
  green: (s) => `\x1B[32m${s}\x1B[0m`,
@@ -23736,7 +23896,7 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23736
23896
  console.log("");
23737
23897
  console.log(` Service: ${color.dim(PLIST_LABEL)}`);
23738
23898
  console.log(` Plist: ${color.dim(plistPath)}`);
23739
- console.log(` Logs: ${color.dim(path18.join(WORKLE_HOME9, "logs/"))}`);
23899
+ console.log(` Logs: ${color.dim(path19.join(WORKLE_HOME9, "logs/"))}`);
23740
23900
  console.log("");
23741
23901
  console.log(
23742
23902
  `To stop: ${color.cyan("npx @getworkle/cli stop")}`
@@ -23781,7 +23941,12 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23781
23941
  await syncService.start();
23782
23942
  try {
23783
23943
  agentService = await createAgentService();
23784
- 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
+ });
23785
23950
  await agentService.startEmbedded((msg) => syncService.sendRelayMessage(msg));
23786
23951
  } catch (err) {
23787
23952
  console.error(
@@ -23804,14 +23969,14 @@ program2.command("start").description("Start the Workle Claw sync service").opti
23804
23969
  }
23805
23970
  });
23806
23971
  program2.command("stop").description("Stop the Workle Claw daemon").action(async () => {
23807
- const plistPath = path18.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
23972
+ const plistPath = path19.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
23808
23973
  try {
23809
23974
  execSync2(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
23810
23975
  console.log(color.green("\u2713 Daemon stopped"));
23811
23976
  } catch {
23812
23977
  console.log(color.dim("No launchd service loaded."));
23813
23978
  }
23814
- const pidFile = path18.join(WORKLE_HOME9, "openclaw.pid");
23979
+ const pidFile = path19.join(WORKLE_HOME9, "openclaw.pid");
23815
23980
  try {
23816
23981
  const pidStr = await fs16.readFile(pidFile, "utf-8");
23817
23982
  const pid = parseInt(pidStr.trim(), 10);
@@ -23856,7 +24021,7 @@ program2.command("status").description("Show connection state and instance info"
23856
24021
  } catch {
23857
24022
  console.log(` Gateway: ${color.yellow("unreachable")}`);
23858
24023
  }
23859
- const plistPath = path18.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
24024
+ const plistPath = path19.join(LAUNCH_AGENTS_DIR2, `${PLIST_LABEL}.plist`);
23860
24025
  try {
23861
24026
  await fs16.access(plistPath);
23862
24027
  try {
@@ -23883,8 +24048,8 @@ program2.command("logs").description("Tail the Workle Claw log files").option("-
23883
24048
  process.exit(1);
23884
24049
  }
23885
24050
  const logFiles = [
23886
- path18.join(WORKLE_HOME9, "openclaw.log"),
23887
- path18.join(WORKLE_HOME9, "logs", "stderr.log")
24051
+ path19.join(WORKLE_HOME9, "openclaw.log"),
24052
+ path19.join(WORKLE_HOME9, "logs", "stderr.log")
23888
24053
  ];
23889
24054
  const args = ["-n", String(lineCount)];
23890
24055
  if (opts.follow) args.push("-f");
@@ -24048,12 +24213,12 @@ agentCmd.command("logs [agentId]").description("Tail agent run logs").option("-n
24048
24213
  console.error(color.red("Error: --lines must be a positive integer."));
24049
24214
  process.exit(1);
24050
24215
  }
24051
- const logsDir = path18.join(WORKLE_HOME9, "agents");
24216
+ const logsDir = path19.join(WORKLE_HOME9, "agents");
24052
24217
  let logFile;
24053
24218
  if (agentId) {
24054
- logFile = path18.join(logsDir, agentId, "run.log");
24219
+ logFile = path19.join(logsDir, agentId, "run.log");
24055
24220
  } else {
24056
- logFile = path18.join(logsDir, "*", "run.log");
24221
+ logFile = path19.join(logsDir, "*", "run.log");
24057
24222
  }
24058
24223
  const args = ["-n", String(lineCount)];
24059
24224
  if (opts.follow) args.push("-f");