cli-jaw 2.17.43 → 2.17.44

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 (223) hide show
  1. package/README.md +13 -2
  2. package/dist/bin/commands/slack.js +73 -7
  3. package/dist/bin/commands/slack.js.map +1 -1
  4. package/dist/server.js +46 -1
  5. package/dist/server.js.map +1 -1
  6. package/dist/src/agent/calendar-context.js +23 -0
  7. package/dist/src/agent/calendar-context.js.map +1 -0
  8. package/dist/src/agent/claude-runtime-run.js +10 -1
  9. package/dist/src/agent/claude-runtime-run.js.map +1 -1
  10. package/dist/src/agent/cursor-acp-models.js +139 -0
  11. package/dist/src/agent/cursor-acp-models.js.map +1 -0
  12. package/dist/src/agent/events/cursor.js +28 -4
  13. package/dist/src/agent/events/cursor.js.map +1 -1
  14. package/dist/src/agent/lifecycle-handler.js +8 -2
  15. package/dist/src/agent/lifecycle-handler.js.map +1 -1
  16. package/dist/src/agent/native-runtime-run.js +22 -1
  17. package/dist/src/agent/native-runtime-run.js.map +1 -1
  18. package/dist/src/agent/runtime/acp/config.js +76 -11
  19. package/dist/src/agent/runtime/acp/config.js.map +1 -1
  20. package/dist/src/agent/runtime/acp/cursor-session.js +6 -1
  21. package/dist/src/agent/runtime/acp/cursor-session.js.map +1 -1
  22. package/dist/src/agent/runtime/liveness.js +24 -0
  23. package/dist/src/agent/runtime/liveness.js.map +1 -0
  24. package/dist/src/agent/runtime/start-failure.js +61 -0
  25. package/dist/src/agent/runtime/start-failure.js.map +1 -0
  26. package/dist/src/agent/spawn/queue.js +11 -6
  27. package/dist/src/agent/spawn/queue.js.map +1 -1
  28. package/dist/src/agent/spawn.js +59 -17
  29. package/dist/src/agent/spawn.js.map +1 -1
  30. package/dist/src/cli/api-auth.js +6 -0
  31. package/dist/src/cli/api-auth.js.map +1 -1
  32. package/dist/src/manager/design/watcher.js +10 -2
  33. package/dist/src/manager/design/watcher.js.map +1 -1
  34. package/dist/src/memory/heartbeat.js +6 -0
  35. package/dist/src/memory/heartbeat.js.map +1 -1
  36. package/dist/src/messaging/channel-validate.js +5 -3
  37. package/dist/src/messaging/channel-validate.js.map +1 -1
  38. package/dist/src/messaging/redact.js +30 -8
  39. package/dist/src/messaging/redact.js.map +1 -1
  40. package/dist/src/messaging/send.js +7 -0
  41. package/dist/src/messaging/send.js.map +1 -1
  42. package/dist/src/orchestrator/collect.js +5 -3
  43. package/dist/src/orchestrator/collect.js.map +1 -1
  44. package/dist/src/orchestrator/gateway.js +10 -3
  45. package/dist/src/orchestrator/gateway.js.map +1 -1
  46. package/dist/src/orchestrator/pipeline.js +21 -9
  47. package/dist/src/orchestrator/pipeline.js.map +1 -1
  48. package/dist/src/orchestrator/request-registry.js +2 -0
  49. package/dist/src/orchestrator/request-registry.js.map +1 -1
  50. package/dist/src/prompt/builder.js +74 -6
  51. package/dist/src/prompt/builder.js.map +1 -1
  52. package/dist/src/prompt/templates/a1-system.md +22 -5
  53. package/dist/src/routes/messaging.js +105 -27
  54. package/dist/src/routes/messaging.js.map +1 -1
  55. package/dist/src/routes/settings.js +20 -8
  56. package/dist/src/routes/settings.js.map +1 -1
  57. package/dist/src/routes/slack-tools.js +176 -0
  58. package/dist/src/routes/slack-tools.js.map +1 -0
  59. package/dist/src/slack/action-rate.js +43 -0
  60. package/dist/src/slack/action-rate.js.map +1 -0
  61. package/dist/src/slack/action-runtime.js +243 -0
  62. package/dist/src/slack/action-runtime.js.map +1 -0
  63. package/dist/src/slack/action-store.js +84 -0
  64. package/dist/src/slack/action-store.js.map +1 -0
  65. package/dist/src/slack/action-types.js +6 -0
  66. package/dist/src/slack/action-types.js.map +1 -0
  67. package/dist/src/slack/actions-canvas.js +108 -0
  68. package/dist/src/slack/actions-canvas.js.map +1 -0
  69. package/dist/src/slack/actions-channel.js +88 -0
  70. package/dist/src/slack/actions-channel.js.map +1 -0
  71. package/dist/src/slack/actions-interactions.js +204 -0
  72. package/dist/src/slack/actions-interactions.js.map +1 -0
  73. package/dist/src/slack/actions-lists.js +308 -0
  74. package/dist/src/slack/actions-lists.js.map +1 -0
  75. package/dist/src/slack/actions-message.js +117 -0
  76. package/dist/src/slack/actions-message.js.map +1 -0
  77. package/dist/src/slack/actions-resources.js +62 -0
  78. package/dist/src/slack/actions-resources.js.map +1 -0
  79. package/dist/src/slack/actions-rts.js +88 -0
  80. package/dist/src/slack/actions-rts.js.map +1 -0
  81. package/dist/src/slack/actions-schedule.js +214 -0
  82. package/dist/src/slack/actions-schedule.js.map +1 -0
  83. package/dist/src/slack/actions.js +17 -0
  84. package/dist/src/slack/actions.js.map +1 -0
  85. package/dist/src/slack/api.js +56 -9
  86. package/dist/src/slack/api.js.map +1 -1
  87. package/dist/src/slack/blocks.js +162 -0
  88. package/dist/src/slack/blocks.js.map +1 -0
  89. package/dist/src/slack/bot.js +562 -378
  90. package/dist/src/slack/bot.js.map +1 -1
  91. package/dist/src/slack/commands.js +24 -5
  92. package/dist/src/slack/commands.js.map +1 -1
  93. package/dist/src/slack/context.js +15 -4
  94. package/dist/src/slack/context.js.map +1 -1
  95. package/dist/src/slack/conversation.js +135 -33
  96. package/dist/src/slack/conversation.js.map +1 -1
  97. package/dist/src/slack/events.js +41 -17
  98. package/dist/src/slack/events.js.map +1 -1
  99. package/dist/src/slack/format.js +181 -0
  100. package/dist/src/slack/format.js.map +1 -1
  101. package/dist/src/slack/history.js +133 -8
  102. package/dist/src/slack/history.js.map +1 -1
  103. package/dist/src/slack/ingress.js +26 -9
  104. package/dist/src/slack/ingress.js.map +1 -1
  105. package/dist/src/slack/interaction-store.js +56 -0
  106. package/dist/src/slack/interaction-store.js.map +1 -0
  107. package/dist/src/slack/manifest.js +3 -0
  108. package/dist/src/slack/manifest.js.map +1 -1
  109. package/dist/src/slack/message-content.js +132 -0
  110. package/dist/src/slack/message-content.js.map +1 -0
  111. package/dist/src/slack/message.js +58 -0
  112. package/dist/src/slack/message.js.map +1 -0
  113. package/dist/src/slack/notice-transport.js +49 -19
  114. package/dist/src/slack/notice-transport.js.map +1 -1
  115. package/dist/src/slack/operator-auth.js +62 -0
  116. package/dist/src/slack/operator-auth.js.map +1 -0
  117. package/dist/src/slack/progress-activity.js +210 -0
  118. package/dist/src/slack/progress-activity.js.map +1 -0
  119. package/dist/src/slack/progress-detail.js +473 -0
  120. package/dist/src/slack/progress-detail.js.map +1 -0
  121. package/dist/src/slack/progress-files.js +70 -0
  122. package/dist/src/slack/progress-files.js.map +1 -0
  123. package/dist/src/slack/progress-lifecycle.js +223 -0
  124. package/dist/src/slack/progress-lifecycle.js.map +1 -0
  125. package/dist/src/slack/progress-restore.js +81 -0
  126. package/dist/src/slack/progress-restore.js.map +1 -0
  127. package/dist/src/slack/progress.js +325 -143
  128. package/dist/src/slack/progress.js.map +1 -1
  129. package/dist/src/slack/quote.js +227 -0
  130. package/dist/src/slack/quote.js.map +1 -0
  131. package/dist/src/slack/render-features.js +105 -0
  132. package/dist/src/slack/render-features.js.map +1 -0
  133. package/dist/src/slack/reply-delivery.js +110 -0
  134. package/dist/src/slack/reply-delivery.js.map +1 -0
  135. package/dist/src/slack/rts-output-store.js +143 -0
  136. package/dist/src/slack/rts-output-store.js.map +1 -0
  137. package/dist/src/slack/scope-status.js +17 -3
  138. package/dist/src/slack/scope-status.js.map +1 -1
  139. package/dist/src/slack/search-quote.js +70 -0
  140. package/dist/src/slack/search-quote.js.map +1 -0
  141. package/dist/src/slack/search.js +54 -0
  142. package/dist/src/slack/search.js.map +1 -0
  143. package/dist/src/slack/send-handler.js +11 -7
  144. package/dist/src/slack/send-handler.js.map +1 -1
  145. package/dist/src/slack/send-only-client.js +116 -79
  146. package/dist/src/slack/send-only-client.js.map +1 -1
  147. package/dist/src/slack/table-content.js +253 -0
  148. package/dist/src/slack/table-content.js.map +1 -0
  149. package/dist/src/slack/table-verification.js +64 -0
  150. package/dist/src/slack/table-verification.js.map +1 -0
  151. package/dist/src/slack/task-input.js +55 -0
  152. package/dist/src/slack/task-input.js.map +1 -0
  153. package/dist/src/slack/tool-access.js +127 -0
  154. package/dist/src/slack/tool-access.js.map +1 -0
  155. package/dist/src/slack/tool-capabilities.js +47 -0
  156. package/dist/src/slack/tool-capabilities.js.map +1 -0
  157. package/dist/src/slack/tool-context.js +91 -0
  158. package/dist/src/slack/tool-context.js.map +1 -0
  159. package/dist/src/slack/verified-workspace.js +17 -6
  160. package/dist/src/slack/verified-workspace.js.map +1 -1
  161. package/dist/src/trace/redact.js +2 -1
  162. package/dist/src/trace/redact.js.map +1 -1
  163. package/package.json +1 -1
  164. package/public/dist/.vite/manifest.json +102 -102
  165. package/public/dist/assets/{Agent-CQ4EBgY8.js → Agent-CNad_A6t.js} +1 -1
  166. package/public/dist/assets/{ChannelEnablementControl-JsYvNMlM.js → ChannelEnablementControl-DwUDKjX9.js} +4 -4
  167. package/public/dist/assets/{ChannelSetupEntry-BpyRWEUE.js → ChannelSetupEntry-DH0AuNNX.js} +1 -1
  168. package/public/dist/assets/{ChannelsDiscord-DNfvz1jn.js → ChannelsDiscord-7NmoTjR7.js} +1 -1
  169. package/public/dist/assets/{ChannelsSlack-DzpxIdgW.js → ChannelsSlack-Ba0ax6iT.js} +1 -1
  170. package/public/dist/assets/{ChannelsTelegram-CUhFc5s6.js → ChannelsTelegram-DKA9atf2.js} +1 -1
  171. package/public/dist/assets/{app-Q0prKOFx.js → app-9OQNfmqw.js} +4 -4
  172. package/public/dist/assets/{bgtask-badge-DAcWaUfS.js → bgtask-badge-BvxHqMGi.js} +1 -1
  173. package/public/dist/assets/bgtask-badge-DeSZJGNN.js +1 -0
  174. package/public/dist/assets/{employees-CWS3Juca.js → employees-CkUqN4oh.js} +1 -1
  175. package/public/dist/assets/{iframe-renderer-DCDKBMb7.js → iframe-renderer-C2gchtOj.js} +2 -2
  176. package/public/dist/assets/iframe-renderer-DfvACXIn.js +1 -0
  177. package/public/dist/assets/{manager-v6GYfoPB.js → manager-rb5X-4DJ.js} +1 -1
  178. package/public/dist/assets/{memory-DhNdKZLO.js → memory-BiWzpoBq.js} +1 -1
  179. package/public/dist/assets/memory-Ckp1Eq5a.js +1 -0
  180. package/public/dist/assets/message-history-Bv0l_t7O.js +1 -0
  181. package/public/dist/assets/{message-history-DbRTl1P0.js → message-history-CuFefS02.js} +1 -1
  182. package/public/dist/assets/{render-DP8SJtdZ.js → render-DUGqq9Mu.js} +1 -1
  183. package/public/dist/assets/{settings-85n9NjvX.js → settings-BqUHavbH.js} +1 -1
  184. package/public/dist/assets/settings-C81Kf9uX.js +1 -0
  185. package/public/dist/assets/{settings-C9_D-pn0.js → settings-DQ1fLygB.js} +31 -30
  186. package/public/dist/assets/{settings-core-BcVD2FgV.js → settings-core-CzdXfoOK.js} +1 -1
  187. package/public/dist/assets/settings-core-DO_5M7Lv.js +1 -0
  188. package/public/dist/assets/{settings-embedding-BSpq785l.js → settings-embedding-BAKFrVLV.js} +1 -1
  189. package/public/dist/assets/{settings-types-B09BmpYe.js → settings-types-D3cd6SWy.js} +1 -1
  190. package/public/dist/assets/{sidebar-BVhLb5Ft.js → sidebar-CvGbp9x5.js} +3 -3
  191. package/public/dist/assets/skills-DFpPmMUR.js +1 -0
  192. package/public/dist/assets/{skills-X7qxmHka.js → skills-abLMqY5_.js} +1 -1
  193. package/public/dist/assets/slash-commands-BU58xYih.js +1 -0
  194. package/public/dist/assets/{slash-commands-BnDH4IU_.js → slash-commands-D8o9pqOS.js} +1 -1
  195. package/public/dist/assets/{trace-drawer-DasaS1z4.js → trace-drawer-C6RvkUAd.js} +1 -1
  196. package/public/dist/assets/{ui-BtiBTXng.js → ui-Bxapl_Eu.js} +1 -1
  197. package/public/dist/assets/ui-CUB4iwz3.js +1 -0
  198. package/public/dist/index.html +1 -1
  199. package/public/dist/manager/index.html +1 -1
  200. package/public/dist/settings/index.html +1 -1
  201. package/public/js/features/settings-cli-status.ts +11 -1
  202. package/public/js/features/settings-types.ts +21 -0
  203. package/public/locales/en.json +34 -1
  204. package/public/locales/ja.json +34 -1
  205. package/public/locales/ko.json +34 -1
  206. package/public/locales/zh.json +34 -1
  207. package/scripts/check-native-load.cjs +17 -4
  208. package/scripts/release-gates.mjs +84 -3
  209. package/scripts/service-artifact.mjs +157 -0
  210. package/scripts/service-shell/zsh/.zlogin +23 -0
  211. package/scripts/service-shell/zsh/.zlogout +23 -0
  212. package/scripts/service-shell/zsh/.zprofile +23 -0
  213. package/scripts/service-shell/zsh/.zshenv +23 -0
  214. package/scripts/service-shell/zsh/.zshrc +23 -0
  215. package/public/dist/assets/bgtask-badge-DHA2OQm8.js +0 -1
  216. package/public/dist/assets/iframe-renderer-RpvBly2x.js +0 -1
  217. package/public/dist/assets/memory-4YH8sz0L.js +0 -1
  218. package/public/dist/assets/message-history-lVcLpAw8.js +0 -1
  219. package/public/dist/assets/settings--EGy3_B9.js +0 -1
  220. package/public/dist/assets/settings-core-8wBl1mg-.js +0 -1
  221. package/public/dist/assets/skills-6GFkHTlQ.js +0 -1
  222. package/public/dist/assets/slash-commands-qu8fPAZ3.js +0 -1
  223. package/public/dist/assets/ui-BucJ1zMA.js +0 -1
