@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.
Files changed (116) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/adapters/commands/desktop.d.ts +5 -0
  3. package/dist/adapters/commands/desktop.d.ts.map +1 -0
  4. package/dist/adapters/commands/desktop.js +58 -0
  5. package/dist/adapters/commands/desktop.js.map +1 -0
  6. package/dist/adapters/commands/manifest.d.ts.map +1 -1
  7. package/dist/adapters/commands/manifest.js +8 -0
  8. package/dist/adapters/commands/manifest.js.map +1 -1
  9. package/dist/adapters/commands/registry.d.ts.map +1 -1
  10. package/dist/adapters/commands/registry.js +2 -0
  11. package/dist/adapters/commands/registry.js.map +1 -1
  12. package/dist/adapters/commands/types.d.ts +3 -1
  13. package/dist/adapters/commands/types.d.ts.map +1 -1
  14. package/dist/adapters/commands/types.js.map +1 -1
  15. package/dist/adapters/messages.d.ts +0 -1
  16. package/dist/adapters/messages.d.ts.map +1 -1
  17. package/dist/adapters/messages.js +0 -3
  18. package/dist/adapters/messages.js.map +1 -1
  19. package/dist/adapters/slack/app-config.d.ts +27 -0
  20. package/dist/adapters/slack/app-config.d.ts.map +1 -0
  21. package/dist/adapters/slack/app-config.js +241 -0
  22. package/dist/adapters/slack/app-config.js.map +1 -0
  23. package/dist/adapters/slack/bot.d.ts +0 -3
  24. package/dist/adapters/slack/bot.d.ts.map +1 -1
  25. package/dist/adapters/slack/bot.js +4 -163
  26. package/dist/adapters/slack/bot.js.map +1 -1
  27. package/dist/adapters/slack/types.d.ts +46 -2
  28. package/dist/adapters/slack/types.d.ts.map +1 -1
  29. package/dist/adapters/slack/types.js.map +1 -1
  30. package/dist/adapters/web/desktop/index.d.ts +16 -0
  31. package/dist/adapters/web/desktop/index.d.ts.map +1 -0
  32. package/dist/adapters/web/desktop/index.js +163 -0
  33. package/dist/adapters/web/desktop/index.js.map +1 -0
  34. package/dist/adapters/web/desktop/page.d.ts +2 -0
  35. package/dist/adapters/web/desktop/page.d.ts.map +1 -0
  36. package/dist/adapters/web/desktop/page.js +83 -0
  37. package/dist/adapters/web/desktop/page.js.map +1 -0
  38. package/dist/adapters/web/desktop/types.d.ts +8 -0
  39. package/dist/adapters/web/desktop/types.d.ts.map +1 -0
  40. package/dist/adapters/web/desktop/types.js +2 -0
  41. package/dist/adapters/web/desktop/types.js.map +1 -0
  42. package/dist/adapters/web/server.d.ts +2 -0
  43. package/dist/adapters/web/server.d.ts.map +1 -1
  44. package/dist/adapters/web/server.js +19 -0
  45. package/dist/adapters/web/server.js.map +1 -1
  46. package/dist/cli/boot.d.ts.map +1 -1
  47. package/dist/cli/boot.js +4 -1
  48. package/dist/cli/boot.js.map +1 -1
  49. package/dist/cli/onboard.d.ts +3 -0
  50. package/dist/cli/onboard.d.ts.map +1 -1
  51. package/dist/cli/onboard.js +79 -3
  52. package/dist/cli/onboard.js.map +1 -1
  53. package/dist/cli/slack.d.ts +9 -0
  54. package/dist/cli/slack.d.ts.map +1 -0
  55. package/dist/cli/slack.js +96 -0
  56. package/dist/cli/slack.js.map +1 -0
  57. package/dist/cli/types.d.ts +2 -1
  58. package/dist/cli/types.d.ts.map +1 -1
  59. package/dist/cli/types.js.map +1 -1
  60. package/dist/harness/desktop.d.ts +16 -0
  61. package/dist/harness/desktop.d.ts.map +1 -0
  62. package/dist/harness/desktop.js +6 -0
  63. package/dist/harness/desktop.js.map +1 -0
  64. package/dist/harness/execution-resolver.d.ts +1 -0
  65. package/dist/harness/execution-resolver.d.ts.map +1 -1
  66. package/dist/harness/execution-resolver.js +5 -0
  67. package/dist/harness/execution-resolver.js.map +1 -1
  68. package/dist/harness/presenter.d.ts.map +1 -1
  69. package/dist/harness/presenter.js +6 -1
  70. package/dist/harness/presenter.js.map +1 -1
  71. package/dist/harness/runner.d.ts.map +1 -1
  72. package/dist/harness/runner.js +22 -1
  73. package/dist/harness/runner.js.map +1 -1
  74. package/dist/harness/session.d.ts +1 -1
  75. package/dist/harness/session.d.ts.map +1 -1
  76. package/dist/harness/session.js +30 -9
  77. package/dist/harness/session.js.map +1 -1
  78. package/dist/harness/tools/codemode.d.ts.map +1 -1
  79. package/dist/harness/tools/codemode.js +2 -2
  80. package/dist/harness/tools/codemode.js.map +1 -1
  81. package/dist/harness/tools/index.d.ts +2 -2
  82. package/dist/harness/tools/index.d.ts.map +1 -1
  83. package/dist/harness/tools/index.js +10 -2
  84. package/dist/harness/tools/index.js.map +1 -1
  85. package/dist/harness/tools/jev-browser.d.ts +12 -1
  86. package/dist/harness/tools/jev-browser.d.ts.map +1 -1
  87. package/dist/harness/tools/jev-browser.js +189 -30
  88. package/dist/harness/tools/jev-browser.js.map +1 -1
  89. package/dist/harness/tools/pi-tools.d.ts.map +1 -1
  90. package/dist/harness/tools/pi-tools.js +2 -1
  91. package/dist/harness/tools/pi-tools.js.map +1 -1
  92. package/dist/harness/tools/types.d.ts +4 -0
  93. package/dist/harness/tools/types.d.ts.map +1 -1
  94. package/dist/harness/tools/types.js.map +1 -1
  95. package/dist/harness/types.d.ts +2 -1
  96. package/dist/harness/types.d.ts.map +1 -1
  97. package/dist/harness/types.js.map +1 -1
  98. package/dist/main.js +29 -0
  99. package/dist/main.js.map +1 -1
  100. package/dist/runtime/conversation-runtime.js +7 -0
  101. package/dist/runtime/conversation-runtime.js.map +1 -1
  102. package/dist/sandbox/desktop.d.ts +30 -0
  103. package/dist/sandbox/desktop.d.ts.map +1 -0
  104. package/dist/sandbox/desktop.js +112 -0
  105. package/dist/sandbox/desktop.js.map +1 -0
  106. package/dist/sandbox/provisioner.d.ts +4 -1
  107. package/dist/sandbox/provisioner.d.ts.map +1 -1
  108. package/dist/sandbox/provisioner.js +21 -0
  109. package/dist/sandbox/provisioner.js.map +1 -1
  110. package/dist/sandbox/types.d.ts +19 -0
  111. package/dist/sandbox/types.d.ts.map +1 -1
  112. package/dist/sandbox/types.js.map +1 -1
  113. package/dist/types.d.ts +17 -1
  114. package/dist/types.d.ts.map +1 -1
  115. package/dist/types.js.map +1 -1
  116. package/package.json +9 -8
@@ -1,4 +1,4 @@
1
- import type { WebClient } from "@slack/web-api";
1
+ import type { AppsManifestUpdateArguments, WebClient } from "@slack/web-api";
2
2
  import type { Attachment, ConversationKind, OfficeAddress } from "../../types.js";
3
3
  import type { Workspace } from "../../office/types.js";
4
4
  import type { SlackMessagingBot } from "./bot.js";
