@atlasharness/atlascode 0.1.95 → 0.1.96

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/cli.js +423 -28
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -34721,7 +34721,7 @@ var init_project = __esm(() => {
34721
34721
  var AGENT_TOOL_NAME = "Agent", MAX_WORKER_SPAWN_DEPTH = 2;
34722
34722
 
34723
34723
  // src/engine/tools/toolNames.ts
34724
- var FILE_READ_TOOL_NAME = "Read", WEB_SEARCH_TOOL_NAME = "WebSearch", TODO_WRITE_TOOL_NAME = "TodoWrite", GREP_TOOL_NAME = "Grep", WEB_FETCH_TOOL_NAME = "WebFetch", GLOB_TOOL_NAME = "Glob", BASH_TOOL_NAME2 = "Bash", POWERSHELL_TOOL_NAME = "PowerShell", FILE_EDIT_TOOL_NAME = "Edit", FILE_WRITE_TOOL_NAME = "Write", NOTEBOOK_EDIT_TOOL_NAME = "NotebookEdit", SKILL_TOOL_NAME = "Skill", SYNTHETIC_OUTPUT_TOOL_NAME = "StructuredOutput", TOOL_SEARCH_TOOL_NAME = "ToolSearch", ENTER_WORKTREE_TOOL_NAME = "EnterWorktree", EXIT_WORKTREE_TOOL_NAME = "ExitWorktree", TEAM_CREATE_TOOL_NAME = "TeamCreate", TEAM_DELETE_TOOL_NAME = "TeamDelete", WAIT_FOR_TEAMMATES_TOOL_NAME = "WaitForTeammates", SNIP_TOOL_NAME = "Snip", SEND_MESSAGE_TOOL_NAME = "SendMessage", TASK_STOP_TOOL_NAME = "TaskStop", TASK_OUTPUT_TOOL_NAME = "TaskOutput", ENTER_PLAN_MODE_TOOL_NAME = "EnterPlanMode", EXIT_PLAN_MODE_V2_TOOL_NAME = "ExitPlanMode", ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion", TASK_CREATE_TOOL_NAME = "TaskCreate", TASK_GET_TOOL_NAME = "TaskGet", TASK_LIST_TOOL_NAME = "TaskList", TASK_UPDATE_TOOL_NAME = "TaskUpdate", CRON_CREATE_TOOL_NAME = "CronCreate", CRON_DELETE_TOOL_NAME = "CronDelete", CRON_LIST_TOOL_NAME = "CronList", CONFIG_TOOL_NAME = "Config", WORKFLOW_TOOL_NAME = "Workflow", REPL_TOOL_NAME = "REPL", LIST_MCP_RESOURCES_TOOL_NAME = "ListMcpResourcesTool", READ_MCP_RESOURCE_TOOL_NAME = "ReadMcpResourceTool", LSP_TOOL_NAME = "LSP", PROPOSE_GOAL_TOOL_NAME = "ProposeGoal", SHELL_TOOL_NAMES, ASYNC_AGENT_ALLOWED_TOOLS, INTERNAL_WORKER_TOOLS, ALL_AGENT_DISALLOWED_TOOLS, CUSTOM_AGENT_DISALLOWED_TOOLS, IN_PROCESS_TEAMMATE_ALLOWED_TOOLS, COORDINATOR_MODE_ALLOWED_TOOLS;
34724
+ var FILE_READ_TOOL_NAME = "Read", WEB_SEARCH_TOOL_NAME = "WebSearch", TODO_WRITE_TOOL_NAME = "TodoWrite", GREP_TOOL_NAME = "Grep", WEB_FETCH_TOOL_NAME = "WebFetch", GLOB_TOOL_NAME = "Glob", BASH_TOOL_NAME2 = "Bash", POWERSHELL_TOOL_NAME = "PowerShell", FILE_EDIT_TOOL_NAME = "Edit", FILE_WRITE_TOOL_NAME = "Write", NOTEBOOK_EDIT_TOOL_NAME = "NotebookEdit", SKILL_TOOL_NAME = "Skill", SYNTHETIC_OUTPUT_TOOL_NAME = "StructuredOutput", TOOL_SEARCH_TOOL_NAME = "ToolSearch", ENTER_WORKTREE_TOOL_NAME = "EnterWorktree", EXIT_WORKTREE_TOOL_NAME = "ExitWorktree", TEAM_CREATE_TOOL_NAME = "TeamCreate", TEAM_DELETE_TOOL_NAME = "TeamDelete", WAIT_FOR_TEAMMATES_TOOL_NAME = "WaitForTeammates", SNIP_TOOL_NAME = "Snip", SEND_MESSAGE_TOOL_NAME = "SendMessage", REQUEST_SHUTDOWN_TOOL_NAME = "RequestShutdown", TASK_STOP_TOOL_NAME = "TaskStop", TASK_OUTPUT_TOOL_NAME = "TaskOutput", ENTER_PLAN_MODE_TOOL_NAME = "EnterPlanMode", EXIT_PLAN_MODE_V2_TOOL_NAME = "ExitPlanMode", ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion", TASK_CREATE_TOOL_NAME = "TaskCreate", TASK_GET_TOOL_NAME = "TaskGet", TASK_LIST_TOOL_NAME = "TaskList", TASK_UPDATE_TOOL_NAME = "TaskUpdate", CRON_CREATE_TOOL_NAME = "CronCreate", CRON_DELETE_TOOL_NAME = "CronDelete", CRON_LIST_TOOL_NAME = "CronList", CONFIG_TOOL_NAME = "Config", WORKFLOW_TOOL_NAME = "Workflow", REPL_TOOL_NAME = "REPL", LIST_MCP_RESOURCES_TOOL_NAME = "ListMcpResourcesTool", READ_MCP_RESOURCE_TOOL_NAME = "ReadMcpResourceTool", LSP_TOOL_NAME = "LSP", PROPOSE_GOAL_TOOL_NAME = "ProposeGoal", SHELL_TOOL_NAMES, ASYNC_AGENT_ALLOWED_TOOLS, INTERNAL_WORKER_TOOLS, ALL_AGENT_DISALLOWED_TOOLS, CUSTOM_AGENT_DISALLOWED_TOOLS, IN_PROCESS_TEAMMATE_ALLOWED_TOOLS, COORDINATOR_MODE_ALLOWED_TOOLS;
34725
34725
  var init_toolNames = __esm(() => {
34726
34726
  SHELL_TOOL_NAMES = [BASH_TOOL_NAME2, POWERSHELL_TOOL_NAME];
34727
34727
  ASYNC_AGENT_ALLOWED_TOOLS = new Set([
@@ -34761,7 +34761,8 @@ var init_toolNames = __esm(() => {
34761
34761
  TASK_GET_TOOL_NAME,
34762
34762
  TASK_LIST_TOOL_NAME,
34763
34763
  TASK_UPDATE_TOOL_NAME,
34764
- SEND_MESSAGE_TOOL_NAME
34764
+ SEND_MESSAGE_TOOL_NAME,
34765
+ REQUEST_SHUTDOWN_TOOL_NAME
34765
34766
  ]);
34766
34767
  COORDINATOR_MODE_ALLOWED_TOOLS = new Set([
34767
34768
  AGENT_TOOL_NAME,
@@ -36987,6 +36988,24 @@ function createShutdownApprovedMessage(params) {
36987
36988
  backendType: params.backendType
36988
36989
  };
36989
36990
  }
36991
+ function createShutdownRequestFromMemberMessage(params) {
36992
+ return {
36993
+ type: "shutdown_request_from_member",
36994
+ requestId: params.requestId,
36995
+ from: params.from,
36996
+ reason: params.reason,
36997
+ timestamp: new Date().toISOString()
36998
+ };
36999
+ }
37000
+ function createShutdownRequestDeniedMessage(params) {
37001
+ return {
37002
+ type: "shutdown_request_denied",
37003
+ requestId: params.requestId,
37004
+ to: params.to,
37005
+ reason: params.reason,
37006
+ timestamp: new Date().toISOString()
37007
+ };
37008
+ }
36990
37009
  function createShutdownRejectedMessage(params) {
36991
37010
  return {
36992
37011
  type: "shutdown_rejected",
@@ -37021,6 +37040,22 @@ function isShutdownRequest(messageText) {
37021
37040
  } catch {}
37022
37041
  return null;
37023
37042
  }
37043
+ function isShutdownRequestFromMember(messageText) {
37044
+ try {
37045
+ const result = ShutdownRequestFromMemberMessageSchema().safeParse(jsonParse(messageText));
37046
+ if (result.success)
37047
+ return result.data;
37048
+ } catch {}
37049
+ return null;
37050
+ }
37051
+ function isShutdownRequestDenied(messageText) {
37052
+ try {
37053
+ const result = ShutdownRequestDeniedMessageSchema().safeParse(jsonParse(messageText));
37054
+ if (result.success)
37055
+ return result.data;
37056
+ } catch {}
37057
+ return null;
37058
+ }
37024
37059
  function isPlanApprovalRequest(messageText) {
37025
37060
  try {
37026
37061
  const result = PlanApprovalRequestMessageSchema().safeParse(jsonParse(messageText));
@@ -37094,7 +37129,7 @@ function isStructuredProtocolMessage(messageText) {
37094
37129
  return false;
37095
37130
  }
37096
37131
  const type = parsed.type;
37097
- return type === "permission_request" || type === "permission_response" || type === "sandbox_permission_request" || type === "sandbox_permission_response" || type === "shutdown_request" || type === "shutdown_approved" || type === "team_permission_update" || type === "mode_set_request" || type === "plan_approval_request" || type === "plan_approval_response";
37132
+ return type === "permission_request" || type === "permission_response" || type === "sandbox_permission_request" || type === "sandbox_permission_response" || type === "shutdown_request" || type === "shutdown_approved" || type === "shutdown_request_from_member" || type === "shutdown_request_denied" || type === "team_permission_update" || type === "mode_set_request" || type === "plan_approval_request" || type === "plan_approval_response";
37098
37133
  } catch {
37099
37134
  return false;
37100
37135
  }
@@ -37148,7 +37183,7 @@ function getLastPeerDmSummary(messages) {
37148
37183
  }
37149
37184
  return;
37150
37185
  }
37151
- var LOCK_OPTIONS, PlanApprovalRequestMessageSchema, PlanApprovalResponseMessageSchema, ShutdownRequestMessageSchema, ShutdownApprovedMessageSchema, ShutdownRejectedMessageSchema, ModeSetRequestMessageSchema;
37186
+ var LOCK_OPTIONS, PlanApprovalRequestMessageSchema, PlanApprovalResponseMessageSchema, ShutdownRequestMessageSchema, ShutdownApprovedMessageSchema, ShutdownRejectedMessageSchema, ShutdownRequestFromMemberMessageSchema, ShutdownRequestDeniedMessageSchema, ModeSetRequestMessageSchema;
37152
37187
  var init_mailbox = __esm(() => {
37153
37188
  init_zod();
37154
37189
  init_config();
@@ -37202,6 +37237,20 @@ var init_mailbox = __esm(() => {
37202
37237
  reason: string2(),
37203
37238
  timestamp: string2()
37204
37239
  }));
37240
+ ShutdownRequestFromMemberMessageSchema = lazySchema(() => object({
37241
+ type: literal("shutdown_request_from_member"),
37242
+ requestId: string2(),
37243
+ from: string2(),
37244
+ reason: string2().optional(),
37245
+ timestamp: string2()
37246
+ }));
37247
+ ShutdownRequestDeniedMessageSchema = lazySchema(() => object({
37248
+ type: literal("shutdown_request_denied"),
37249
+ requestId: string2(),
37250
+ to: string2(),
37251
+ reason: string2().optional(),
37252
+ timestamp: string2()
37253
+ }));
37205
37254
  ModeSetRequestMessageSchema = lazySchema(() => object({
37206
37255
  type: literal("mode_set_request"),
37207
37256
  mode: PermissionModeSchema(),
@@ -73737,7 +73786,8 @@ function resolveTeammateAgentFace(params) {
73737
73786
  TASK_CREATE_TOOL_NAME,
73738
73787
  TASK_GET_TOOL_NAME,
73739
73788
  TASK_LIST_TOOL_NAME,
73740
- TASK_UPDATE_TOOL_NAME
73789
+ TASK_UPDATE_TOOL_NAME,
73790
+ REQUEST_SHUTDOWN_TOOL_NAME
73741
73791
  ])
73742
73792
  ] : undefined,
73743
73793
  ...agentDefinition?.disallowedTools ? { disallowedTools: agentDefinition.disallowedTools } : {},
@@ -74105,6 +74155,32 @@ async function waitForNextPromptOrShutdown(identity, abortController, taskId, ge
74105
74155
  originalMessage: msg.text
74106
74156
  };
74107
74157
  }
74158
+ let deniedIndex = -1;
74159
+ let deniedFrom = "";
74160
+ let deniedParsed = null;
74161
+ for (let i = 0;i < allMessages.length; i++) {
74162
+ const m = allMessages[i];
74163
+ if (m && !m.read) {
74164
+ const parsed = isShutdownRequestDenied(m.text);
74165
+ if (parsed && m.from.toLowerCase() === TEAM_LEAD_NAME2.toLowerCase() && parsed.to.toLowerCase() === identity.agentName.toLowerCase()) {
74166
+ deniedIndex = i;
74167
+ deniedFrom = m.from;
74168
+ deniedParsed = parsed;
74169
+ break;
74170
+ }
74171
+ }
74172
+ }
74173
+ if (deniedIndex !== -1) {
74174
+ logForDebugging(`[inProcessRunner] ${identity.agentName} received shutdown request denial (${deniedParsed?.requestId}) from ${deniedFrom}`);
74175
+ await markMessageAsReadByIndex(identity.agentName, identity.teamName, deniedIndex);
74176
+ recordMemberShutdownRequestDenied(identity.agentName, deniedParsed.requestId);
74177
+ return {
74178
+ type: "shutdown_request_denied",
74179
+ requestId: deniedParsed.requestId,
74180
+ reason: deniedParsed.reason,
74181
+ from: deniedFrom
74182
+ };
74183
+ }
74108
74184
  let selectedIndex = -1;
74109
74185
  for (let i = 0;i < allMessages.length; i++) {
74110
74186
  const m = allMessages[i];
@@ -74178,13 +74254,6 @@ async function runInProcessTeammate(config) {
74178
74254
  allowedTools,
74179
74255
  avoidPermissionPrompts: !canShowPermissionPrompts
74180
74256
  });
74181
- const basePool = getTools(buildTeammateToolPermissionContext(getAppState().toolPermissionContext), getTeammateToolRegistryDeps());
74182
- const { def: resolvedAgentDefinition, tools } = resolveTeammateAgentFace({
74183
- identity,
74184
- teammateSystemPrompt,
74185
- agentDefinition,
74186
- basePool
74187
- });
74188
74257
  const allMessages = [];
74189
74258
  const wrappedInitialPrompt = formatAsTeammateMessage("team-lead", prompt, undefined, undefined);
74190
74259
  let currentPrompt = wrappedInitialPrompt;
@@ -74250,6 +74319,13 @@ async function runInProcessTeammate(config) {
74250
74319
  let workWasAborted = false;
74251
74320
  await runWithTeammateContext(teammateContext, async () => {
74252
74321
  updateTaskState(taskId, setAppState, (task) => ({ ...task, status: "running", isIdle: false }));
74322
+ const basePool = getTools(buildTeammateToolPermissionContext(getAppState().toolPermissionContext), getTeammateToolRegistryDeps());
74323
+ const { def: resolvedAgentDefinition, tools } = resolveTeammateAgentFace({
74324
+ identity,
74325
+ teammateSystemPrompt,
74326
+ agentDefinition,
74327
+ basePool
74328
+ });
74253
74329
  const agentResult = await runAgent({
74254
74330
  agentDefinition: resolvedAgentDefinition,
74255
74331
  prompt: currentPrompt,
@@ -74330,12 +74406,19 @@ async function runInProcessTeammate(config) {
74330
74406
  const waitResult = await waitForNextPromptOrShutdown(identity, abortController, taskId, getAppState, setAppState, identity.parentSessionId);
74331
74407
  switch (waitResult.type) {
74332
74408
  case "shutdown_request":
74409
+ clearMemberShutdownRequestState(identity.agentName);
74333
74410
  logForDebugging(`[inProcessRunner] ${identity.agentId} received shutdown request - passing to model`);
74334
74411
  currentPrompt = formatAsTeammateMessage(waitResult.request?.from || "team-lead", waitResult.originalMessage);
74335
74412
  appendTeammateMessage(taskId, createUserMessage({ content: currentPrompt }), setAppState);
74336
74413
  break;
74414
+ case "shutdown_request_denied":
74415
+ logForDebugging(`[inProcessRunner] ${identity.agentId} shutdown request denied - latch held until next input`);
74416
+ currentPrompt = formatAsTeammateMessage(waitResult.from, `Your shutdown request (${waitResult.requestId}) was denied by the team lead${waitResult.reason ? `: ${waitResult.reason}` : ""}. Stay in your current role; wait for new input before requesting shutdown again.`);
74417
+ appendTeammateMessage(taskId, createUserMessage({ content: currentPrompt }), setAppState);
74418
+ break;
74337
74419
  case "new_message":
74338
74420
  logForDebugging(`[inProcessRunner] ${identity.agentId} received new message from ${waitResult.from}`);
74421
+ clearMemberShutdownRequestState(identity.agentName);
74339
74422
  if (waitResult.from === "user") {
74340
74423
  currentPrompt = waitResult.message;
74341
74424
  } else {
@@ -74769,7 +74852,16 @@ If you receive a JSON message with \`type: "shutdown_request"\` or \`type: "plan
74769
74852
 
74770
74853
  Approving shutdown terminates your process. Rejecting plan sends the teammate back to revise. Don't originate \`shutdown_request\` unless asked. Don't send structured JSON status messages — use TaskUpdate.
74771
74854
 
74772
- Always send protocol responses as JSON **objects** in the \`message\` field, exactly as shown above — never stringify them into a string. (String-encoded JSON of the three protocol types is tolerated as a fallback, but the object form is authoritative.)`.trim();
74855
+ ## Member shutdown requests (as lead)
74856
+
74857
+ Teammates can ask you to approve their exit via the RequestShutdown tool. WaitForTeammates surfaces these as \`pending_requests\` entries ({ from, reason, request_id }). Decide each one via this tool (0.1.96 A1):
74858
+
74859
+ - **Approve**: \`{"to": "<member>", "message": {"type": "shutdown_request", "reason": "..."}}\` — the member runs its existing approval path and exits.
74860
+ - **Deny**: \`{"to": "<member>", "message": {"type": "shutdown_request_denied", "request_id": "<request_id from pending_requests>", "reason": "..."}}\` — the member is told to wait for new input before requesting again.
74861
+
74862
+ Deciding either way clears the entry from \`pending_requests\`. Don't leave member shutdown requests unanswered — a member that asked to leave and got no reply stays idle.
74863
+
74864
+ Always send protocol responses as JSON **objects** in the \`message\` field, exactly as shown above — never stringify them into a string. (String-encoded JSON of the protocol types is tolerated as a fallback, but the object form is authoritative.)`.trim();
74773
74865
  }
74774
74866
  function getSendMessagePrompt() {
74775
74867
  const on = isUdsInboxEnabled();
@@ -74794,6 +74886,14 @@ var init_sendMessagePrompt = __esm(() => {
74794
74886
  PROMPT2 = buildPrompt("", "");
74795
74887
  });
74796
74888
 
74889
+ // src/engine/tools/team/teamRouting.ts
74890
+ function resolveOutgoingTeamName(teamContext) {
74891
+ return getTeamName(teamContext) ?? peekTeamContext()?.teamName;
74892
+ }
74893
+ var init_teamRouting = __esm(() => {
74894
+ init_messaging();
74895
+ });
74896
+
74797
74897
  // src/engine/tools/team/sendMessageTool.ts
74798
74898
  function tryParseStructuredMessage(text) {
74799
74899
  let parsed;
@@ -74806,7 +74906,7 @@ function tryParseStructuredMessage(text) {
74806
74906
  return;
74807
74907
  }
74808
74908
  const type = parsed.type;
74809
- if (type === "shutdown_request" || type === "shutdown_response" || type === "plan_approval_response") {
74909
+ if (type === "shutdown_request" || type === "shutdown_response" || type === "plan_approval_response" || type === "shutdown_request_denied") {
74810
74910
  return parsed;
74811
74911
  }
74812
74912
  return;
@@ -74829,8 +74929,8 @@ function setSelfTerminatePort(port) {
74829
74929
  function resetSelfTerminatePort() {
74830
74930
  selfTerminatePort = undefined;
74831
74931
  }
74832
- function resolveOutgoingTeamName(teamContext) {
74833
- return getTeamName(teamContext) ?? peekTeamContext()?.teamName;
74932
+ function isLeadDualSource(appState) {
74933
+ return isTeamLead(appState.teamContext) || isTeamLead(peekTeamContext());
74834
74934
  }
74835
74935
  function unresolvedTeamMailboxError(recipient) {
74836
74936
  return new Error(`Cannot route message to "${recipient}": no team mailbox is resolvable ` + "(no teamContext in appState, no in-process teammate context, and no team " + "registered via TeamCreate). Create a team with TeamCreate first; the " + "message was NOT delivered.");
@@ -74977,6 +75077,9 @@ async function handleShutdownRequest(targetName, reason, context) {
74977
75077
  const teamName = resolveOutgoingTeamName(appState.teamContext);
74978
75078
  if (!teamName)
74979
75079
  throw unresolvedTeamMailboxError(targetName);
75080
+ if (!isLeadDualSource(appState)) {
75081
+ throw new Error("Only the team lead can approve member shutdown requests. Teammates cannot approve their own or other shutdown requests.");
75082
+ }
74980
75083
  const senderName = getAgentName() || TEAM_LEAD_NAME;
74981
75084
  const requestId = generateRequestId("shutdown", targetName);
74982
75085
  const shutdownMessage = createShutdownRequestMessage({
@@ -74990,6 +75093,9 @@ async function handleShutdownRequest(targetName, reason, context) {
74990
75093
  timestamp: new Date().toISOString(),
74991
75094
  color: getTeammateColor()
74992
75095
  }, teamName);
75096
+ try {
75097
+ await markMessagesAsReadByPredicate(TEAM_LEAD_NAME, (m) => !!isShutdownRequestFromMember(m.text) && m.from.toLowerCase() === targetName.toLowerCase(), teamName);
75098
+ } catch {}
74993
75099
  return {
74994
75100
  data: {
74995
75101
  success: true,
@@ -74999,6 +75105,38 @@ async function handleShutdownRequest(targetName, reason, context) {
74999
75105
  }
75000
75106
  };
75001
75107
  }
75108
+ async function handleShutdownRequestDenied(targetName, requestId, reason, context) {
75109
+ const appState = context.getAppState();
75110
+ const teamName = resolveOutgoingTeamName(appState.teamContext);
75111
+ if (!teamName)
75112
+ throw unresolvedTeamMailboxError(targetName);
75113
+ if (!isLeadDualSource(appState)) {
75114
+ throw new Error("Only the team lead can deny member shutdown requests. Teammates cannot deny their own or other shutdown requests.");
75115
+ }
75116
+ const senderName = getAgentName() || TEAM_LEAD_NAME;
75117
+ const deniedMessage = createShutdownRequestDeniedMessage({
75118
+ requestId,
75119
+ to: targetName,
75120
+ reason
75121
+ });
75122
+ await writeToMailbox(targetName, {
75123
+ from: senderName,
75124
+ text: jsonStringify(deniedMessage),
75125
+ timestamp: new Date().toISOString(),
75126
+ color: getTeammateColor()
75127
+ }, teamName);
75128
+ try {
75129
+ await markMessagesAsReadByPredicate(TEAM_LEAD_NAME, (m) => !!isShutdownRequestFromMember(m.text) && m.from.toLowerCase() === targetName.toLowerCase(), teamName);
75130
+ } catch {}
75131
+ return {
75132
+ data: {
75133
+ success: true,
75134
+ message: `Shutdown request ${requestId} from ${targetName} denied. The member has been told to wait for new input before requesting again.`,
75135
+ request_id: requestId,
75136
+ target: targetName
75137
+ }
75138
+ };
75139
+ }
75002
75140
  async function handleShutdownApproval(requestId, context) {
75003
75141
  const teamName = resolveOutgoingTeamName();
75004
75142
  if (!teamName)
@@ -75096,7 +75234,7 @@ async function handlePlanApproval(recipientName, requestId, context) {
75096
75234
  const teamName = resolveOutgoingTeamName(appState.teamContext);
75097
75235
  if (!teamName)
75098
75236
  throw unresolvedTeamMailboxError(recipientName);
75099
- if (!isTeamLead(appState.teamContext)) {
75237
+ if (!isLeadDualSource(appState)) {
75100
75238
  throw new Error("Only the team lead can approve plans. Teammates cannot approve their own or other plans.");
75101
75239
  }
75102
75240
  const leaderMode = appState.toolPermissionContext.mode;
@@ -75126,7 +75264,7 @@ async function handlePlanRejection(recipientName, requestId, feedback, context)
75126
75264
  const teamName = resolveOutgoingTeamName(appState.teamContext);
75127
75265
  if (!teamName)
75128
75266
  throw unresolvedTeamMailboxError(recipientName);
75129
- if (!isTeamLead(appState.teamContext)) {
75267
+ if (!isLeadDualSource(appState)) {
75130
75268
  throw new Error("Only the team lead can reject plans. Teammates cannot reject their own or other plans.");
75131
75269
  }
75132
75270
  const rejectionResponse = {
@@ -75153,6 +75291,8 @@ async function dispatchStructuredMessage(message, to, ctx) {
75153
75291
  switch (message.type) {
75154
75292
  case "shutdown_request":
75155
75293
  return handleShutdownRequest(to, message.reason, ctx);
75294
+ case "shutdown_request_denied":
75295
+ return handleShutdownRequestDenied(to, message.request_id, message.reason, ctx);
75156
75296
  case "shutdown_response":
75157
75297
  if (message.approve) {
75158
75298
  return handleShutdownApproval(message.request_id, ctx);
@@ -75174,6 +75314,7 @@ var init_sendMessageTool = __esm(() => {
75174
75314
  init_task2();
75175
75315
  init_toolNames();
75176
75316
  init_sendMessagePrompt();
75317
+ init_teamRouting();
75177
75318
  SEND_MESSAGE_TOOL_INPUT_SCHEMA = {
75178
75319
  type: "object",
75179
75320
  properties: {
@@ -75188,7 +75329,7 @@ var init_sendMessageTool = __esm(() => {
75188
75329
  description: "A 5-10 word summary shown as a preview in the UI (required when message is a string)"
75189
75330
  },
75190
75331
  message: {
75191
- description: "Plain text message content, or a structured protocol message (shutdown_request / shutdown_response / plan_approval_response)",
75332
+ description: "Plain text message content, or a structured protocol message (shutdown_request / shutdown_response / shutdown_request_denied / plan_approval_response)",
75192
75333
  anyOf: [
75193
75334
  { type: "string" },
75194
75335
  {
@@ -75218,6 +75359,15 @@ var init_sendMessageTool = __esm(() => {
75218
75359
  feedback: { type: "string" }
75219
75360
  },
75220
75361
  required: ["type", "request_id", "approve"]
75362
+ },
75363
+ {
75364
+ type: "object",
75365
+ properties: {
75366
+ type: { const: "shutdown_request_denied" },
75367
+ request_id: { type: "string" },
75368
+ reason: { type: "string" }
75369
+ },
75370
+ required: ["type", "request_id"]
75221
75371
  }
75222
75372
  ]
75223
75373
  }
@@ -76491,6 +76641,11 @@ The call blocks (event-driven, no busy-waiting) until every working teammate is
76491
76641
  - On success it returns { status: 'idle', waited_ms, idle }.
76492
76642
  - On timeout it returns { status: 'timeout', waited_ms, still_working } listing the teammates that are still working — it never blocks forever. You may call again with a longer timeout, or proceed without those teammates.
76493
76643
 
76644
+ Pending member shutdown requests (0.1.96 A1): teammates can ask YOU (the lead) for permission to shut down by calling RequestShutdown. Every result therefore also carries pending_requests — an array of { from, reason, request_id } entries for members whose shutdown requests are awaiting your decision. For each entry you must decide:
76645
+ - Approve: send the member a shutdown_request via SendMessage (type: 'shutdown_request') — the member will run its existing approval path and exit.
76646
+ - Deny: send the member a shutdown_request_denied via SendMessage (type: 'shutdown_request_denied', request_id = the entry's request_id) — the member is told to wait for new input before requesting again.
76647
+ Deciding (either way) clears the entry from pending_requests; do not ignore pending requests — a member that asked to leave and got no answer stays idle forever.
76648
+
76494
76649
  This tool never aborts or kills teammates; it only waits. Graceful termination is driven by shutdown requests via SendMessage, and cleanup remains TeamDelete's responsibility. When no teammates are working, it returns immediately with status 'idle'.
76495
76650
 
76496
76651
  Parameters:
@@ -76510,9 +76665,36 @@ function listWorkingTeammateNames(appState) {
76510
76665
  }
76511
76666
  return names;
76512
76667
  }
76668
+ async function collectPendingMemberRequests(teamName) {
76669
+ const messages = await readMailbox(TEAM_LEAD_NAME, teamName);
76670
+ const pending = [];
76671
+ for (const m of messages) {
76672
+ if (m.read)
76673
+ continue;
76674
+ const req = isShutdownRequestFromMember(m.text);
76675
+ if (req && m.from.toLowerCase() === req.from.toLowerCase()) {
76676
+ pending.push({
76677
+ from: m.from,
76678
+ reason: req.reason,
76679
+ request_id: req.requestId
76680
+ });
76681
+ }
76682
+ }
76683
+ return pending;
76684
+ }
76685
+ async function attachPendingRequests(data) {
76686
+ try {
76687
+ const pending = await collectPendingMemberRequests(resolveOutgoingTeamName());
76688
+ if (pending.length > 0) {
76689
+ return { ...data, pending_requests: pending };
76690
+ }
76691
+ } catch {}
76692
+ return data;
76693
+ }
76513
76694
  var WAIT_FOR_TEAMMATES_TOOL_INPUT_SCHEMA, WAIT_FOR_TEAMMATES_DEFAULT_TIMEOUT_MS = 120000, WAIT_FOR_TEAMMATES_MAX_TIMEOUT_MS = 600000, WaitForTeammatesTool;
76514
76695
  var init_waitForTeammatesTool = __esm(() => {
76515
76696
  init_messaging();
76697
+ init_teamRouting();
76516
76698
  init_task2();
76517
76699
  init_json();
76518
76700
  init_toolNames();
@@ -76583,7 +76765,12 @@ var init_waitForTeammatesTool = __esm(() => {
76583
76765
  const workingNames = listWorkingTeammateNames(appState);
76584
76766
  if (workingNames.length === 0) {
76585
76767
  return {
76586
- data: { status: "idle", waited_ms: 0, idle: [], still_working: [] }
76768
+ data: await attachPendingRequests({
76769
+ status: "idle",
76770
+ waited_ms: 0,
76771
+ idle: [],
76772
+ still_working: []
76773
+ })
76587
76774
  };
76588
76775
  }
76589
76776
  const setAppState = (updater) => {
@@ -76612,31 +76799,31 @@ var init_waitForTeammatesTool = __esm(() => {
76612
76799
  const idleNames = workingNames.filter((name) => !nowWorking.includes(name));
76613
76800
  if (outcome === "timeout" && nowWorking.length === 0) {
76614
76801
  return {
76615
- data: {
76802
+ data: await attachPendingRequests({
76616
76803
  status: "idle",
76617
76804
  waited_ms: waitedMs,
76618
76805
  idle: idleNames,
76619
76806
  still_working: []
76620
- }
76807
+ })
76621
76808
  };
76622
76809
  }
76623
76810
  if (outcome === "idle") {
76624
76811
  return {
76625
- data: {
76812
+ data: await attachPendingRequests({
76626
76813
  status: "idle",
76627
76814
  waited_ms: waitedMs,
76628
76815
  idle: idleNames,
76629
76816
  still_working: []
76630
- }
76817
+ })
76631
76818
  };
76632
76819
  }
76633
76820
  return {
76634
- data: {
76821
+ data: await attachPendingRequests({
76635
76822
  status: "timeout",
76636
76823
  waited_ms: waitedMs,
76637
76824
  idle: idleNames,
76638
76825
  still_working: nowWorking
76639
- }
76826
+ })
76640
76827
  };
76641
76828
  } finally {
76642
76829
  if (timer)
@@ -76646,6 +76833,150 @@ var init_waitForTeammatesTool = __esm(() => {
76646
76833
  };
76647
76834
  });
76648
76835
 
76836
+ // src/engine/tools/team/requestShutdownTool.ts
76837
+ function generateMemberRequestId() {
76838
+ return `rs-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
76839
+ }
76840
+ function isMemberShutdownRequestPending(memberName) {
76841
+ return pendingByMember.has(memberName);
76842
+ }
76843
+ function peekPendingMemberShutdownRequest(memberName) {
76844
+ return pendingByMember.get(memberName);
76845
+ }
76846
+ function recordMemberShutdownRequestDenied(memberName, _requestId) {
76847
+ deniedByMember.add(memberName);
76848
+ pendingByMember.delete(memberName);
76849
+ }
76850
+ function clearMemberShutdownRequestState(memberName) {
76851
+ deniedByMember.delete(memberName);
76852
+ pendingByMember.delete(memberName);
76853
+ }
76854
+ function clearMemberPendingShutdownRequest(memberName) {
76855
+ pendingByMember.delete(memberName);
76856
+ }
76857
+ function resetRequestShutdownStateForTest() {
76858
+ pendingByMember.clear();
76859
+ deniedByMember.clear();
76860
+ }
76861
+ var REQUEST_SHUTDOWN_TOOL_INPUT_SCHEMA, pendingByMember, deniedByMember, RequestShutdownTool;
76862
+ var init_requestShutdownTool = __esm(() => {
76863
+ init_messaging();
76864
+ init_json();
76865
+ init_toolNames();
76866
+ REQUEST_SHUTDOWN_TOOL_INPUT_SCHEMA = {
76867
+ type: "object",
76868
+ properties: {
76869
+ reason: {
76870
+ type: "string",
76871
+ description: "Why you are requesting to shut down (task complete, persistently blocked, etc.)"
76872
+ }
76873
+ },
76874
+ additionalProperties: false
76875
+ };
76876
+ pendingByMember = new Map;
76877
+ deniedByMember = new Set;
76878
+ RequestShutdownTool = {
76879
+ name: REQUEST_SHUTDOWN_TOOL_NAME,
76880
+ inputSchema: REQUEST_SHUTDOWN_TOOL_INPUT_SCHEMA,
76881
+ inputJSONSchema: REQUEST_SHUTDOWN_TOOL_INPUT_SCHEMA,
76882
+ strict: true,
76883
+ searchHint: "ask the team lead to approve this teammate shutting down",
76884
+ maxResultSizeChars: 1e4,
76885
+ shouldDefer: true,
76886
+ isEnabled: () => isAgentSwarmsEnabled() && isTeammate(),
76887
+ isReadOnly: () => false,
76888
+ isDestructive: () => false,
76889
+ isConcurrencySafe: () => true,
76890
+ userFacingName: () => "Request Shutdown",
76891
+ toAutoClassifierInput: () => "",
76892
+ async checkPermissions(input) {
76893
+ return { behavior: "allow", updatedInput: input };
76894
+ },
76895
+ mapToolResultToToolResultBlockParam(data, toolUseID) {
76896
+ return {
76897
+ tool_use_id: toolUseID,
76898
+ type: "tool_result",
76899
+ content: [
76900
+ {
76901
+ type: "text",
76902
+ text: data.message
76903
+ }
76904
+ ]
76905
+ };
76906
+ },
76907
+ async description() {
76908
+ return "Request permission from the team lead to shut down. Use when your " + "task is complete or you are persistently blocked with no further " + "progress possible. This only submits the request — the lead decides " + "whether to approve it. If a previous request was denied, wait for " + "new input before requesting again.";
76909
+ },
76910
+ renderToolUseMessage(input) {
76911
+ const { reason } = input ?? {};
76912
+ return reason ? `requesting shutdown: ${reason}` : "requesting shutdown";
76913
+ },
76914
+ async call(args) {
76915
+ const { reason } = args ?? {};
76916
+ const memberName = getAgentName();
76917
+ if (!memberName) {
76918
+ return {
76919
+ data: {
76920
+ success: false,
76921
+ message: "No teammate identity available; cannot submit a shutdown request."
76922
+ }
76923
+ };
76924
+ }
76925
+ const teamName = getTeamName();
76926
+ if (deniedByMember.has(memberName)) {
76927
+ return {
76928
+ data: {
76929
+ success: false,
76930
+ message: "Your previous shutdown request was denied by the lead. " + "Wait for new input before requesting again."
76931
+ }
76932
+ };
76933
+ }
76934
+ const existingId = peekPendingMemberShutdownRequest(memberName);
76935
+ if (existingId) {
76936
+ return {
76937
+ data: {
76938
+ success: false,
76939
+ message: `A shutdown request (${existingId}) is already pending with the lead.`
76940
+ }
76941
+ };
76942
+ }
76943
+ try {
76944
+ const leadMessages = await readMailbox(TEAM_LEAD_NAME, teamName);
76945
+ const ownUnread = leadMessages.some((m) => {
76946
+ const req = isShutdownRequestFromMember(m.text);
76947
+ return !m.read && !!req && m.from.toLowerCase() === req.from.toLowerCase() && m.from.toLowerCase() === memberName.toLowerCase();
76948
+ });
76949
+ if (ownUnread) {
76950
+ return {
76951
+ data: {
76952
+ success: false,
76953
+ message: "A shutdown request from you is already pending with the lead."
76954
+ }
76955
+ };
76956
+ }
76957
+ } catch {}
76958
+ const requestId = generateMemberRequestId();
76959
+ await writeToMailbox(TEAM_LEAD_NAME, {
76960
+ from: memberName,
76961
+ text: jsonStringify(createShutdownRequestFromMemberMessage({
76962
+ requestId,
76963
+ from: memberName,
76964
+ reason
76965
+ })),
76966
+ timestamp: new Date().toISOString(),
76967
+ color: getTeammateColor()
76968
+ }, teamName);
76969
+ pendingByMember.set(memberName, requestId);
76970
+ return {
76971
+ data: {
76972
+ success: true,
76973
+ message: "Shutdown request submitted to the team lead. Approval is the " + "lead's decision — you will keep working until the lead sends " + "a shutdown request back (approve) or a denial receipt."
76974
+ }
76975
+ };
76976
+ }
76977
+ };
76978
+ });
76979
+
76649
76980
  // src/engine/tools/team/index.ts
76650
76981
  var init_team = __esm(() => {
76651
76982
  init_sendMessageTool();
@@ -76657,6 +76988,7 @@ var init_team = __esm(() => {
76657
76988
  init_teamDeleteTool();
76658
76989
  init_teamDeletePrompt();
76659
76990
  init_waitForTeammatesTool();
76991
+ init_requestShutdownTool();
76660
76992
  });
76661
76993
 
76662
76994
  // src/engine/scheduler/cron.ts
@@ -84348,6 +84680,7 @@ function getBaseToolEntities() {
84348
84680
  SendMessageTool,
84349
84681
  TeamCreateTool,
84350
84682
  TeamDeleteTool,
84683
+ RequestShutdownTool,
84351
84684
  SnipTool
84352
84685
  ];
84353
84686
  }
@@ -88079,8 +88412,10 @@ __export(exports_engine, {
88079
88412
  PlanApprovalRequestMessageSchema: () => PlanApprovalRequestMessageSchema,
88080
88413
  PlanApprovalResponseMessageSchema: () => PlanApprovalResponseMessageSchema,
88081
88414
  REPL_TOOL_NAME: () => REPL_TOOL_NAME,
88415
+ REQUEST_SHUTDOWN_TOOL_NAME: () => REQUEST_SHUTDOWN_TOOL_NAME,
88082
88416
  ReadMcpResourceTool: () => ReadMcpResourceTool,
88083
88417
  ReadTool: () => ReadTool,
88418
+ RequestShutdownTool: () => RequestShutdownTool,
88084
88419
  SAFE_ENV_VARS: () => SAFE_ENV_VARS,
88085
88420
  SEND_MESSAGE_TOOL_NAME: () => SEND_MESSAGE_TOOL_NAME,
88086
88421
  SETTING_SOURCES: () => SETTING_SOURCES,
@@ -88181,6 +88516,8 @@ __export(exports_engine, {
88181
88516
  clearGoal: () => clearGoal,
88182
88517
  clearLeaderTeamName: () => clearLeaderTeamName,
88183
88518
  clearMailbox: () => clearMailbox,
88519
+ clearMemberPendingShutdownRequest: () => clearMemberPendingShutdownRequest,
88520
+ clearMemberShutdownRequestState: () => clearMemberShutdownRequestState,
88184
88521
  clearPendingNotifications: () => clearPendingNotifications,
88185
88522
  clearPluginSettingsBase: () => clearPluginSettingsBase,
88186
88523
  clearPostCompactResetsForTesting: () => clearPostCompactResetsForTesting,
@@ -88440,6 +88777,7 @@ __export(exports_engine, {
88440
88777
  isLocalShellTask: () => isLocalShellTask,
88441
88778
  isLoggableMessage: () => isLoggableMessage,
88442
88779
  isMainThreadSource: () => isMainThreadSource,
88780
+ isMemberShutdownRequestPending: () => isMemberShutdownRequestPending,
88443
88781
  isModeSetRequest: () => isModeSetRequest,
88444
88782
  isPanelAgentTask: () => isPanelAgentTask,
88445
88783
  isPermissionRequest: () => isPermissionRequest,
@@ -88466,6 +88804,7 @@ __export(exports_engine, {
88466
88804
  isShutdownApproved: () => isShutdownApproved,
88467
88805
  isShutdownRejected: () => isShutdownRejected,
88468
88806
  isShutdownRequest: () => isShutdownRequest,
88807
+ isShutdownRequestDenied: () => isShutdownRequestDenied,
88469
88808
  isSlashCommand: () => isSlashCommand,
88470
88809
  isSnipBoundaryMessage: () => isSnipBoundaryMessage,
88471
88810
  isSnipMarkerMessage: () => isSnipMarkerMessage,
@@ -88551,6 +88890,7 @@ __export(exports_engine, {
88551
88890
  partitionToolCalls: () => partitionToolCalls,
88552
88891
  pauseGoal: () => pauseGoal,
88553
88892
  peek: () => peek,
88893
+ peekPendingMemberShutdownRequest: () => peekPendingMemberShutdownRequest,
88554
88894
  persistPermissionUpdate: () => persistPermissionUpdate,
88555
88895
  persistPermissionUpdates: () => persistPermissionUpdates,
88556
88896
  pollTasks: () => pollTasks,
@@ -88577,6 +88917,7 @@ __export(exports_engine, {
88577
88917
  recordCheckIn: () => recordCheckIn,
88578
88918
  recordContentReplacement: () => recordContentReplacement,
88579
88919
  recordExtractionTokenCount: () => recordExtractionTokenCount,
88920
+ recordMemberShutdownRequestDenied: () => recordMemberShutdownRequestDenied,
88580
88921
  recordSidechainTranscript: () => recordSidechainTranscript,
88581
88922
  recordTranscript: () => recordTranscript,
88582
88923
  refreshOnUserMessage: () => refreshOnUserMessage,
@@ -88612,6 +88953,7 @@ __export(exports_engine, {
88612
88953
  resetPendingNotifications: () => resetPendingNotifications,
88613
88954
  resetProjectFlushStateForTesting: () => resetProjectFlushStateForTesting,
88614
88955
  resetProjectForTesting: () => resetProjectForTesting,
88956
+ resetRequestShutdownStateForTest: () => resetRequestShutdownStateForTest,
88615
88957
  resetRestrictedMode: () => resetRestrictedMode,
88616
88958
  resetSchedulerEnv: () => resetSchedulerEnv,
88617
88959
  resetSdkEventQueueForTesting: () => resetSdkEventQueueForTesting,
@@ -193692,8 +194034,10 @@ __export(exports_engineCompat, {
193692
194034
  PlanApprovalRequestMessageSchema: () => PlanApprovalRequestMessageSchema,
193693
194035
  PlanApprovalResponseMessageSchema: () => PlanApprovalResponseMessageSchema,
193694
194036
  REPL_TOOL_NAME: () => REPL_TOOL_NAME,
194037
+ REQUEST_SHUTDOWN_TOOL_NAME: () => REQUEST_SHUTDOWN_TOOL_NAME,
193695
194038
  ReadMcpResourceTool: () => ReadMcpResourceTool,
193696
194039
  ReadTool: () => ReadTool,
194040
+ RequestShutdownTool: () => RequestShutdownTool,
193697
194041
  SAFE_ENV_VARS: () => SAFE_ENV_VARS,
193698
194042
  SEND_MESSAGE_TOOL_NAME: () => SEND_MESSAGE_TOOL_NAME,
193699
194043
  SETTING_SOURCES: () => SETTING_SOURCES,
@@ -193794,6 +194138,8 @@ __export(exports_engineCompat, {
193794
194138
  clearGoal: () => clearGoal,
193795
194139
  clearLeaderTeamName: () => clearLeaderTeamName,
193796
194140
  clearMailbox: () => clearMailbox,
194141
+ clearMemberPendingShutdownRequest: () => clearMemberPendingShutdownRequest,
194142
+ clearMemberShutdownRequestState: () => clearMemberShutdownRequestState,
193797
194143
  clearPendingNotifications: () => clearPendingNotifications,
193798
194144
  clearPluginSettingsBase: () => clearPluginSettingsBase,
193799
194145
  clearPostCompactResetsForTesting: () => clearPostCompactResetsForTesting,
@@ -194053,6 +194399,7 @@ __export(exports_engineCompat, {
194053
194399
  isLocalShellTask: () => isLocalShellTask,
194054
194400
  isLoggableMessage: () => isLoggableMessage,
194055
194401
  isMainThreadSource: () => isMainThreadSource,
194402
+ isMemberShutdownRequestPending: () => isMemberShutdownRequestPending,
194056
194403
  isModeSetRequest: () => isModeSetRequest,
194057
194404
  isPanelAgentTask: () => isPanelAgentTask,
194058
194405
  isPermissionRequest: () => isPermissionRequest,
@@ -194079,6 +194426,7 @@ __export(exports_engineCompat, {
194079
194426
  isShutdownApproved: () => isShutdownApproved,
194080
194427
  isShutdownRejected: () => isShutdownRejected,
194081
194428
  isShutdownRequest: () => isShutdownRequest,
194429
+ isShutdownRequestDenied: () => isShutdownRequestDenied,
194082
194430
  isSlashCommand: () => isSlashCommand,
194083
194431
  isSnipBoundaryMessage: () => isSnipBoundaryMessage,
194084
194432
  isSnipMarkerMessage: () => isSnipMarkerMessage,
@@ -194164,6 +194512,7 @@ __export(exports_engineCompat, {
194164
194512
  partitionToolCalls: () => partitionToolCalls,
194165
194513
  pauseGoal: () => pauseGoal,
194166
194514
  peek: () => peek,
194515
+ peekPendingMemberShutdownRequest: () => peekPendingMemberShutdownRequest,
194167
194516
  persistPermissionUpdate: () => persistPermissionUpdate,
194168
194517
  persistPermissionUpdates: () => persistPermissionUpdates,
194169
194518
  pollTasks: () => pollTasks,
@@ -194190,6 +194539,7 @@ __export(exports_engineCompat, {
194190
194539
  recordCheckIn: () => recordCheckIn,
194191
194540
  recordContentReplacement: () => recordContentReplacement,
194192
194541
  recordExtractionTokenCount: () => recordExtractionTokenCount,
194542
+ recordMemberShutdownRequestDenied: () => recordMemberShutdownRequestDenied,
194193
194543
  recordSidechainTranscript: () => recordSidechainTranscript,
194194
194544
  recordTranscript: () => recordTranscript,
194195
194545
  refreshOnUserMessage: () => refreshOnUserMessage,
@@ -194225,6 +194575,7 @@ __export(exports_engineCompat, {
194225
194575
  resetPendingNotifications: () => resetPendingNotifications,
194226
194576
  resetProjectFlushStateForTesting: () => resetProjectFlushStateForTesting,
194227
194577
  resetProjectForTesting: () => resetProjectForTesting,
194578
+ resetRequestShutdownStateForTest: () => resetRequestShutdownStateForTest,
194228
194579
  resetRestrictedMode: () => resetRestrictedMode,
194229
194580
  resetSchedulerEnv: () => resetSchedulerEnv,
194230
194581
  resetSdkEventQueueForTesting: () => resetSdkEventQueueForTesting,
@@ -295616,6 +295967,8 @@ __export(exports_teammateMailbox, {
295616
295967
  PlanApprovalResponseMessageSchema: () => PlanApprovalResponseMessageSchema2,
295617
295968
  ShutdownApprovedMessageSchema: () => ShutdownApprovedMessageSchema2,
295618
295969
  ShutdownRejectedMessageSchema: () => ShutdownRejectedMessageSchema2,
295970
+ ShutdownRequestDeniedMessageSchema: () => ShutdownRequestDeniedMessageSchema2,
295971
+ ShutdownRequestFromMemberMessageSchema: () => ShutdownRequestFromMemberMessageSchema2,
295619
295972
  ShutdownRequestMessageSchema: () => ShutdownRequestMessageSchema2,
295620
295973
  clearMailbox: () => clearMailbox2,
295621
295974
  createIdleNotification: () => createIdleNotification2,
@@ -295641,6 +295994,8 @@ __export(exports_teammateMailbox, {
295641
295994
  isShutdownApproved: () => isShutdownApproved2,
295642
295995
  isShutdownRejected: () => isShutdownRejected2,
295643
295996
  isShutdownRequest: () => isShutdownRequest2,
295997
+ isShutdownRequestDenied: () => isShutdownRequestDenied2,
295998
+ isShutdownRequestFromMember: () => isShutdownRequestFromMember2,
295644
295999
  isStructuredProtocolMessage: () => isStructuredProtocolMessage2,
295645
296000
  isTaskAssignment: () => isTaskAssignment2,
295646
296001
  isTeamPermissionUpdate: () => isTeamPermissionUpdate2,
@@ -296000,6 +296355,22 @@ function isShutdownRequest2(messageText) {
296000
296355
  } catch {}
296001
296356
  return null;
296002
296357
  }
296358
+ function isShutdownRequestFromMember2(messageText) {
296359
+ try {
296360
+ const result = ShutdownRequestFromMemberMessageSchema2().safeParse(jsonParse2(messageText));
296361
+ if (result.success)
296362
+ return result.data;
296363
+ } catch {}
296364
+ return null;
296365
+ }
296366
+ function isShutdownRequestDenied2(messageText) {
296367
+ try {
296368
+ const result = ShutdownRequestDeniedMessageSchema2().safeParse(jsonParse2(messageText));
296369
+ if (result.success)
296370
+ return result.data;
296371
+ } catch {}
296372
+ return null;
296373
+ }
296003
296374
  function isPlanApprovalRequest2(messageText) {
296004
296375
  try {
296005
296376
  const result = PlanApprovalRequestMessageSchema2().safeParse(jsonParse2(messageText));
@@ -296073,7 +296444,7 @@ function isStructuredProtocolMessage2(messageText) {
296073
296444
  return false;
296074
296445
  }
296075
296446
  const type = parsed.type;
296076
- return type === "permission_request" || type === "permission_response" || type === "sandbox_permission_request" || type === "sandbox_permission_response" || type === "shutdown_request" || type === "shutdown_approved" || type === "team_permission_update" || type === "mode_set_request" || type === "plan_approval_request" || type === "plan_approval_response";
296447
+ return type === "permission_request" || type === "permission_response" || type === "sandbox_permission_request" || type === "sandbox_permission_response" || type === "shutdown_request" || type === "shutdown_approved" || type === "shutdown_request_from_member" || type === "shutdown_request_denied" || type === "team_permission_update" || type === "mode_set_request" || type === "plan_approval_request" || type === "plan_approval_response";
296077
296448
  } catch {
296078
296449
  return false;
296079
296450
  }
@@ -296127,7 +296498,7 @@ function getLastPeerDmSummary2(messages) {
296127
296498
  }
296128
296499
  return;
296129
296500
  }
296130
- var LOCK_OPTIONS4, PlanApprovalRequestMessageSchema2, PlanApprovalResponseMessageSchema2, ShutdownRequestMessageSchema2, ShutdownApprovedMessageSchema2, ShutdownRejectedMessageSchema2, ModeSetRequestMessageSchema2;
296501
+ var LOCK_OPTIONS4, PlanApprovalRequestMessageSchema2, PlanApprovalResponseMessageSchema2, ShutdownRequestMessageSchema2, ShutdownRequestFromMemberMessageSchema2, ShutdownRequestDeniedMessageSchema2, ShutdownApprovedMessageSchema2, ShutdownRejectedMessageSchema2, ModeSetRequestMessageSchema2;
296131
296502
  var init_teammateMailbox = __esm(() => {
296132
296503
  init_v4();
296133
296504
  init_xml();
@@ -296169,6 +296540,20 @@ var init_teammateMailbox = __esm(() => {
296169
296540
  reason: string2().optional(),
296170
296541
  timestamp: string2()
296171
296542
  }));
296543
+ ShutdownRequestFromMemberMessageSchema2 = lazySchema2(() => object({
296544
+ type: literal("shutdown_request_from_member"),
296545
+ requestId: string2(),
296546
+ from: string2(),
296547
+ reason: string2().optional(),
296548
+ timestamp: string2()
296549
+ }));
296550
+ ShutdownRequestDeniedMessageSchema2 = lazySchema2(() => object({
296551
+ type: literal("shutdown_request_denied"),
296552
+ requestId: string2(),
296553
+ to: string2(),
296554
+ reason: string2().optional(),
296555
+ timestamp: string2()
296556
+ }));
296172
296557
  ShutdownApprovedMessageSchema2 = lazySchema2(() => object({
296173
296558
  type: literal("shutdown_approved"),
296174
296559
  requestId: string2(),
@@ -477047,6 +477432,7 @@ function useInboxPoller({
477047
477432
  const sandboxPermissionRequests = [];
477048
477433
  const sandboxPermissionResponses = [];
477049
477434
  const shutdownRequests = [];
477435
+ const shutdownRequestDenials = [];
477050
477436
  const shutdownApprovals = [];
477051
477437
  const teamPermissionUpdates = [];
477052
477438
  const modeSetRequests = [];
@@ -477058,6 +477444,7 @@ function useInboxPoller({
477058
477444
  const sandboxReq = isSandboxPermissionRequest2(m.text);
477059
477445
  const sandboxResp = isSandboxPermissionResponse2(m.text);
477060
477446
  const shutdownReq = isShutdownRequest2(m.text);
477447
+ const shutdownDenial = isShutdownRequestDenied2(m.text);
477061
477448
  const shutdownApproval = isShutdownApproved2(m.text);
477062
477449
  const teamPermUpdate = isTeamPermissionUpdate2(m.text);
477063
477450
  const modeSetReq = isModeSetRequest2(m.text);
@@ -477072,6 +477459,8 @@ function useInboxPoller({
477072
477459
  sandboxPermissionResponses.push(m);
477073
477460
  } else if (shutdownReq) {
477074
477461
  shutdownRequests.push(m);
477462
+ } else if (shutdownDenial) {
477463
+ shutdownRequestDenials.push(m);
477075
477464
  } else if (shutdownApproval) {
477076
477465
  shutdownApprovals.push(m);
477077
477466
  } else if (teamPermUpdate) {
@@ -477337,6 +477726,12 @@ function useInboxPoller({
477337
477726
  regularMessages.push(m);
477338
477727
  }
477339
477728
  }
477729
+ if (shutdownRequestDenials.length > 0 && isTeammate()) {
477730
+ logForDebugging3(`[InboxPoller] Found ${shutdownRequestDenials.length} shutdown request denial(s)`);
477731
+ for (const m of shutdownRequestDenials) {
477732
+ regularMessages.push(m);
477733
+ }
477734
+ }
477340
477735
  if (shutdownApprovals.length > 0 && isTeamLead(currentAppState.teamContext)) {
477341
477736
  logForDebugging3(`[InboxPoller] Found ${shutdownApprovals.length} shutdown approval(s)`);
477342
477737
  for (const m of shutdownApprovals) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@atlasharness/atlascode",
3
- "version": "0.1.95",
4
- "description": "AtlasCode \u2014 Coding Agent for the domestic computing ecosystem (Ascend NPU + domestic LLM backends)",
3
+ "version": "0.1.96",
4
+ "description": "AtlasCode — Coding Agent for the domestic computing ecosystem (Ascend NPU + domestic LLM backends)",
5
5
  "homepage": "https://www.atlaswork.cn/",
6
6
  "bin": {
7
7
  "atlas": "dist/cli.js",