@@ -1,3 +1,5 @@
1
+ import { calendarContext } from './calendar-context.js';
2
+ import { createSlackToolSecretStream, activateSlackToolGrant, revokeSlackToolGrant, revokeSlackToolScope, redactSlackToolSecrets, SLACK_TOOL_GRANT_ENV } from '../slack/tool-context.js';
1
3
  // ─── Agent Spawn + Kill/Steer/Queue ──────────────────
2
4
  import fs from 'fs';
3
5
  import os from 'os';
@@ -60,6 +62,7 @@ import { PiProjection } from './runtime/pi-projection.js';
60
62
  import { PiRawTrace } from './runtime/pi-raw-trace.js';
61
63
  import { createPrintActivity, finishPrintActivity } from './runtime/print-activity.js';
62
64
  import { isNativeAdapterImplemented, isNativeWorkerImplemented, isSwitchableNativeCli, resolveRuntimeTransport, runtimeSessionBucket } from './runtime/selection.js';
65
+ import { clearNativeStartFailure, nativeStartFailure, recordNativeStartFailure } from './runtime/start-failure.js';
63
66
  import { asCliEventRecord, discriminate, fieldString } from '../types/cli-events.js';
64
67
  import { isRemoteTarget } from '../messaging/types.js';
65
68
  import { buildRemoteBindingKey } from '../messaging/session-key.js';
