@adhdev/daemon-standalone 0.9.82-rc.58 → 0.9.82-rc.59

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-standalone",
3
- "version": "0.9.82-rc.58",
3
+ "version": "0.9.82-rc.59",
4
4
  "description": "ADHDev standalone daemon — embedded HTTP/WS server for local dashboard",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -35,6 +35,9 @@ __export(index_exports, {
35
35
  });
36
36
  module.exports = __toCommonJS(index_exports);
37
37
 
38
+ // src/tools/mesh-tools.ts
39
+ var import_node_crypto = require("crypto");
40
+
38
41
  // src/transports/ipc.ts
39
42
  var DEFAULT_IPC_PORT = 19222;
40
43
  var DEFAULT_IPC_PATH = "/ipc";
@@ -245,6 +248,25 @@ var meshSessionProviderMetadata = /* @__PURE__ */ new Map();
245
248
  function readString(value) {
246
249
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
247
250
  }
251
+ function summarizeTaskMessage(message) {
252
+ const taskSummary = message.replace(/\s+/g, " ").trim();
253
+ const taskTitle = taskSummary.length > 96 ? `${taskSummary.slice(0, 93)}...` : taskSummary;
254
+ return { taskTitle: taskTitle || "(untitled task)", taskSummary };
255
+ }
256
+ function buildDirectTaskPayload(message, via, opts) {
257
+ const descriptor = summarizeTaskMessage(message);
258
+ return {
259
+ source: "direct",
260
+ via,
261
+ taskId: opts.taskId,
262
+ message,
263
+ taskTitle: descriptor.taskTitle,
264
+ taskSummary: descriptor.taskSummary,
265
+ ...opts.taskMode ? { taskMode: opts.taskMode } : {},
266
+ ...opts.providerType ? { providerType: opts.providerType } : {},
267
+ ...opts.targetSessionId ? { targetSessionId: opts.targetSessionId } : {}
268
+ };
269
+ }
248
270
  function findNode(mesh, nodeId) {
249
271
  const node = mesh.nodes.find((n) => n.id === nodeId);
250
272
  if (!node) throw new Error(`Node '${nodeId}' is not a member of mesh '${mesh.name}'`);
@@ -929,7 +951,7 @@ async function ipcDispatchToRemoteAgent(ctx, node, args) {
929
951
  error: `P2P dispatch failed: ${errorMessage}`
930
952
  };
931
953
  }
932
- return { success: true, dispatched: true, sessionId: sessionId || resolvedProviderType };
954
+ return { success: true, dispatched: true, sessionId: sessionId || resolvedProviderType, providerType: resolvedProviderType };
933
955
  } catch (e) {
934
956
  const errorMessage = e?.message || String(e);
935
957
  return {
@@ -1310,7 +1332,9 @@ var MESH_ENQUEUE_TASK_TOOL = {
1310
1332
  inputSchema: {
1311
1333
  type: "object",
1312
1334
  properties: {
1313
- message: { type: "string", description: "The task instruction for the agent." }
1335
+ message: { type: "string", description: "The task instruction for the agent." },
1336
+ task_mode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "Optional task-mode contract. live_debug_readonly rejects obvious write/commit/push/deploy/destructive instructions before dispatch." },
1337
+ taskMode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "CamelCase alias for task_mode." }
1314
1338
  },
1315
1339
  required: ["message"]
1316
1340
  }
@@ -1370,7 +1394,9 @@ var MESH_SEND_TASK_TOOL = {
1370
1394
  properties: {
1371
1395
  node_id: { type: "string", description: "Target node ID (from mesh_list_nodes)." },
1372
1396
  session_id: { type: "string", description: "Agent session ID on the target node." },
1373
- message: { type: "string", description: "Natural-language task to send to the agent." }
1397
+ message: { type: "string", description: "Natural-language task to send to the agent." },
1398
+ task_mode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "Optional task-mode contract. live_debug_readonly rejects obvious write/commit/push/deploy/destructive instructions before local or remote direct dispatch." },
1399
+ taskMode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "CamelCase alias for task_mode." }
1374
1400
  },
1375
1401
  required: ["node_id", "session_id", "message"]