@@ -8,7 +8,6 @@ export interface SlackWebApi {
8
8
  conversations: Pick<WebClient["conversations"], "open" | "history" | "replies" | "list">;
9
9
  users: Pick<WebClient["users"], "list">;
10
10
  reactions: Pick<WebClient["reactions"], "add">;
11
- views: Pick<WebClient["views"], "publish">;
12
11
  files: Pick<WebClient["files"], "uploadV2">;
13
12
  assistant: {
14
13
  threads: Pick<WebClient["assistant"]["threads"], "setSuggestedPrompts" | "setTitle">;
@@ -167,4 +166,49 @@ export interface AssistantSurfaceOps {
167
166
  setTitle(channel: string, threadTs: string, title: string): Promise<void>;
168
167
  channelName(channelId: string): string | undefined;
169
168
  }
169
+ export type SlackAppManifest = AppsManifestUpdateArguments["manifest"];
170
+ export interface SlackAppCustomization {
171
+ display_information?: {
172
+ name?: string;
173
+ description?: string;
174
+ long_description?: string;
175
+ background_color?: string;
176
+ };
177
+ }
178
+ export interface SlackConfigTokens {
179
+ token: string;
180
+ refreshToken: string;
181
+ }
182
+ export interface SlackAppApi {
183
+ rotate(refreshToken: string): Promise<SlackConfigTokens & {
184
+ userId: string;
185
+ }>;
186
+ export(token: string, appId: string): Promise<unknown>;
187
+ update(token: string, appId: string, manifest: SlackAppManifest): Promise<{
188
+ permissionsUpdated: boolean;
189
+ }>;
190
+ create(token: string, manifest: SlackAppManifest): Promise<{
191
+ appId: string;
192
+ installUrl: string;
193
+ }>;
194
+ delete(token: string, appId: string): Promise<void>;
195
+ }
196
+ export interface SlackBotApi {
197
+ appId(): Promise<string>;
198
+ scopes(): Promise<string[]>;
199
+ directMessage(userId: string, text: string): Promise<void>;
200
+ }
201
+ export type SlackAppSyncResult = {
202
+ status: "no-token";
203
+ } | {
204
+ status: "failed";
205
+ reason: string;
206
+ } | {
207
+ status: "unchanged";
208
+ appId: string;
209
+ } | {
210
+ status: "updated";
211
+ appId: string;
212
+ missingScopes: string[];
213
+ };
170
214
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/adapters/slack/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { WebClient } from \"@slack/web-api\";\nimport type { Attachment, ConversationKind, OfficeAddress } from \"../../types.js\";\nimport type { Workspace } from \"../../office/types.js\";\nimport type { SlackMessagingBot } from \"./bot.js\";\n\nexport interface SlackWebApi {\n auth: Pick<WebClient[\"auth\"], \"test\">;\n chat: Pick<WebClient[\"chat\"], \"postMessage\" | \"postEphemeral\" | \"update\" | \"delete\">;\n conversations: Pick<WebClient[\"conversations\"], \"open\" | \"history\" | \"replies\" | \"list\">;\n users: Pick<WebClient[\"users\"], \"list\">;\n reactions: Pick<WebClient[\"reactions\"], \"add\">;\n views: Pick<WebClient[\"views\"], \"publish\">;\n files: Pick<WebClient[\"files\"], \"uploadV2\">;\n assistant: {\n threads: Pick<WebClient[\"assistant\"][\"threads\"], \"setSuggestedPrompts\" | \"setTitle\">;\n };\n apiCall: WebClient[\"apiCall\"];\n}\n\nexport interface SlackSocketEventArgs {\n ack: () => Promise<void>;\n event?: unknown;\n body?: unknown;\n}\n\nexport interface SlackSocketConnection {\n on(event: string, listener: (args: SlackSocketEventArgs) => unknown): unknown;\n start(): Promise<unknown>;\n disconnect(): Promise<void>;\n}\n\nexport interface SlackMessagingBotOptions {\n appToken: string;\n botToken: string;\n workspace: Workspace;\n webApi?: SlackWebApi;\n socket?: SlackSocketConnection;\n fetch?: typeof fetch;\n}\n\nexport type SlackResponderBot = Pick<\n SlackMessagingBot,\n | \"getUser\"\n | \"getMessagingInfo\"\n | \"postMessage\"\n | \"postInThread\"\n | \"postInThreadBlocks\"\n | \"updateMessage\"\n | \"deleteMessage\"\n | \"logBotResponse\"\n | \"tryReserveStreamStart\"\n | \"startMessageStream\"\n | \"appendMessageStream\"\n | \"stopMessageStream\"\n | \"uploadFile\"\n | \"addReaction\"\n | \"setAssistantStatus\"\n>;\n\nexport interface SlackEvent {\n address: OfficeAddress;\n type: \"mention\" | \"dm\";\n conversationKind: ConversationKind;\n channel: string;\n ts: string;\n thread_ts?: string;\n user: string;\n text: string;\n files?: Array<{ name?: string; url_private_download?: string; url_private?: string }>;\n attachments?: Attachment[];\n sessionKey?: string;\n}\n\nexport interface SlackUser {\n id: string;\n userName: string;\n displayName: string;\n isBot?: boolean;\n}\n\nexport interface SlackChannel {\n id: string;\n name: string;\n isPrivate?: boolean;\n isExternallyShared?: boolean;\n}\n\nexport interface SlackAdapterOptions {\n initialMessageTs?: string;\n replyMode?: \"top-level\" | \"thread\";\n}\n\nexport type SlackSessionRef =\n | { kind: \"channel\"; channelId: string }\n | { kind: \"thread\"; channelId: string; threadTs: string };\n\nexport interface SlackAdapterSessionPlan {\n sessionKey: string;\n rootTs?: string;\n initialMessageTs?: string;\n isThreaded: boolean;\n}\n\nexport interface SlackEventAnchorRunPlan<T = SlackEvent> {\n event: T;\n initialMessageTs?: string;\n}\n\nexport interface SlackBlockAction {\n action_id: string;\n block_id?: string;\n type?: string;\n value?: string;\n selected_option?: { text?: { text?: string }; value?: string };\n selected_options?: Array<{ text?: { text?: string }; value?: string }>;\n}\n\nexport interface SlackBlockActionBody {\n actions?: SlackBlockAction[];\n container?: { channel_id?: string; thread_ts?: string; message_ts?: string };\n user?: { id?: string; username?: string; name?: string };\n}\n\nexport interface PlatformSlackOps {\n postBlocks(\n conversationId: string,\n args: { text: string; blocks: object[]; threadTs?: string },\n ): Promise<{ ts: string }>;\n updateBlocks(\n conversationId: string,\n args: { ts: string; text: string; blocks: object[]; threadTs?: string },\n ): Promise<void>;\n ownsBlockKitMessage(conversationId: string, ts: string, threadTs?: string): boolean;\n}\n\nexport interface SlackBlockKitOps {\n postBlocks(args: { text: string; blocks: object[]; threadTs?: string }): Promise<{ ts: string }>;\n updateBlocks(args: { ts: string; text: string; blocks: object[] }): Promise<void>;\n}\n\nexport interface AssistantThreadPayload {\n user_id?: string;\n channel_id?: string;\n thread_ts?: string;\n context?: AgentContext;\n}\n\nexport interface AgentContext {\n channel_id?: string;\n team_id?: string;\n enterprise_id?: string | null;\n}\n\nexport interface SuggestedPrompt {\n title: string;\n message: string;\n}\n\nexport interface AssistantSurfaceOps {\n postInThread(channel: string, threadTs: string, text: string): Promise<string>;\n setSuggestedPrompts(\n channel: string,\n threadTs: string | undefined,\n prompts: SuggestedPrompt[],\n ): Promise<void>;\n setTitle(channel: string, threadTs: string, title: string): Promise<void>;\n channelName(channelId: string): string | undefined;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/adapters/slack/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AppsManifestUpdateArguments, WebClient } from \"@slack/web-api\";\nimport type { Attachment, ConversationKind, OfficeAddress } from \"../../types.js\";\nimport type { Workspace } from \"../../office/types.js\";\nimport type { SlackMessagingBot } from \"./bot.js\";\n\nexport interface SlackWebApi {\n auth: Pick<WebClient[\"auth\"], \"test\">;\n chat: Pick<WebClient[\"chat\"], \"postMessage\" | \"postEphemeral\" | \"update\" | \"delete\">;\n conversations: Pick<WebClient[\"conversations\"], \"open\" | \"history\" | \"replies\" | \"list\">;\n users: Pick<WebClient[\"users\"], \"list\">;\n reactions: Pick<WebClient[\"reactions\"], \"add\">;\n files: Pick<WebClient[\"files\"], \"uploadV2\">;\n assistant: {\n threads: Pick<WebClient[\"assistant\"][\"threads\"], \"setSuggestedPrompts\" | \"setTitle\">;\n };\n apiCall: WebClient[\"apiCall\"];\n}\n\nexport interface SlackSocketEventArgs {\n ack: () => Promise<void>;\n event?: unknown;\n body?: unknown;\n}\n\nexport interface SlackSocketConnection {\n on(event: string, listener: (args: SlackSocketEventArgs) => unknown): unknown;\n start(): Promise<unknown>;\n disconnect(): Promise<void>;\n}\n\nexport interface SlackMessagingBotOptions {\n appToken: string;\n botToken: string;\n workspace: Workspace;\n webApi?: SlackWebApi;\n socket?: SlackSocketConnection;\n fetch?: typeof fetch;\n}\n\nexport type SlackResponderBot = Pick<\n SlackMessagingBot,\n | \"getUser\"\n | \"getMessagingInfo\"\n | \"postMessage\"\n | \"postInThread\"\n | \"postInThreadBlocks\"\n | \"updateMessage\"\n | \"deleteMessage\"\n | \"logBotResponse\"\n | \"tryReserveStreamStart\"\n | \"startMessageStream\"\n | \"appendMessageStream\"\n | \"stopMessageStream\"\n | \"uploadFile\"\n | \"addReaction\"\n | \"setAssistantStatus\"\n>;\n\nexport interface SlackEvent {\n address: OfficeAddress;\n type: \"mention\" | \"dm\";\n conversationKind: ConversationKind;\n channel: string;\n ts: string;\n thread_ts?: string;\n user: string;\n text: string;\n files?: Array<{ name?: string; url_private_download?: string; url_private?: string }>;\n attachments?: Attachment[];\n sessionKey?: string;\n}\n\nexport interface SlackUser {\n id: string;\n userName: string;\n displayName: string;\n isBot?: boolean;\n}\n\nexport interface SlackChannel {\n id: string;\n name: string;\n isPrivate?: boolean;\n isExternallyShared?: boolean;\n}\n\nexport interface SlackAdapterOptions {\n initialMessageTs?: string;\n replyMode?: \"top-level\" | \"thread\";\n}\n\nexport type SlackSessionRef =\n | { kind: \"channel\"; channelId: string }\n | { kind: \"thread\"; channelId: string; threadTs: string };\n\nexport interface SlackAdapterSessionPlan {\n sessionKey: string;\n rootTs?: string;\n initialMessageTs?: string;\n isThreaded: boolean;\n}\n\nexport interface SlackEventAnchorRunPlan<T = SlackEvent> {\n event: T;\n initialMessageTs?: string;\n}\n\nexport interface SlackBlockAction {\n action_id: string;\n block_id?: string;\n type?: string;\n value?: string;\n selected_option?: { text?: { text?: string }; value?: string };\n selected_options?: Array<{ text?: { text?: string }; value?: string }>;\n}\n\nexport interface SlackBlockActionBody {\n actions?: SlackBlockAction[];\n container?: { channel_id?: string; thread_ts?: string; message_ts?: string };\n user?: { id?: string; username?: string; name?: string };\n}\n\nexport interface PlatformSlackOps {\n postBlocks(\n conversationId: string,\n args: { text: string; blocks: object[]; threadTs?: string },\n ): Promise<{ ts: string }>;\n updateBlocks(\n conversationId: string,\n args: { ts: string; text: string; blocks: object[]; threadTs?: string },\n ): Promise<void>;\n ownsBlockKitMessage(conversationId: string, ts: string, threadTs?: string): boolean;\n}\n\nexport interface SlackBlockKitOps {\n postBlocks(args: { text: string; blocks: object[]; threadTs?: string }): Promise<{ ts: string }>;\n updateBlocks(args: { ts: string; text: string; blocks: object[] }): Promise<void>;\n}\n\nexport interface AssistantThreadPayload {\n user_id?: string;\n channel_id?: string;\n thread_ts?: string;\n context?: AgentContext;\n}\n\nexport interface AgentContext {\n channel_id?: string;\n team_id?: string;\n enterprise_id?: string | null;\n}\n\nexport interface SuggestedPrompt {\n title: string;\n message: string;\n}\n\nexport interface AssistantSurfaceOps {\n postInThread(channel: string, threadTs: string, text: string): Promise<string>;\n setSuggestedPrompts(\n channel: string,\n threadTs: string | undefined,\n prompts: SuggestedPrompt[],\n ): Promise<void>;\n setTitle(channel: string, threadTs: string, title: string): Promise<void>;\n channelName(channelId: string): string | undefined;\n}\n\nexport type SlackAppManifest = AppsManifestUpdateArguments[\"manifest\"];\n\nexport interface SlackAppCustomization {\n display_information?: {\n name?: string;\n description?: string;\n long_description?: string;\n background_color?: string;\n };\n}\n\nexport interface SlackConfigTokens {\n token: string;\n refreshToken: string;\n}\n\nexport interface SlackAppApi {\n rotate(refreshToken: string): Promise<SlackConfigTokens & { userId: string }>;\n export(token: string, appId: string): Promise<unknown>;\n update(\n token: string,\n appId: string,\n manifest: SlackAppManifest,\n ): Promise<{ permissionsUpdated: boolean }>;\n create(token: string, manifest: SlackAppManifest): Promise<{ appId: string; installUrl: string }>;\n delete(token: string, appId: string): Promise<void>;\n}\n\nexport interface SlackBotApi {\n appId(): Promise<string>;\n scopes(): Promise<string[]>;\n directMessage(userId: string, text: string): Promise<void>;\n}\n\nexport type SlackAppSyncResult =\n | { status: \"no-token\" }\n | { status: \"failed\"; reason: string }\n | { status: \"unchanged\"; appId: string }\n | { status: \"updated\"; appId: string; missingScopes: string[] };\n"]}
@@ -0,0 +1,16 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { Duplex } from "node:stream";
3
+ import type { OfficeDesktop } from "../../../sandbox/desktop.js";
4
+ import type { DesktopTokenCreateOptions } from "../../../types.js";
5
+ import { InMemoryTokenStore } from "../token-store.js";
6
+ import type { DesktopToken } from "./types.js";
7
+ export interface DesktopWebOptions {
8
+ tokenStore: InMemoryDesktopTokenStore;
9
+ desktop: Pick<OfficeDesktop, "start" | "status" | "setBrowserOwner" | "connect">;
10
+ }
11
+ export declare class InMemoryDesktopTokenStore extends InMemoryTokenStore<DesktopToken> {
12
+ create(options: DesktopTokenCreateOptions): DesktopToken;
13
+ }
14
+ export declare function handleDesktopRequest(req: IncomingMessage, res: ServerResponse, url: URL, options: DesktopWebOptions | undefined): Promise<boolean>;
15
+ export declare function handleDesktopUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer, url: URL, options: DesktopWebOptions | undefined): Promise<boolean>;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapters/web/desktop/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAI1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,yBAAyB,CAAC;IACtC,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,GAAG,QAAQ,GAAG,iBAAiB,GAAG,SAAS,CAAC,CAAC;CAClF;AAED,qBAAa,yBAA0B,SAAQ,kBAAkB,CAAC,YAAY,CAAC;IAC7E,MAAM,CAAC,OAAO,EAAE,yBAAyB,GAAG,YAAY,CAMvD;CACF;AAgCD,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,iBAAiB,GAAG,SAAS,GACrC,OAAO,CAAC,OAAO,CAAC,CA0DlB;AAmBD,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,iBAAiB,GAAG,SAAS,GACrC,OAAO,CAAC,OAAO,CAAC,CAsClB"}
@@ -0,0 +1,163 @@
1
+ import { existsSync, readFileSync, realpathSync } from "node:fs";
2
+ import { dirname, extname, join, sep } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import * as log from "../../../log.js";
5
+ import { errorMessage } from "../../../unknown-values.js";
6
+ import { InMemoryTokenStore } from "../token-store.js";
7
+ import { jsonResponse, readJsonBody } from "../portal-shell.js";
8
+ import { renderDesktopPage } from "./page.js";
9
+ const DESKTOP_TOKEN_TTL_MS = 24 * 60 * 60 * 1000;
10
+ const NOVNC_PREFIX = "/desktop/novnc/";
11
+ const NOVNC_DIRS = ["core", "vendor"];
12
+ export class InMemoryDesktopTokenStore extends InMemoryTokenStore {
13
+ create(options) {
14
+ return this.createRecord(DESKTOP_TOKEN_TTL_MS, {
15
+ platform: options.platform,
16
+ platformUserId: options.platformUserId,
17
+ containerKey: options.office.key,
18
+ });
19
+ }
20
+ }
21
+ const novncRoot = realpathSync(dirname(dirname(fileURLToPath(import.meta.resolve("@novnc/novnc")))));
22
+ function novncFile(pathname) {
23
+ let relative;
24
+ try {
25
+ relative = decodeURIComponent(pathname.slice(NOVNC_PREFIX.length));
26
+ }
27
+ catch {
28
+ return undefined;
29
+ }
30
+ if (!NOVNC_DIRS.some((dir) => relative.startsWith(`${dir}/`)))
31
+ return undefined;
32
+ if (extname(relative) !== ".js")
33
+ return undefined;
34
+ const file = join(novncRoot, relative);
35
+ if (!file.startsWith(novncRoot + sep) || !existsSync(file))
36
+ return undefined;
37
+ return realpathSync(file).startsWith(novncRoot + sep) ? file : undefined;
38
+ }
39
+ function tokenOf(store, url) {
40
+ const raw = url.searchParams.get("token");
41
+ return raw ? store?.peek(raw) : undefined;
42
+ }
43
+ function notFound(res) {
44
+ res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "no-store" });
45
+ res.end("This desktop link is invalid or has expired. Ask for a new one with the desktop command.");
46
+ }
47
+ export async function handleDesktopRequest(req, res, url, options) {
48
+ if (!url.pathname.startsWith("/desktop"))
49
+ return false;
50
+ if (url.pathname !== "/desktop" && !url.pathname.startsWith("/desktop/"))
51
+ return false;
52
+ if (req.method === "GET" && url.pathname.startsWith(NOVNC_PREFIX)) {
53
+ const file = novncFile(url.pathname);
54
+ if (!file) {
55
+ res.writeHead(404);
56
+ res.end();
57
+ return true;
58
+ }
59
+ res.writeHead(200, {
60
+ "Content-Type": "text/javascript; charset=utf-8",
61
+ "Cache-Control": "public, max-age=3600",
62
+ });
63
+ res.end(readFileSync(file));
64
+ return true;
65
+ }
66
+ const token = tokenOf(options?.tokenStore, url);
67
+ if (!options || !token) {
68
+ notFound(res);
69
+ return true;
70
+ }
71
+ if (req.method === "GET" && url.pathname === "/desktop") {
72
+ res.writeHead(200, {
73
+ "Content-Type": "text/html; charset=utf-8",
74
+ "Cache-Control": "no-store",
75
+ "Referrer-Policy": "no-referrer",
76
+ });
77
+ res.end(renderDesktopPage());
78
+ return true;
79
+ }
80
+ if (url.pathname === "/desktop/control" && (req.method === "GET" || req.method === "POST")) {
81
+ try {
82
+ if (req.method === "POST") {
83
+ const body = await readJsonBody(req, res, 1024);
84
+ if (!body)
85
+ return true;
86
+ if (body.owner !== "agent" && body.owner !== "user") {
87
+ jsonResponse(res, 400, { error: "owner must be agent or user" });
88
+ return true;
89
+ }
90
+ await options.desktop.setBrowserOwner(token.containerKey, body.owner);
91
+ }
92
+ const status = await options.desktop.status(token.containerKey);
93
+ jsonResponse(res, 200, { owner: status.control, running: status.display !== undefined });
94
+ }
95
+ catch (error) {
96
+ log.logWarning("Desktop control failed", errorMessage(error));
97
+ jsonResponse(res, 409, { error: "The desktop is not running. Ask for a new link." });
98
+ }
99
+ return true;
100
+ }
101
+ res.writeHead(404);
102
+ res.end();
103
+ return true;
104
+ }
105
+ const REFUSAL_GRACE_MS = 1_000;
106
+ function refuse(socket, status, reason) {
107
+ socket.end(`HTTP/1.1 ${status} ${reason}\r\nConnection: close\r\nContent-Length: 0\r\n\r\n`);
108
+ setTimeout(() => socket.destroy(), REFUSAL_GRACE_MS).unref();
109
+ }
110
+ function upstreamRequest(req) {
111
+ const lines = ["GET / HTTP/1.1", "Host: 127.0.0.1"];
112
+ for (let i = 0; i < req.rawHeaders.length; i += 2) {
113
+ const name = req.rawHeaders[i] ?? "";
114
+ if (/^(host|origin|cookie|authorization)$/i.test(name))
115
+ continue;
116
+ lines.push(`${name}: ${req.rawHeaders[i + 1] ?? ""}`);
117
+ }
118
+ return `${lines.join("\r\n")}\r\n\r\n`;
119
+ }
120
+ export async function handleDesktopUpgrade(req, socket, head, url, options) {
121
+ if (url.pathname !== "/desktop/ws")
122
+ return false;
123
+ const token = tokenOf(options?.tokenStore, url);
124
+ if (!options || !token) {
125
+ refuse(socket, 403, "Forbidden");
126
+ return true;
127
+ }
128
+ let started;
129
+ try {
130
+ started = await options.desktop.start(token.containerKey);
131
+ }
132
+ catch (error) {
133
+ log.logWarning("Desktop start failed", errorMessage(error));
134
+ refuse(socket, 503, "Service Unavailable");
135
+ return true;
136
+ }
137
+ if (started !== "ready") {
138
+ refuse(socket, 409, "Conflict");
139
+ return true;
140
+ }
141
+ if (socket.destroyed)
142
+ return true;
143
+ const stream = options.desktop.connect(token.containerKey);
144
+ const expiry = setTimeout(() => close(), Math.max(0, token.expiresAt - Date.now()));
145
+ expiry.unref();
146
+ function close() {
147
+ clearTimeout(expiry);
148
+ stream.close();
149
+ socket.destroy();
150
+ }
151
+ stream.input.on("error", close);
152
+ stream.output.on("error", close);
153
+ stream.process.once("exit", close);
154
+ socket.on("error", close);
155
+ socket.on("close", close);
156
+ stream.input.write(upstreamRequest(req));
157
+ if (head.length > 0)
158
+ stream.input.write(head);
159
+ socket.pipe(stream.input);
160
+ stream.output.pipe(socket);
161
+ return true;
162
+ }
163
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/web/desktop/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, realpathSync } from \"node:fs\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { Duplex } from \"node:stream\";\nimport { dirname, extname, join, sep } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as log from \"../../../log.js\";\nimport type { OfficeDesktop } from \"../../../sandbox/desktop.js\";\nimport type { DesktopTokenCreateOptions } from \"../../../types.js\";\nimport { errorMessage } from \"../../../unknown-values.js\";\nimport { InMemoryTokenStore } from \"../token-store.js\";\nimport { jsonResponse, readJsonBody } from \"../portal-shell.js\";\nimport { renderDesktopPage } from \"./page.js\";\nimport type { DesktopToken } from \"./types.js\";\n\nconst DESKTOP_TOKEN_TTL_MS = 24 * 60 * 60 * 1000;\nconst NOVNC_PREFIX = \"/desktop/novnc/\";\nconst NOVNC_DIRS = [\"core\", \"vendor\"];\n\nexport interface DesktopWebOptions {\n tokenStore: InMemoryDesktopTokenStore;\n desktop: Pick<OfficeDesktop, \"start\" | \"status\" | \"setBrowserOwner\" | \"connect\">;\n}\n\nexport class InMemoryDesktopTokenStore extends InMemoryTokenStore<DesktopToken> {\n create(options: DesktopTokenCreateOptions): DesktopToken {\n return this.createRecord(DESKTOP_TOKEN_TTL_MS, {\n platform: options.platform,\n platformUserId: options.platformUserId,\n containerKey: options.office.key,\n });\n }\n}\n\nconst novncRoot = realpathSync(\n dirname(dirname(fileURLToPath(import.meta.resolve(\"@novnc/novnc\")))),\n);\n\nfunction novncFile(pathname: string): string | undefined {\n let relative: string;\n try {\n relative = decodeURIComponent(pathname.slice(NOVNC_PREFIX.length));\n } catch {\n return undefined;\n }\n if (!NOVNC_DIRS.some((dir) => relative.startsWith(`${dir}/`))) return undefined;\n if (extname(relative) !== \".js\") return undefined;\n const file = join(novncRoot, relative);\n if (!file.startsWith(novncRoot + sep) || !existsSync(file)) return undefined;\n return realpathSync(file).startsWith(novncRoot + sep) ? file : undefined;\n}\n\nfunction tokenOf(store: InMemoryDesktopTokenStore | undefined, url: URL): DesktopToken | undefined {\n const raw = url.searchParams.get(\"token\");\n return raw ? store?.peek(raw) : undefined;\n}\n\nfunction notFound(res: ServerResponse): void {\n res.writeHead(404, { \"Content-Type\": \"text/plain; charset=utf-8\", \"Cache-Control\": \"no-store\" });\n res.end(\n \"This desktop link is invalid or has expired. Ask for a new one with the desktop command.\",\n );\n}\n\nexport async function handleDesktopRequest(\n req: IncomingMessage,\n res: ServerResponse,\n url: URL,\n options: DesktopWebOptions | undefined,\n): Promise<boolean> {\n if (!url.pathname.startsWith(\"/desktop\")) return false;\n if (url.pathname !== \"/desktop\" && !url.pathname.startsWith(\"/desktop/\")) return false;\n\n if (req.method === \"GET\" && url.pathname.startsWith(NOVNC_PREFIX)) {\n const file = novncFile(url.pathname);\n if (!file) {\n res.writeHead(404);\n res.end();\n return true;\n }\n res.writeHead(200, {\n \"Content-Type\": \"text/javascript; charset=utf-8\",\n \"Cache-Control\": \"public, max-age=3600\",\n });\n res.end(readFileSync(file));\n return true;\n }\n\n const token = tokenOf(options?.tokenStore, url);\n if (!options || !token) {\n notFound(res);\n return true;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/desktop\") {\n res.writeHead(200, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n \"Referrer-Policy\": \"no-referrer\",\n });\n res.end(renderDesktopPage());\n return true;\n }\n\n if (url.pathname === \"/desktop/control\" && (req.method === \"GET\" || req.method === \"POST\")) {\n try {\n if (req.method === \"POST\") {\n const body = await readJsonBody(req, res, 1024);\n if (!body) return true;\n if (body.owner !== \"agent\" && body.owner !== \"user\") {\n jsonResponse(res, 400, { error: \"owner must be agent or user\" });\n return true;\n }\n await options.desktop.setBrowserOwner(token.containerKey, body.owner);\n }\n const status = await options.desktop.status(token.containerKey);\n jsonResponse(res, 200, { owner: status.control, running: status.display !== undefined });\n } catch (error) {\n log.logWarning(\"Desktop control failed\", errorMessage(error));\n jsonResponse(res, 409, { error: \"The desktop is not running. Ask for a new link.\" });\n }\n return true;\n }\n\n res.writeHead(404);\n res.end();\n return true;\n}\n\nconst REFUSAL_GRACE_MS = 1_000;\n\nfunction refuse(socket: Duplex, status: number, reason: string): void {\n socket.end(`HTTP/1.1 ${status} ${reason}\\r\\nConnection: close\\r\\nContent-Length: 0\\r\\n\\r\\n`);\n setTimeout(() => socket.destroy(), REFUSAL_GRACE_MS).unref();\n}\n\nfunction upstreamRequest(req: IncomingMessage): string {\n const lines = [\"GET / HTTP/1.1\", \"Host: 127.0.0.1\"];\n for (let i = 0; i < req.rawHeaders.length; i += 2) {\n const name = req.rawHeaders[i] ?? \"\";\n if (/^(host|origin|cookie|authorization)$/i.test(name)) continue;\n lines.push(`${name}: ${req.rawHeaders[i + 1] ?? \"\"}`);\n }\n return `${lines.join(\"\\r\\n\")}\\r\\n\\r\\n`;\n}\n\nexport async function handleDesktopUpgrade(\n req: IncomingMessage,\n socket: Duplex,\n head: Buffer,\n url: URL,\n options: DesktopWebOptions | undefined,\n): Promise<boolean> {\n if (url.pathname !== \"/desktop/ws\") return false;\n const token = tokenOf(options?.tokenStore, url);\n if (!options || !token) {\n refuse(socket, 403, \"Forbidden\");\n return true;\n }\n let started: Awaited<ReturnType<OfficeDesktop[\"start\"]>>;\n try {\n started = await options.desktop.start(token.containerKey);\n } catch (error) {\n log.logWarning(\"Desktop start failed\", errorMessage(error));\n refuse(socket, 503, \"Service Unavailable\");\n return true;\n }\n if (started !== \"ready\") {\n refuse(socket, 409, \"Conflict\");\n return true;\n }\n if (socket.destroyed) return true;\n const stream = options.desktop.connect(token.containerKey);\n const expiry = setTimeout(() => close(), Math.max(0, token.expiresAt - Date.now()));\n expiry.unref();\n function close() {\n clearTimeout(expiry);\n stream.close();\n socket.destroy();\n }\n stream.input.on(\"error\", close);\n stream.output.on(\"error\", close);\n stream.process.once(\"exit\", close);\n socket.on(\"error\", close);\n socket.on(\"close\", close);\n stream.input.write(upstreamRequest(req));\n if (head.length > 0) stream.input.write(head);\n socket.pipe(stream.input);\n stream.output.pipe(socket);\n return true;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function renderDesktopPage(): string;
2
+ //# sourceMappingURL=page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../src/adapters/web/desktop/page.ts"],"names":[],"mappings":"AA8DA,wBAAgB,iBAAiB,IAAI,MAAM,CAqB1C"}
@@ -0,0 +1,83 @@
1
+ const STYLE = `
2
+ html, body { margin: 0; height: 100%; background: #1a1b26; color: #c0caf5;
3
+ font: 13px/1.4 system-ui, -apple-system, "Segoe UI", sans-serif; }
4
+ body { display: flex; flex-direction: column; }
5
+ header { display: flex; align-items: center; gap: 12px; padding: 6px 12px;
6
+ background: #16161e; border-bottom: 1px solid #292e42; }
7
+ header strong { font-weight: 600; letter-spacing: .02em; }
8
+ #state { color: #7a88cf; }
9
+ #owner { margin-left: auto; color: #9ece6a; }
10
+ #owner[data-owner="user"] { color: #e0af68; }
11
+ button { font: inherit; color: #1a1b26; background: #7aa2f7; border: 0; border-radius: 6px;
12
+ padding: 4px 12px; cursor: pointer; }
13
+ button:disabled { opacity: .5; cursor: default; }
14
+ #screen { flex: 1; min-height: 0; }
15
+ `;
16
+ const SCRIPT = `
17
+ import RFB from "./desktop/novnc/core/rfb.js";
18
+
19
+ const token = new URLSearchParams(location.search).get("token") ?? "";
20
+ const query = "?token=" + encodeURIComponent(token);
21
+ const state = document.getElementById("state");
22
+ const owner = document.getElementById("owner");
23
+ const toggle = document.getElementById("toggle");
24
+ const wsUrl = new URL("desktop/ws" + query, location.href);
25
+ wsUrl.protocol = location.protocol === "https:" ? "wss:" : "ws:";
26
+
27
+ const rfb = new RFB(document.getElementById("screen"), wsUrl.href);
28
+ rfb.resizeSession = true;
29
+ rfb.scaleViewport = true;
30
+ rfb.focusOnClick = true;
31
+ rfb.addEventListener("connect", () => { state.textContent = "Connected"; rfb.focus(); });
32
+ rfb.addEventListener("disconnect", (event) => {
33
+ clearInterval(polling);
34
+ toggle.disabled = true;
35
+ state.textContent = event.detail.clean ? "Disconnected" : "Connection lost. Reload or ask for a new link.";
36
+ });
37
+
38
+ function showOwner(value) {
39
+ owner.dataset.owner = value;
40
+ owner.textContent = value === "user" ? "You control the browser" : "The agent controls the browser";
41
+ toggle.textContent = value === "user" ? "Hand back to agent" : "Take control";
42
+ toggle.disabled = false;
43
+ }
44
+
45
+ async function control(method, body) {
46
+ const response = await fetch("desktop/control" + query, {
47
+ method,
48
+ headers: body ? { "content-type": "application/json" } : undefined,
49
+ body: body ? JSON.stringify(body) : undefined,
50
+ });
51
+ if (response.ok) showOwner((await response.json()).owner);
52
+ }
53
+
54
+ toggle.addEventListener("click", () => {
55
+ toggle.disabled = true;
56
+ control("POST", { owner: owner.dataset.owner === "user" ? "agent" : "user" });
57
+ });
58
+ control("GET");
59
+ const polling = setInterval(() => control("GET"), 5000);
60
+ `;
61
+ export function renderDesktopPage() {
62
+ return `<!DOCTYPE html>
63
+ <html lang="en">
64
+ <head>
65
+ <meta charset="utf-8">
66
+ <meta name="viewport" content="width=device-width, initial-scale=1">
67
+ <meta name="referrer" content="no-referrer">
68
+ <title>Desktop — mikan</title>
69
+ <style>${STYLE}</style>
70
+ </head>
71
+ <body>
72
+ <header>
73
+ <strong>mikan desktop</strong>
74
+ <span id="state">Connecting…</span>
75
+ <span id="owner"></span>
76
+ <button id="toggle" type="button" disabled>Take control</button>
77
+ </header>
78
+ <div id="screen"></div>
79
+ <script type="module">${SCRIPT}</script>
80
+ </body>
81
+ </html>`;
82
+ }
83
+ //# sourceMappingURL=page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.js","sourceRoot":"","sources":["../../../../src/adapters/web/desktop/page.ts"],"names":[],"mappings":"AAAA,MAAM,KAAK,GAAG;;;;;;;;;;;;;;CAcb,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4Cd,CAAC;AAEF,MAAM,UAAU,iBAAiB;IAC/B,OAAO;;;;;;;SAOA,KAAK;;;;;;;;;;wBAUU,MAAM;;QAEtB,CAAC;AACT,CAAC","sourcesContent":["const STYLE = `\nhtml, body { margin: 0; height: 100%; background: #1a1b26; color: #c0caf5;\n font: 13px/1.4 system-ui, -apple-system, \"Segoe UI\", sans-serif; }\nbody { display: flex; flex-direction: column; }\nheader { display: flex; align-items: center; gap: 12px; padding: 6px 12px;\n background: #16161e; border-bottom: 1px solid #292e42; }\nheader strong { font-weight: 600; letter-spacing: .02em; }\n#state { color: #7a88cf; }\n#owner { margin-left: auto; color: #9ece6a; }\n#owner[data-owner=\"user\"] { color: #e0af68; }\nbutton { font: inherit; color: #1a1b26; background: #7aa2f7; border: 0; border-radius: 6px;\n padding: 4px 12px; cursor: pointer; }\nbutton:disabled { opacity: .5; cursor: default; }\n#screen { flex: 1; min-height: 0; }\n`;\n\nconst SCRIPT = `\nimport RFB from \"./desktop/novnc/core/rfb.js\";\n\nconst token = new URLSearchParams(location.search).get(\"token\") ?? \"\";\nconst query = \"?token=\" + encodeURIComponent(token);\nconst state = document.getElementById(\"state\");\nconst owner = document.getElementById(\"owner\");\nconst toggle = document.getElementById(\"toggle\");\nconst wsUrl = new URL(\"desktop/ws\" + query, location.href);\nwsUrl.protocol = location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n\nconst rfb = new RFB(document.getElementById(\"screen\"), wsUrl.href);\nrfb.resizeSession = true;\nrfb.scaleViewport = true;\nrfb.focusOnClick = true;\nrfb.addEventListener(\"connect\", () => { state.textContent = \"Connected\"; rfb.focus(); });\nrfb.addEventListener(\"disconnect\", (event) => {\n clearInterval(polling);\n toggle.disabled = true;\n state.textContent = event.detail.clean ? \"Disconnected\" : \"Connection lost. Reload or ask for a new link.\";\n});\n\nfunction showOwner(value) {\n owner.dataset.owner = value;\n owner.textContent = value === \"user\" ? \"You control the browser\" : \"The agent controls the browser\";\n toggle.textContent = value === \"user\" ? \"Hand back to agent\" : \"Take control\";\n toggle.disabled = false;\n}\n\nasync function control(method, body) {\n const response = await fetch(\"desktop/control\" + query, {\n method,\n headers: body ? { \"content-type\": \"application/json\" } : undefined,\n body: body ? JSON.stringify(body) : undefined,\n });\n if (response.ok) showOwner((await response.json()).owner);\n}\n\ntoggle.addEventListener(\"click\", () => {\n toggle.disabled = true;\n control(\"POST\", { owner: owner.dataset.owner === \"user\" ? \"agent\" : \"user\" });\n});\ncontrol(\"GET\");\nconst polling = setInterval(() => control(\"GET\"), 5000);\n`;\n\nexport function renderDesktopPage(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<meta name=\"referrer\" content=\"no-referrer\">\n<title>Desktop — mikan</title>\n<style>${STYLE}</style>\n</head>\n<body>\n<header>\n<strong>mikan desktop</strong>\n<span id=\"state\">Connecting…</span>\n<span id=\"owner\"></span>\n<button id=\"toggle\" type=\"button\" disabled>Take control</button>\n</header>\n<div id=\"screen\"></div>\n<script type=\"module\">${SCRIPT}</script>\n</body>\n</html>`;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { PlatformName } from "../../../types.js";
2
+ import type { TokenRecord } from "../types.js";
3
+ export interface DesktopToken extends TokenRecord {
4
+ platform: PlatformName;
5
+ platformUserId: string;
6
+ containerKey: string;
7
+ }
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/adapters/web/desktop/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,QAAQ,EAAE,YAAY,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/adapters/web/desktop/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { PlatformName } from \"../../../types.js\";\nimport type { TokenRecord } from \"../types.js\";\n\nexport interface DesktopToken extends TokenRecord {\n platform: PlatformName;\n platformUserId: string;\n containerKey: string;\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { type Server } from "node:http";
2
+ import { type DesktopWebOptions } from "./desktop/index.js";
2
3
  import type { MessagingBot, PlatformName } from "../../types.js";