@@ -470,6 +473,10 @@ function clearMainLiveRunOnStop(scopeKey, reason) {
470
473
  export function killActiveAgent(scopeKeyOrReason = 'user', scopedReason) {
471
474
  const scopeKey = scopedReason === undefined ? 'default' : scopeKeyOrReason;
472
475
  const reason = scopedReason ?? scopeKeyOrReason;
476
+ if (reason === 'user' || reason === 'api')
477
+ revokeSlackToolScope(scopeKey);
478
+ else
479
+ revokeSlackToolGrant(activeMainProcesses.get(scopeKey)?.meta?.requestId);
473
480
  cancelSteerInputs(scopeKey);
474
481
  const cancelledClaude = cancelClaudeScope(scopeKey, reason, reason === 'api' || reason === 'user');
475
482
  const run = activeMainProcesses.get(scopeKey);
@@ -734,6 +741,12 @@ export async function steerAgent(scopeKey, newPrompt, source, meta) {
734
741
  settleOnce(meta?.requestId, 'steered');
735
742
  return 'steered';
736
743
  }
744
+ // Capture the admitted Slack address before kill/wait can yield ownership.
745
+ const slackRestart = source === 'slack' && isRemoteTarget(meta?.target) && meta.target.channel === 'slack'
746
+ ? stripUndefined({ mode: 'restart', scope: scopeKey, sessionId: chatSessionId,
747
+ target: { ...meta.target }, chatId: meta.chatId, requestId: meta.requestId,
748
+ remoteKey: meta.remoteKey, replyViaTarget: true })
749
+ : undefined;
737
750
  const steerWaitMs = getSteerWaitMsForActiveAgent(scopeKey);
738
751
  // Snapshot BEFORE the kill: the interrupted partial-output row is identified
739
752
  // as the first ⏹️-tagged assistant message with id above this mark. A
@@ -769,19 +782,16 @@ export async function steerAgent(scopeKey, newPrompt, source, meta) {
769
782
  broadcast('new_message', { role: 'user', content: newPrompt, source, scope: scopeKey, sessionId: chatSessionId });
770
783
  broadcast('steer_started', stripUndefined({ prompt: newPrompt, origin: source || 'web', scope: scopeKey,
771
784
  sessionId: chatSessionId, target: meta?.target, chatId: meta?.chatId, requestId: meta?.requestId,
772
- remoteKey: meta?.remoteKey, replyViaTarget: meta?.replyViaTarget, mode: 'kill-steer' }));
785
+ remoteKey: meta?.remoteKey, replyViaTarget: meta?.replyViaTarget, mode: 'kill-steer', ...slackRestart }));
773
786
  const { orchestrate, orchestrateContinue, orchestrateReset, isContinueIntent, isResetIntent } = await import('../orchestrator/pipeline.js');
