@geminixiang/mikan 1.5.0-beta.0 → 1.5.1

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 (51) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/dist/adapters/messages.d.ts +1 -3
  3. package/dist/adapters/messages.d.ts.map +1 -1
  4. package/dist/adapters/messages.js +2 -8
  5. package/dist/adapters/messages.js.map +1 -1
  6. package/dist/adapters/slack/app-config.js +1 -1
  7. package/dist/adapters/slack/app-config.js.map +1 -1
  8. package/dist/adapters/slack/bot.d.ts +2 -5
  9. package/dist/adapters/slack/bot.d.ts.map +1 -1
  10. package/dist/adapters/slack/bot.js +39 -212
  11. package/dist/adapters/slack/bot.js.map +1 -1
  12. package/dist/adapters/slack/types.d.ts +0 -1
  13. package/dist/adapters/slack/types.d.ts.map +1 -1
  14. package/dist/adapters/slack/types.js.map +1 -1
  15. package/dist/harness/continued-run.d.ts +3 -0
  16. package/dist/harness/continued-run.d.ts.map +1 -0
  17. package/dist/harness/continued-run.js +8 -0
  18. package/dist/harness/continued-run.js.map +1 -0
  19. package/dist/harness/prompt.d.ts.map +1 -1
  20. package/dist/harness/prompt.js +1 -0
  21. package/dist/harness/prompt.js.map +1 -1
  22. package/dist/harness/runner.d.ts.map +1 -1
  23. package/dist/harness/runner.js +14 -7
  24. package/dist/harness/runner.js.map +1 -1
  25. package/dist/harness/session.d.ts +3 -0
  26. package/dist/harness/session.d.ts.map +1 -1
  27. package/dist/harness/session.js +14 -1
  28. package/dist/harness/session.js.map +1 -1
  29. package/dist/harness/tools/codemode.js +1 -1
  30. package/dist/harness/tools/codemode.js.map +1 -1
  31. package/dist/harness/tools/jev-browser.d.ts.map +1 -1
  32. package/dist/harness/tools/jev-browser.js +31 -6
  33. package/dist/harness/tools/jev-browser.js.map +1 -1
  34. package/dist/harness/tools/task.d.ts +0 -2
  35. package/dist/harness/tools/task.d.ts.map +1 -1
  36. package/dist/harness/tools/task.js +1 -6
  37. package/dist/harness/tools/task.js.map +1 -1
  38. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  39. package/dist/runtime/conversation-runtime.js +6 -3
  40. package/dist/runtime/conversation-runtime.js.map +1 -1
  41. package/dist/sessions/session-store.d.ts +4 -3
  42. package/dist/sessions/session-store.d.ts.map +1 -1
  43. package/dist/sessions/session-store.js +92 -47
  44. package/dist/sessions/session-store.js.map +1 -1
  45. package/dist/sessions/types.d.ts +0 -1
  46. package/dist/sessions/types.d.ts.map +1 -1
  47. package/dist/sessions/types.js.map +1 -1
  48. package/dist/types.d.ts +1 -0
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/types.js.map +1 -1
  51. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -11,7 +11,30 @@ change in a minor release.
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
- ## [1.5.0-beta.0]
14
+ ## [1.5.1] - 2026-10-14
15
+
16
+ ### Changed
17
+
18
+ - A Slack reply or task that a restart interrupts now continues after the restart instead of
19
+ stopping with its progress message stuck: mikan posts "Restarted for an update; continuing." and
20
+ pi-durable continues the same turn, telling the model which step was interrupted. A deploy no
21
+ longer waits up to five minutes for Slack runs to finish. Tasks continue the same way, without the
22
+ earlier limit of two automatic resumes. Other platforms keep the five-minute drain.
23
+ - A codemode script has no deadline unless it sets `timeout_ms`, as in Pi. Before, mikan stopped
24
+ every script after 60 seconds, which cut off scripts that call slow tools such as
25
+ `jev_browser`'s goal loop. A stuck script now runs until the conversation is stopped, or until
26
+ the run's budget ends it where one is set, as for scheduled events.
27
+ - `jev_browser` with only `url` opens the page and returns its final URL and title, for example to
28
+ show it on the office desktop. Before, it refused the call, and models made up a goal that ran the
29
+ slower goal loop.
30
+
31
+ ### Fixed
32
+
33
+ - `jev_browser` no longer refuses a call because the model filled `handOff` with an empty string,
34
+ as models that fill every optional field do; an empty `handOff` and `frame: "main"` count as not
35
+ given.
36
+
37
+ ## [1.5.0] - 2026-10-13
15
38
 
16
39
  ### Added
17
40
 
@@ -40,6 +63,13 @@ change in a minor release.
40
63
  now fails to start; this release works with it. A nonzero `bash` exit is now an error result that
41
64
  carries the output and the exit code, instead of a thrown error.
42
65
 
66
+ ### Removed
67
+
68
+ - The Slack App Home tab, which listed running tasks and scheduled jobs with force-stop buttons.
69
+ mikan's Slack manifest turns the tab off; an app synced from a configuration token loses it on
70
+ the next start, and an app configured by hand keeps showing an empty tab until it is turned off in
71
+ Slack's App Home settings. Use the stop command or the Admin portal to stop work.
72
+
43
73
  ## [1.4.0] - 2026-10-11
44
74
 
45
75
  ### Added
@@ -5,11 +5,9 @@ export declare function formatNothingRunning(source: PlatformSource): string;
5
5
  export declare function formatStopping(source: PlatformSource): string;
6
6
  export declare function formatStopped(source: PlatformSource): string;
7
7
  export declare function formatRestarting(source: PlatformSource): string;
8
- export declare function formatResumingTask(source: PlatformSource): string;
9
- export declare function formatTaskResumesExhausted(source: PlatformSource): string;
8
+ export declare function formatContinuingRun(source: PlatformSource): string;
10
9
  export declare function formatAlreadyWorking(source: PlatformSource, stopCommand: string, options?: {
11
10
  scope?: "thread";
12
11
  }): string;
13
- export declare function formatForceStopped(source: PlatformSource, actorLabel: string): string;
14
12
  export {};
15
13
  //# sourceMappingURL=messages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/adapters/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/D,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,KAAK,cAAc,GAAG,YAAY,GAAG,aAAa,GAAG,MAAM,CAAC;AAoB5D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAEnE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE7D;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE5D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAK/D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAKjE;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAKzE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,QAAQ,CAAA;CAAE,GAC7B,MAAM,CAMR;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAErF"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/adapters/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/D,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,KAAK,cAAc,GAAG,YAAY,GAAG,aAAa,GAAG,MAAM,CAAC;AAoB5D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAEnE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE7D;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE5D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAK/D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAElE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,QAAQ,CAAA;CAAE,GAC7B,MAAM,CAMR"}