1376
1402
  }
@@ -1736,6 +1762,12 @@ async function meshStatus(ctx) {
1736
1762
  if (relatedRepos.length) entry.relatedRepos = relatedRepos;
1737
1763
  results.push(entry);
1738
1764
  }
1765
+ const activeWorkEvidence = (0, import_daemon_core.buildMeshActiveWork)({
1766
+ meshId: mesh.id,
1767
+ queue: (0, import_daemon_core.getQueue)(mesh.id),
1768
+ ledgerEntries: (0, import_daemon_core.readLedgerEntries)(mesh.id, { tail: 500 }),
1769
+ nodes: mesh.nodes
1770
+ });
1739
1771
  const response = {
1740
1772
  meshId: mesh.id,
1741
1773
  meshName: mesh.name,
@@ -1745,9 +1777,12 @@ async function meshStatus(ctx) {
1745
1777
  sourceOfTruth: {
1746
1778
  membership: "coordinator_daemon_live_mesh",
1747
1779
  currentStatus: "live_git_and_session_probes",
1780
+ activeWork: "mesh_queue_file_and_local_ledger",
1748
1781
  historicalEvidenceOnly: ["recoveryHints", "ledgerSummary"]
1749
1782
  },
1750
1783
  nodes: results,
1784
+ activeWork: activeWorkEvidence.activeWork,
1785
+ activeWorkSummary: activeWorkEvidence.summary,
1751
1786
  branchConvergenceSummary: summarizeBranchConvergence(results)
1752
1787
  };
1753
1788
  try {
@@ -1869,12 +1904,13 @@ async function meshListNodes(ctx) {
1869
1904
  }, null, 2);
1870
1905
  }
1871
1906
  async function meshEnqueueTask(ctx, args) {
1907
+ const taskMode = readString(args.task_mode) || readString(args.taskMode);
1872
1908
  try {
1873
- const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message);
1909
+ const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message, { taskMode });
1874
1910
  if (isLocalTransport(ctx.transport) && !(ctx.transport instanceof IpcTransport)) {
1875
1911
  ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
1876
1912
  });
1877
- return JSON.stringify({ success: true, taskId: task.id, status: task.status });
1913
+ return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode });
1878
1914
  }
1879
1915
  if (ctx.transport instanceof IpcTransport) {
1880
1916
  ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
@@ -1887,11 +1923,24 @@ async function meshEnqueueTask(ctx, args) {
1887
1923
  ipcDispatchToRemoteAgent(ctx, node, { message: args.message }).then((result) => {
1888
1924
  if (result.success) {
1889
1925
  try {
1926
+ const providerType = result.providerType;
1927
+ const descriptor = summarizeTaskMessage(args.message);
1890
1928
  (0, import_daemon_core.appendLedgerEntry)(ctx.mesh.id, {
1891
1929
  kind: "task_dispatched",
1892
1930
  nodeId: node.id,
1893
1931
  sessionId: result.sessionId,
1894
- payload: { message: args.message, via: "p2p_direct", taskId: task.id }
1932
+ providerType,
1933
+ payload: {
1934
+ source: "queue",
1935
+ via: "p2p_direct",
1936
+ taskId: task.id,
1937
+ message: args.message,
1938
+ taskTitle: descriptor.taskTitle,
1939
+ taskSummary: descriptor.taskSummary,
1940
+ ...task.taskMode ? { taskMode: task.taskMode } : {},
1941
+ ...providerType ? { providerType } : {},
1942
+ targetSessionId: result.sessionId
1943
+ }
1895
1944
  });
1896
1945
  } catch {
1897
1946
  }
@@ -1902,11 +1951,15 @@ async function meshEnqueueTask(ctx, args) {
1902
1951
  }
1903
1952
  Promise.all(dispatchPromises).catch(() => {
1904
1953
  });
1905
- return JSON.stringify({ success: true, taskId: task.id, status: task.status });
1954
+ return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode });
1906
1955
  }
1907
- return JSON.stringify({ success: true, taskId: task.id, status: task.status });
1956
+ return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode });
1908
1957
  } catch (e) {
1909
- return JSON.stringify({ success: false, error: e.message });
1958
+ const message = e?.message || String(e);
1959
+ if (message.includes("live_debug_readonly_guardrail_violation")) {
1960
+ return JSON.stringify({ success: false, code: "live_debug_readonly_guardrail_violation", taskMode, error: message });
1961
+ }
1962
+ return JSON.stringify({ success: false, error: message });
1910
1963
  }