774
787
  const origin = source || 'web';
775
- // The follow-up run answers the SAME conversation the killed turn came from,
776
- // but nothing downstream can infer that: a remote caller's reply is addressed
777
- // by `target`, and dropping it here left the answer with nowhere to go. The
778
- // dispatch waiter is already gone (ingress returns early for a steered
779
- // submission), so an unaddressed terminal is silently discarded and the
780
- // channel just goes quiet after a steer.
788
+ // Union of both contracts: the #655 steer identity (target/chatId/remoteKey/
789
+ // replyViaTarget/_fromSteer) plus the #654 pre-kill capture (slackRestart),
790
+ // whose mode restart is what the reply-control observer treats as a start.
781
791
  const steerMeta = stripUndefined({ origin, scope: scopeKey, chatSessionId, requestId: meta?.requestId,
782
792
  target: meta?.target, chatId: meta?.chatId, remoteKey: meta?.remoteKey,
783
793
  replyViaTarget: meta?.replyViaTarget, _fromSteer: true,
784
- _skipInsert: true, _steerContext: steerContext || undefined });
794
+ ...slackRestart, _skipInsert: true, _steerContext: steerContext || undefined });
785
795
  const task = isResetIntent(newPrompt)
786
796
  ? orchestrateReset(steerMeta)
