@geminixiang/mikan 1.4.0 → 1.5.0
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 +36 -0
- package/dist/adapters/commands/desktop.d.ts +5 -0
- package/dist/adapters/commands/desktop.d.ts.map +1 -0
- package/dist/adapters/commands/desktop.js +58 -0
- package/dist/adapters/commands/desktop.js.map +1 -0
- package/dist/adapters/commands/manifest.d.ts.map +1 -1
- package/dist/adapters/commands/manifest.js +8 -0
- package/dist/adapters/commands/manifest.js.map +1 -1
- package/dist/adapters/commands/registry.d.ts.map +1 -1
- package/dist/adapters/commands/registry.js +2 -0
- package/dist/adapters/commands/registry.js.map +1 -1
- package/dist/adapters/commands/types.d.ts +3 -1
- package/dist/adapters/commands/types.d.ts.map +1 -1
- package/dist/adapters/commands/types.js.map +1 -1
- package/dist/adapters/messages.d.ts +0 -1
- package/dist/adapters/messages.d.ts.map +1 -1
- package/dist/adapters/messages.js +0 -3
- package/dist/adapters/messages.js.map +1 -1
- package/dist/adapters/slack/app-config.d.ts +27 -0
- package/dist/adapters/slack/app-config.d.ts.map +1 -0
- package/dist/adapters/slack/app-config.js +241 -0
- package/dist/adapters/slack/app-config.js.map +1 -0
- package/dist/adapters/slack/bot.d.ts +0 -3
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +4 -163
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/types.d.ts +46 -2
- package/dist/adapters/slack/types.d.ts.map +1 -1
- package/dist/adapters/slack/types.js.map +1 -1
- package/dist/adapters/web/desktop/index.d.ts +16 -0
- package/dist/adapters/web/desktop/index.d.ts.map +1 -0
- package/dist/adapters/web/desktop/index.js +163 -0
- package/dist/adapters/web/desktop/index.js.map +1 -0
- package/dist/adapters/web/desktop/page.d.ts +2 -0
- package/dist/adapters/web/desktop/page.d.ts.map +1 -0
- package/dist/adapters/web/desktop/page.js +83 -0
- package/dist/adapters/web/desktop/page.js.map +1 -0
- package/dist/adapters/web/desktop/types.d.ts +8 -0
- package/dist/adapters/web/desktop/types.d.ts.map +1 -0
- package/dist/adapters/web/desktop/types.js +2 -0
- package/dist/adapters/web/desktop/types.js.map +1 -0
- package/dist/adapters/web/server.d.ts +2 -0
- package/dist/adapters/web/server.d.ts.map +1 -1
- package/dist/adapters/web/server.js +19 -0
- package/dist/adapters/web/server.js.map +1 -1
- package/dist/cli/boot.d.ts.map +1 -1
- package/dist/cli/boot.js +4 -1
- package/dist/cli/boot.js.map +1 -1
- package/dist/cli/onboard.d.ts +3 -0
- package/dist/cli/onboard.d.ts.map +1 -1
- package/dist/cli/onboard.js +79 -3
- package/dist/cli/onboard.js.map +1 -1
- package/dist/cli/slack.d.ts +9 -0
- package/dist/cli/slack.d.ts.map +1 -0
- package/dist/cli/slack.js +96 -0
- package/dist/cli/slack.js.map +1 -0
- package/dist/cli/types.d.ts +2 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli/types.js.map +1 -1
- package/dist/harness/desktop.d.ts +16 -0
- package/dist/harness/desktop.d.ts.map +1 -0
- package/dist/harness/desktop.js +6 -0
- package/dist/harness/desktop.js.map +1 -0
- package/dist/harness/execution-resolver.d.ts +1 -0
- package/dist/harness/execution-resolver.d.ts.map +1 -1
- package/dist/harness/execution-resolver.js +5 -0
- package/dist/harness/execution-resolver.js.map +1 -1
- package/dist/harness/presenter.d.ts.map +1 -1
- package/dist/harness/presenter.js +6 -1
- package/dist/harness/presenter.js.map +1 -1
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +22 -1
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/session.d.ts +1 -1
- package/dist/harness/session.d.ts.map +1 -1
- package/dist/harness/session.js +30 -9
- package/dist/harness/session.js.map +1 -1
- package/dist/harness/tools/codemode.d.ts.map +1 -1
- package/dist/harness/tools/codemode.js +2 -2
- package/dist/harness/tools/codemode.js.map +1 -1
- package/dist/harness/tools/index.d.ts +2 -2
- package/dist/harness/tools/index.d.ts.map +1 -1
- package/dist/harness/tools/index.js +10 -2
- package/dist/harness/tools/index.js.map +1 -1
- package/dist/harness/tools/jev-browser.d.ts +12 -1
- package/dist/harness/tools/jev-browser.d.ts.map +1 -1
- package/dist/harness/tools/jev-browser.js +189 -30
- package/dist/harness/tools/jev-browser.js.map +1 -1
- package/dist/harness/tools/pi-tools.d.ts.map +1 -1
- package/dist/harness/tools/pi-tools.js +2 -1
- package/dist/harness/tools/pi-tools.js.map +1 -1
- package/dist/harness/tools/types.d.ts +4 -0
- package/dist/harness/tools/types.d.ts.map +1 -1
- package/dist/harness/tools/types.js.map +1 -1
- package/dist/harness/types.d.ts +2 -1
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/main.js +29 -0
- package/dist/main.js.map +1 -1
- package/dist/runtime/conversation-runtime.js +7 -0
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/sandbox/desktop.d.ts +30 -0
- package/dist/sandbox/desktop.d.ts.map +1 -0
- package/dist/sandbox/desktop.js +112 -0
- package/dist/sandbox/desktop.js.map +1 -0
- package/dist/sandbox/provisioner.d.ts +4 -1
- package/dist/sandbox/provisioner.d.ts.map +1 -1
- package/dist/sandbox/provisioner.js +21 -0
- package/dist/sandbox/provisioner.js.map +1 -1
- package/dist/sandbox/types.d.ts +19 -0
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/sandbox/types.js.map +1 -1
- package/dist/types.d.ts +17 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +9 -8
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,42 @@ change in a minor release.
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [1.5.0] - 2026-10-13
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- `/pi-desktop` (`/desktop` on other platforms) sends a private 24-hour link to the conversation's
|
|
19
|
+
desktop in the managed `oci` sandbox: watch or use the browser the agent drives, open its tabs,
|
|
20
|
+
DevTools, or a terminal. "Take control" pauses the agent's browser until you hand it back, and the
|
|
21
|
+
agent can hand you a step such as signing in with `jev_browser`'s `handOff`, which posts the step
|
|
22
|
+
with a link and ends its turn. The desktop starts on the first link, stops with the sandbox's idle
|
|
23
|
+
stop, and keeps the sandbox from stopping while someone has it open. It needs the sandbox image of
|
|
24
|
+
this release; an office whose sandbox still runs an older image gets it after the sandbox idles out.
|
|
25
|
+
Register `/pi-desktop` in the Slack app manifest, or let mikan do it (next entry).
|
|
26
|
+
- mikan creates and updates its Slack app (ADR 0026). With a Slack app configuration token,
|
|
27
|
+
`mikan onboard` creates the app from mikan's manifest, and every start replaces the app's
|
|
28
|
+
configuration with the manifest of the running release, so new slash commands, scopes, and events
|
|
29
|
+
need no edit in Slack's settings. Store a token for an existing app with `mikan slack token`, and
|
|
30
|
+
set the app's and bot's name and the description with `mikan slack set`. Settings added by hand in Slack are
|
|
31
|
+
removed. When a release adds a scope, mikan DMs the token's owner a reinstall link. Without a
|
|
32
|
+
token nothing changes.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- `jev_browser` closes only tabs it opened when it passes its three-tab limit, so tabs a person
|
|
37
|
+
opened stay open.
|
|
38
|
+
- The sandbox image adds `sway`, `wayvnc`, and `foot` (about 1 MB) and the `mikan-desktop` script.
|
|
39
|
+
- Upgraded Pi to 1.2.0. Pi 1.2 removed an export mikan 1.4.0 imports, so a fresh install of 1.4.0
|
|
40
|
+
now fails to start; this release works with it. A nonzero `bash` exit is now an error result that
|
|
41
|
+
carries the output and the exit code, instead of a thrown error.
|
|
42
|
+
|
|
43
|
+
### Removed
|
|
44
|
+
|
|
45
|
+
- The Slack App Home tab, which listed running tasks and scheduled jobs with force-stop buttons.
|
|
46
|
+
mikan's Slack manifest turns the tab off; an app synced from a configuration token loses it on
|
|
47
|
+
the next start, and an app configured by hand keeps showing an empty tab until it is turned off in
|
|
48
|
+
Slack's App Home settings. Use the stop command or the Admin portal to stop work.
|
|
49
|
+
|
|
14
50
|
## [1.4.0] - 2026-10-11
|
|
15
51
|
|
|
16
52
|
### Added
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop.d.ts","sourceRoot":"","sources":["../../../src/adapters/commands/desktop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAMjE,qBAAa,qBAAsB,YAAW,cAAc;IACpD,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAuDzD;CACF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { commandForms, matchCommand } from "./manifest.js";
|
|
2
|
+
import { portalNotConfiguredLines, replySummaryPrivately } from "./utils.js";
|
|
3
|
+
const DESKTOP_COMMANDS = commandForms("desktop");
|
|
4
|
+
const TITLE = "Desktop";
|
|
5
|
+
export class DesktopCommandHandler {
|
|
6
|
+
async tryHandle(context) {
|
|
7
|
+
if (!matchCommand(context.commandText, DESKTOP_COMMANDS))
|
|
8
|
+
return false;
|
|
9
|
+
if (!context.privateConversation &&
|
|
10
|
+
!context.bot.postPrivate &&
|
|
11
|
+
!context.bot.postPrivateDiagnostic) {
|
|
12
|
+
await replySummaryPrivately(context, TITLE, [
|
|
13
|
+
"A desktop link gives full use of this conversation's sandbox, so it is sent only privately. Ask for it in a direct message with the bot.",
|
|
14
|
+
]);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
const { sandbox, openDesktop, desktopTokenStore, portalBaseUrl } = context.services;
|
|
18
|
+
if (sandbox.type !== "oci" || !openDesktop) {
|
|
19
|
+
await replySummaryPrivately(context, TITLE, [
|
|
20
|
+
"The desktop runs in a sandbox that mikan manages; start mikan with --sandbox=oci to use it.",
|
|
21
|
+
]);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
if (!portalBaseUrl || !desktopTokenStore) {
|
|
25
|
+
await replySummaryPrivately(context, TITLE, portalNotConfiguredLines("Desktop"));
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
const started = await openDesktop({
|
|
29
|
+
address: context.address,
|
|
30
|
+
userId: context.platformUserId,
|
|
31
|
+
trustModel: context.messagingInfo.trustModel,
|
|
32
|
+
});
|
|
33
|
+
if (started === "outdated-image") {
|
|
34
|
+
await replySummaryPrivately(context, TITLE, [
|
|
35
|
+
"This conversation's sandbox is still running an older sandbox image without the desktop.",
|
|
36
|
+
"It moves to the current image once it has been idle and stops; ask again after that.",
|
|
37
|
+
]);
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
if (started === "stopped") {
|
|
41
|
+
await replySummaryPrivately(context, TITLE, [
|
|
42
|
+
"This conversation's sandbox could not start. Try again, or ask the operator to check it.",
|
|
43
|
+
]);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
const { token } = desktopTokenStore.create({
|
|
47
|
+
platform: context.platform,
|
|
48
|
+
platformUserId: context.platformUserId,
|
|
49
|
+
office: context.services.workspace.office(context.address),
|
|
50
|
+
});
|
|
51
|
+
await replySummaryPrivately(context, TITLE, [
|
|
52
|
+
`${portalBaseUrl}/desktop?token=${token}`,
|
|
53
|
+
"Expires: 24 hours",
|
|
54
|
+
]);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=desktop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop.js","sourceRoot":"","sources":["../../../src/adapters/commands/desktop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE3D,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE7E,MAAM,gBAAgB,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;AACjD,MAAM,KAAK,GAAG,SAAS,CAAC;AAExB,MAAM,OAAO,qBAAqB;IAChC,KAAK,CAAC,SAAS,CAAC,OAAuB;QACrC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,gBAAgB,CAAC;YAAE,OAAO,KAAK,CAAC;QAEvE,IACE,CAAC,OAAO,CAAC,mBAAmB;YAC5B,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW;YACxB,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAClC,CAAC;YACD,MAAM,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE;gBAC1C,0IAA0I;aAC3I,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;QACpF,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE;gBAC1C,6FAA6F;aAC9F,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC,aAAa,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzC,MAAM,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE,wBAAwB,CAAC,SAAS,CAAC,CAAC,CAAC;YACjF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC;YAChC,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM,EAAE,OAAO,CAAC,cAAc;YAC9B,UAAU,EAAE,OAAO,CAAC,aAAa,CAAC,UAAU;SAC7C,CAAC,CAAC;QACH,IAAI,OAAO,KAAK,gBAAgB,EAAE,CAAC;YACjC,MAAM,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE;gBAC1C,0FAA0F;gBAC1F,sFAAsF;aACvF,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE;gBAC1C,0FAA0F;aAC3F,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC;YACzC,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;SAC3D,CAAC,CAAC;QACH,MAAM,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE;YAC1C,GAAG,aAAa,kBAAkB,KAAK,EAAE;YACzC,mBAAmB;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF","sourcesContent":["import { commandForms, matchCommand } from \"./manifest.js\";\nimport type { CommandContext, CommandHandler } from \"./types.js\";\nimport { portalNotConfiguredLines, replySummaryPrivately } from \"./utils.js\";\n\nconst DESKTOP_COMMANDS = commandForms(\"desktop\");\nconst TITLE = \"Desktop\";\n\nexport class DesktopCommandHandler implements CommandHandler {\n async tryHandle(context: CommandContext): Promise<boolean> {\n if (!matchCommand(context.commandText, DESKTOP_COMMANDS)) return false;\n\n if (\n !context.privateConversation &&\n !context.bot.postPrivate &&\n !context.bot.postPrivateDiagnostic\n ) {\n await replySummaryPrivately(context, TITLE, [\n \"A desktop link gives full use of this conversation's sandbox, so it is sent only privately. Ask for it in a direct message with the bot.\",\n ]);\n return true;\n }\n\n const { sandbox, openDesktop, desktopTokenStore, portalBaseUrl } = context.services;\n if (sandbox.type !== \"oci\" || !openDesktop) {\n await replySummaryPrivately(context, TITLE, [\n \"The desktop runs in a sandbox that mikan manages; start mikan with --sandbox=oci to use it.\",\n ]);\n return true;\n }\n if (!portalBaseUrl || !desktopTokenStore) {\n await replySummaryPrivately(context, TITLE, portalNotConfiguredLines(\"Desktop\"));\n return true;\n }\n\n const started = await openDesktop({\n address: context.address,\n userId: context.platformUserId,\n trustModel: context.messagingInfo.trustModel,\n });\n if (started === \"outdated-image\") {\n await replySummaryPrivately(context, TITLE, [\n \"This conversation's sandbox is still running an older sandbox image without the desktop.\",\n \"It moves to the current image once it has been idle and stops; ask again after that.\",\n ]);\n return true;\n }\n if (started === \"stopped\") {\n await replySummaryPrivately(context, TITLE, [\n \"This conversation's sandbox could not start. Try again, or ask the operator to check it.\",\n ]);\n return true;\n }\n\n const { token } = desktopTokenStore.create({\n platform: context.platform,\n platformUserId: context.platformUserId,\n office: context.services.workspace.office(context.address),\n });\n await replySummaryPrivately(context, TITLE, [\n `${portalBaseUrl}/desktop?token=${token}`,\n \"Expires: 24 hours\",\n ]);\n return true;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/adapters/commands/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,gBAAgB,EAAE,SAAS,oBAAoB,
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/adapters/commands/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,gBAAgB,EAAE,SAAS,oBAAoB,EAwG3D,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,CAIvE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAM1D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAG5D;AAED,wBAAgB,mBAAmB,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EAAE,CAKhF;AAED,wBAAgB,YAAY,CAAC,OAAO,SAAS,MAAM,EACjD,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,SAAS,OAAO,EAAE,EAC3B,OAAO,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GACnC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAQ7C;AASD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD"}
|
|
@@ -16,6 +16,14 @@ export const COMMAND_MANIFEST = [
|
|
|
16
16
|
discord: true,
|
|
17
17
|
telegramMenu: {},
|
|
18
18
|
},
|
|
19
|
+
{
|
|
20
|
+
name: "desktop",
|
|
21
|
+
description: "Open this conversation's desktop to watch or use its browser",
|
|
22
|
+
slackCommand: "/pi-desktop",
|
|
23
|
+
slackRoute: {},
|
|
24
|
+
discord: true,
|
|
25
|
+
telegramMenu: {},
|
|
26
|
+
},
|
|
19
27
|
{
|
|
20
28
|
name: "model",
|
|
21
29
|
description: "Switch this conversation's LLM model",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/adapters/commands/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CommandManifestEntry } from \"./types.js\";\n\nexport const COMMAND_MANIFEST: readonly CommandManifestEntry[] = [\n {\n name: \"login\",\n description: \"Store credentials in your private vault\",\n slackCommand: \"/pi-login\",\n slackRoute: { includeText: true, privateCommand: true },\n discord: true,\n telegramMenu: {},\n },\n {\n name: \"session\",\n description: \"Open the current session in the web viewer\",\n bare: true,\n slackCommand: \"/pi-session\",\n slackRoute: { thread: true },\n discord: true,\n telegramMenu: {},\n },\n {\n name: \"model\",\n description: \"Switch this conversation's LLM model\",\n arg: {\n name: \"model\",\n description: \"provider/model[:thinking], e.g. anthropic/claude-sonnet-4-6:off\",\n required: false,\n },\n slackCommand: \"/pi-model\",\n slackRoute: { includeText: true },\n discord: true,\n telegramMenu: {},\n },\n {\n name: \"sandbox\",\n description: \"Show sandbox status or boost limits\",\n arg: {\n name: \"action\",\n description: \"'boost' temporarily applies the configured boost limits\",\n required: false,\n },\n slackCommand: \"/pi-sandbox\",\n slackRoute: { includeText: true },\n discord: true,\n telegramMenu: { description: \"Show or boost sandbox limits\" },\n telegramCommand: true,\n },\n {\n name: \"autoreply\",\n aliases: [\"auto-reply\"],\n description: \"Enable, disable, or Jev-assist replies without mentions\",\n arg: {\n name: \"state\",\n description: \"on, off, or jev\",\n required: true,\n },\n slackCommand: \"/pi-auto-reply\",\n slackRoute: { includeText: true },\n },\n {\n name: \"stop\",\n description: \"Stop the current conversation\",\n magicWord: true,\n discord: true,\n telegramMenu: { description: \"Stop ongoing conversation\" },\n },\n {\n name: \"new\",\n description: \"Reset conversation history and start fresh\",\n slackCommand: \"/pi-new\",\n slackRoute: {},\n discord: true,\n telegramMenu: {},\n telegramCommand: true,\n },\n {\n name: \"compact\",\n description: \"Summarize older messages to free up context\",\n arg: {\n name: \"instructions\",\n description: \"What the summary should keep\",\n required: false,\n },\n slackCommand: \"/pi-compact\",\n slackRoute: { includeText: true },\n discord: true,\n telegramMenu: {},\n telegramCommand: true,\n },\n {\n name: \"admin\",\n description: \"Open the admin portal\",\n slackCommand: \"/pi-admin\",\n slackRoute: { thread: true },\n discord: true,\n telegramMenu: {},\n telegramCommand: true,\n },\n];\n\nexport function commandManifestEntry(name: string): CommandManifestEntry {\n const entry = COMMAND_MANIFEST.find((candidate) => candidate.name === name);\n if (!entry) throw new Error(`Unknown command in manifest: ${name}`);\n return entry;\n}\n\nexport function slashForms(name: string): readonly string[] {\n const entry = commandManifestEntry(name);\n return [entry.name, ...(entry.aliases ?? [])].flatMap((spelling) => [\n `/${spelling}`,\n `/pi-${spelling}`,\n ]);\n}\n\nexport function commandForms(name: string): readonly string[] {\n const entry = commandManifestEntry(name);\n return [...(entry.bare ? [entry.name] : []), ...slashForms(name)];\n}\n\nexport function telegramCommandMenu(): { command: string; description: string }[] {\n return COMMAND_MANIFEST.filter((entry) => entry.telegramMenu).map((entry) => ({\n command: entry.name,\n description: entry.telegramMenu?.description ?? entry.description,\n }));\n}\n\nexport function matchCommand<Command extends string>(\n text: string,\n aliases: readonly Command[],\n options?: { stripMention?: boolean },\n): { command: Command; args: string[] } | null {\n const tokens = text.trim().split(/\\s+/).filter(Boolean);\n const first = tokens[0];\n if (first === undefined) return null;\n\n const token = options?.stripMention ? first.replace(/@\\w+$/i, \"\") : first;\n const command = token.toLowerCase() as Command;\n return aliases.includes(command) ? { command, args: tokens.slice(1) } : null;\n}\n\nconst COMMAND_NAMES = COMMAND_MANIFEST.flatMap((entry) => [entry.name].concat(entry.aliases ?? []));\n\nconst COMMAND_TEXT_PATTERN = new RegExp(\n `^\\\\/(?:pi-[\\\\w-]+|${COMMAND_NAMES.join(\"|\")})(?:@\\\\w+)?(?:\\\\s|$)`,\n \"i\",\n);\n\nexport function isCommandText(text: string): boolean {\n return COMMAND_TEXT_PATTERN.test(text.trim());\n}\n"]}
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/adapters/commands/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CommandManifestEntry } from \"./types.js\";\n\nexport const COMMAND_MANIFEST: readonly CommandManifestEntry[] = [\n {\n name: \"login\",\n description: \"Store credentials in your private vault\",\n slackCommand: \"/pi-login\",\n slackRoute: { includeText: true, privateCommand: true },\n discord: true,\n telegramMenu: {},\n },\n {\n name: \"session\",\n description: \"Open the current session in the web viewer\",\n bare: true,\n slackCommand: \"/pi-session\",\n slackRoute: { thread: true },\n discord: true,\n telegramMenu: {},\n },\n {\n name: \"desktop\",\n description: \"Open this conversation's desktop to watch or use its browser\",\n slackCommand: \"/pi-desktop\",\n slackRoute: {},\n discord: true,\n telegramMenu: {},\n },\n {\n name: \"model\",\n description: \"Switch this conversation's LLM model\",\n arg: {\n name: \"model\",\n description: \"provider/model[:thinking], e.g. anthropic/claude-sonnet-4-6:off\",\n required: false,\n },\n slackCommand: \"/pi-model\",\n slackRoute: { includeText: true },\n discord: true,\n telegramMenu: {},\n },\n {\n name: \"sandbox\",\n description: \"Show sandbox status or boost limits\",\n arg: {\n name: \"action\",\n description: \"'boost' temporarily applies the configured boost limits\",\n required: false,\n },\n slackCommand: \"/pi-sandbox\",\n slackRoute: { includeText: true },\n discord: true,\n telegramMenu: { description: \"Show or boost sandbox limits\" },\n telegramCommand: true,\n },\n {\n name: \"autoreply\",\n aliases: [\"auto-reply\"],\n description: \"Enable, disable, or Jev-assist replies without mentions\",\n arg: {\n name: \"state\",\n description: \"on, off, or jev\",\n required: true,\n },\n slackCommand: \"/pi-auto-reply\",\n slackRoute: { includeText: true },\n },\n {\n name: \"stop\",\n description: \"Stop the current conversation\",\n magicWord: true,\n discord: true,\n telegramMenu: { description: \"Stop ongoing conversation\" },\n },\n {\n name: \"new\",\n description: \"Reset conversation history and start fresh\",\n slackCommand: \"/pi-new\",\n slackRoute: {},\n discord: true,\n telegramMenu: {},\n telegramCommand: true,\n },\n {\n name: \"compact\",\n description: \"Summarize older messages to free up context\",\n arg: {\n name: \"instructions\",\n description: \"What the summary should keep\",\n required: false,\n },\n slackCommand: \"/pi-compact\",\n slackRoute: { includeText: true },\n discord: true,\n telegramMenu: {},\n telegramCommand: true,\n },\n {\n name: \"admin\",\n description: \"Open the admin portal\",\n slackCommand: \"/pi-admin\",\n slackRoute: { thread: true },\n discord: true,\n telegramMenu: {},\n telegramCommand: true,\n },\n];\n\nexport function commandManifestEntry(name: string): CommandManifestEntry {\n const entry = COMMAND_MANIFEST.find((candidate) => candidate.name === name);\n if (!entry) throw new Error(`Unknown command in manifest: ${name}`);\n return entry;\n}\n\nexport function slashForms(name: string): readonly string[] {\n const entry = commandManifestEntry(name);\n return [entry.name, ...(entry.aliases ?? [])].flatMap((spelling) => [\n `/${spelling}`,\n `/pi-${spelling}`,\n ]);\n}\n\nexport function commandForms(name: string): readonly string[] {\n const entry = commandManifestEntry(name);\n return [...(entry.bare ? [entry.name] : []), ...slashForms(name)];\n}\n\nexport function telegramCommandMenu(): { command: string; description: string }[] {\n return COMMAND_MANIFEST.filter((entry) => entry.telegramMenu).map((entry) => ({\n command: entry.name,\n description: entry.telegramMenu?.description ?? entry.description,\n }));\n}\n\nexport function matchCommand<Command extends string>(\n text: string,\n aliases: readonly Command[],\n options?: { stripMention?: boolean },\n): { command: Command; args: string[] } | null {\n const tokens = text.trim().split(/\\s+/).filter(Boolean);\n const first = tokens[0];\n if (first === undefined) return null;\n\n const token = options?.stripMention ? first.replace(/@\\w+$/i, \"\") : first;\n const command = token.toLowerCase() as Command;\n return aliases.includes(command) ? { command, args: tokens.slice(1) } : null;\n}\n\nconst COMMAND_NAMES = COMMAND_MANIFEST.flatMap((entry) => [entry.name].concat(entry.aliases ?? []));\n\nconst COMMAND_TEXT_PATTERN = new RegExp(\n `^\\\\/(?:pi-[\\\\w-]+|${COMMAND_NAMES.join(\"|\")})(?:@\\\\w+)?(?:\\\\s|$)`,\n \"i\",\n);\n\nexport function isCommandText(text: string): boolean {\n return COMMAND_TEXT_PATTERN.test(text.trim());\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/adapters/commands/registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/adapters/commands/registry.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAchF,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,aAAa,GAAG,cAAc,EAAE,CAUrF;AAED,wBAAsB,eAAe,CACnC,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,CAKlB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AdminCommandHandler } from "./admin.js";
|
|
2
2
|
import { AutoReplyCommandHandler } from "./auto-reply.js";
|
|
3
3
|
import { CompactCommandHandler } from "./compact.js";
|
|
4
|
+
import { DesktopCommandHandler } from "./desktop.js";
|
|
4
5
|
import { LoginCommandHandler } from "./login.js";
|
|
5
6
|
import { COMMAND_MANIFEST } from "./manifest.js";
|
|
6
7
|
import { ModelCommandHandler } from "./model.js";
|
|
@@ -12,6 +13,7 @@ const HANDLER_FACTORIES = {
|
|
|
12
13
|
autoreply: () => new AutoReplyCommandHandler(),
|
|
13
14
|
login: () => new LoginCommandHandler(),
|
|
14
15
|
session: () => new SessionViewCommandHandler(),
|
|
16
|
+
desktop: () => new DesktopCommandHandler(),
|
|
15
17
|
model: (modelRegistry) => new ModelCommandHandler(modelRegistry),
|
|
16
18
|
sandbox: () => new SandboxCommandHandler(),
|
|
17
19
|
new: () => new NewCommandHandler(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/adapters/commands/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,MAAM,iBAAiB,GAAqE;IAC1F,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE;IACtC,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,uBAAuB,EAAE;IAC9C,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE;IACtC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,yBAAyB,EAAE;IAC9C,KAAK,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,IAAI,mBAAmB,CAAC,aAAa,CAAC;IAChE,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,qBAAqB,EAAE;IAC1C,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE;IAClC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,qBAAqB,EAAE;CAC3C,CAAC;AAEF,MAAM,UAAU,sBAAsB,CAAC,aAA4B;IACjE,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACxE,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,2BAA2B,KAAK,CAAC,IAAI,kDAAkD,CACxF,CAAC;QACJ,CAAC;QACD,OAAO,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAmC,EACnC,OAAuB;IAEvB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,MAAM,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;IACpD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { AdminCommandHandler } from \"./admin.js\";\nimport { AutoReplyCommandHandler } from \"./auto-reply.js\";\nimport { CompactCommandHandler } from \"./compact.js\";\nimport { LoginCommandHandler } from \"./login.js\";\nimport { COMMAND_MANIFEST } from \"./manifest.js\";\nimport { ModelCommandHandler } from \"./model.js\";\nimport { NewCommandHandler } from \"./new.js\";\nimport { SandboxCommandHandler } from \"./sandbox.js\";\nimport { SessionViewCommandHandler } from \"./session-view.js\";\nimport type { CommandContext, CommandHandler, ModelRegistry } from \"./types.js\";\n\nconst HANDLER_FACTORIES: Record<string, (modelRegistry: ModelRegistry) => CommandHandler> = {\n admin: () => new AdminCommandHandler(),\n autoreply: () => new AutoReplyCommandHandler(),\n login: () => new LoginCommandHandler(),\n session: () => new SessionViewCommandHandler(),\n model: (modelRegistry) => new ModelCommandHandler(modelRegistry),\n sandbox: () => new SandboxCommandHandler(),\n new: () => new NewCommandHandler(),\n compact: () => new CompactCommandHandler(),\n};\n\nexport function defaultCommandHandlers(modelRegistry: ModelRegistry): CommandHandler[] {\n return COMMAND_MANIFEST.filter((entry) => !entry.magicWord).map((entry) => {\n const factory = HANDLER_FACTORIES[entry.name];\n if (!factory) {\n throw new Error(\n `Command manifest entry \"${entry.name}\" has no handler factory in commands/registry.ts`,\n );\n }\n return factory(modelRegistry);\n });\n}\n\nexport async function dispatchCommand(\n handlers: readonly CommandHandler[],\n context: CommandContext,\n): Promise<boolean> {\n for (const handler of handlers) {\n if (await handler.tryHandle(context)) return true;\n }\n return false;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/adapters/commands/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,MAAM,iBAAiB,GAAqE;IAC1F,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE;IACtC,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,uBAAuB,EAAE;IAC9C,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE;IACtC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,yBAAyB,EAAE;IAC9C,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,qBAAqB,EAAE;IAC1C,KAAK,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,IAAI,mBAAmB,CAAC,aAAa,CAAC;IAChE,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,qBAAqB,EAAE;IAC1C,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE;IAClC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,qBAAqB,EAAE;CAC3C,CAAC;AAEF,MAAM,UAAU,sBAAsB,CAAC,aAA4B;IACjE,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACxE,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,2BAA2B,KAAK,CAAC,IAAI,kDAAkD,CACxF,CAAC;QACJ,CAAC;QACD,OAAO,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAmC,EACnC,OAAuB;IAEvB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,MAAM,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;IACpD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { AdminCommandHandler } from \"./admin.js\";\nimport { AutoReplyCommandHandler } from \"./auto-reply.js\";\nimport { CompactCommandHandler } from \"./compact.js\";\nimport { DesktopCommandHandler } from \"./desktop.js\";\nimport { LoginCommandHandler } from \"./login.js\";\nimport { COMMAND_MANIFEST } from \"./manifest.js\";\nimport { ModelCommandHandler } from \"./model.js\";\nimport { NewCommandHandler } from \"./new.js\";\nimport { SandboxCommandHandler } from \"./sandbox.js\";\nimport { SessionViewCommandHandler } from \"./session-view.js\";\nimport type { CommandContext, CommandHandler, ModelRegistry } from \"./types.js\";\n\nconst HANDLER_FACTORIES: Record<string, (modelRegistry: ModelRegistry) => CommandHandler> = {\n admin: () => new AdminCommandHandler(),\n autoreply: () => new AutoReplyCommandHandler(),\n login: () => new LoginCommandHandler(),\n session: () => new SessionViewCommandHandler(),\n desktop: () => new DesktopCommandHandler(),\n model: (modelRegistry) => new ModelCommandHandler(modelRegistry),\n sandbox: () => new SandboxCommandHandler(),\n new: () => new NewCommandHandler(),\n compact: () => new CompactCommandHandler(),\n};\n\nexport function defaultCommandHandlers(modelRegistry: ModelRegistry): CommandHandler[] {\n return COMMAND_MANIFEST.filter((entry) => !entry.magicWord).map((entry) => {\n const factory = HANDLER_FACTORIES[entry.name];\n if (!factory) {\n throw new Error(\n `Command manifest entry \"${entry.name}\" has no handler factory in commands/registry.ts`,\n );\n }\n return factory(modelRegistry);\n });\n}\n\nexport async function dispatchCommand(\n handlers: readonly CommandHandler[],\n context: CommandContext,\n): Promise<boolean> {\n for (const handler of handlers) {\n if (await handler.tryHandle(context)) return true;\n }\n return false;\n}\n"]}
|
|
@@ -3,7 +3,7 @@ import type { Api, Model } from "@earendil-works/pi-ai";
|
|
|
3
3
|
import type { Workspace } from "../../office/types.js";
|
|
4
4
|
import type { DockerContainerManager } from "../../sandbox/provisioner.js";
|
|
5
5
|
import type { SandboxConfig } from "../../sandbox/types.js";
|
|
6
|
-
import type { SandboxResourceController, ConversationContext, CompactOutcome, HandleCompactCommandOptions, HandleNewCommandOptions, MessagingInfo, MessagingBot, OfficeAddress, PlatformName, RunnerCacheControl, SessionViewTokenStoreLike } from "../../types.js";
|
|
6
|
+
import type { SandboxResourceController, ConversationContext, CompactOutcome, HandleCompactCommandOptions, HandleNewCommandOptions, MessagingInfo, MessagingBot, OfficeAddress, PlatformName, RunnerCacheControl, SessionViewTokenStoreLike, DesktopTokenStoreLike, OpenDesktop } from "../../types.js";
|
|
7
7
|
import type { VaultManager } from "../../vault/types.js";
|
|
8
8
|
import type { AdminTokenCreateOptions } from "../web/admin/types.js";
|
|
9
9
|
interface CommandArgSpec {
|
|
@@ -54,6 +54,8 @@ export interface CommandServices {
|
|
|
54
54
|
resourceController?: SandboxResourceController;
|
|
55
55
|
linkTokenStore: LinkTokenStoreLike;
|
|
56
56
|
sessionViewTokenStore: SessionViewTokenStoreLike;
|
|
57
|
+
desktopTokenStore?: DesktopTokenStoreLike;
|
|
58
|
+
openDesktop?: OpenDesktop;
|
|
57
59
|
adminTokenStore: AdminTokenStoreLike;
|
|
58
60
|
portalBaseUrl?: string;
|
|
59
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/adapters/commands/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EACV,yBAAyB,EACzB,mBAAmB,EACnB,cAAc,EACd,2BAA2B,EAC3B,uBAAuB,EACvB,aAAa,EACb,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,yBAAyB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/adapters/commands/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/adapters/commands/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\n\nimport type { Workspace } from \"../../office/types.js\";\nimport type { DockerContainerManager } from \"../../sandbox/provisioner.js\";\nimport type { SandboxConfig } from \"../../sandbox/types.js\";\nimport type {\n SandboxResourceController,\n ConversationContext,\n CompactOutcome,\n HandleCompactCommandOptions,\n HandleNewCommandOptions,\n MessagingInfo,\n MessagingBot,\n OfficeAddress,\n PlatformName,\n RunnerCacheControl,\n SessionViewTokenStoreLike,\n} from \"../../types.js\";\nimport type { VaultManager } from \"../../vault/types.js\";\nimport type { AdminTokenCreateOptions } from \"../web/admin/types.js\";\n\ninterface CommandArgSpec {\n name: string;\n description: string;\n required: boolean;\n}\n\nexport interface SlackSlashRoute {\n includeText?: boolean;\n thread?: boolean;\n privateCommand?: boolean;\n}\n\nexport interface CommandManifestEntry {\n name: string;\n description: string;\n aliases?: readonly string[];\n arg?: CommandArgSpec;\n bare?: boolean;\n magicWord?: boolean;\n slackCommand?: string;\n slackRoute?: SlackSlashRoute;\n discord?: boolean;\n telegramMenu?: { description?: string };\n telegramCommand?: boolean;\n}\n\nexport interface LinkTokenStoreLike {\n create(\n platform: PlatformName,\n platformUserId: string,\n conversationId: string,\n vaultId: string,\n providerId: string,\n ): { token: string };\n}\n\nexport interface AdminTokenStoreLike {\n create(options: AdminTokenCreateOptions): { token: string };\n}\n\ninterface CommandRuntimeBridge extends RunnerCacheControl {\n handleNewCommand(options: HandleNewCommandOptions): Promise<void>;\n handleCompactCommand(options: HandleCompactCommandOptions): Promise<CompactOutcome>;\n}\n\nexport interface CommandServices {\n workspace: Workspace;\n runtime?: CommandRuntimeBridge;\n sandbox: SandboxConfig;\n vaultManager: VaultManager;\n provisioner?: DockerContainerManager;\n resourceController?: SandboxResourceController;\n linkTokenStore: LinkTokenStoreLike;\n sessionViewTokenStore: SessionViewTokenStoreLike;\n adminTokenStore: AdminTokenStoreLike;\n portalBaseUrl?: string;\n}\n\nexport interface CommandContext {\n bot: MessagingBot;\n responder: ConversationContext[\"responder\"];\n platform: PlatformName;\n address: OfficeAddress;\n platformUserId: string;\n platformUserName?: string;\n conversationId: string;\n vaultConversationId?: string;\n sessionKey: string;\n commandText: string;\n privateConversation: boolean;\n messagingInfo: MessagingInfo;\n services: CommandServices;\n}\n\nexport interface CommandHandler {\n tryHandle(context: CommandContext): Promise<boolean>;\n}\n\nexport interface ModelRegistry {\n find(provider: string, modelId: string): Model<Api> | undefined;\n}\n\nexport interface ParsedModelCommand {\n provider?: string;\n model?: string;\n modelCandidate?: string;\n thinkingLevelCandidate?: string;\n thinkingLevel?: ThinkingLevel;\n error?: \"invalid_spec\";\n}\n\nexport interface ParsedSandboxCommand {\n action?: \"boost\" | \"visibility\";\n visibility?: string;\n}\n\nexport type ParsedLoginCommand =\n | { action: \"setup\" }\n | { action: \"shared_create\" | \"shared_update\" | \"shared_delete\"; name: string }\n | { action: \"shared_list\" }\n | { action: \"copy_shared\"; name: string };\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/adapters/commands/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\n\nimport type { Workspace } from \"../../office/types.js\";\nimport type { DockerContainerManager } from \"../../sandbox/provisioner.js\";\nimport type { SandboxConfig } from \"../../sandbox/types.js\";\nimport type {\n SandboxResourceController,\n ConversationContext,\n CompactOutcome,\n HandleCompactCommandOptions,\n HandleNewCommandOptions,\n MessagingInfo,\n MessagingBot,\n OfficeAddress,\n PlatformName,\n RunnerCacheControl,\n SessionViewTokenStoreLike,\n DesktopTokenStoreLike,\n OpenDesktop,\n} from \"../../types.js\";\nimport type { VaultManager } from \"../../vault/types.js\";\nimport type { AdminTokenCreateOptions } from \"../web/admin/types.js\";\n\ninterface CommandArgSpec {\n name: string;\n description: string;\n required: boolean;\n}\n\nexport interface SlackSlashRoute {\n includeText?: boolean;\n thread?: boolean;\n privateCommand?: boolean;\n}\n\nexport interface CommandManifestEntry {\n name: string;\n description: string;\n aliases?: readonly string[];\n arg?: CommandArgSpec;\n bare?: boolean;\n magicWord?: boolean;\n slackCommand?: string;\n slackRoute?: SlackSlashRoute;\n discord?: boolean;\n telegramMenu?: { description?: string };\n telegramCommand?: boolean;\n}\n\nexport interface LinkTokenStoreLike {\n create(\n platform: PlatformName,\n platformUserId: string,\n conversationId: string,\n vaultId: string,\n providerId: string,\n ): { token: string };\n}\n\nexport interface AdminTokenStoreLike {\n create(options: AdminTokenCreateOptions): { token: string };\n}\n\ninterface CommandRuntimeBridge extends RunnerCacheControl {\n handleNewCommand(options: HandleNewCommandOptions): Promise<void>;\n handleCompactCommand(options: HandleCompactCommandOptions): Promise<CompactOutcome>;\n}\n\nexport interface CommandServices {\n workspace: Workspace;\n runtime?: CommandRuntimeBridge;\n sandbox: SandboxConfig;\n vaultManager: VaultManager;\n provisioner?: DockerContainerManager;\n resourceController?: SandboxResourceController;\n linkTokenStore: LinkTokenStoreLike;\n sessionViewTokenStore: SessionViewTokenStoreLike;\n desktopTokenStore?: DesktopTokenStoreLike;\n openDesktop?: OpenDesktop;\n adminTokenStore: AdminTokenStoreLike;\n portalBaseUrl?: string;\n}\n\nexport interface CommandContext {\n bot: MessagingBot;\n responder: ConversationContext[\"responder\"];\n platform: PlatformName;\n address: OfficeAddress;\n platformUserId: string;\n platformUserName?: string;\n conversationId: string;\n vaultConversationId?: string;\n sessionKey: string;\n commandText: string;\n privateConversation: boolean;\n messagingInfo: MessagingInfo;\n services: CommandServices;\n}\n\nexport interface CommandHandler {\n tryHandle(context: CommandContext): Promise<boolean>;\n}\n\nexport interface ModelRegistry {\n find(provider: string, modelId: string): Model<Api> | undefined;\n}\n\nexport interface ParsedModelCommand {\n provider?: string;\n model?: string;\n modelCandidate?: string;\n thinkingLevelCandidate?: string;\n thinkingLevel?: ThinkingLevel;\n error?: \"invalid_spec\";\n}\n\nexport interface ParsedSandboxCommand {\n action?: \"boost\" | \"visibility\";\n visibility?: string;\n}\n\nexport type ParsedLoginCommand =\n | { action: \"setup\" }\n | { action: \"shared_create\" | \"shared_update\" | \"shared_delete\"; name: string }\n | { action: \"shared_list\" }\n | { action: \"copy_shared\"; name: string };\n"]}
|
|
@@ -10,6 +10,5 @@ export declare function formatTaskResumesExhausted(source: PlatformSource): stri
|
|
|
10
10
|
export declare function formatAlreadyWorking(source: PlatformSource, stopCommand: string, options?: {
|
|
11
11
|
scope?: "thread";
|
|
12
12
|
}): string;
|
|
13
|
-
export declare function formatForceStopped(source: PlatformSource, actorLabel: string): string;
|
|
14
13
|
export {};
|
|
15
14
|
//# 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
|
|
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"}
|
|
@@ -39,7 +39,4 @@ export function formatAlreadyWorking(source, stopCommand, options) {
|
|
|
39
39
|
const prefix = options?.scope === "thread" ? "Already working in this thread." : "Already working.";
|
|
40
40
|
return formatItalic(platformName, `${prefix} Send ${command} to cancel.`);
|
|
41
41
|
}
|
|
42
|
-
export function formatForceStopped(source, actorLabel) {
|
|
43
|
-
return formatItalic(resolvePlatformName(source), `Force stopped by ${actorLabel}.`);
|
|
44
|
-
}
|
|
45
42
|
//# 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
|
|
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","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"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SlackAppApi, SlackAppCustomization, SlackAppManifest, SlackAppSyncResult, SlackBotApi, SlackConfigTokens } from "./types.js";
|
|
2
|
+
export declare const SLACK_APP_CUSTOMIZATION_FILE = "slack.json";
|
|
3
|
+
export declare const SLACK_CONFIG_TOKEN_FILE = "slack-config-token.json";
|
|
4
|
+
export declare function slackBotNameProblem(name: string): string | undefined;
|
|
5
|
+
export declare function slackAppManifest(customization?: SlackAppCustomization): SlackAppManifest;
|
|
6
|
+
export declare function readSlackAppCustomization(stateDir: string): SlackAppCustomization;
|
|
7
|
+
export declare function slackAppCustomizationProblem(customization: SlackAppCustomization): string | undefined;
|
|
8
|
+
export declare function writeSlackAppCustomization(stateDir: string, customization: SlackAppCustomization): void;
|
|
9
|
+
export declare function writeConfigTokens(stateDir: string, tokens: SlackConfigTokens): void;
|
|
10
|
+
export declare function syncSlackApp(options: {
|
|
11
|
+
stateDir: string;
|
|
12
|
+
apps: SlackAppApi;
|
|
13
|
+
bot: SlackBotApi;
|
|
14
|
+
}): Promise<SlackAppSyncResult>;
|
|
15
|
+
export declare function describeSlackAppSync(result: SlackAppSyncResult): string | undefined;
|
|
16
|
+
export declare function createSlackApp(options: {
|
|
17
|
+
apps: SlackAppApi;
|
|
18
|
+
refreshToken: string;
|
|
19
|
+
customization: SlackAppCustomization;
|
|
20
|
+
}): Promise<{
|
|
21
|
+
appId: string;
|
|
22
|
+
installUrl: string;
|
|
23
|
+
tokens: SlackConfigTokens;
|
|
24
|
+
}>;
|
|
25
|
+
export declare function slackAppApi(): SlackAppApi;
|
|
26
|
+
export declare function slackBotApi(botToken: string): SlackBotApi;
|
|
27
|
+
//# sourceMappingURL=app-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-config.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/app-config.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,4BAA4B,eAAe,CAAC;AACzD,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AAqDjE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIpE;AAOD,wBAAgB,gBAAgB,CAAC,aAAa,GAAE,qBAA0B,GAAG,gBAAgB,CA4C5F;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CASjF;AAED,wBAAgB,4BAA4B,CAC1C,aAAa,EAAE,qBAAqB,GACnC,MAAM,GAAG,SAAS,CAIpB;AAED,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,qBAAqB,GACnC,IAAI,CAON;AAYD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAKnF;AAoCD,wBAAsB,YAAY,CAAC,OAAO,EAAE;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,EAAE,WAAW,CAAC;CAClB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAwB9B;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,GAAG,SAAS,CAanF;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,qBAAqB,CAAC;CACtC,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAC,CAI5E;AASD,wBAAgB,WAAW,IAAI,WAAW,CAgCzC;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAYzD"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { WebClient } from "@slack/web-api";
|
|
3
|
+
import { Type } from "typebox";
|
|
4
|
+
import { Value } from "typebox/value";
|
|
5
|
+
import { COMMAND_MANIFEST } from "../commands/manifest.js";
|
|
6
|
+
import { atomicWritePrivateFile, readJsonSchemaFileIfExists } from "../../file-guards.js";
|
|
7
|
+
import { errorMessage, isRecord } from "../../unknown-values.js";
|
|
8
|
+
export const SLACK_APP_CUSTOMIZATION_FILE = "slack.json";
|
|
9
|
+
export const SLACK_CONFIG_TOKEN_FILE = "slack-config-token.json";
|
|
10
|
+
const BOT_SCOPES = [
|
|
11
|
+
"app_mentions:read",
|
|
12
|
+
"channels:history",
|
|
13
|
+
"channels:read",
|
|
14
|
+
"chat:write",
|
|
15
|
+
"chat:write.customize",
|
|
16
|
+
"commands",
|
|
17
|
+
"files:read",
|
|
18
|
+
"files:write",
|
|
19
|
+
"groups:history",
|
|
20
|
+
"groups:read",
|
|
21
|
+
"im:history",
|
|
22
|
+
"im:read",
|
|
23
|
+
"im:write",
|
|
24
|
+
"reactions:write",
|
|
25
|
+
"users:read",
|
|
26
|
+
];
|
|
27
|
+
const BOT_EVENTS = [
|
|
28
|
+
"app_home_opened",
|
|
29
|
+
"app_mention",
|
|
30
|
+
"message.channels",
|
|
31
|
+
"message.groups",
|
|
32
|
+
"message.im",
|
|
33
|
+
];
|
|
34
|
+
const SlackAppCustomizationSchema = Type.Object({
|
|
35
|
+
display_information: Type.Optional(Type.Object({
|
|
36
|
+
name: Type.Optional(Type.String({ minLength: 1, maxLength: 35 })),
|
|
37
|
+
description: Type.Optional(Type.String({ maxLength: 140 })),
|
|
38
|
+
long_description: Type.Optional(Type.String({ maxLength: 4000 })),
|
|
39
|
+
background_color: Type.Optional(Type.String({ pattern: "^#[0-9a-fA-F]{6}$" })),
|
|
40
|
+
}, { additionalProperties: false })),
|
|
41
|
+
}, { additionalProperties: false });
|
|
42
|
+
const ConfigTokenFileSchema = Type.Object({
|
|
43
|
+
token: Type.String({ minLength: 1 }),
|
|
44
|
+
refresh_token: Type.String({ minLength: 1 }),
|
|
45
|
+
});
|
|
46
|
+
const DEFAULT_BOT_NAME = "mikan";
|
|
47
|
+
const SLACK_BOT_NAME = /^[A-Za-z0-9 ._-]{1,80}$/;
|
|
48
|
+
export function slackBotNameProblem(name) {
|
|
49
|
+
return SLACK_BOT_NAME.test(name)
|
|
50
|
+
? undefined
|
|
51
|
+
: `Slack names the bot user only with letters, digits, spaces, ".", "_", and "-" (up to 80), so the bot keeps the name ${DEFAULT_BOT_NAME}.`;
|
|
52
|
+
}
|
|
53
|
+
function botName(customization) {
|
|
54
|
+
const name = customization.display_information?.name;
|
|
55
|
+
return name !== undefined && slackBotNameProblem(name) === undefined ? name : DEFAULT_BOT_NAME;
|
|
56
|
+
}
|
|
57
|
+
export function slackAppManifest(customization = {}) {
|
|
58
|
+
const manifest = {
|
|
59
|
+
display_information: {
|
|
60
|
+
name: "mikan",
|
|
61
|
+
description: "mikan Slack assistant",
|
|
62
|
+
background_color: "#4d5673",
|
|
63
|
+
...customization.display_information,
|
|
64
|
+
},
|
|
65
|
+
features: {
|
|
66
|
+
app_home: {
|
|
67
|
+
home_tab_enabled: false,
|
|
68
|
+
messages_tab_enabled: true,
|
|
69
|
+
messages_tab_read_only_enabled: false,
|
|
70
|
+
},
|
|
71
|
+
bot_user: { display_name: botName(customization), always_online: true },
|
|
72
|
+
slash_commands: COMMAND_MANIFEST.flatMap((entry) => entry.slackCommand
|
|
73
|
+
? [
|
|
74
|
+
{
|
|
75
|
+
command: entry.slackCommand,
|
|
76
|
+
description: entry.description,
|
|
77
|
+
usage_hint: entry.arg?.description,
|
|
78
|
+
should_escape: false,
|
|
79
|
+
},
|
|
80
|
+
]
|
|
81
|
+
: []),
|
|
82
|
+
},
|
|
83
|
+
oauth_config: {
|
|
84
|
+
redirect_urls: ["https://localhost"],
|
|
85
|
+
scopes: { bot: [...BOT_SCOPES] },
|
|
86
|
+
pkce_enabled: false,
|
|
87
|
+
},
|
|
88
|
+
settings: {
|
|
89
|
+
event_subscriptions: { bot_events: [...BOT_EVENTS] },
|
|
90
|
+
interactivity: { is_enabled: true },
|
|
91
|
+
org_deploy_enabled: false,
|
|
92
|
+
socket_mode_enabled: true,
|
|
93
|
+
token_rotation_enabled: false,
|
|
94
|
+
app_level_token_rotation_enabled: false,
|
|
95
|
+
is_mcp_enabled: false,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
return manifest;
|
|
99
|
+
}
|
|
100
|
+
export function readSlackAppCustomization(stateDir) {
|
|
101
|
+
const path = join(stateDir, SLACK_APP_CUSTOMIZATION_FILE);
|
|
102
|
+
return (readJsonSchemaFileIfExists(path, SlackAppCustomizationSchema, (detail) => `Invalid ${path}: ${detail}. It may hold only display_information fields.`) ?? {});
|
|
103
|
+
}
|
|
104
|
+
export function slackAppCustomizationProblem(customization) {
|
|
105
|
+
if (Value.Check(SlackAppCustomizationSchema, customization))
|
|
106
|
+
return undefined;
|
|
107
|
+
const first = Value.Errors(SlackAppCustomizationSchema, customization)[0];
|
|
108
|
+
return `Slack would reject this app setting: ${first?.instancePath ?? ""} ${first?.message ?? ""}`.trim();
|
|
109
|
+
}
|
|
110
|
+
export function writeSlackAppCustomization(stateDir, customization) {
|
|
111
|
+
const problem = slackAppCustomizationProblem(customization);
|
|
112
|
+
if (problem)
|
|
113
|
+
throw new Error(problem);
|
|
114
|
+
atomicWritePrivateFile(join(stateDir, SLACK_APP_CUSTOMIZATION_FILE), `${JSON.stringify(customization, null, 2)}\n`);
|
|
115
|
+
}
|
|
116
|
+
function readConfigTokens(stateDir) {
|
|
117
|
+
const path = join(stateDir, SLACK_CONFIG_TOKEN_FILE);
|
|
118
|
+
const stored = readJsonSchemaFileIfExists(path, ConfigTokenFileSchema, (detail) => `Invalid ${path}: ${detail}`);
|
|
119
|
+
return stored ? { token: stored.token, refreshToken: stored.refresh_token } : undefined;
|
|
120
|
+
}
|
|
121
|
+
export function writeConfigTokens(stateDir, tokens) {
|
|
122
|
+
atomicWritePrivateFile(join(stateDir, SLACK_CONFIG_TOKEN_FILE), `${JSON.stringify({ token: tokens.token, refresh_token: tokens.refreshToken })}\n`);
|
|
123
|
+
}
|
|
124
|
+
function canonical(value) {
|
|
125
|
+
if (Array.isArray(value))
|
|
126
|
+
return value.map(canonical);
|
|
127
|
+
if (!isRecord(value))
|
|
128
|
+
return value;
|
|
129
|
+
return Object.fromEntries(Object.keys(value)
|
|
130
|
+
.filter((key) => value[key] !== undefined)
|
|
131
|
+
.toSorted()
|
|
132
|
+
.map((key) => [key, canonical(value[key])]));
|
|
133
|
+
}
|
|
134
|
+
const SLACK_MANAGED_APP_HOME_FIELDS = new Set(["agent_tasks_enabled"]);
|
|
135
|
+
function withoutSlackManagedFields(live) {
|
|
136
|
+
if (!isRecord(live) || !isRecord(live.features) || !isRecord(live.features.app_home))
|
|
137
|
+
return live;
|
|
138
|
+
const appHome = Object.fromEntries(Object.entries(live.features.app_home).filter(([key]) => !SLACK_MANAGED_APP_HOME_FIELDS.has(key)));
|
|
139
|
+
return { ...live, features: { ...live.features, app_home: appHome } };
|
|
140
|
+
}
|
|
141
|
+
function sameManifest(live, desired) {
|
|
142
|
+
return (JSON.stringify(canonical(withoutSlackManagedFields(live))) ===
|
|
143
|
+
JSON.stringify(canonical(desired)));
|
|
144
|
+
}
|
|
145
|
+
function reinstallMessage(appId, missingScopes) {
|
|
146
|
+
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`;
|
|
147
|
+
}
|
|
148
|
+
export async function syncSlackApp(options) {
|
|
149
|
+
const { stateDir, apps, bot } = options;
|
|
150
|
+
const stored = readConfigTokens(stateDir);
|
|
151
|
+
if (!stored)
|
|
152
|
+
return { status: "no-token" };
|
|
153
|
+
try {
|
|
154
|
+
const rotated = await apps.rotate(stored.refreshToken);
|
|
155
|
+
writeConfigTokens(stateDir, rotated);
|
|
156
|
+
const appId = await bot.appId();
|
|
157
|
+
const desired = slackAppManifest(readSlackAppCustomization(stateDir));
|
|
158
|
+
if (sameManifest(await apps.export(rotated.token, appId), desired)) {
|
|
159
|
+
return { status: "unchanged", appId };
|
|
160
|
+
}
|
|
161
|
+
const { permissionsUpdated } = await apps.update(rotated.token, appId, desired);
|
|
162
|
+
const granted = permissionsUpdated ? new Set(await bot.scopes()) : undefined;
|
|
163
|
+
const missingScopes = granted
|
|
164
|
+
? (desired.oauth_config?.scopes?.bot ?? []).filter((scope) => !granted.has(scope))
|
|
165
|
+
: [];
|
|
166
|
+
if (missingScopes.length > 0) {
|
|
167
|
+
await bot.directMessage(rotated.userId, reinstallMessage(appId, missingScopes));
|
|
168
|
+
}
|
|
169
|
+
return { status: "updated", appId, missingScopes };
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
return { status: "failed", reason: errorMessage(error) };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
export function describeSlackAppSync(result) {
|
|
176
|
+
switch (result.status) {
|
|
177
|
+
case "no-token":
|
|
178
|
+
return undefined;
|
|
179
|
+
case "failed":
|
|
180
|
+
return `Slack app sync failed, app left as it was: ${result.reason}`;
|
|
181
|
+
case "unchanged":
|
|
182
|
+
return `Slack app ${result.appId} already matches mikan's manifest`;
|
|
183
|
+
case "updated":
|
|
184
|
+
return result.missingScopes.length > 0
|
|
185
|
+
? `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`
|
|
186
|
+
: `Slack app ${result.appId} updated to mikan's manifest`;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export async function createSlackApp(options) {
|
|
190
|
+
const tokens = await options.apps.rotate(options.refreshToken);
|
|
191
|
+
const created = await options.apps.create(tokens.token, slackAppManifest(options.customization));
|
|
192
|
+
return { ...created, tokens };
|
|
193
|
+
}
|
|
194
|
+
function required(value, what) {
|
|
195
|
+
if (value === undefined)
|
|
196
|
+
throw new Error(`Slack did not return ${what}`);
|
|
197
|
+
return value;
|
|
198
|
+
}
|
|
199
|
+
const NO_RETRIES = { retryConfig: { retries: 0 }, timeout: 15_000 };
|
|
200
|
+
export function slackAppApi() {
|
|
201
|
+
const client = new WebClient(undefined, NO_RETRIES);
|
|
202
|
+
return {
|
|
203
|
+
rotate: async (refreshToken) => {
|
|
204
|
+
const result = await client.tooling.tokens.rotate({ refresh_token: refreshToken });
|
|
205
|
+
return {
|
|
206
|
+
token: required(result.token, "a configuration token"),
|
|
207
|
+
refreshToken: required(result.refresh_token, "a refresh token"),
|
|
208
|
+
userId: required(result.user_id, "the token owner"),
|
|
209
|
+
};
|
|
210
|
+
},
|
|
211
|
+
export: async (token, appId) => required((await client.apps.manifest.export({ token, app_id: appId })).manifest, "a manifest"),
|
|
212
|
+
update: async (token, appId, manifest) => ({
|
|
213
|
+
permissionsUpdated: (await client.apps.manifest.update({ token, app_id: appId, manifest }))
|
|
214
|
+
.permissions_updated === true,
|
|
215
|
+
}),
|
|
216
|
+
create: async (token, manifest) => {
|
|
217
|
+
const result = await client.apps.manifest.create({ token, manifest });
|
|
218
|
+
return {
|
|
219
|
+
appId: required(result.app_id, "an app ID"),
|
|
220
|
+
installUrl: required(result.oauth_authorize_url, "an install link"),
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
delete: async (token, appId) => {
|
|
224
|
+
await client.apps.manifest.delete({ token, app_id: appId });
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
export function slackBotApi(botToken) {
|
|
229
|
+
const client = new WebClient(botToken, NO_RETRIES);
|
|
230
|
+
return {
|
|
231
|
+
appId: async () => {
|
|
232
|
+
const bot = required((await client.auth.test()).bot_id, "the bot ID");
|
|
233
|
+
return required((await client.bots.info({ bot })).bot?.app_id, "the app ID");
|
|
234
|
+
},
|
|
235
|
+
scopes: async () => (await client.auth.test()).response_metadata?.scopes ?? [],
|
|
236
|
+
directMessage: async (userId, text) => {
|
|
237
|
+
await client.chat.postMessage({ channel: userId, text });
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=app-config.js.map
|