1911
1964
  }
1912
1965
  async function meshViewQueue(ctx, args) {
@@ -1918,6 +1971,12 @@ async function meshViewQueue(ctx, args) {
1918
1971
  const summary = buildQueueStatusSummary(fullQueue);
1919
1972
  const visibleSummary = buildQueueStatusSummary(queue);
1920
1973
  const maintenance = buildQueueMaintenanceReport(fullQueue);
1974
+ const activeWorkEvidence = (0, import_daemon_core.buildMeshActiveWork)({
1975
+ meshId: ctx.mesh.id,
1976
+ queue: fullQueue,
1977
+ ledgerEntries: (0, import_daemon_core.readLedgerEntries)(ctx.mesh.id, { tail: 500 }),
1978
+ nodes: ctx.mesh.nodes
1979
+ });
1921
1980
  const staleAssignedTasks = maintenance.staleAssignedTasks || [];
1922
1981
  const requestedHistoricalRows = queue.some((task) => HISTORICAL_QUEUE_STATUSES.has(String(task?.status || "")));
1923
1982
  return JSON.stringify({
@@ -1935,6 +1994,8 @@ async function meshViewQueue(ctx, args) {
1935
1994
  },
1936
1995
  queue,
1937
1996
  visibleQueue: queue,
1997
+ activeWork: activeWorkEvidence.activeWork,
1998
+ activeWorkSummary: activeWorkEvidence.summary,
1938
1999
  visibleSummary,
1939
2000
  summary,
1940
2001
  activeCounts: summary.activeCounts,
@@ -1998,6 +2059,19 @@ async function meshQueueRequeue(ctx, args) {
1998
2059
  }
1999
2060
  }
2000
2061
  async function meshSendTask(ctx, args) {
2062
+ const requestedTaskMode = readString(args.task_mode) || readString(args.taskMode);
2063
+ const modeValidation = (0, import_daemon_core.validateMeshTaskModeRequest)(requestedTaskMode, args.message);
2064
+ if (!modeValidation.valid) {
2065
+ return JSON.stringify({
2066
+ success: false,
2067
+ code: "live_debug_readonly_guardrail_violation",
2068
+ taskMode: modeValidation.taskMode || requestedTaskMode,
2069
+ violations: modeValidation.violations,
2070
+ allowedOperations: modeValidation.allowedOperations,
2071
+ error: `live_debug_readonly_guardrail_violation: forbidden operations (${modeValidation.violations.join(", ")})`
2072
+ });
2073
+ }
2074
+ const taskMode = modeValidation.taskMode;
2001
2075
  const node = await findNodeWithRefresh(ctx, args.node_id);
2002
2076
  if (node.policy?.readOnly) {
2003
2077
  return JSON.stringify({ error: `Node '${args.node_id}' is read-only` });
@@ -2025,13 +2099,15 @@ async function meshSendTask(ctx, args) {
2025
2099
  const res = await ctx.transport.meshEnqueueTask(node.daemonId, {
2026
2100
  meshId: ctx.mesh.id,
2027
2101
  message: args.message,
2028
- targetNodeId: args.node_id
2102
+ targetNodeId: args.node_id,
2103
+ ...taskMode ? { taskMode } : {}
2029
2104
  });
2030
2105
  return JSON.stringify(res);
2031
2106
  }
2032
2107
  const isLocalNode = isLocalControlPlaneNode(ctx, node);
2033
2108
  if (ctx.transport instanceof IpcTransport && node.daemonId && !isLocalNode) {
2034
2109
  const cached = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id || ""));
2110
+ const taskId = (0, import_node_crypto.randomUUID)();
2035
2111
  const result2 = await ipcDispatchToRemoteAgent(ctx, node, {
2036
2112
  session_id: args.session_id,
2037
2113
  message: args.message,
@@ -2040,20 +2116,31 @@ async function meshSendTask(ctx, args) {
2040
2116
  if (result2.success) {
2041
2117
  const dispatchedSessionId = args.session_id || result2.sessionId;
2042
2118
  try {
2119
+ const providerType = result2.providerType || cached?.providerType;
2043
2120
  (0, import_daemon_core.appendLedgerEntry)(ctx.mesh.id, {
2044
2121
  kind: "task_dispatched",
2045
2122
  nodeId: args.node_id,
2046
2123
  sessionId: dispatchedSessionId,
2047
- payload: {
2048
- message: args.message,
2049
- via: "p2p_direct",
2050
- ...dispatchedSessionId ? { targetSessionId: dispatchedSessionId } : {}
2051
- }
2124
+ providerType,
2125
+ payload: buildDirectTaskPayload(args.message, "p2p_direct", {
2126
+ taskId,
2127
+ taskMode,
2128
+ providerType,
2129
+ targetSessionId: dispatchedSessionId
2130
+ })
2052
2131
  });
2053
2132
  } catch {
2054
2133
  }
2055
2134
  }
2056
- return JSON.stringify({ ...result2, nodeId: args.node_id, dispatched: result2.success === true });
2135
+ return JSON.stringify({
2136
+ ...result2,
2137
+ nodeId: args.node_id,
2138
+ sessionId: result2.success ? args.session_id || result2.sessionId : args.session_id,
2139
+ ...result2.success ? { source: "direct", taskId } : {},
2140
+ taskMode,
2141
+ ...result2.success && result2.providerType ? { providerType: result2.providerType } : {},
2142
+ dispatched: result2.success === true
2143
+ });
2057
2144
  }
2058
2145
  if (args.session_id && isLocalTransport(ctx.transport)) {
2059
2146
  const cached = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id));
@@ -2115,28 +2202,35 @@ async function meshSendTask(ctx, args) {
2115
2202
  error: dispatchPayload?.error || dispatchResult?.error || "agent_command rejected the task"
2116
2203
  });
2117
2204
  }
2205
+ const taskId = (0, import_node_crypto.randomUUID)();
2118
2206
  try {
2119
2207
  (0, import_daemon_core.appendLedgerEntry)(ctx.mesh.id, {
2120
2208
  kind: "task_dispatched",
2121
2209
  nodeId: args.node_id,
2122
2210
  sessionId: args.session_id,
2123
2211
  providerType: resolvedProviderType,
2124
- payload: { message: args.message, via: "local_direct" }
2212
+ payload: buildDirectTaskPayload(args.message, "local_direct", {
2213
+ taskId,
2214
+ taskMode,
2215
+ providerType: resolvedProviderType,
2216
+ targetSessionId: args.session_id
2217
+ })
2125
2218
  });
2126
2219
  } catch {
2127
2220
  }
2128
- return JSON.stringify({ success: true, dispatched: true, nodeId: args.node_id, sessionId: args.session_id });
2221
+ return JSON.stringify({ success: true, dispatched: true, source: "direct", taskId, taskMode, providerType: resolvedProviderType, nodeId: args.node_id, sessionId: args.session_id });
2129
2222
  }
2130
2223
  const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message, {
2131
2224
  targetNodeId: args.node_id,
2132
- targetSessionId: args.session_id
2225
+ targetSessionId: args.session_id,
2226
+ taskMode
2133
2227
  });
2134
2228
  if (isLocalTransport(ctx.transport) || ctx.transport instanceof IpcTransport) {
2135
2229
  ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
2136
2230
  });
2137
2231
  }
2138
2232
  const pendingEvents = isLocalTransport(ctx.transport) ? (0, import_daemon_core.drainPendingMeshCoordinatorEvents)(ctx.mesh.id) : [];
2139
- const result = { success: true, nodeId: args.node_id, taskId: task.id, status: task.status };
2233
+ const result = { success: true, source: "queue", nodeId: args.node_id, taskId: task.id, status: task.status, taskMode: task.taskMode };
2140
2234
  if (pendingEvents.length > 0) {
2141
2235
  result.pendingCoordinatorEvents = pendingEvents;
2142
2236
  }