787
797
  : isContinueIntent(newPrompt)
@@ -791,8 +801,8 @@ export async function steerAgent(scopeKey, newPrompt, source, meta) {
791
801
  console.error('[steer:orchestrate]', err.message);
792
802
  broadcast('orchestrate_done', stripUndefined({ text: `[error] ${err.message}`, error: true, origin,
793
803
  target: meta?.target, chatId: meta?.chatId, replyViaTarget: meta?.replyViaTarget,
794
- fromSteer: true, requestId: meta?.requestId }));
795
- settleOnce(meta?.requestId, 'failed', { error: err.message });
804
+ fromSteer: true, requestId: meta?.requestId, ...slackRestart }));
805
+ settleOnce(slackRestart ? slackRestart.requestId : meta?.requestId, 'failed', { error: err.message });
796
806
  });
797
807
  // The follow-up was started as a new run (kill-path or idle race). The caller
798
808
  // must NOT also queue the message.
@@ -846,6 +856,9 @@ export function makeCleanEnv(extraEnv = {}, inheritedEnv = process.env, platform
846
856
  // Same platform passthrough as above. This is the call that produces the
847
857
  // RETURNED PATH, so a win32/POSIX disagreement here reaches the child.
848
858
  merged["PATH"] = buildServicePath(extraPath || env["PATH"] || '', [], os.homedir(), platform);
859
+ for (const key of Object.keys(merged))
860
+ if (key.toUpperCase() === SLACK_TOOL_GRANT_ENV)
861
+ delete merged[key];
849
862
  return merged;
850
863
  }