3
4
  import type { SandboxConfig } from "../../sandbox/types.js";
4
5
  import { type EventScheduleSink } from "../../events/index.js";
@@ -28,6 +29,7 @@ interface StartWebServerOptions {
28
29
  eventScheduler?: () => EventScheduleSink | undefined;
29
30
  };
30
31
  githubWebhook?: GithubWebhookOptions;
32
+ desktop?: DesktopWebOptions;
31
33
  }
32
34
  export declare function startWebServer(options: StartWebServerOptions): Server;
33
35
  export declare function closeWebServer(server: Server, graceMs: number): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/adapters/web/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AACjG,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAGjE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,KAAK,EAAU,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAE/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG/D,UAAU,qBAAqB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,sBAAsB,CAAC;IACvC,YAAY,EAAE,YAAY,CAAC;IAC3B,MAAM,EAAE,QAAQ,CAAC;IACjB,qBAAqB,CAAC,EAAE,6BAA6B,CAAC;IACtD,sBAAsB,CAAC,EAAE,6BAA6B,CAAC;IACvD,YAAY,CAAC,EAAE;QACb,eAAe,EAAE,uBAAuB,CAAC;QACzC,SAAS,EAAE,SAAS,CAAC;QACrB,OAAO,CAAC,EAAE,kBAAkB,CAAC;QAC7B,OAAO,CAAC,EAAE,aAAa,CAAC;QACxB,cAAc,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;QAC7D,cAAc,CAAC,EAAE,MAAM,iBAAiB,GAAG,SAAS,CAAC;KACtD,CAAC;IACF,aAAa,CAAC,EAAE,oBAAoB,CAAC;CACtC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAuFrE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO7E"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/adapters/web/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AAEjG,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAGjE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,KAAK,EAAU,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAE/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG/D,UAAU,qBAAqB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,sBAAsB,CAAC;IACvC,YAAY,EAAE,YAAY,CAAC;IAC3B,MAAM,EAAE,QAAQ,CAAC;IACjB,qBAAqB,CAAC,EAAE,6BAA6B,CAAC;IACtD,sBAAsB,CAAC,EAAE,6BAA6B,CAAC;IACvD,YAAY,CAAC,EAAE;QACb,eAAe,EAAE,uBAAuB,CAAC;QACzC,SAAS,EAAE,SAAS,CAAC;QACrB,OAAO,CAAC,EAAE,kBAAkB,CAAC;QAC7B,OAAO,CAAC,EAAE,aAAa,CAAC;QACxB,cAAc,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;QAC7D,cAAc,CAAC,EAAE,MAAM,iBAAiB,GAAG,SAAS,CAAC;KACtD,CAAC;IACF,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAyGrE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO7E"}
