@adhdev/daemon-standalone 0.9.82-rc.288 → 0.9.82-rc.290

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/public/index.html CHANGED
@@ -7,9 +7,9 @@
7
7
  <meta name="description" content="ADHDev self-hosted dashboard for controlling AI agents" />
8
8
  <link rel="icon" href="/otter-logo.png" />
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
10
- <script type="module" crossorigin src="/assets/index-NSq-hUrT.js"></script>
10
+ <script type="module" crossorigin src="/assets/index-Bp_R6Vha.js"></script>
11
11
  <link rel="modulepreload" crossorigin href="/assets/vendor-BHUMCOj6.js">
12
- <link rel="stylesheet" crossorigin href="/assets/index-CRoMHXE0.css">
12
+ <link rel="stylesheet" crossorigin href="/assets/index-77wzVjtD.css">
13
13
  </head>
14
14
  <body>
15
15
  <!-- Apply theme immediately to prevent FOIT (Flash of Incorrect Theme) -->
@@ -1684,6 +1684,12 @@ function findClonedFromNode(ctx, node) {
1684
1684
  if (!clonedFromNodeId) return void 0;
1685
1685
  return ctx.mesh.nodes.find((n) => n.id === clonedFromNodeId || n.nodeId === clonedFromNodeId || n.node_id === clonedFromNodeId);
1686
1686
  }
1687
+ function resolvePreferredWorktreeNodeId(ctx) {
1688
+ const worktreeNodes = (ctx.mesh.nodes || []).filter((n) => n.isLocalWorktree === true);
1689
+ if (worktreeNodes.length === 0) return void 0;
1690
+ const chosen = worktreeNodes[worktreeNodes.length - 1];
1691
+ return readString(chosen?.id) || readString(chosen?.nodeId) || readString(chosen?.node_id);
1692
+ }
1687
1693
  function isLocalControlPlaneNode(ctx, node) {
1688
1694
  return !!getLocalControlPlaneMatchReason(ctx, node);
1689
1695
  }