851
864
  function buildHistoryBlock(currentPrompt, workingDir, chatSessionId, maxSessions = PROMPT_HISTORY_MAX_ROWS, maxTotalChars = PROMPT_HISTORY_MAX_CHARS) {
@@ -1295,7 +1308,7 @@ export function spawnAgent(prompt, opts = {}) {
1295
1308
  ? '\n(need history? L1: cli-jaw chat/memory search/context | L2: cli-jaw dashboard memory search, cli-jaw dashboard chat search)'
1296
1309
  : '';
1297
1310
  const promptWithConversation = prependRemoteConversationContext(prompt, opts.target);
1298
- prompt = `${ts}\n${projLine}${promptWithConversation}${memoryNudge}`;
1311
+ prompt = `${ts}\n${calendarContext(_d)}\n${projLine}${promptWithConversation}${memoryNudge}`;
1299
1312
  }
1300
1313
  const resumeSessionId = empSid || (isResume ? bucketSessionId : null);
1301
1314
  const needsHistory = shouldBuildHistoryBlock({
@@ -1640,9 +1653,21 @@ export function spawnAgent(prompt, opts = {}) {
1640
1653
  text: outcome.finalText?.trim() ?? '', code: outcome.status === 'done' ? 0 : outcome.status === 'stopped' ? 130 : 1,
1641
1654
  runtimeOutcome: outcome, traceRunId,
1642
1655
  });
1643
- const diagnostic = () => grok ? 'Grok native runtime failed. Check the native model, effort and existing CLI login.' : facade?.lastError?.includes('config')
1644
- ? 'Cursor native model or effort is unsupported. Choose an advertised model/effort; Composer models may require an unset effort.'
1645
- : 'Cursor native runtime failed. Check the native model, effort and existing CLI login.';
1656
+ // A runtime that never acquired a lease has no facade to ask, so the
1657
+ // substring heuristic below could only ever produce the generic sentence
1658
+ // for exactly the failures that need naming. The recorded start code is
1659
+ // provider-independent by construction, so it decides the wording and is
1660
+ // shown alongside it (#658).
1661
+ const diagnostic = () => {
1662
+ const code = nativeStarted ? undefined : nativeStartFailure(cli)?.code;
1663
+ const named = code ? ` (${code})` : '';
1664
+ if (grok)
1665
+ return `Grok native runtime failed.${named} Check the native model, effort and existing CLI login.`;
1666
+ const configFault = code ? code.startsWith('acp_config_') : facade?.lastError?.includes('config');
1667
+ return configFault
1668
+ ? `Cursor native model or effort is unsupported.${named} Choose an advertised model/effort; Composer models may require an unset effort.`
1669
+ : `Cursor native runtime failed.${named} Check the native model, effort and existing CLI login.`;
1670
+ };
1646
1671
  const startFailedRuntime = () => {
1647
1672
  if (!failedStart) {
1648
1673
  failedStart = new RuntimeProjection(identity);
@@ -1752,6 +1777,8 @@ export function spawnAgent(prompt, opts = {}) {
1752
1777
  if (!ownsRun())
1753
1778
  throw new Error('native_run_owner_lost');
1754
1779
  capturedRun.process = lease.child;
1780
+ // This start reached its lease, so the previous start failure is spent.
1781
+ clearNativeStartFailure(cli);
1755
1782
  if (!opts._skipInsert)
1756
1783
  insertMessage.run('user', prompt, cli, runtimeModel, nativeCwd, chatSessionId);
1757
1784
  capturedRun.starting = false;
@@ -1858,7 +1885,14 @@ export function spawnAgent(prompt, opts = {}) {
1858
1885
  await lease.retire(new Error('native_runtime_finalization_failed'));
1859
1886
  return selectedResult ?? resultFor(ctx.runtimeOutcome ?? outcome);
1860
1887
  },
1861
- failed: (_error, _lease, outcome) => failRuntime(outcome),
1888
+ failed: (error, lease, outcome) => {
1889
+ // A null lease means acquire never returned: the runtime failed to
1890
+ // start, which is the only class this diagnostic answers (#658).
1891
+ // Teardown faults after a claimed answer are a different failure.
1892
+ if (!lease)
1893
+ recordNativeStartFailure(cli, error);
1894
+ return failRuntime(outcome);
1895
+ },
1862
1896
  finalized: () => {
1863
1897
  finalized = true;
1864
1898
  try {
@@ -3354,6 +3388,10 @@ export function spawnAgent(prompt, opts = {}) {
3354
3388
  }
3355
3389
  // The snapshot has to predate the child; the helper owns that ordering (073 §2.4).
3356
3390
  const kiroPlainText = isKiroPlainTextCli(cli, effectiveProvider);
3391
+ const slackToolGrant = !isEmployee && ['cursor', 'claude', 'codex', 'grok'].includes(cli)
3392
+ ? activateSlackToolGrant(opts.requestId, scopeKey, chatSessionId) : undefined;
3393
+ if (slackToolGrant)
3394
+ launchEnv[SLACK_TOOL_GRANT_ENV] = slackToolGrant;
3357
3395
  const { child, kiroConversationIdsBefore, kiroSpawnStartedAt } = spawnWithKiroSnapshot({
3358
3396
  kiroPlainText,
3359
3397
  isFreshMainRun: !isResume && !empSid,
@@ -3593,6 +3631,7 @@ export function spawnAgent(prompt, opts = {}) {
3593
3631
  ctx.opencodeLastEventAt = Date.now();
3594
3632
  };
3595
3633
  const dispatchNdjsonLine = (line) => {
3634
+ line = redactSlackToolSecrets(line);
3596
3635
  let raw;
3597
3636
  try {
3598
3637
  raw = JSON.parse(line);
@@ -3772,13 +3811,15 @@ export function spawnAgent(prompt, opts = {}) {
3772
3811
  dispatchNdjsonLine(line);
3773
3812
  }
3774
3813
  });
3814
+ const slackStderr = slackToolGrant ? createSlackToolSecretStream() : undefined;
3775
3815
  child.stderr.on('data', (chunk) => {
3776
3816
  opts.lifecycle?.onActivity?.('stderr');
3777
3817
  clearAgyQuietCompletionTimer();
3778
3818
  lastOpencodeIoAt = Date.now();
3779
3819
  // No per-chunk trim: trimming a chunk destroys legitimate leading/trailing
3780
3820
  // whitespace and line boundaries that only exist across chunks (#372).
3781
- const text = stderrReader.write(chunk);
3821
+ const decoded = stderrReader.write(chunk);
3822
+ const text = slackStderr ? slackStderr(decoded) : decoded;
3782
3823
  if (!text)
3783
3824
  return;
3784
3825
  if (cli === 'agy')
@@ -3815,7 +3856,8 @@ export function spawnAgent(prompt, opts = {}) {
3815
3856
  buffer += stdoutResidual;
3816
3857
  }
3817
3858
  }
3818
- const stderrResidual = stderrReader.end();
3859
+ const stderrEnd = stderrReader.end();
3860
+ const stderrResidual = slackStderr ? slackStderr(stderrEnd, true) : stderrEnd;
3819
3861
  if (stderrResidual && ctx.stderrBuf.length < STDERR_BUF_CAP) {
3820
3862
  ctx.stderrBuf = sliceWithoutSplittingSurrogate(ctx.stderrBuf + stderrResidual, STDERR_BUF_CAP);
3821
3863
  }