@alfe.ai/gateway 0.9.19 → 0.10.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 (2) hide show
  1. package/dist/health.js +50 -5
  2. package/package.json +2 -2
package/dist/health.js CHANGED
@@ -5662,16 +5662,20 @@ const MAX_IPC_MESSAGE_BYTES = 1024 * 1024;
5662
5662
  * Map a cloud command name to an IPC method name.
5663
5663
  * Cloud commands use dot-notation matching IPC methods.
5664
5664
  *
5665
- * Currently empty — Phase 1 has no daemon-to-plugin commands.
5666
- * Commands will be added here as the protocol evolves.
5665
+ * Work reads are dispatched by executeWorkCommand so they select a capable
5666
+ * OpenClaw plugin and fail immediately instead of joining an offline queue.
5667
5667
  */
5668
- const CLOUD_COMMAND_TO_IPC = {};
5668
+ const CLOUD_COMMAND_TO_IPC = {
5669
+ "work.snapshot": "work.snapshot",
5670
+ "work.job_runs": "work.job_runs",
5671
+ "work.actions": "work.actions"
5672
+ };
5669
5673
  /**
5670
5674
  * Translate a cloud COMMAND into a local IPC request.
5671
5675
  * Returns null if the command isn't recognized.
5672
5676
  */
5673
5677
  function cloudCommandToIPCRequest(command) {
5674
- const method = CLOUD_COMMAND_TO_IPC[command.command];
5678
+ const method = Object.hasOwn(CLOUD_COMMAND_TO_IPC, command.command) ? CLOUD_COMMAND_TO_IPC[command.command] : void 0;
5675
5679
  if (!method) return null;
5676
5680
  return {
5677
5681
  type: "req",
@@ -6997,6 +7001,42 @@ var CommandQueue = class {
6997
7001
  }
6998
7002
  };
6999
7003
  //#endregion
7004
+ //#region src/work-commands.ts
7005
+ const WORK_COMMANDS = [
7006
+ "work.snapshot",
7007
+ "work.job_runs",
7008
+ "work.actions"
7009
+ ];
7010
+ function isWorkCommand(command) {
7011
+ return WORK_COMMANDS.includes(command);
7012
+ }
7013
+ const MAX_WORK_RESPONSE_BYTES = 768 * 1024;
7014
+ /** Read requests never enter an offline queue or choose an arbitrary connected plugin. */
7015
+ async function executeWorkCommand(command, agentId, runtime, ipc) {
7016
+ const error = (code, message) => ({
7017
+ type: "COMMAND_ACK",
7018
+ commandId: command.commandId,
7019
+ status: "error",
7020
+ result: {
7021
+ code,
7022
+ message
7023
+ }
7024
+ });
7025
+ if (!isWorkCommand(command.command)) return error("UNKNOWN_COMMAND", "Unsupported work command");
7026
+ if (command.agentId !== agentId) return error("AGENT_MISMATCH", "Work request targets a different agent");
7027
+ if (runtime !== "openclaw") return error("UNSUPPORTED_RUNTIME", "Work visibility is available for OpenClaw agents");
7028
+ if (!command.payload || typeof command.payload !== "object" || Array.isArray(command.payload)) return error("INVALID_PARAMS", "Work parameters must be an object");
7029
+ const plugin = ipc?.getRegisteredPlugins().find(([, info]) => info.name === "@alfe.ai/openclaw" && info.capabilities.includes("work.read"));
7030
+ if (!ipc || !plugin) return error("WORK_UNAVAILABLE", "The runtime work bridge is unavailable; update the agent if needed");
7031
+ try {
7032
+ const response = await ipc.sendRequest(plugin[0], command.command, command.payload, 6e3);
7033
+ if (Buffer.byteLength(JSON.stringify(response), "utf8") > MAX_WORK_RESPONSE_BYTES) return error("RESPONSE_TOO_LARGE", "Runtime work data exceeds the response limit");
7034
+ return ipcResponseToCloudAck(command.commandId, response);
7035
+ } catch {
7036
+ return error("WORK_UNAVAILABLE", "The runtime work bridge did not respond");
7037
+ }
7038
+ }
7039
+ //#endregion
7000
7040
  //#region src/process-manager.ts
7001
7041
  /**
7002
7042
  * Process management — launchd/systemd service installation.
@@ -9211,6 +9251,10 @@ let cloudConnected = false;
9211
9251
  * so a duplicate is ACKed with the prior result without re-executing.
9212
9252
  */
9213
9253
  const commandDedupe = new CommandDedupe();
9254
+ const workCommandDedupe = new CommandDedupe({
9255
+ maxEntries: 4,
9256
+ ttlMs: 5e3
9257
+ });
9214
9258
  let shuttingDown = false;
9215
9259
  let commandRegistry;
9216
9260
  let resolvedCliVersion;
@@ -9553,7 +9597,7 @@ async function startDaemon() {
9553
9597
  * bounce the box a second time.
9554
9598
  */
9555
9599
  async function handleCloudCommand(command) {
9556
- const { ack, duplicate } = await commandDedupe.run(command.commandId, () => executeCloudCommand(command));
9600
+ const { ack, duplicate } = await (isWorkCommand(command.command) ? workCommandDedupe : commandDedupe).run(command.commandId, () => executeCloudCommand(command));
9557
9601
  if (duplicate) {
9558
9602
  logger.info({
9559
9603
  commandId: command.commandId,
@@ -9606,6 +9650,7 @@ async function drainRuntimeBeforeExit(reason) {
9606
9650
  }, "Runtime still mid-turn at drain grace deadline — proceeding with daemon exit");
9607
9651
  }
9608
9652
  async function executeCloudCommand(command) {
9653
+ if (isWorkCommand(command.command)) return executeWorkCommand(command, config.agentId, config.runtime, ipcServer);
9609
9654
  if (command.command === "daemon.update") {
9610
9655
  const version = command.payload?.version ?? "latest";
9611
9656
  setTimeout(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/gateway",
3
- "version": "0.9.19",
3
+ "version": "0.10.0",
4
4
  "description": "Alfe local gateway daemon — persistent control plane for agent integrations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,7 +23,7 @@
23
23
  "pino-roll": "^1.2.0",
24
24
  "smol-toml": ">=1.6.1",
25
25
  "ws": "^8.18.0",
26
- "@alfe.ai/agent-api-client": "^0.19.1",
26
+ "@alfe.ai/agent-api-client": "^0.19.2",
27
27
  "@alfe.ai/ai-proxy-local": "^0.0.17",
28
28
  "@alfe.ai/config": "^0.4.1",
29
29
  "@alfe.ai/integration-manifest": "^0.4.2",