@@ -27,11 +27,8 @@ export function formatStopped(source) {
27
27
  export function formatRestarting(source) {
28
28
  return formatItalic(resolvePlatformName(source), "Restarting for an update; this reply was interrupted. Please send your message again.");
29
29
  }
30
- export function formatResumingTask(source) {
31
- return formatItalic(resolvePlatformName(source), "Restarted for an update; continuing this task.");
32
- }
33
- export function formatTaskResumesExhausted(source) {
34
- return formatItalic(resolvePlatformName(source), "Interrupted again after two automatic restarts; not continuing this task. Ask me to continue when you are ready.");
30
+ export function formatContinuingRun(source) {
31
+ return formatItalic(resolvePlatformName(source), "Restarted for an update; continuing.");
35
32
  }
36
33
  export function formatAlreadyWorking(source, stopCommand, options) {
37
34
  const platformName = resolvePlatformName(source);
@@ -39,7 +36,4 @@ export function formatAlreadyWorking(source, stopCommand, options) {
39
36
  const prefix = options?.scope === "thread" ? "Already working in this thread." : "Already working.";
40
37
  return formatItalic(platformName, `${prefix} Send ${command} to cancel.`);
41
38
  }
42
- export function formatForceStopped(source, actorLabel) {
43
- return formatItalic(resolvePlatformName(source), `Force stopped by ${actorLabel}.`);
44
- }
45
39
  //# sourceMappingURL=messages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/adapters/messages.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAIpC,SAAS,mBAAmB,CAAC,MAAsB;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC9C,IAAI,kBAAkB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC;IACxE,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,SAAS,sBAAsB,CAAC,YAAoB;IAClD,OAAO,YAAY,KAAK,UAAU,CAAC;AACrC,CAAC;AAED,SAAS,YAAY,CAAC,YAAoB,EAAE,IAAY;IACtD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;AACnE,CAAC;AAED,SAAS,UAAU,CAAC,YAAoB,EAAE,IAAY;IACpD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAsB;IACzD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAsB;IAClD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAsB;IACrD,OAAO,YAAY,CACjB,mBAAmB,CAAC,MAAM,CAAC,EAC3B,uFAAuF,CACxF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAsB;IACvD,OAAO,YAAY,CACjB,mBAAmB,CAAC,MAAM,CAAC,EAC3B,gDAAgD,CACjD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,MAAsB;IAC/D,OAAO,YAAY,CACjB,mBAAmB,CAAC,MAAM,CAAC,EAC3B,kHAAkH,CACnH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAAsB,EACtB,WAAmB,EACnB,OAA8B;IAE9B,MAAM,YAAY,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,MAAM,GACV,OAAO,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,kBAAkB,CAAC;IACvF,OAAO,YAAY,CAAC,YAAY,EAAE,GAAG,MAAM,SAAS,OAAO,aAAa,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAsB,EAAE,UAAkB;IAC3E,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,oBAAoB,UAAU,GAAG,CAAC,CAAC;AACtF,CAAC","sourcesContent":["import type { MessagingBot, MessagingInfo } from \"../types.js\";\n\nexport const PRODUCT_NAME = \"mikan\";\n\ntype PlatformSource = MessagingBot | MessagingInfo | string;\n\nfunction resolvePlatformName(source: PlatformSource): string {\n if (typeof source === \"string\") return source;\n if (\"getMessagingInfo\" in source) return source.getMessagingInfo().name;\n return source.name;\n}\n\nfunction supportsHtmlFormatting(platformName: string): boolean {\n return platformName === \"telegram\";\n}\n\nfunction formatItalic(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? text : `_${text}_`;\n}\n\nfunction formatCode(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? `<code>${text}</code>` : `\\`${text}\\``;\n}\n\nexport function formatNothingRunning(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Nothing running.\");\n}\n\nexport function formatStopping(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopping…\");\n}\n\nexport function formatStopped(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopped.\");\n}\n\nexport function formatRestarting(source: PlatformSource): string {\n return formatItalic(\n resolvePlatformName(source),\n \"Restarting for an update; this reply was interrupted. Please send your message again.\",\n );\n}\n\nexport function formatResumingTask(source: PlatformSource): string {\n return formatItalic(\n resolvePlatformName(source),\n \"Restarted for an update; continuing this task.\",\n );\n}\n\nexport function formatTaskResumesExhausted(source: PlatformSource): string {\n return formatItalic(\n resolvePlatformName(source),\n \"Interrupted again after two automatic restarts; not continuing this task. Ask me to continue when you are ready.\",\n );\n}\n\nexport function formatAlreadyWorking(\n source: PlatformSource,\n stopCommand: string,\n options?: { scope?: \"thread\" },\n): string {\n const platformName = resolvePlatformName(source);\n const command = formatCode(platformName, stopCommand);\n const prefix =\n options?.scope === \"thread\" ? \"Already working in this thread.\" : \"Already working.\";\n return formatItalic(platformName, `${prefix} Send ${command} to cancel.`);\n}\n\nexport function formatForceStopped(source: PlatformSource, actorLabel: string): string {\n return formatItalic(resolvePlatformName(source), `Force stopped by ${actorLabel}.`);\n}\n"]}
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/adapters/messages.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAIpC,SAAS,mBAAmB,CAAC,MAAsB;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC9C,IAAI,kBAAkB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC;IACxE,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,SAAS,sBAAsB,CAAC,YAAoB;IAClD,OAAO,YAAY,KAAK,UAAU,CAAC;AACrC,CAAC;AAED,SAAS,YAAY,CAAC,YAAoB,EAAE,IAAY;IACtD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;AACnE,CAAC;AAED,SAAS,UAAU,CAAC,YAAoB,EAAE,IAAY;IACpD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAsB;IACzD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAsB;IAClD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAsB;IACrD,OAAO,YAAY,CACjB,mBAAmB,CAAC,MAAM,CAAC,EAC3B,uFAAuF,CACxF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAsB;IACxD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,sCAAsC,CAAC,CAAC;AAC3F,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAAsB,EACtB,WAAmB,EACnB,OAA8B;IAE9B,MAAM,YAAY,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,MAAM,GACV,OAAO,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,kBAAkB,CAAC;IACvF,OAAO,YAAY,CAAC,YAAY,EAAE,GAAG,MAAM,SAAS,OAAO,aAAa,CAAC,CAAC;AAC5E,CAAC","sourcesContent":["import type { MessagingBot, MessagingInfo } from \"../types.js\";\n\nexport const PRODUCT_NAME = \"mikan\";\n\ntype PlatformSource = MessagingBot | MessagingInfo | string;\n\nfunction resolvePlatformName(source: PlatformSource): string {\n if (typeof source === \"string\") return source;\n if (\"getMessagingInfo\" in source) return source.getMessagingInfo().name;\n return source.name;\n}\n\nfunction supportsHtmlFormatting(platformName: string): boolean {\n return platformName === \"telegram\";\n}\n\nfunction formatItalic(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? text : `_${text}_`;\n}\n\nfunction formatCode(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? `<code>${text}</code>` : `\\`${text}\\``;\n}\n\nexport function formatNothingRunning(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Nothing running.\");\n}\n\nexport function formatStopping(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopping…\");\n}\n\nexport function formatStopped(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopped.\");\n}\n\nexport function formatRestarting(source: PlatformSource): string {\n return formatItalic(\n resolvePlatformName(source),\n \"Restarting for an update; this reply was interrupted. Please send your message again.\",\n );\n}\n\nexport function formatContinuingRun(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Restarted for an update; continuing.\");\n}\n\nexport function formatAlreadyWorking(\n source: PlatformSource,\n stopCommand: string,\n options?: { scope?: \"thread\" },\n): string {\n const platformName = resolvePlatformName(source);\n const command = formatCode(platformName, stopCommand);\n const prefix =\n options?.scope === \"thread\" ? \"Already working in this thread.\" : \"Already working.\";\n return formatItalic(platformName, `${prefix} Send ${command} to cancel.`);\n}\n"]}
@@ -64,7 +64,7 @@ export function slackAppManifest(customization = {}) {
64
64
  },
65
65
  features: {
66
66
  app_home: {
67
- home_tab_enabled: true,
67
+ home_tab_enabled: false,
68
68
  messages_tab_enabled: true,
69
69
  messages_tab_read_only_enabled: false,
70
70
  },
@@ -1 +1 @@
1
- {"version":3,"file":"app-config.js","sourceRoot":"","sources":["../../../src/adapters/slack/app-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport { WebClient } from \"@slack/web-api\";\nimport { Type } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport { COMMAND_MANIFEST } from \"../commands/manifest.js\";\nimport { atomicWritePrivateFile, readJsonSchemaFileIfExists } from \"../../file-guards.js\";\nimport { errorMessage, isRecord } from \"../../unknown-values.js\";\nimport type {\n SlackAppApi,\n SlackAppCustomization,\n SlackAppManifest,\n SlackAppSyncResult,\n SlackBotApi,\n SlackConfigTokens,\n} from \"./types.js\";\n\nexport const SLACK_APP_CUSTOMIZATION_FILE = \"slack.json\";\nexport const SLACK_CONFIG_TOKEN_FILE = \"slack-config-token.json\";\n\nconst BOT_SCOPES = [\n \"app_mentions:read\",\n \"channels:history\",\n \"channels:read\",\n \"chat:write\",\n \"chat:write.customize\",\n \"commands\",\n \"files:read\",\n \"files:write\",\n \"groups:history\",\n \"groups:read\",\n \"im:history\",\n \"im:read\",\n \"im:write\",\n \"reactions:write\",\n \"users:read\",\n] as const;\n\nconst BOT_EVENTS = [\n \"app_home_opened\",\n \"app_mention\",\n \"message.channels\",\n \"message.groups\",\n \"message.im\",\n] as const;\n\nconst SlackAppCustomizationSchema = Type.Object(\n {\n display_information: Type.Optional(\n Type.Object(\n {\n name: Type.Optional(Type.String({ minLength: 1, maxLength: 35 })),\n description: Type.Optional(Type.String({ maxLength: 140 })),\n long_description: Type.Optional(Type.String({ maxLength: 4000 })),\n background_color: Type.Optional(Type.String({ pattern: \"^#[0-9a-fA-F]{6}$\" })),\n },\n { additionalProperties: false },\n ),\n ),\n },\n { additionalProperties: false },\n);\n\nconst ConfigTokenFileSchema = Type.Object({\n token: Type.String({ minLength: 1 }),\n refresh_token: Type.String({ minLength: 1 }),\n});\n\nconst DEFAULT_BOT_NAME = \"mikan\";\nconst SLACK_BOT_NAME = /^[A-Za-z0-9 ._-]{1,80}$/;\n\nexport function slackBotNameProblem(name: string): string | undefined {\n return SLACK_BOT_NAME.test(name)\n ? undefined\n : `Slack names the bot user only with letters, digits, spaces, \".\", \"_\", and \"-\" (up to 80), so the bot keeps the name ${DEFAULT_BOT_NAME}.`;\n}\n\nfunction botName(customization: SlackAppCustomization): string {\n const name = customization.display_information?.name;\n return name !== undefined && slackBotNameProblem(name) === undefined ? name : DEFAULT_BOT_NAME;\n}\n\nexport function slackAppManifest(customization: SlackAppCustomization = {}): SlackAppManifest {\n const manifest = {\n display_information: {\n name: \"mikan\",\n description: \"mikan Slack assistant\",\n background_color: \"#4d5673\",\n ...customization.display_information,\n },\n features: {\n app_home: {\n home_tab_enabled: true,\n messages_tab_enabled: true,\n messages_tab_read_only_enabled: false,\n },\n bot_user: { display_name: botName(customization), always_online: true },\n slash_commands: COMMAND_MANIFEST.flatMap((entry) =>\n entry.slackCommand\n ? [\n {\n command: entry.slackCommand,\n description: entry.description,\n usage_hint: entry.arg?.description,\n should_escape: false,\n },\n ]\n : [],\n ),\n },\n oauth_config: {\n redirect_urls: [\"https://localhost\"],\n scopes: { bot: [...BOT_SCOPES] },\n pkce_enabled: false,\n },\n settings: {\n event_subscriptions: { bot_events: [...BOT_EVENTS] },\n interactivity: { is_enabled: true },\n org_deploy_enabled: false,\n socket_mode_enabled: true,\n token_rotation_enabled: false,\n app_level_token_rotation_enabled: false,\n is_mcp_enabled: false,\n },\n };\n return manifest;\n}\n\nexport function readSlackAppCustomization(stateDir: string): SlackAppCustomization {\n const path = join(stateDir, SLACK_APP_CUSTOMIZATION_FILE);\n return (\n readJsonSchemaFileIfExists(\n path,\n SlackAppCustomizationSchema,\n (detail) => `Invalid ${path}: ${detail}. It may hold only display_information fields.`,\n ) ?? {}\n );\n}\n\nexport function slackAppCustomizationProblem(\n customization: SlackAppCustomization,\n): string | undefined {\n if (Value.Check(SlackAppCustomizationSchema, customization)) return undefined;\n const first = Value.Errors(SlackAppCustomizationSchema, customization)[0];\n return `Slack would reject this app setting: ${first?.instancePath ?? \"\"} ${first?.message ?? \"\"}`.trim();\n}\n\nexport function writeSlackAppCustomization(\n stateDir: string,\n customization: SlackAppCustomization,\n): void {\n const problem = slackAppCustomizationProblem(customization);\n if (problem) throw new Error(problem);\n atomicWritePrivateFile(\n join(stateDir, SLACK_APP_CUSTOMIZATION_FILE),\n `${JSON.stringify(customization, null, 2)}\\n`,\n );\n}\n\nfunction readConfigTokens(stateDir: string): SlackConfigTokens | undefined {\n const path = join(stateDir, SLACK_CONFIG_TOKEN_FILE);\n const stored = readJsonSchemaFileIfExists(\n path,\n ConfigTokenFileSchema,\n (detail) => `Invalid ${path}: ${detail}`,\n );\n return stored ? { token: stored.token, refreshToken: stored.refresh_token } : undefined;\n}\n\nexport function writeConfigTokens(stateDir: string, tokens: SlackConfigTokens): void {\n atomicWritePrivateFile(\n join(stateDir, SLACK_CONFIG_TOKEN_FILE),\n `${JSON.stringify({ token: tokens.token, refresh_token: tokens.refreshToken })}\\n`,\n );\n}\n\nfunction canonical(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonical);\n if (!isRecord(value)) return value;\n return Object.fromEntries(\n Object.keys(value)\n .filter((key) => value[key] !== undefined)\n .toSorted()\n .map((key) => [key, canonical(value[key])]),\n );\n}\n\nconst SLACK_MANAGED_APP_HOME_FIELDS = new Set([\"agent_tasks_enabled\"]);\n\nfunction withoutSlackManagedFields(live: unknown): unknown {\n if (!isRecord(live) || !isRecord(live.features) || !isRecord(live.features.app_home)) return live;\n const appHome = Object.fromEntries(\n Object.entries(live.features.app_home).filter(\n ([key]) => !SLACK_MANAGED_APP_HOME_FIELDS.has(key),\n ),\n );\n return { ...live, features: { ...live.features, app_home: appHome } };\n}\n\nfunction sameManifest(live: unknown, desired: SlackAppManifest): boolean {\n return (\n JSON.stringify(canonical(withoutSlackManagedFields(live))) ===\n JSON.stringify(canonical(desired))\n );\n}\n\nfunction reinstallMessage(appId: string, missingScopes: string[]): string {\n return `mikan updated this Slack app, and it now needs permissions the installed bot does not have: ${missingScopes.join(\", \")}. Reinstall the app to grant them: https://api.slack.com/apps/${appId}/install-on-team`;\n}\n\nexport async function syncSlackApp(options: {\n stateDir: string;\n apps: SlackAppApi;\n bot: SlackBotApi;\n}): Promise<SlackAppSyncResult> {\n const { stateDir, apps, bot } = options;\n const stored = readConfigTokens(stateDir);\n if (!stored) return { status: \"no-token\" };\n try {\n const rotated = await apps.rotate(stored.refreshToken);\n writeConfigTokens(stateDir, rotated);\n const appId = await bot.appId();\n const desired = slackAppManifest(readSlackAppCustomization(stateDir));\n if (sameManifest(await apps.export(rotated.token, appId), desired)) {\n return { status: \"unchanged\", appId };\n }\n const { permissionsUpdated } = await apps.update(rotated.token, appId, desired);\n const granted = permissionsUpdated ? new Set(await bot.scopes()) : undefined;\n const missingScopes = granted\n ? (desired.oauth_config?.scopes?.bot ?? []).filter((scope) => !granted.has(scope))\n : [];\n if (missingScopes.length > 0) {\n await bot.directMessage(rotated.userId, reinstallMessage(appId, missingScopes));\n }\n return { status: \"updated\", appId, missingScopes };\n } catch (error) {\n return { status: \"failed\", reason: errorMessage(error) };\n }\n}\n\nexport function describeSlackAppSync(result: SlackAppSyncResult): string | undefined {\n switch (result.status) {\n case \"no-token\":\n return undefined;\n case \"failed\":\n return `Slack app sync failed, app left as it was: ${result.reason}`;\n case \"unchanged\":\n return `Slack app ${result.appId} already matches mikan's manifest`;\n case \"updated\":\n return result.missingScopes.length > 0\n ? `Slack app ${result.appId} updated to mikan's manifest; it needs a reinstall to grant ${result.missingScopes.join(\", \")}, and the configuration token owner was asked by DM`\n : `Slack app ${result.appId} updated to mikan's manifest`;\n }\n}\n\nexport async function createSlackApp(options: {\n apps: SlackAppApi;\n refreshToken: string;\n customization: SlackAppCustomization;\n}): Promise<{ appId: string; installUrl: string; tokens: SlackConfigTokens }> {\n const tokens = await options.apps.rotate(options.refreshToken);\n const created = await options.apps.create(tokens.token, slackAppManifest(options.customization));\n return { ...created, tokens };\n}\n\nfunction required<T>(value: T | undefined, what: string): T {\n if (value === undefined) throw new Error(`Slack did not return ${what}`);\n return value;\n}\n\nconst NO_RETRIES = { retryConfig: { retries: 0 }, timeout: 15_000 };\n\nexport function slackAppApi(): SlackAppApi {\n const client = new WebClient(undefined, NO_RETRIES);\n return {\n rotate: async (refreshToken) => {\n const result = await client.tooling.tokens.rotate({ refresh_token: refreshToken });\n return {\n token: required(result.token, \"a configuration token\"),\n refreshToken: required(result.refresh_token, \"a refresh token\"),\n userId: required(result.user_id, \"the token owner\"),\n };\n },\n export: async (token, appId) =>\n required(\n (await client.apps.manifest.export({ token, app_id: appId })).manifest,\n \"a manifest\",\n ),\n update: async (token, appId, manifest) => ({\n permissionsUpdated:\n (await client.apps.manifest.update({ token, app_id: appId, manifest }))\n .permissions_updated === true,\n }),\n create: async (token, manifest) => {\n const result = await client.apps.manifest.create({ token, manifest });\n return {\n appId: required(result.app_id, \"an app ID\"),\n installUrl: required(result.oauth_authorize_url, \"an install link\"),\n };\n },\n delete: async (token, appId) => {\n await client.apps.manifest.delete({ token, app_id: appId });\n },\n };\n}\n\nexport function slackBotApi(botToken: string): SlackBotApi {\n const client = new WebClient(botToken, NO_RETRIES);\n return {\n appId: async () => {\n const bot = required((await client.auth.test()).bot_id, \"the bot ID\");\n return required((await client.bots.info({ bot })).bot?.app_id, \"the app ID\");\n },\n scopes: async () => (await client.auth.test()).response_metadata?.scopes ?? [],\n directMessage: async (userId, text) => {\n await client.chat.postMessage({ channel: userId, text });\n },\n };\n}\n"]}
1
+ {"version":3,"file":"app-config.js","sourceRoot":"","sources":["../../../src/adapters/slack/app-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAUjE,MAAM,CAAC,MAAM,4BAA4B,GAAG,YAAY,CAAC;AACzD,MAAM,CAAC,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAEjE,MAAM,UAAU,GAAG;IACjB,mBAAmB;IACnB,kBAAkB;IAClB,eAAe;IACf,YAAY;IACZ,sBAAsB;IACtB,UAAU;IACV,YAAY;IACZ,aAAa;IACb,gBAAgB;IAChB,aAAa;IACb,YAAY;IACZ,SAAS;IACT,UAAU;IACV,iBAAiB;IACjB,YAAY;CACJ,CAAC;AAEX,MAAM,UAAU,GAAG;IACjB,iBAAiB;IACjB,aAAa;IACb,kBAAkB;IAClB,gBAAgB;IAChB,YAAY;CACJ,CAAC;AAEX,MAAM,2BAA2B,GAAG,IAAI,CAAC,MAAM,CAC7C;IACE,mBAAmB,EAAE,IAAI,CAAC,QAAQ,CAChC,IAAI,CAAC,MAAM,CACT;QACE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QACjE,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,gBAAgB,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjE,gBAAgB,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;KAC/E,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAChC,CACF;CACF,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAChC,CAAC;AAEF,MAAM,qBAAqB,GAAG,IAAI,CAAC,MAAM,CAAC;IACxC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IACpC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;CAC7C,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,OAAO,CAAC;AACjC,MAAM,cAAc,GAAG,yBAAyB,CAAC;AAEjD,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QAC9B,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,uHAAuH,gBAAgB,GAAG,CAAC;AACjJ,CAAC;AAED,SAAS,OAAO,CAAC,aAAoC;IACnD,MAAM,IAAI,GAAG,aAAa,CAAC,mBAAmB,EAAE,IAAI,CAAC;IACrD,OAAO,IAAI,KAAK,SAAS,IAAI,mBAAmB,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC;AACjG,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,aAAa,GAA0B,EAAE;IACxE,MAAM,QAAQ,GAAG;QACf,mBAAmB,EAAE;YACnB,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,uBAAuB;YACpC,gBAAgB,EAAE,SAAS;YAC3B,GAAG,aAAa,CAAC,mBAAmB;SACrC;QACD,QAAQ,EAAE;YACR,QAAQ,EAAE;gBACR,gBAAgB,EAAE,KAAK;gBACvB,oBAAoB,EAAE,IAAI;gBAC1B,8BAA8B,EAAE,KAAK;aACtC;YACD,QAAQ,EAAE,EAAE,YAAY,EAAE,OAAO,CAAC,aAAa,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE;YACvE,cAAc,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CACjD,KAAK,CAAC,YAAY;gBAChB,CAAC,CAAC;oBACE;wBACE,OAAO,EAAE,KAAK,CAAC,YAAY;wBAC3B,WAAW,EAAE,KAAK,CAAC,WAAW;wBAC9B,UAAU,EAAE,KAAK,CAAC,GAAG,EAAE,WAAW;wBAClC,aAAa,EAAE,KAAK;qBACrB;iBACF;gBACH,CAAC,CAAC,EAAE,CACP;SACF;QACD,YAAY,EAAE;YACZ,aAAa,EAAE,CAAC,mBAAmB,CAAC;YACpC,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,UAAU,CAAC,EAAE;YAChC,YAAY,EAAE,KAAK;SACpB;QACD,QAAQ,EAAE;YACR,mBAAmB,EAAE,EAAE,UAAU,EAAE,CAAC,GAAG,UAAU,CAAC,EAAE;YACpD,aAAa,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;YACnC,kBAAkB,EAAE,KAAK;YACzB,mBAAmB,EAAE,IAAI;YACzB,sBAAsB,EAAE,KAAK;YAC7B,gCAAgC,EAAE,KAAK;YACvC,cAAc,EAAE,KAAK;SACtB;KACF,CAAC;IACF,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,QAAgB;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,4BAA4B,CAAC,CAAC;IAC1D,OAAO,CACL,0BAA0B,CACxB,IAAI,EACJ,2BAA2B,EAC3B,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,IAAI,KAAK,MAAM,gDAAgD,CACvF,IAAI,EAAE,CACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,aAAoC;IAEpC,IAAI,KAAK,CAAC,KAAK,CAAC,2BAA2B,EAAE,aAAa,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9E,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,2BAA2B,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,OAAO,wCAAwC,KAAK,EAAE,YAAY,IAAI,EAAE,IAAI,KAAK,EAAE,OAAO,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;AAC5G,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,QAAgB,EAChB,aAAoC;IAEpC,MAAM,OAAO,GAAG,4BAA4B,CAAC,aAAa,CAAC,CAAC;IAC5D,IAAI,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,sBAAsB,CACpB,IAAI,CAAC,QAAQ,EAAE,4BAA4B,CAAC,EAC5C,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAC9C,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAgB;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,0BAA0B,CACvC,IAAI,EACJ,qBAAqB,EACrB,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,IAAI,KAAK,MAAM,EAAE,CACzC,CAAC;IACF,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1F,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,MAAyB;IAC3E,sBAAsB,CACpB,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,EACvC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,IAAI,CACnF,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;SACf,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;SACzC,QAAQ,EAAE;SACV,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAC9C,CAAC;AACJ,CAAC;AAED,MAAM,6BAA6B,GAAG,IAAI,GAAG,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC;AAEvE,SAAS,yBAAyB,CAAC,IAAa;IAC9C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAClG,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAChC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,CAC3C,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,6BAA6B,CAAC,GAAG,CAAC,GAAG,CAAC,CACnD,CACF,CAAC;IACF,OAAO,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC;AACxE,CAAC;AAED,SAAS,YAAY,CAAC,IAAa,EAAE,OAAyB;IAC5D,OAAO,CACL,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CACnC,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa,EAAE,aAAuB;IAC9D,OAAO,+FAA+F,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,iEAAiE,KAAK,kBAAkB,CAAC;AACzN,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAIlC;IACC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IACxC,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACvD,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,gBAAgB,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC,CAAC;QACtE,IAAI,YAAY,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC;YACnE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;QACxC,CAAC;QACD,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChF,MAAM,OAAO,GAAG,kBAAkB,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC7E,MAAM,aAAa,GAAG,OAAO;YAC3B,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAClF,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;IACrD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAA0B;IAC7D,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;QACtB,KAAK,UAAU;YACb,OAAO,SAAS,CAAC;QACnB,KAAK,QAAQ;YACX,OAAO,8CAA8C,MAAM,CAAC,MAAM,EAAE,CAAC;QACvE,KAAK,WAAW;YACd,OAAO,aAAa,MAAM,CAAC,KAAK,mCAAmC,CAAC;QACtE,KAAK,SAAS;YACZ,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC;gBACpC,CAAC,CAAC,aAAa,MAAM,CAAC,KAAK,+DAA+D,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,qDAAqD;gBAC9K,CAAC,CAAC,aAAa,MAAM,CAAC,KAAK,8BAA8B,CAAC;IAChE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAIpC;IACC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;IACjG,OAAO,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,QAAQ,CAAI,KAAoB,EAAE,IAAY;IACrD,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;IACzE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,GAAG,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAEpE,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACpD,OAAO;QACL,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE;YAC7B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,CAAC;YACnF,OAAO;gBACL,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,uBAAuB,CAAC;gBACtD,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,iBAAiB,CAAC;gBAC/D,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,iBAAiB,CAAC;aACpD,CAAC;QACJ,CAAC;QACD,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAC7B,QAAQ,CACN,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,EACtE,YAAY,CACb;QACH,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YACzC,kBAAkB,EAChB,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;iBACpE,mBAAmB,KAAK,IAAI;SAClC,CAAC;QACF,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YAChC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YACtE,OAAO;gBACL,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;gBAC3C,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,mBAAmB,EAAE,iBAAiB,CAAC;aACpE,CAAC;QACJ,CAAC;QACD,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YAC7B,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9D,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACnD,OAAO;QACL,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YACtE,OAAO,QAAQ,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;QAC/E,CAAC;QACD,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,iBAAiB,EAAE,MAAM,IAAI,EAAE;QAC9E,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;YACpC,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { join } from \"node:path\";\nimport { WebClient } from \"@slack/web-api\";\nimport { Type } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport { COMMAND_MANIFEST } from \"../commands/manifest.js\";\nimport { atomicWritePrivateFile, readJsonSchemaFileIfExists } from \"../../file-guards.js\";\nimport { errorMessage, isRecord } from \"../../unknown-values.js\";\nimport type {\n SlackAppApi,\n SlackAppCustomization,\n SlackAppManifest,\n SlackAppSyncResult,\n SlackBotApi,\n SlackConfigTokens,\n} from \"./types.js\";\n\nexport const SLACK_APP_CUSTOMIZATION_FILE = \"slack.json\";\nexport const SLACK_CONFIG_TOKEN_FILE = \"slack-config-token.json\";\n\nconst BOT_SCOPES = [\n \"app_mentions:read\",\n \"channels:history\",\n \"channels:read\",\n \"chat:write\",\n \"chat:write.customize\",\n \"commands\",\n \"files:read\",\n \"files:write\",\n \"groups:history\",\n \"groups:read\",\n \"im:history\",\n \"im:read\",\n \"im:write\",\n \"reactions:write\",\n \"users:read\",\n] as const;\n\nconst BOT_EVENTS = [\n \"app_home_opened\",\n \"app_mention\",\n \"message.channels\",\n \"message.groups\",\n \"message.im\",\n] as const;\n\nconst SlackAppCustomizationSchema = Type.Object(\n {\n display_information: Type.Optional(\n Type.Object(\n {\n name: Type.Optional(Type.String({ minLength: 1, maxLength: 35 })),\n description: Type.Optional(Type.String({ maxLength: 140 })),\n long_description: Type.Optional(Type.String({ maxLength: 4000 })),\n background_color: Type.Optional(Type.String({ pattern: \"^#[0-9a-fA-F]{6}$\" })),\n },\n { additionalProperties: false },\n ),\n ),\n },\n { additionalProperties: false },\n);\n\nconst ConfigTokenFileSchema = Type.Object({\n token: Type.String({ minLength: 1 }),\n refresh_token: Type.String({ minLength: 1 }),\n});\n\nconst DEFAULT_BOT_NAME = \"mikan\";\nconst SLACK_BOT_NAME = /^[A-Za-z0-9 ._-]{1,80}$/;\n\nexport function slackBotNameProblem(name: string): string | undefined {\n return SLACK_BOT_NAME.test(name)\n ? undefined\n : `Slack names the bot user only with letters, digits, spaces, \".\", \"_\", and \"-\" (up to 80), so the bot keeps the name ${DEFAULT_BOT_NAME}.`;\n}\n\nfunction botName(customization: SlackAppCustomization): string {\n const name = customization.display_information?.name;\n return name !== undefined && slackBotNameProblem(name) === undefined ? name : DEFAULT_BOT_NAME;\n}\n\nexport function slackAppManifest(customization: SlackAppCustomization = {}): SlackAppManifest {\n const manifest = {\n display_information: {\n name: \"mikan\",\n description: \"mikan Slack assistant\",\n background_color: \"#4d5673\",\n ...customization.display_information,\n },\n features: {\n app_home: {\n home_tab_enabled: false,\n messages_tab_enabled: true,\n messages_tab_read_only_enabled: false,\n },\n bot_user: { display_name: botName(customization), always_online: true },\n slash_commands: COMMAND_MANIFEST.flatMap((entry) =>\n entry.slackCommand\n ? [\n {\n command: entry.slackCommand,\n description: entry.description,\n usage_hint: entry.arg?.description,\n should_escape: false,\n },\n ]\n : [],\n ),\n },\n oauth_config: {\n redirect_urls: [\"https://localhost\"],\n scopes: { bot: [...BOT_SCOPES] },\n pkce_enabled: false,\n },\n settings: {\n event_subscriptions: { bot_events: [...BOT_EVENTS] },\n interactivity: { is_enabled: true },\n org_deploy_enabled: false,\n socket_mode_enabled: true,\n token_rotation_enabled: false,\n app_level_token_rotation_enabled: false,\n is_mcp_enabled: false,\n },\n };\n return manifest;\n}\n\nexport function readSlackAppCustomization(stateDir: string): SlackAppCustomization {\n const path = join(stateDir, SLACK_APP_CUSTOMIZATION_FILE);\n return (\n readJsonSchemaFileIfExists(\n path,\n SlackAppCustomizationSchema,\n (detail) => `Invalid ${path}: ${detail}. It may hold only display_information fields.`,\n ) ?? {}\n );\n}\n\nexport function slackAppCustomizationProblem(\n customization: SlackAppCustomization,\n): string | undefined {\n if (Value.Check(SlackAppCustomizationSchema, customization)) return undefined;\n const first = Value.Errors(SlackAppCustomizationSchema, customization)[0];\n return `Slack would reject this app setting: ${first?.instancePath ?? \"\"} ${first?.message ?? \"\"}`.trim();\n}\n\nexport function writeSlackAppCustomization(\n stateDir: string,\n customization: SlackAppCustomization,\n): void {\n const problem = slackAppCustomizationProblem(customization);\n if (problem) throw new Error(problem);\n atomicWritePrivateFile(\n join(stateDir, SLACK_APP_CUSTOMIZATION_FILE),\n `${JSON.stringify(customization, null, 2)}\\n`,\n );\n}\n\nfunction readConfigTokens(stateDir: string): SlackConfigTokens | undefined {\n const path = join(stateDir, SLACK_CONFIG_TOKEN_FILE);\n const stored = readJsonSchemaFileIfExists(\n path,\n ConfigTokenFileSchema,\n (detail) => `Invalid ${path}: ${detail}`,\n );\n return stored ? { token: stored.token, refreshToken: stored.refresh_token } : undefined;\n}\n\nexport function writeConfigTokens(stateDir: string, tokens: SlackConfigTokens): void {\n atomicWritePrivateFile(\n join(stateDir, SLACK_CONFIG_TOKEN_FILE),\n `${JSON.stringify({ token: tokens.token, refresh_token: tokens.refreshToken })}\\n`,\n );\n}\n\nfunction canonical(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonical);\n if (!isRecord(value)) return value;\n return Object.fromEntries(\n Object.keys(value)\n .filter((key) => value[key] !== undefined)\n .toSorted()\n .map((key) => [key, canonical(value[key])]),\n );\n}\n\nconst SLACK_MANAGED_APP_HOME_FIELDS = new Set([\"agent_tasks_enabled\"]);\n\nfunction withoutSlackManagedFields(live: unknown): unknown {\n if (!isRecord(live) || !isRecord(live.features) || !isRecord(live.features.app_home)) return live;\n const appHome = Object.fromEntries(\n Object.entries(live.features.app_home).filter(\n ([key]) => !SLACK_MANAGED_APP_HOME_FIELDS.has(key),\n ),\n );\n return { ...live, features: { ...live.features, app_home: appHome } };\n}\n\nfunction sameManifest(live: unknown, desired: SlackAppManifest): boolean {\n return (\n JSON.stringify(canonical(withoutSlackManagedFields(live))) ===\n JSON.stringify(canonical(desired))\n );\n}\n\nfunction reinstallMessage(appId: string, missingScopes: string[]): string {\n return `mikan updated this Slack app, and it now needs permissions the installed bot does not have: ${missingScopes.join(\", \")}. Reinstall the app to grant them: https://api.slack.com/apps/${appId}/install-on-team`;\n}\n\nexport async function syncSlackApp(options: {\n stateDir: string;\n apps: SlackAppApi;\n bot: SlackBotApi;\n}): Promise<SlackAppSyncResult> {\n const { stateDir, apps, bot } = options;\n const stored = readConfigTokens(stateDir);\n if (!stored) return { status: \"no-token\" };\n try {\n const rotated = await apps.rotate(stored.refreshToken);\n writeConfigTokens(stateDir, rotated);\n const appId = await bot.appId();\n const desired = slackAppManifest(readSlackAppCustomization(stateDir));\n if (sameManifest(await apps.export(rotated.token, appId), desired)) {\n return { status: \"unchanged\", appId };\n }\n const { permissionsUpdated } = await apps.update(rotated.token, appId, desired);\n const granted = permissionsUpdated ? new Set(await bot.scopes()) : undefined;\n const missingScopes = granted\n ? (desired.oauth_config?.scopes?.bot ?? []).filter((scope) => !granted.has(scope))\n : [];\n if (missingScopes.length > 0) {\n await bot.directMessage(rotated.userId, reinstallMessage(appId, missingScopes));\n }\n return { status: \"updated\", appId, missingScopes };\n } catch (error) {\n return { status: \"failed\", reason: errorMessage(error) };\n }\n}\n\nexport function describeSlackAppSync(result: SlackAppSyncResult): string | undefined {\n switch (result.status) {\n case \"no-token\":\n return undefined;\n case \"failed\":\n return `Slack app sync failed, app left as it was: ${result.reason}`;\n case \"unchanged\":\n return `Slack app ${result.appId} already matches mikan's manifest`;\n case \"updated\":\n return result.missingScopes.length > 0\n ? `Slack app ${result.appId} updated to mikan's manifest; it needs a reinstall to grant ${result.missingScopes.join(\", \")}, and the configuration token owner was asked by DM`\n : `Slack app ${result.appId} updated to mikan's manifest`;\n }\n}\n\nexport async function createSlackApp(options: {\n apps: SlackAppApi;\n refreshToken: string;\n customization: SlackAppCustomization;\n}): Promise<{ appId: string; installUrl: string; tokens: SlackConfigTokens }> {\n const tokens = await options.apps.rotate(options.refreshToken);\n const created = await options.apps.create(tokens.token, slackAppManifest(options.customization));\n return { ...created, tokens };\n}\n\nfunction required<T>(value: T | undefined, what: string): T {\n if (value === undefined) throw new Error(`Slack did not return ${what}`);\n return value;\n}\n\nconst NO_RETRIES = { retryConfig: { retries: 0 }, timeout: 15_000 };\n\nexport function slackAppApi(): SlackAppApi {\n const client = new WebClient(undefined, NO_RETRIES);\n return {\n rotate: async (refreshToken) => {\n const result = await client.tooling.tokens.rotate({ refresh_token: refreshToken });\n return {\n token: required(result.token, \"a configuration token\"),\n refreshToken: required(result.refresh_token, \"a refresh token\"),\n userId: required(result.user_id, \"the token owner\"),\n };\n },\n export: async (token, appId) =>\n required(\n (await client.apps.manifest.export({ token, app_id: appId })).manifest,\n \"a manifest\",\n ),\n update: async (token, appId, manifest) => ({\n permissionsUpdated:\n (await client.apps.manifest.update({ token, app_id: appId, manifest }))\n .permissions_updated === true,\n }),\n create: async (token, manifest) => {\n const result = await client.apps.manifest.create({ token, manifest });\n return {\n appId: required(result.app_id, \"an app ID\"),\n installUrl: required(result.oauth_authorize_url, \"an install link\"),\n };\n },\n delete: async (token, appId) => {\n await client.apps.manifest.delete({ token, app_id: appId });\n },\n };\n}\n\nexport function slackBotApi(botToken: string): SlackBotApi {\n const client = new WebClient(botToken, NO_RETRIES);\n return {\n appId: async () => {\n const bot = required((await client.auth.test()).bot_id, \"the bot ID\");\n return required((await client.bots.info({ bot })).bot?.app_id, \"the app ID\");\n },\n scopes: async () => (await client.auth.test()).response_metadata?.scopes ?? [],\n directMessage: async (userId, text) => {\n await client.chat.postMessage({ channel: userId, text });\n },\n };\n}\n"]}
@@ -26,7 +26,6 @@ export declare class SlackMessagingBot implements MessagingBot {
26
26
  private streamStarts;
27
27
  private stopped;
28
28
  private queues;
29
- private readonly taskQueueKeys;
30
29
  private intake;
31
30
  private readonly recentMessageKeys;
32
31
  private agentSurfaceUnavailable;
@@ -83,16 +82,14 @@ export declare class SlackMessagingBot implements MessagingBot {
83
82
  private getQueue;
84
83
  private resolveQueueKey;
85
84
  private enqueueTaskRun;
86
- private resumeInterruptedTasks;
85
+ private continueInterruptedRuns;
86
+ private enqueueContinuation;
87
87
  private isTaskThread;
88
88
  private hasRunningTaskThread;
89
89
  private hasKnownThreadSession;
90
90
  private channelKindFor;
91
91
  private backfillChannelKinds;
92
92
  private processSlackMessageIntake;
93
- private appendRunningTasks;
94
- private appendScheduledJobs;
95
- private buildHomeView;
96
93
  private createCommandAdapters;
97
94
  private buildSlashCommandEvent;
98
95
  private routeSlashCommand;
@@ -1 +1 @@
1
- {"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/bot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/bot.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { appendBotResponseLog, appendOfficeLog, readOfficeLog } from "../../office/log.js";
2
2
  import { SessionStore } from "../../sessions/session-store.js";
3
- import { RESUMED_TASK_PROMPT, resumedTaskRunId, taskRunId } from "../../harness/tools/task.js";
3
+ import { taskRunId } from "../../harness/tools/task.js";
4
+ import { continuedRunId } from "../../harness/continued-run.js";
4
5
  import { SocketModeClient } from "@slack/socket-mode";
5
6
  import { WebAPIRateLimitedError, WebClient } from "@slack/web-api";
6
7
  import { existsSync, readFileSync } from "node:fs";
@@ -12,14 +13,13 @@ import { evaluateWithJev, JevNotConfiguredError } from "../../harness/jev.js";
12
13
  import * as log from "../../log.js";
13
14
  import { SlackSocketAgent } from "./socket-agent.js";
14
15
  import { readTextFileNoFollowIfExists } from "../../file-guards.js";
15
- import { PRODUCT_NAME, formatForceStopped, formatResumingTask, formatTaskResumesExhausted, } from "../messages.js";
16
+ import { formatContinuingRun } from "../messages.js";
16
17
  import { MessagingEventQueue, MessagingIntakeTracker, AttachmentRejectedError, saveIncomingAttachments, writeResponseToFile, withRetry, } from "../shared.js";
17
18
  import { matchMagicWord, processMessageIntake } from "../intake.js";
18
19
  import { readPlatformChannelKind, recordPlatformChannelKind } from "../../office/projection.js";
19
20
  import { AssistantThreadRegistry, handleAgentContextChanged, handleAgentDmOpened, handleAssistantThreadStarted, titleAssistantThread, } from "./assistant.js";
20
21
  import { createSlackAdapters } from "./context.js";
21
22
  import { hasMaterializedChatSession, registerThreadSession, } from "../../sessions/chat-history-sync.js";
22
- import { conversationIdOf } from "../../sessions/session-key.js";
23
23
  import { isSlackThreadSessionKey, parseSlackSessionKey, planSlackAdapterSession, planSlackEventAnchorRun, resolveSlackSessionKey, } from "./session.js";
24
24
  import { reportUserFacingError } from "../../observability/index.js";
25
25
  import { recordSlackUpdate } from "./update-diagnostics.js";
@@ -30,8 +30,6 @@ import { buildTaskIntentState, classifyTaskIntent } from "./task-intent.js";
30
30
  import { StreamStartLimiter } from "./stream-limits.js";
31
31
  import { errorMessage, isRecord } from "../../unknown-values.js";
32
32
  const SLACK_EVENT_ANCHOR_TEXT = "Working on it...";
33
- const TASK_RESUME_WINDOW_MS = 24 * 60 * 60 * 1000;
34
- const MAX_TASK_RESUMES = 2;
35
33
  function hasMessageContent(message, includeBlocks = true) {
36
34
  const content = [message.text, message.files];
37
35
  if (includeBlocks)
@@ -221,7 +219,6 @@ export class SlackMessagingBot {
221
219
  this.streamStarts = new StreamStartLimiter();
222
220
  this.stopped = false;
223
221
  this.queues = new Map();
224
- this.taskQueueKeys = new Set();
225
222
  this.intake = new MessagingIntakeTracker("Slack");
226
223
  this.recentMessageKeys = new Set();
227
224
  this.agentSurfaceUnavailable = false;
@@ -260,6 +257,9 @@ export class SlackMessagingBot {
260
257
  log.logInfo(`Loaded ${this.channels.size} channels, ${this.users.size} users`);
261
258
  this.backfillChannelKinds();
262
259
  this.startupTs = (Date.now() / 1000).toFixed(6);
260
+ await this.continueInterruptedRuns().catch((error) => {
261
+ log.logWarning("Could not continue interrupted runs", errorMessage(error));
262
+ });
263
263
  this.setupEventHandlers();
264
264
  try {
265
265
  await this.socketClient.start();
@@ -270,9 +270,6 @@ export class SlackMessagingBot {
270
270
  throw error;
271
271
  }
272
272
  log.logConnected("Slack");
273
- void this.resumeInterruptedTasks().catch((error) => {
274
- log.logWarning("Could not resume interrupted tasks", String(error));
275
- });
276
273
  void this.backfillAllChannels(this.startupTs).catch((error) => {
277
274
  log.logWarning("Slack backfill failed", String(error));
278
275
  });
@@ -284,11 +281,8 @@ export class SlackMessagingBot {
284
281
  }
285
282
  finally {
286
283
  await this.intake.close();
287
- const closing = [...this.queues].map(([key, queue]) => ({
288
- waits: !this.taskQueueKeys.has(key),
289
- closed: queue.close(),
290
- }));
291
- await Promise.all(closing.filter(({ waits }) => waits).map(({ closed }) => closed));
284
+ for (const queue of this.queues.values())
285
+ void queue.close();
292
286
  }
293
287
  }
294
288
  getUser(userId) {
@@ -576,6 +570,7 @@ export class SlackMessagingBot {
576
570
  name: "slack",
577
571
  workspaceId: this.teamId || undefined,
578
572
  trustModel: "membership",
573
+ continuesInterruptedRuns: true,
579
574
  formattingGuide: "## Slack Formatting\nWrite standard Markdown/GFM: **bold**, _italic_, ~~strike~~, `code`, fenced code blocks, [links](url), lists, and pipe tables (rendered as native Slack tables).\nDo NOT use Slack mrkdwn syntax like *single-asterisk bold* or <url|label> links.",
580
575
  channels: this.getAllChannels().map((c) => ({ id: c.id, name: c.name })),
581
576
  users: this.getAllUsers().map((u) => ({
@@ -677,7 +672,6 @@ export class SlackMessagingBot {
677
672
  }
678
673
  enqueueTaskRun(child) {
679
674
  const { channel, thread_ts: root, sessionKey } = child;
680
- this.taskQueueKeys.add(sessionKey);
681
675
  const enqueued = this.getQueue(sessionKey).enqueue(async () => {
682
676
  try {
683
677
  await this.handler.handleEvent({
@@ -704,53 +698,44 @@ export class SlackMessagingBot {
704
698
  if (!enqueued)
705
699
  throw new Error("Task queue is closed.");
706
700
  }
707
- async resumeInterruptedTasks() {
708
- const since = Date.now() - TASK_RESUME_WINDOW_MS;
709
- let resumed = 0;
701
+ async continueInterruptedRuns() {
702
+ let continued = 0;
710
703
  for (const channelId of this.channels.keys()) {
711
704
  if (this.stopped)
712
705
  return;
713
- if (this.channelKindFor(channelId) !== "im")
714
- continue;
715
706
  const office = this.office(channelId);
716
- const keys = new Map((await SessionStore.listTasks(office, channelId)).flatMap((task) => {
717
- const ref = parseSlackSessionKey(task.sessionKey);
718
- return ref.kind === "thread" && Number(ref.threadTs) * 1000 >= since
719
- ? [[task.sessionKey, ref.threadTs]]
720
- : [];
721
- }));
722
- if (keys.size === 0)
723
- continue;
724
- const interrupted = await SessionStore.interruptedSince(office, [...keys.keys()], since);
725
- if (interrupted.length === 0)
726
- continue;
727
- const requester = readOfficeLog(office).findLast((entry) => !entry.isMessagingBot && entry.user)?.user;
728
- if (!requester)
707
+ const sessionKeys = await SessionStore.continueInterrupted(office);
708
+ if (sessionKeys.length === 0)
729
709
  continue;
730
- for (const sessionKey of interrupted) {
731
- const root = keys.get(sessionKey);
732
- if ((await SessionStore.claimResume(office, sessionKey, MAX_TASK_RESUMES)) === "exhausted") {
733
- log.logInfo(`Not resuming task ${sessionKey}: interrupted after ${MAX_TASK_RESUMES} resumes`);
734
- await this.postInThread(channelId, root, formatTaskResumesExhausted(this));
735
- continue;
736
- }
737
- log.logInfo(`Resuming interrupted task ${sessionKey}`);
738
- await this.postInThread(channelId, root, formatResumingTask(this));
739
- this.enqueueTaskRun({
740
- type: "dm",
741
- conversationKind: "direct",
710
+ const entries = readOfficeLog(office);
711
+ for (const sessionKey of sessionKeys) {
712
+ const ref = parseSlackSessionKey(sessionKey);
713
+ const threadTs = ref.kind === "thread" ? ref.threadTs : undefined;
714
+ const user = entries.findLast((entry) => !entry.isMessagingBot && entry.user && entry.sessionKey === sessionKey)?.user ??
715
+ entries.findLast((entry) => !entry.isMessagingBot && entry.user)?.user ??
716
+ "";
717
+ const direct = this.channelKindFor(channelId) === "im";
718
+ this.enqueueContinuation({
719
+ type: direct ? "dm" : "mention",
720
+ conversationKind: direct ? "direct" : "shared",
742
721
  address: createOfficeAddress("slack", channelId),
743
722
  channel: channelId,
744
- user: requester,
745
- ts: resumedTaskRunId(root),
746
- thread_ts: root,
723
+ user,
724
+ ts: continuedRunId(sessionKey),
725
+ thread_ts: threadTs,
747
726
  sessionKey,
748
- text: RESUMED_TASK_PROMPT,
727
+ text: formatContinuingRun(this),
749
728
  });
750
- resumed += 1;
729
+ continued += 1;
751
730
  }
752
731
  }
753
- log.logInfo(`Resumed ${resumed} interrupted tasks`);
732
+ log.logInfo(`Continued ${continued} interrupted runs`);
733
+ }
734
+ enqueueContinuation(event) {
735
+ void (event.thread_ts
736
+ ? this.postInThread(event.channel, event.thread_ts, event.text)
737
+ : this.postMessage(event.channel, event.text)).catch((error) => log.logWarning("Could not post the continuation notice", errorMessage(error)));
738
+ this.getQueue(event.sessionKey).enqueue(() => this.handler.handleEvent({ ...event, attachments: undefined }, this, this.createContext(event)));
754
739
  }
755
740
  isTaskThread(channel, root) {
756
741
  return SessionStore.isTask(this.office(channel), resolveSlackSessionKey(channel, root));
@@ -850,127 +835,6 @@ export class SlackMessagingBot {
850
835
  absorbAttachmentFailure();
851
836
  });
852
837
  }
853
- appendRunningTasks(blocks) {
854
- const runningSessions = this.handler.getRunningSessions();
855
- blocks.push({ type: "divider" }, {
856
- type: "header",
857
- text: {
858
- type: "plain_text",
859
- text: `Running Tasks (${runningSessions.length})`,
860
- emoji: true,
861
- },
862
- });
863
- if (runningSessions.length === 0) {
864
- blocks.push({
865
- type: "context",
866
- elements: [{ type: "mrkdwn", text: "_No tasks running right now._" }],
867
- });
868
- return;
869
- }
870
- const stuckThresholdMs = 10 * 60 * 1000;
871
- for (const session of runningSessions) {
872
- const channelId = conversationIdOf(session.sessionKey);
873
- const channelName = this.channels.get(channelId)?.name;
874
- const elapsed = Math.floor((Date.now() - session.startedAt) / 60000);
875
- const elapsedStr = elapsed < 1 ? "<1 min" : `${elapsed} min`;
876
- const lastActivity = session.lastActivityAt ? Date.now() - session.lastActivityAt : 0;
877
- const isStuck = lastActivity > stuckThresholdMs;
878
- let statusLine = `${isStuck ? "_stuck_" : "_running_"} · ${elapsedStr}`;
879
- if (session.currentTool)
880
- statusLine += ` · ${session.currentTool}`;
881
- if (isStuck)
882
- statusLine += ` · idle ${Math.floor(lastActivity / 60000)}m`;
883
- blocks.push({
884
- type: "context",
885
- elements: [
886
- {
887
- type: "mrkdwn",
888
- text: `*${channelName ? `#${channelName}` : channelId}* · ${statusLine}`,
889
- },
890
- ],
891
- });
892
- if (isStuck) {
893
- blocks.push({
894
- type: "context",
895
- elements: [
896
- { type: "mrkdwn", text: " " },
897
- {
898
- type: "button",
899
- text: { type: "plain_text", text: "Force Stop", emoji: true },
900
- action_id: `force_stop_${session.sessionKey.replace(/:/g, "_")}`,
901
- value: session.sessionKey,
902
- style: "danger",
903
- },
904
- ],
905
- });
906
- }
907
- }
908
- }
909
- appendScheduledJobs(blocks, dmChannelId) {
910
- const periodicEvents = dmChannelId && this.eventScheduler
911
- ? this.eventScheduler.periodicEvents(createOfficeAddress("slack", dmChannelId))
912
- : [];
913
- blocks.push({ type: "divider" }, {
914
- type: "header",
915
- text: {
916
- type: "plain_text",
917
- text: `Scheduled Jobs (${periodicEvents.length})`,
918
- emoji: true,
919
- },
920
- });
921
- if (periodicEvents.length === 0) {
922
- blocks.push({
923
- type: "context",
924
- elements: [{ type: "mrkdwn", text: "_No scheduled jobs._" }],
925
- });
926
- return;
927
- }
928
- for (const event of periodicEvents) {
929
- const channel = event.platform === "slack" ? this.channels.get(event.conversationId) : undefined;
930
- const channelId = channel ? `#${channel.name}` : event.conversationId;
931
- const channelLabel = `${event.platform}:${channelId}`;
932
- const nextRun = event.nextRun
933
- ? new Date(event.nextRun).toLocaleString("en-US", {
934
- month: "short",
935
- day: "numeric",
936
- hour: "2-digit",
937
- minute: "2-digit",
938
- })
939
- : "—";
940
- blocks.push({
941
- type: "section",
942
- text: {
943
- type: "mrkdwn",
944
- text: `*${event.text}*\n└ \`${event.schedule}\` · ${channelLabel} · Next: ${nextRun}`,
945
- },
946
- });
947
- }
948
- }
949
- buildHomeView(dmChannelId) {
950
- const blocks = [
951
- {
952
- type: "section",
953
- text: {
954
- type: "mrkdwn",
955
- text: `*${PRODUCT_NAME}*\nStart a new task or check on running work.`,
956
- },
957
- accessory: {
958
- type: "image",
959
- image_url: "https://media1.tenor.com/m/lfDATg4Bhc0AAAAC/happy-cat.gif",
960
- alt_text: PRODUCT_NAME,
961
- },
962
- },
963
- ];
964
- this.appendRunningTasks(blocks);
965
- this.appendScheduledJobs(blocks, dmChannelId);
966
- blocks.push({ type: "divider" }, {
967
- type: "context",
968
- elements: [
969
- { type: "mrkdwn", text: "💡 @mention in a channel or send a DM to start a new task" },
970
- ],
971
- });
972
- return { type: "home", blocks: blocks };
973
- }
974
838
  createCommandAdapters(input) {
975
839
  const { conversationId, userId, userName, text, ts, ...options } = input;
976
840
  const message = createConversationMessage({
@@ -1379,22 +1243,9 @@ export class SlackMessagingBot {
1379
1243
  handleAppHomeOpened({ event, ack }) {
1380
1244
  const e = event;
1381
1245
  ack();
1382
- if (e.tab === "messages") {
1383
- if (e.channel) {
1384
- void handleAgentDmOpened(this.assistantOps(), this.assistantThreads, e.channel, e.context);
1385
- }
1246
+ if (e.tab !== "messages" || !e.channel)
1386
1247
  return;
1387
- }
1388
- if (e.tab !== "home")
1389
- return;
1390
- this.webClient.views
1391
- .publish({
1392
- user_id: e.user,
1393
- view: this.buildHomeView(e.channel),
1394
- })
1395
- .catch((err) => {
1396
- log.logWarning(`Failed to publish App Home view`, String(err));
1397
- });
1248
+ void handleAgentDmOpened(this.assistantOps(), this.assistantThreads, e.channel, e.context);
1398
1249
  }
1399
1250
  async handleBlockAction({ body, ack, }) {
1400
1251
  const action = body.actions?.[0];
@@ -1402,32 +1253,8 @@ export class SlackMessagingBot {
1402
1253
  ack();
1403
1254
  return;
1404
1255
  }
1405
- if (!action.action_id?.startsWith("force_stop_")) {
1406
- ack();
1407
- await this.handleSlackInteraction(body, action);
1408
- return;
1409
- }
1410
1256
  ack();
1411
- const sessionKey = action.value;
1412
- if (!sessionKey) {
1413
- log.logWarning("[Force Stop] Ignored a button without a session key", action.action_id);
1414
- return;
1415
- }
1416
- const userId = body.user?.id;
1417
- const channelId = body.container?.channel_id || conversationIdOf(sessionKey);
1418
- log.logInfo(`[Force Stop] User ${userId} requested force stop for ${sessionKey}`);
1419
- this.handler.forceStop(createOfficeAddress("slack", channelId), sessionKey);
1420
- await this.postMessage(channelId, formatForceStopped("slack", userId ?? "unknown"));
1421
- if (userId) {
1422
- this.openDirectConversation(userId)
1423
- .then((dmChannelId) => this.webClient.views.publish({
1424
- user_id: userId,
1425
- view: this.buildHomeView(dmChannelId),
1426
- }))
1427
- .catch((err) => {
1428
- log.logWarning(`Failed to refresh App Home view`, String(err));
1429
- });
1430
- }
1257
+ await this.handleSlackInteraction(body, action);
1431
1258
  }
1432
1259
  async handleSlackInteraction(body, action) {
1433
1260
  const container = body.container ?? {};