@@ -2203,11 +2209,12 @@ async function drainCoordinatorPendingEvents(ctx, opts) {
2203
2209
  function isP2pTransportUnavailableError(error) {
2204
2210
  return (0, import_daemon_core.isP2pRelayTransportFailure)(error);
2205
2211
  }
2206
- function buildRemoveNodeArgs(ctx, nodeId, sessionCleanupMode) {
2212
+ function buildRemoveNodeArgs(ctx, nodeId, sessionCleanupMode, force) {
2207
2213
  return {
2208
2214
  meshId: ctx.mesh.id,
2209
2215
  nodeId,
2210
2216
  ...sessionCleanupMode ? { sessionCleanupMode } : {},
2217
+ ...force === true ? { force: true } : {},
2211
2218
  inlineMesh: ctx.mesh
2212
2219
  };
2213
2220
  }
@@ -2246,6 +2253,10 @@ var MESH_ENQUEUE_TASK_TOOL = {
2246
2253
  taskMode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "CamelCase alias for task_mode." },
2247
2254
  requiredTags: { type: "array", items: { type: "string" }, description: "Optional capability tags that every eligible node must have, e.g. os=darwin, provider=codex-cli, gpu." },
2248
2255
  required_tags: { type: "array", items: { type: "string" }, description: "Snake_case alias for requiredTags." },
2256
+ target_node_id: { type: "string", description: "Optional: only this node may claim the task. Use to route a queued task to a specific (e.g. freshly cloned) worktree node instead of letting the first idle base node claim it. Takes priority over prefer_worktree." },
2257
+ targetNodeId: { type: "string", description: "CamelCase alias for target_node_id." },
2258
+ prefer_worktree: { type: "boolean", description: "Optional: when true, route this task to the most recently cloned idle worktree node (avoids the main/base workspace preemptively claiming an isolated task). No-op if no worktree node exists; resolves to a target_node_id when one does." },
2259
+ preferWorktree: { type: "boolean", description: "CamelCase alias for prefer_worktree." },
2249
2260
  depends_on: { type: "array", items: { type: "string" }, description: "Task ids that must complete before this task becomes claimable. Cycles are rejected at enqueue." },
2250
2261
  dependsOn: { type: "array", items: { type: "string" }, description: "CamelCase alias for depends_on." },
2251
2262
  mission_id: { type: "string", description: "Mission this task belongs to (mesh_mission record id)." },
@@ -2445,7 +2456,7 @@ var MESH_CLONE_NODE_TOOL = {
2445
2456
  };
2446
2457
  var MESH_REMOVE_NODE_TOOL = {
2447
2458
  name: "mesh_remove_node",
2448
- description: "Remove a node from the mesh. If the node is a worktree, also cleans up the git worktree and directory. Session cleanup is controlled by mesh policy sessionCleanupOnNodeRemove unless session_cleanup_mode overrides it for this call.",
2459
+ description: "Remove a node from the mesh. If the node is a worktree, also cleans up the git worktree and directory. Session cleanup is controlled by mesh policy sessionCleanupOnNodeRemove unless session_cleanup_mode overrides it for this call. The coordinator's own local base node (same machine, NOT a worktree) is protected \u2014 removing it breaks live mesh membership and is rejected unless force:true is passed.",
2449
2460
  inputSchema: {
2450
2461
  type: "object",
2451
2462
  properties: {
@@ -2454,7 +2465,8 @@ var MESH_REMOVE_NODE_TOOL = {
2454
2465
  type: "string",
2455
2466
  enum: ["preserve", "stop", "delete_stopped", "stop_and_delete"],
2456
2467
  description: "Optional override for cleanup of delegated sessions attached to this node. preserve keeps history/processes; stop stops live runtimes only; delete_stopped removes completed transcripts only; stop_and_delete stops live runtimes and deletes records."
2457
- }
2468
+ },
2469
+ force: { type: "boolean", description: "Override the coordinator-base-node guard. Only set true to intentionally tear down this mesh; the coordinator must then be re-registered/restarted. Worktree nodes never need force." }
2458
2470
  },
2459
2471
  required: ["node_id"]
2460
2472
  }
@@ -3225,8 +3237,11 @@ async function meshEnqueueTask(ctx, args) {
3225
3237
  const requiredTags = (0, import_daemon_core.normalizeMeshCapabilityTags)(Array.isArray(args.requiredTags) ? args.requiredTags : args.required_tags);
3226
3238
  const dependsOn = Array.isArray(args.dependsOn) ? args.dependsOn : Array.isArray(args.depends_on) ? args.depends_on : void 0;
3227
3239
  const missionId = readString(args.missionId) || readString(args.mission_id) || void 0;
3240
+ const explicitTarget = readString(args.targetNodeId) || readString(args.target_node_id) || void 0;
3241
+ const preferWorktree = args.preferWorktree === true || args.prefer_worktree === true;
3242
+ const targetNodeId = explicitTarget || (preferWorktree ? resolvePreferredWorktreeNodeId(ctx) : void 0);
3228
3243
  try {
3229
- const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message, { taskMode, requiredTags, dependsOn, missionId });
3244
+ const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message, { taskMode, requiredTags, dependsOn, missionId, targetNodeId });
3230
3245
  if (!(ctx.transport instanceof IpcTransport)) {
3231
3246
  const queueTrigger = await triggerMeshQueueAndReport(ctx);
3232
3247
  return JSON.stringify({
@@ -3236,6 +3251,8 @@ async function meshEnqueueTask(ctx, args) {
3236
3251
  status: task.status,
3237
3252
  taskMode: task.taskMode,
3238
3253
  requiredTags: task.requiredTags,
3254
+ ...targetNodeId ? { targetNodeId } : {},
3255
+ ...preferWorktree && !explicitTarget && !targetNodeId ? { preferWorktreeNoOp: true } : {},
3239
3256
  queueTrigger,
3240
3257
  ...buildQueueTriggerGuidance(queueTrigger)
3241
3258
  });
@@ -3246,6 +3263,7 @@ async function meshEnqueueTask(ctx, args) {
3246
3263
  for (const node of ctx.mesh.nodes) {
3247
3264
  const isLocalNode = isLocalControlPlaneNode(ctx, node);
3248
3265
  if (isLocalNode || !node.daemonId) continue;
3266
+ if (targetNodeId && node.id !== targetNodeId) continue;
3249
3267
  if (!(0, import_daemon_core.nodeSatisfiesRequiredTags)(requiredTags, (0, import_daemon_core.buildMeshNodeCapabilityTags)(node))) continue;
3250
3268
  dispatchPromises.push(
3251
3269
  ipcDispatchToRemoteAgent(ctx, node, { message: args.message }).then((result) => {
@@ -3300,6 +3318,8 @@ async function meshEnqueueTask(ctx, args) {
3300
3318
  status: task.status,
3301
3319
  taskMode: task.taskMode,
3302
3320
  requiredTags: task.requiredTags,
3321
+ ...targetNodeId ? { targetNodeId } : {},
3322
+ ...preferWorktree && !explicitTarget && !targetNodeId ? { preferWorktreeNoOp: true } : {},
3303
3323
  queueTrigger,
3304
3324
  ...buildQueueTriggerGuidance(queueTrigger)
3305
3325
  });
@@ -4163,7 +4183,7 @@ async function meshCleanupSessions(ctx, args) {
4163
4183
  }
4164
4184
  async function meshRemoveNode(ctx, args) {
4165
4185
  const node = await findNodeWithRefresh(ctx, args.node_id);
4166
- const removeArgs = buildRemoveNodeArgs(ctx, args.node_id, args.session_cleanup_mode);
4186
+ const removeArgs = buildRemoveNodeArgs(ctx, args.node_id, args.session_cleanup_mode, args.force === true);
4167
4187
  let result;
4168
4188
  let transportFallback;
4169
4189
  try {