@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.
- package/CHANGELOG.md +31 -1
- package/dist/adapters/messages.d.ts +1 -3
- package/dist/adapters/messages.d.ts.map +1 -1
- package/dist/adapters/messages.js +2 -8
- package/dist/adapters/messages.js.map +1 -1
- package/dist/adapters/slack/app-config.js +1 -1
- package/dist/adapters/slack/app-config.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +2 -5
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +39 -212
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/types.d.ts +0 -1
- package/dist/adapters/slack/types.d.ts.map +1 -1
- package/dist/adapters/slack/types.js.map +1 -1
- package/dist/harness/continued-run.d.ts +3 -0
- package/dist/harness/continued-run.d.ts.map +1 -0
- package/dist/harness/continued-run.js +8 -0
- package/dist/harness/continued-run.js.map +1 -0
- package/dist/harness/prompt.d.ts.map +1 -1
- package/dist/harness/prompt.js +1 -0
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +14 -7
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/session.d.ts +3 -0
- package/dist/harness/session.d.ts.map +1 -1
- package/dist/harness/session.js +14 -1
- package/dist/harness/session.js.map +1 -1
- package/dist/harness/tools/codemode.js +1 -1
- package/dist/harness/tools/codemode.js.map +1 -1
- package/dist/harness/tools/jev-browser.d.ts.map +1 -1
- package/dist/harness/tools/jev-browser.js +31 -6
- package/dist/harness/tools/jev-browser.js.map +1 -1
- package/dist/harness/tools/task.d.ts +0 -2
- package/dist/harness/tools/task.d.ts.map +1 -1
- package/dist/harness/tools/task.js +1 -6
- package/dist/harness/tools/task.js.map +1 -1
- package/dist/runtime/conversation-runtime.d.ts.map +1 -1
- package/dist/runtime/conversation-runtime.js +6 -3
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/sessions/session-store.d.ts +4 -3
- package/dist/sessions/session-store.d.ts.map +1 -1
- package/dist/sessions/session-store.js +92 -47
- package/dist/sessions/session-store.js.map +1 -1
- package/dist/sessions/types.d.ts +0 -1
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- 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.
|
|
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
|
|
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,
|
|
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
|
|
31
|
-
return formatItalic(resolvePlatformName(source), "Restarted for an update; continuing
|
|
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,
|
|
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"]}
|
|
@@ -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":"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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: 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
|
|
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":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/bot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAUxE,OAAO,KAAK,EACV,YAAY,EAEZ,iBAAiB,EACjB,qBAAqB,EAIrB,aAAa,EAGd,MAAM,gBAAgB,CAAC;AAexB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,OAAO,KAAK,EAGV,YAAY,EAEZ,wBAAwB,EAGxB,SAAS,EAKT,eAAe,EAChB,MAAM,YAAY,CAAC;AAyBpB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAgEzD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAwB,GAAG,MAAM,EAAE,CAOrF;AAwDD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnD;AAmBD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM5D;AAwBD,qBAAa,iBAAkB,YAAW,YAAY;IACpD,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAY;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoC;IAClE,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,SAAS,CAAuB;IAExC,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,gBAAgB,CAAiC;IACzD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAqB;IACvD,OAAO,CAAC,uBAAuB,CAAS;IACxC,OAAO,CAAC,cAAc,CAA+B;IAErD,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,aAAa;IAkErB,YAAY,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,wBAAwB,EAmB3E;IAED,iBAAiB,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,CAEjD;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CA+B3B;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ1B;IAED,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAE7C;IAED,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEtD;IAED,WAAW,IAAI,SAAS,EAAE,CAEzB;IAED,cAAc,IAAI,YAAY,EAAE,CAE/B;IAED,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,eAAe;IAIjB,WAAW,CACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAYjB;IAEK,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUlF;IAEK,aAAa,CACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,IAAI,CAAC,CAUf;IAEK,mBAAmB,CACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAEf;IAEK,iBAAiB,CACrB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAWjB;IAEK,mBAAmB,CACvB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,IAAI,CAAC,CAIf;IAEK,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErF;IAEK,qBAAqB,CACzB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;KAAE,GACtC,OAAO,CAAC,IAAI,CAAC,CAUf;YAEa,sBAAsB;IAW9B,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW5E;IAED,qBAAqB,IAAI,OAAO,CAE/B;IAEK,kBAAkB,CACtB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EACjB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,CAgBjB;IAEK,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIlF;YAEa,iBAAiB;IAUzB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIlE;IAEK,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9D;IAEK,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBzF;IAEK,4BAA4B,CAChC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,eAAe,EAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAef;IAEK,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQvF;IAED,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,4BAA4B;IAWpC,OAAO,CAAC,8BAA8B;IAqBhC,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAIjB;IAEK,kBAAkB,CACtB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,MAAM,CAAC,CAEjB;IAEK,UAAU,CACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAYf;IAED,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAE9D;IAED,cAAc,CACZ,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,QAAQ,CAAC,EAAE,MAAM,EACjB,EAAE,WAAW,EAAE,MAAM,EAAE,GAAE;QAAE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,CAAA;KAAO,GAC3E,IAAI,CASN;IAED,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAQ3E;IAED,gBAAgB,IAAI,aAAa,CAkBhC;IAED,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAoE9C;IAED,OAAO,CAAC,QAAQ;YAUF,eAAe;IAU7B,OAAO,CAAC,cAAc;YAmCR,uBAAuB;IAmCrC,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,YAAY;YAIN,oBAAoB;IAWlC,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,yBAAyB;IAgDjC,OAAO,CAAC,qBAAqB;IAoE7B,OAAO,CAAC,sBAAsB;YA6DhB,iBAAiB;IAuB/B,OAAO,CAAC,kBAAkB;IAoC1B,OAAO,CAAC,YAAY;YAWN,gBAAgB;IA6D9B,OAAO,CAAC,iBAAiB;YAiCX,iBAAiB;YAkEjB,oBAAoB;YAuCpB,kBAAkB;YA0FlB,kBAAkB;IAmChC,OAAO,CAAC,mBAAmB;YAOb,iBAAiB;YAiBjB,sBAAsB;YAqFtB,kBAAkB;YA8BlB,iBAAiB;YAmBjB,cAAc;YA0Bd,8BAA8B;YAoC9B,qBAAqB;IAiBnC,OAAO,CAAC,qBAAqB;YAaf,eAAe;YAmEf,mBAAmB;YA+BnB,UAAU;YA0BV,aAAa;CAgD5B"}
|
|
@@ -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 {
|
|
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 {
|
|
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
|
|
288
|
-
|
|
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
|
|
708
|
-
|
|
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
|
|
717
|
-
|
|
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
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
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
|
|
745
|
-
ts:
|
|
746
|
-
thread_ts:
|
|
723
|
+
user,
|
|
724
|
+
ts: continuedRunId(sessionKey),
|
|
725
|
+
thread_ts: threadTs,
|
|
747
726
|
sessionKey,
|
|
748
|
-
text:
|
|
727
|
+
text: formatContinuingRun(this),
|
|
749
728
|
});
|
|
750
|
-
|
|
729
|
+
continued += 1;
|
|
751
730
|
}
|
|
752
731
|
}
|
|
753
|
-
log.logInfo(`
|
|
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
|
|
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
|
-
|
|
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 ?? {};
|