@@ -1,4 +1,5 @@
1
1
  import { createServer } from "node:http";
2
+ import { handleDesktopRequest, handleDesktopUpgrade, } from "./desktop/index.js";
2
3
  import { resolveLinkBaseUrl } from "../../env-manifest.js";
3
4
  import * as log from "../../log.js";
4
5
  import { OfficeEventStore } from "../../events/index.js";
@@ -43,6 +44,8 @@ export function startWebServer(options) {
43
44
  if (await handleSessionViewRequest(req, res, url, options.sessionViewTokenStore, options.sessionViewInteractive)) {
44
45
  return;
45
46
  }
47
+ if (await handleDesktopRequest(req, res, url, options.desktop))
48
+ return;
46
49
  if (loginHandler(req, res, url))
47
50
  return;
48
51
  res.writeHead(404);
@@ -64,6 +67,22 @@ export function startWebServer(options) {
64
67
  "MIKAN_LINK_URL=https://your-host.example.com for production.");
65
68
  }
66
69
  });
70
+ server.on("upgrade", (req, socket, head) => {
71
+ socket.on("error", () => socket.destroy());
72
+ Promise.resolve()
73
+ .then(() => {
74
+ const url = new URL(req.url ?? "/", requestBaseUrl(req));
75
+ return handleDesktopUpgrade(req, socket, head, url, options.desktop);
76
+ })
77
+ .then((handled) => {
78
+ if (!handled)
79
+ socket.destroy();
80
+ })
81
+ .catch((err) => {
82
+ log.logWarning("Web server upgrade error", errorMessage(err));
83
+ socket.destroy();
84
+ });
85
+ });
67
86
  server.on("error", (err) => {
68
87
  log.logWarning("Web server error", err.message);
69
88
  });
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/adapters/web/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { MessagingBot, PlatformName } from \"../../types.js\";\nimport { resolveLinkBaseUrl } from \"../../env-manifest.js\";\nimport * as log from \"../../log.js\";\nimport type { SandboxConfig } from \"../../sandbox/types.js\";\nimport { OfficeEventStore, type EventScheduleSink } from \"../../events/index.js\";\nimport type { VaultManager } from \"../../vault/types.js\";\nimport { handleAdminRequest } from \"./admin/portal.js\";\nimport type { AdminRuntimeBridge } from \"./admin/types.js\";\nimport type { InMemoryAdminTokenStore } from \"./admin/portal.js\";\nimport { createLoginRequestHandler } from \"./login/portal.js\";\nimport { requestBaseUrl } from \"./portal-shell.js\";\nimport type { InMemoryLinkTokenStore } from \"./login/portal.js\";\nimport type { NotifyFn } from \"./login/types.js\";\nimport { handleSessionViewRequest } from \"./session-view/portal.js\";\nimport type { SessionViewInteractiveOptions } from \"./session-view/types.js\";\nimport type { InMemorySessionViewTokenStore } from \"./session-view/portal.js\";\nimport type { Office, Workspace } from \"../../office/types.js\";\nimport { createGithubWebhookHandler } from \"../github/webhook.js\";\nimport type { GithubWebhookOptions } from \"../github/types.js\";\nimport { errorMessage } from \"../../unknown-values.js\";\n\ninterface StartWebServerOptions {\n port: number;\n host: string;\n linkTokenStore: InMemoryLinkTokenStore;\n vaultManager: VaultManager;\n notify: NotifyFn;\n sessionViewTokenStore?: InMemorySessionViewTokenStore;\n sessionViewInteractive?: SessionViewInteractiveOptions;\n adminOptions?: {\n adminTokenStore: InMemoryAdminTokenStore;\n workspace: Workspace;\n runtime?: AdminRuntimeBridge;\n sandbox?: SandboxConfig;\n botsByPlatform?: Partial<Record<PlatformName, MessagingBot>>;\n eventScheduler?: () => EventScheduleSink | undefined;\n };\n githubWebhook?: GithubWebhookOptions;\n}\n\nexport function startWebServer(options: StartWebServerOptions): Server {\n const loginHandler = createLoginRequestHandler(\n options.linkTokenStore,\n options.vaultManager,\n options.notify,\n );\n\n const adminEventStore = (office: Office) =>\n new OfficeEventStore(office, options.adminOptions?.eventScheduler?.());\n\n const githubWebhook = options.githubWebhook\n ? createGithubWebhookHandler(options.githubWebhook)\n : undefined;\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n try {\n const url = new URL(req.url ?? \"/\", requestBaseUrl(req));\n\n if (req.method === \"GET\" && url.pathname === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true }));\n return;\n }\n\n if (githubWebhook && (await githubWebhook(req, res, url))) {\n return;\n }\n\n const adminOptions = options.adminOptions;\n if (\n adminOptions?.adminTokenStore &&\n (await handleAdminRequest(req, res, url, {\n linkTokenStore: options.linkTokenStore,\n sessionViewTokenStore: options.sessionViewTokenStore,\n adminTokenStore: adminOptions.adminTokenStore,\n portalBaseUrl: resolveLinkBaseUrl() ?? undefined,\n workspace: adminOptions.workspace,\n eventStore: adminEventStore,\n runtime: adminOptions.runtime,\n sandbox: adminOptions.sandbox,\n botsByPlatform: adminOptions.botsByPlatform,\n }))\n ) {\n return;\n }\n\n if (\n await handleSessionViewRequest(\n req,\n res,\n url,\n options.sessionViewTokenStore,\n options.sessionViewInteractive,\n )\n ) {\n return;\n }\n\n if (loginHandler(req, res, url)) return;\n\n res.writeHead(404);\n res.end();\n } catch (err) {\n log.logWarning(\"Web server request error\", errorMessage(err));\n if (!res.headersSent) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n }\n res.end(JSON.stringify({ error: \"Internal server error\" }));\n }\n });\n\n server.listen(options.port, options.host, () => {\n log.logInfo(`Web server listening on ${options.host}:${options.port}`);\n if (!resolveLinkBaseUrl()) {\n log.logWarning(\n \"MIKAN_LINK_URL is not set — OAuth redirect_uri will be \" +\n \"derived from request headers (Host / X-Forwarded-*). Set \" +\n \"MIKAN_LINK_URL=https://your-host.example.com for production.\",\n );\n }\n });\n\n server.on(\"error\", (err) => {\n log.logWarning(\"Web server error\", err.message);\n });\n\n return server;\n}\n\nexport function closeWebServer(server: Server, graceMs: number): Promise<void> {\n const closed = new Promise<void>((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()));\n });\n server.closeIdleConnections();\n const forceClose = setTimeout(() => server.closeAllConnections(), graceMs);\n return closed.finally(() => clearTimeout(forceClose));\n}\n"]}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/adapters/web/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { Duplex } from \"node:stream\";\nimport {\n handleDesktopRequest,\n handleDesktopUpgrade,\n type DesktopWebOptions,\n} from \"./desktop/index.js\";\nimport type { MessagingBot, PlatformName } from \"../../types.js\";\nimport { resolveLinkBaseUrl } from \"../../env-manifest.js\";\nimport * as log from \"../../log.js\";\nimport type { SandboxConfig } from \"../../sandbox/types.js\";\nimport { OfficeEventStore, type EventScheduleSink } from \"../../events/index.js\";\nimport type { VaultManager } from \"../../vault/types.js\";\nimport { handleAdminRequest } from \"./admin/portal.js\";\nimport type { AdminRuntimeBridge } from \"./admin/types.js\";\nimport type { InMemoryAdminTokenStore } from \"./admin/portal.js\";\nimport { createLoginRequestHandler } from \"./login/portal.js\";\nimport { requestBaseUrl } from \"./portal-shell.js\";\nimport type { InMemoryLinkTokenStore } from \"./login/portal.js\";\nimport type { NotifyFn } from \"./login/types.js\";\nimport { handleSessionViewRequest } from \"./session-view/portal.js\";\nimport type { SessionViewInteractiveOptions } from \"./session-view/types.js\";\nimport type { InMemorySessionViewTokenStore } from \"./session-view/portal.js\";\nimport type { Office, Workspace } from \"../../office/types.js\";\nimport { createGithubWebhookHandler } from \"../github/webhook.js\";\nimport type { GithubWebhookOptions } from \"../github/types.js\";\nimport { errorMessage } from \"../../unknown-values.js\";\n\ninterface StartWebServerOptions {\n port: number;\n host: string;\n linkTokenStore: InMemoryLinkTokenStore;\n vaultManager: VaultManager;\n notify: NotifyFn;\n sessionViewTokenStore?: InMemorySessionViewTokenStore;\n sessionViewInteractive?: SessionViewInteractiveOptions;\n adminOptions?: {\n adminTokenStore: InMemoryAdminTokenStore;\n workspace: Workspace;\n runtime?: AdminRuntimeBridge;\n sandbox?: SandboxConfig;\n botsByPlatform?: Partial<Record<PlatformName, MessagingBot>>;\n eventScheduler?: () => EventScheduleSink | undefined;\n };\n githubWebhook?: GithubWebhookOptions;\n desktop?: DesktopWebOptions;\n}\n\nexport function startWebServer(options: StartWebServerOptions): Server {\n const loginHandler = createLoginRequestHandler(\n options.linkTokenStore,\n options.vaultManager,\n options.notify,\n );\n\n const adminEventStore = (office: Office) =>\n new OfficeEventStore(office, options.adminOptions?.eventScheduler?.());\n\n const githubWebhook = options.githubWebhook\n ? createGithubWebhookHandler(options.githubWebhook)\n : undefined;\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n try {\n const url = new URL(req.url ?? \"/\", requestBaseUrl(req));\n\n if (req.method === \"GET\" && url.pathname === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true }));\n return;\n }\n\n if (githubWebhook && (await githubWebhook(req, res, url))) {\n return;\n }\n\n const adminOptions = options.adminOptions;\n if (\n adminOptions?.adminTokenStore &&\n (await handleAdminRequest(req, res, url, {\n linkTokenStore: options.linkTokenStore,\n sessionViewTokenStore: options.sessionViewTokenStore,\n adminTokenStore: adminOptions.adminTokenStore,\n portalBaseUrl: resolveLinkBaseUrl() ?? undefined,\n workspace: adminOptions.workspace,\n eventStore: adminEventStore,\n runtime: adminOptions.runtime,\n sandbox: adminOptions.sandbox,\n botsByPlatform: adminOptions.botsByPlatform,\n }))\n ) {\n return;\n }\n\n if (\n await handleSessionViewRequest(\n req,\n res,\n url,\n options.sessionViewTokenStore,\n options.sessionViewInteractive,\n )\n ) {\n return;\n }\n\n if (await handleDesktopRequest(req, res, url, options.desktop)) return;\n\n if (loginHandler(req, res, url)) return;\n\n res.writeHead(404);\n res.end();\n } catch (err) {\n log.logWarning(\"Web server request error\", errorMessage(err));\n if (!res.headersSent) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n }\n res.end(JSON.stringify({ error: \"Internal server error\" }));\n }\n });\n\n server.listen(options.port, options.host, () => {\n log.logInfo(`Web server listening on ${options.host}:${options.port}`);\n if (!resolveLinkBaseUrl()) {\n log.logWarning(\n \"MIKAN_LINK_URL is not set — OAuth redirect_uri will be \" +\n \"derived from request headers (Host / X-Forwarded-*). Set \" +\n \"MIKAN_LINK_URL=https://your-host.example.com for production.\",\n );\n }\n });\n\n server.on(\"upgrade\", (req: IncomingMessage, socket: Duplex, head: Buffer) => {\n socket.on(\"error\", () => socket.destroy());\n Promise.resolve()\n .then(() => {\n const url = new URL(req.url ?? \"/\", requestBaseUrl(req));\n return handleDesktopUpgrade(req, socket, head, url, options.desktop);\n })\n .then((handled) => {\n if (!handled) socket.destroy();\n })\n .catch((err: unknown) => {\n log.logWarning(\"Web server upgrade error\", errorMessage(err));\n socket.destroy();\n });\n });\n\n server.on(\"error\", (err) => {\n log.logWarning(\"Web server error\", err.message);\n });\n\n return server;\n}\n\nexport function closeWebServer(server: Server, graceMs: number): Promise<void> {\n const closed = new Promise<void>((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()));\n });\n server.closeIdleConnections();\n const forceClose = setTimeout(() => server.closeAllConnections(), graceMs);\n return closed.finally(() => clearTimeout(forceClose));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../src/cli/boot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAwB3C,wBAAgB,WAAW,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,QAAQ,CAkB5E;AAwBD,wBAAgB,QAAQ,IAAI,MAAM,CAcjC"}
1
+ {"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../src/cli/boot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAwB3C,wBAAgB,WAAW,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,QAAQ,CAkB5E;AAyBD,wBAAgB,QAAQ,IAAI,MAAM,CAgBjC"}
package/dist/cli/boot.js CHANGED
@@ -2,7 +2,7 @@ import { join, resolve } from "node:path";
2
2
  import { envSummaryLines } from "../env-manifest.js";
3
3
  import { parseSandboxArg } from "../sandbox/registry.js";
4
4
  import { cliCommand, nonEmptyValue, stateDirPath } from "./arg-grammar.js";
5
- const SUBCOMMANDS = ["migrate", "office", "env"];
5
+ const SUBCOMMANDS = ["migrate", "office", "env", "slack"];
6
6
  function bootCommand() {
7
7
  return cliCommand("mikan")
8
8
  .description("Multi-platform chat agent daemon")
@@ -42,6 +42,7 @@ function subcommandPlan(args) {
42
42
  mode,
43
43
  migrateArgs: mode === "migrate" ? args.slice(1) : undefined,
44
44
  officeArgs: mode === "office" ? args.slice(1) : undefined,
45
+ slackArgs: mode === "slack" ? args.slice(1) : undefined,
45
46
  stateDir,
46
47
  workingDir: join(stateDir, "workspace"),
47
48
  workingDirExplicit: false,
@@ -64,6 +65,8 @@ Commands:
64
65
  mikan migrate --sandbox <spec> [--dry-run] Apply pending state migrations (stop the daemon first).
65
66
  mikan office list List office keys with their platform and conversation id.
66
67
  mikan env Show environment-variable inventory.
68
+ mikan slack token Store a Slack configuration token; mikan then keeps the Slack app configured.
69
+ mikan slack set --name … Customize the Slack app's name and description.
67
70
  mikan onboard Interactive first-run setup.
68
71
 
69
72
  Environment (platform tokens select which chat adapters start):