tide-commander 1.96.0 → 1.97.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 (44) hide show
  1. package/dist/assets/{BossLogsModal-BFy6Rxdn.js → BossLogsModal-CT25hD17.js} +1 -1
  2. package/dist/assets/{BossSpawnModal-KQyJYj_B.js → BossSpawnModal-9rS7AFkZ.js} +1 -1
  3. package/dist/assets/{ControlsModal-W_ghuG_Q.js → ControlsModal-D-mymoM7.js} +1 -1
  4. package/dist/assets/{DockerLogsModal-valTcuRy.js → DockerLogsModal-Ae-ZCeeP.js} +1 -1
  5. package/dist/assets/EmbeddedEditor-DLOOpM0K.js +33 -0
  6. package/dist/assets/{GmailOAuthSetup-AcW1zAlk.js → GmailOAuthSetup-C9NLhWLo.js} +1 -1
  7. package/dist/assets/{GoogleOAuthSetup-C9uZ46Oe.js → GoogleOAuthSetup-1kzgrPV6.js} +1 -1
  8. package/dist/assets/{IframeModal-CmWv7GXl.js → IframeModal-DKS0IFsr.js} +1 -1
  9. package/dist/assets/{IntegrationsPanel-CNvzosgx.js → IntegrationsPanel-CBvKOeud.js} +2 -2
  10. package/dist/assets/{LogViewerModal-imTE-619.js → LogViewerModal-Dlt8JfVg.js} +1 -1
  11. package/dist/assets/{MonitoringModal-DLxBY738.js → MonitoringModal-BM1IEZv6.js} +1 -1
  12. package/dist/assets/{PM2LogsModal-S4n0D11V.js → PM2LogsModal-B1-HUHWZ.js} +1 -1
  13. package/dist/assets/{RestoreArchivedAreaModal-B32sqCxN.js → RestoreArchivedAreaModal-DXmYo7fp.js} +1 -1
  14. package/dist/assets/{Scene2DCanvas-bEu0UPUm.js → Scene2DCanvas-CuUxSaPb.js} +1 -1
  15. package/dist/assets/{SceneManager-Ce3X0awy.js → SceneManager-UD3IHY20.js} +1 -1
  16. package/dist/assets/{SkillsPanel-Dj22nDU8.js → SkillsPanel-DjRBVrO2.js} +1 -1
  17. package/dist/assets/SlackMultiInstanceSetup-Csp81Dqn.js +2 -0
  18. package/dist/assets/{SpawnModal-F9nspdWd.js → SpawnModal-dg0mH3d9.js} +1 -1
  19. package/dist/assets/{SubordinateAssignmentModal-DT31CkPr.js → SubordinateAssignmentModal-CeBPRNNX.js} +1 -1
  20. package/dist/assets/{TriggerManagerPanel-CVJ9ozHz.js → TriggerManagerPanel-D1QPpFhP.js} +1 -1
  21. package/dist/assets/{WorkflowEditorPanel-BYRi0cU9.js → WorkflowEditorPanel-IIsptZgp.js} +1 -1
  22. package/dist/assets/{index-ByfAbkqv.js → index-BGh9tRSy.js} +1 -1
  23. package/dist/assets/{index-DkjWoHhy.js → index-CIqkVLo1.js} +1 -1
  24. package/dist/assets/{index-B9G4hrFR.js → index-CNDUxsGy.js} +1 -1
  25. package/dist/assets/{index-C5wC_Xis.js → index-CR9w26tq.js} +1 -1
  26. package/dist/assets/{index-BmjrPptb.js → index-CsyPNc8u.js} +1 -1
  27. package/dist/assets/{index-DqZhHROd.js → index-DEI-vrXk.js} +1 -1
  28. package/dist/assets/{index-CLr8DpLX.js → index-h-IcmGfB.js} +2 -2
  29. package/dist/assets/index-sDgBtEgH.js +19 -0
  30. package/dist/assets/{index-DJm7oMXk.js → index-vJkimYqD.js} +1 -1
  31. package/dist/assets/main-BV_IuaBg.css +1 -0
  32. package/dist/assets/main-klWBzHh0.js +214 -0
  33. package/dist/assets/{web-D-a3phls.js → web-BgPjNMBK.js} +1 -1
  34. package/dist/assets/{web-CLuvtqCm.js → web-BmPSJLwQ.js} +1 -1
  35. package/dist/assets/{web-DM2bFWBN.js → web-Dggt4D4N.js} +1 -1
  36. package/dist/index.html +2 -2
  37. package/dist/src/packages/server/integrations/slack/slack-config.js +13 -0
  38. package/dist/src/packages/server/integrations/slack/slack-trigger-handler.js +12 -4
  39. package/package.json +1 -1
  40. package/dist/assets/EmbeddedEditor-CIsFWo6A.js +0 -1
  41. package/dist/assets/SlackMultiInstanceSetup-J9NdRY0U.js +0 -2
  42. package/dist/assets/index-BPy8NE5B.js +0 -51
  43. package/dist/assets/main-9uTEp9Lr.js +0 -214
  44. package/dist/assets/main-BfT_95fk.css +0 -1
@@ -1 +1 @@
1
- import{ck as t}from"./main-9uTEp9Lr.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class o extends t{constructor(){super(),this.handleVisibilityChange=()=>{const e={isActive:document.hidden!==!0};this.notifyListeners("appStateChange",e),document.hidden?this.notifyListeners("pause",null):this.notifyListeners("resume",null)},document.addEventListener("visibilitychange",this.handleVisibilityChange,!1)}exitApp(){throw this.unimplemented("Not implemented on web.")}async getInfo(){throw this.unimplemented("Not implemented on web.")}async getLaunchUrl(){return{url:""}}async getState(){return{isActive:document.hidden!==!0}}async minimizeApp(){throw this.unimplemented("Not implemented on web.")}async toggleBackButtonHandler(){throw this.unimplemented("Not implemented on web.")}async getAppLanguage(){return{value:navigator.language.split("-")[0].toLowerCase()}}}export{o as AppWeb};
1
+ import{ck as t}from"./main-klWBzHh0.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class o extends t{constructor(){super(),this.handleVisibilityChange=()=>{const e={isActive:document.hidden!==!0};this.notifyListeners("appStateChange",e),document.hidden?this.notifyListeners("pause",null):this.notifyListeners("resume",null)},document.addEventListener("visibilitychange",this.handleVisibilityChange,!1)}exitApp(){throw this.unimplemented("Not implemented on web.")}async getInfo(){throw this.unimplemented("Not implemented on web.")}async getLaunchUrl(){return{url:""}}async getState(){return{isActive:document.hidden!==!0}}async minimizeApp(){throw this.unimplemented("Not implemented on web.")}async toggleBackButtonHandler(){throw this.unimplemented("Not implemented on web.")}async getAppLanguage(){return{value:navigator.language.split("-")[0].toLowerCase()}}}export{o as AppWeb};
@@ -1 +1 @@
1
- import{ck as a}from"./main-9uTEp9Lr.js";import{ImpactStyle as i,NotificationType as r}from"./index-CLr8DpLX.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class h extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{h as HapticsWeb};
1
+ import{ck as a}from"./main-klWBzHh0.js";import{ImpactStyle as i,NotificationType as r}from"./index-h-IcmGfB.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class h extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{h as HapticsWeb};
@@ -1 +1 @@
1
- import{ck as s}from"./main-9uTEp9Lr.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class l extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{l as LocalNotificationsWeb};
1
+ import{ck as s}from"./main-klWBzHh0.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class l extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{l as LocalNotificationsWeb};
package/dist/index.html CHANGED
@@ -22,10 +22,10 @@
22
22
  <link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16x16.png" />
23
23
  <link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png" />
24
24
  <title>Tide Commander</title>
25
- <script type="module" crossorigin src="/assets/main-9uTEp9Lr.js"></script>
25
+ <script type="module" crossorigin src="/assets/main-klWBzHh0.js"></script>
26
26
  <link rel="modulepreload" crossorigin href="/assets/vendor-react--Eh9ivFN.js">
27
27
  <link rel="modulepreload" crossorigin href="/assets/vendor-three-Chj50gSY.js">
28
- <link rel="stylesheet" crossorigin href="/assets/main-BfT_95fk.css">
28
+ <link rel="stylesheet" crossorigin href="/assets/main-BV_IuaBg.css">
29
29
  </head>
30
30
  <body>
31
31
  <div id="app"></div>
@@ -19,6 +19,7 @@ const DEFAULT_CONFIG = {
19
19
  pollingMinMsBetweenCalls: 1500,
20
20
  pollingUseSearch: false,
21
21
  mirrorOwnMessages: false,
22
+ reactOnTrigger: true,
22
23
  currentMode: 'none',
23
24
  };
24
25
  // ─── Config File Persistence ───
@@ -201,6 +202,14 @@ export const slackConfigSchema = [
201
202
  defaultValue: false,
202
203
  group: 'General',
203
204
  },
205
+ {
206
+ key: 'reactOnTrigger',
207
+ label: 'Auto-react with :eyes: on trigger',
208
+ type: 'boolean',
209
+ description: 'When a Slack trigger fires on an incoming message, react with 👀 as a visual acknowledgement. Default on. Per-instance — turn off for accounts where the reaction is noisy.',
210
+ defaultValue: true,
211
+ group: 'General',
212
+ },
204
213
  ];
205
214
  // ─── Per-Instance Secret Keys ───
206
215
  /**
@@ -243,6 +252,7 @@ export function getConfigValues(secrets, instanceId = DEFAULT_INSTANCE_ID) {
243
252
  pollingMinMsBetweenCalls: config.pollingMinMsBetweenCalls ?? 1500,
244
253
  pollingUseSearch: config.pollingUseSearch ?? false,
245
254
  mirrorOwnMessages: config.mirrorOwnMessages ?? false,
255
+ reactOnTrigger: config.reactOnTrigger ?? true,
246
256
  currentMode: config.currentMode ?? 'none',
247
257
  // Mask secret values for UI display
248
258
  SLACK_BOT_TOKEN: secrets.get(instanceSecretKey('SLACK_BOT_TOKEN', instanceId)) ? '********' : '',
@@ -296,6 +306,9 @@ export async function setConfigValues(values, secrets, instanceId = DEFAULT_INST
296
306
  if (typeof values.mirrorOwnMessages === 'boolean') {
297
307
  updates.mirrorOwnMessages = values.mirrorOwnMessages;
298
308
  }
309
+ if (typeof values.reactOnTrigger === 'boolean') {
310
+ updates.reactOnTrigger = values.reactOnTrigger;
311
+ }
299
312
  updateConfig(updates, instanceId);
300
313
  }
301
314
  // ─── Mode Detection ───
@@ -10,10 +10,15 @@
10
10
  import * as slackClient from './slack-client.js';
11
11
  import { listInstances } from './slack-instance.js';
12
12
  import { listInstanceMetas } from './slack-instance-manifest.js';
13
+ import { loadConfig } from './slack-config.js';
13
14
  import { formatAttachmentLine } from '../../services/attachment-downloader.js';
14
15
  const unsubscribers = [];
15
- /** Env toggle: set SLACK_REACT_ON_TRIGGER=false (or 0/no/off) to disable the auto-:eyes: ack. */
16
- function reactOnTriggerEnabled() {
16
+ /**
17
+ * Global kill-switch: `SLACK_REACT_ON_TRIGGER=false` (or 0/no/off) disables the
18
+ * auto-:eyes: ack across every instance regardless of per-instance config.
19
+ * Defaults to enabled when unset.
20
+ */
21
+ function envAllowsReact() {
17
22
  const raw = (process.env.SLACK_REACT_ON_TRIGGER ?? '').toLowerCase().trim();
18
23
  if (!raw)
19
24
  return true;
@@ -22,7 +27,7 @@ function reactOnTriggerEnabled() {
22
27
  export const slackTriggerHandler = {
23
28
  triggerType: 'slack',
24
29
  async startListening(onEvent) {
25
- const autoReact = reactOnTriggerEnabled();
30
+ const envOn = envAllowsReact();
26
31
  // Subscribe to every instance the manifest knows about. Unknown instances
27
32
  // (created later via the UI) are auto-created with `getInstance()` when
28
33
  // reconnect runs, but we re-subscribe on each integration shutdown/init
@@ -32,7 +37,10 @@ export const slackTriggerHandler = {
32
37
  const allInstances = listInstances().filter((i) => idSet.has(i.id));
33
38
  for (const inst of allInstances) {
34
39
  const off = inst.onMessage((message) => {
35
- if (autoReact) {
40
+ // Per-instance toggle is read fresh on each message so flipping the
41
+ // checkbox in the UI takes effect without restarting the trigger.
42
+ const perInstance = loadConfig(inst.id).reactOnTrigger ?? true;
43
+ if (envOn && perInstance) {
36
44
  // Use the instance-specific reaction so it posts as the right account.
37
45
  inst.addReaction({ channel: message.channel, ts: message.ts, name: 'eyes' })
38
46
  .catch(() => { });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tide-commander",
3
- "version": "1.96.0",
3
+ "version": "1.97.0",
4
4
  "description": "Visual multi-agent orchestrator and manager for Claude Code with 3D/2D interface",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1 +0,0 @@
1
- import{r as e,j as s}from"./main-9uTEp9Lr.js";import{g as j,o as k,E as f,l as N,h as R,a as T,f as A,d as w,r as C,i as K,b as L,c as M,e as q,j as B,s as D,k as G,m as H,n as O,p as V,q as W,t as F,u as I,v as U,w as Y,x as z}from"./index-BPy8NE5B.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";const J=1e3,$=({content:_,extension:p,onSave:h,onCancel:b})=>{const c=e.useRef(null),d=e.useRef(null),t=e.useRef(null),o=e.useRef(!1),v=e.useRef(h);v.current=h;const[u,i]=e.useState("idle"),[S,l]=e.useState(null),a=e.useCallback(async()=>{if(!(!d.current||o.current)){o.current=!0,i("saving"),l(null);try{const r=d.current.state.doc.toString();await v.current(r),i("saved"),setTimeout(()=>i(n=>n==="saved"?"idle":n),1500)}catch(r){i("error"),l(r.message||"Save failed")}finally{o.current=!1}}},[]),x=e.useCallback(()=>{t.current&&clearTimeout(t.current),t.current=setTimeout(()=>{a()},J)},[a]),g=e.useCallback(()=>{t.current&&(clearTimeout(t.current),t.current=null,a()),b()},[b,a]);return e.useEffect(()=>()=>{t.current&&clearTimeout(t.current)},[]),e.useEffect(()=>{if(!c.current)return;const r=j(p),n=[N(),R(),T(),A(),w(),C(),K(),L(),M(),q(),B(),D({top:!0}),G(z,{fallback:!0}),k,f.lineWrapping,H.of([...O,...V,...W,...F,...I,U,{key:"Mod-s",run:()=>(t.current&&(clearTimeout(t.current),t.current=null),a(),!0)},{key:"Escape",run:()=>(g(),!0)}]),f.updateListener.of(y=>{y.docChanged&&(l(null),x())})];r&&n.push(r);const E=Y.create({doc:_,extensions:n}),m=new f({state:E,parent:c.current});return d.current=m,requestAnimationFrame(()=>m.focus()),()=>{m.destroy(),d.current=null}},[]),s.jsxs("div",{className:"embedded-editor",children:[s.jsxs("div",{className:"embedded-editor__toolbar",children:[s.jsxs("div",{className:"embedded-editor__toolbar-left",children:[u==="saving"&&s.jsx("span",{className:"embedded-editor__status embedded-editor__status--saving",children:"Saving..."}),u==="saved"&&s.jsx("span",{className:"embedded-editor__status embedded-editor__status--saved",children:"Saved"}),u==="error"&&s.jsx("span",{className:"embedded-editor__status embedded-editor__status--error",children:S||"Save failed"})]}),s.jsxs("div",{className:"embedded-editor__toolbar-right",children:[s.jsx("span",{className:"embedded-editor__shortcut-hint",children:"Auto-saves · Esc to close"}),s.jsx("button",{className:"embedded-editor__btn embedded-editor__btn--close",onClick:g,children:"Close"})]})]}),s.jsx("div",{className:"embedded-editor__container",ref:c})]})};export{$ as EmbeddedEditor};
@@ -1,2 +0,0 @@
1
- import{r as u,j as e,aJ as b,l as m}from"./main-9uTEp9Lr.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";const C=["public_channel","private_channel","im","mpim"],O={public_channel:"Public channels",private_channel:"Private channels",im:"1:1 DMs",mpim:"Group DMs"};function M(l){const i=new Set;for(const s of(l||"").split(",")){const f=s.trim();C.includes(f)&&i.add(f)}return i}function N(l){return C.filter(i=>l.has(i)).join(",")}const t={container:{display:"flex",gap:16,minHeight:420},list:{width:200,flexShrink:0,background:"var(--surface-1, #181825)",borderRadius:8,border:"1px solid var(--border, #313244)",padding:8,display:"flex",flexDirection:"column",gap:4},listItem:l=>({padding:"8px 10px",borderRadius:6,cursor:"pointer",background:l?"rgba(137,180,250,0.15)":"transparent",border:l?"1px solid rgba(137,180,250,0.3)":"1px solid transparent",color:l?"#cdd6f4":"#a6adc8",fontSize:13}),label:{fontWeight:500},sub:{fontSize:11,color:"#6c7086",marginTop:2},addBtn:{marginTop:8,padding:"8px 10px",borderRadius:6,background:"transparent",color:"#89b4fa",border:"1px dashed rgba(137,180,250,0.4)",cursor:"pointer",fontSize:13},editor:{flex:1,display:"flex",flexDirection:"column",gap:12},field:{display:"flex",flexDirection:"column",gap:4},fieldLabel:{fontSize:12,fontWeight:500,color:"#a6adc8"},fieldDesc:{fontSize:11,color:"#6c7086"},input:{padding:"8px 10px",background:"var(--surface-0, #1e1e2e)",border:"1px solid var(--border, #313244)",borderRadius:6,color:"#cdd6f4",fontSize:13,fontFamily:"inherit"},badge:l=>{const s={socket:"#a6e3a1",polling:"#89b4fa",none:"#6c7086"}[l]??"#6c7086";return{display:"inline-block",padding:"2px 8px",borderRadius:4,fontSize:11,fontWeight:500,background:`${s}26`,color:s,border:`1px solid ${s}55`}},rowGap:{display:"flex",gap:12},buttons:{display:"flex",gap:8,marginTop:12},btnPrimary:{padding:"8px 16px",background:"#89b4fa",color:"#1e1e2e",border:"none",borderRadius:6,cursor:"pointer",fontWeight:500,fontSize:13},btnSecondary:{padding:"8px 16px",background:"transparent",color:"#cdd6f4",border:"1px solid var(--border, #313244)",borderRadius:6,cursor:"pointer",fontSize:13},btnDanger:{padding:"8px 16px",background:"transparent",color:"#f38ba8",border:"1px solid rgba(243,139,168,0.4)",borderRadius:6,cursor:"pointer",fontSize:13},alert:l=>({padding:"8px 12px",borderRadius:6,fontSize:12,background:l==="error"?"rgba(243,139,168,0.15)":"rgba(166,227,161,0.15)",color:l==="error"?"#f38ba8":"#a6e3a1",border:`1px solid ${l==="error"?"rgba(243,139,168,0.3)":"rgba(166,227,161,0.3)"}`})},j="/api/slack/instances";async function R(){const l=await b(m(j));if(!l.ok)throw new Error(`HTTP ${l.status}`);return(await l.json()).instances}async function B(l){const i=await b(m(`${j}/${encodeURIComponent(l)}/values`));if(!i.ok)throw new Error(`HTTP ${i.status}`);return(await i.json()).values}async function K(l,i){const s=await b(m(j),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:l,label:i})});if(!s.ok){const f=await s.json().catch(()=>({}));throw new Error(f.error||`HTTP ${s.status}`)}}async function H(l,i){const s=await b(m(`${j}/${encodeURIComponent(l)}`),{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!s.ok){const f=await s.json().catch(()=>({}));throw new Error(f.error||`HTTP ${s.status}`)}}async function W(l){const i=await b(m(`${j}/${encodeURIComponent(l)}`),{method:"DELETE"});if(!i.ok){const s=await i.json().catch(()=>({}));throw new Error(s.error||`HTTP ${i.status}`)}}const V=({integration:l,onCancel:i})=>{const[s,f]=u.useState([]),[o,v]=u.useState("default"),[a,S]=u.useState(null),[T,P]=u.useState(null),[g,D]=u.useState(""),[I,A]=u.useState(!1),[L,E]=u.useState(!1),[w,x]=u.useState(null),y=u.useCallback(async()=>{try{const n=await R();f(n),!n.some(c=>c.id===o)&&n.length>0&&v(n[0].id)}catch(n){x({kind:"error",message:`Failed to load instances: ${n.message}`})}},[o]),k=u.useCallback(async()=>{if(o){A(!0);try{const n=await B(o);S(n),P(n);const r=s.find(c=>c.id===o);D((r==null?void 0:r.label)??o)}catch(n){x({kind:"error",message:`Failed to load instance: ${n.message}`})}finally{A(!1)}}},[o,s]);u.useEffect(()=>{y()},[y]),u.useEffect(()=>{k()},[k]);const _=async()=>{const n=window.prompt('Instance id (kebab-case, e.g. "personal", "team-bot"):');if(!n)return;const r=window.prompt("Display label:",n)||n;try{await K(n.trim(),r.trim()),await y(),v(n.trim()),x({kind:"success",message:`Created "${n}"`})}catch(c){x({kind:"error",message:c.message})}},z=async()=>{if(o!=="default"&&window.confirm(`Delete Slack instance "${o}"? This disconnects it and removes its config.`))try{await W(o),v("default"),await y(),x({kind:"success",message:"Instance deleted"})}catch(n){x({kind:"error",message:n.message})}},$=async()=>{if(!(!a||!T)){E(!0);try{const n={};Object.keys(a).forEach(p=>{const h=a[p];if(h!==T[p]){if((p==="SLACK_BOT_TOKEN"||p==="SLACK_APP_TOKEN")&&h==="********")return;n[p]=h}});const r=s.find(p=>p.id===o),c=r&&g.trim()&&g.trim()!==r.label;await H(o,{label:c?g.trim():void 0,values:Object.keys(n).length>0?n:void 0}),x({kind:"success",message:"Saved. Slack will reconnect with the new settings."}),await y(),await k()}catch(n){x({kind:"error",message:n.message})}finally{E(!1)}}},d=(n,r)=>{a&&S({...a,[n]:r})};return e.jsxs("div",{children:[e.jsx("div",{style:{marginBottom:12,fontSize:12,color:"#a6adc8"},children:"Add multiple Slack connections side-by-side. The default instance maps to your existing bot / token; add more for personal (xoxp-) tokens or additional workspaces."}),w&&e.jsx("div",{style:{...t.alert(w.kind),marginBottom:12},children:w.message}),e.jsxs("div",{style:t.container,children:[e.jsxs("div",{style:t.list,children:[s.map(n=>{var c,p,h;const r=((c=n.config)==null?void 0:c.currentMode)??"none";return e.jsxs("div",{style:t.listItem(n.id===o),onClick:()=>v(n.id),children:[e.jsx("div",{style:t.label,children:n.label}),e.jsxs("div",{style:t.sub,children:[e.jsx("span",{style:t.badge(r),children:r==="none"?"—":r}),(p=n.status)!=null&&p.connected?" • connected":(h=n.status)!=null&&h.error?" • error":" • idle"]})]},n.id)}),e.jsx("button",{type:"button",style:t.addBtn,onClick:_,children:"+ Add Instance"})]}),e.jsxs("div",{style:t.editor,children:[I&&e.jsx("div",{style:{color:"#6c7086",fontSize:13},children:"Loading…"}),!I&&a&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:t.field,children:[e.jsx("span",{style:t.fieldLabel,children:"Display label"}),e.jsx("input",{type:"text",style:t.input,value:g,onChange:n=>D(n.target.value),disabled:!1}),e.jsxs("span",{style:t.fieldDesc,children:["Shown in the instance list. Id is fixed: ",e.jsx("code",{children:o})]})]}),e.jsxs("div",{style:t.field,children:[e.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,cursor:"pointer"},children:[e.jsx("input",{type:"checkbox",checked:a.enabled,onChange:n=>d("enabled",n.target.checked)}),e.jsx("span",{style:t.fieldLabel,children:"Enabled"})]}),e.jsx("span",{style:t.fieldDesc,children:"Toggle off to disconnect this instance without deleting its config."})]}),e.jsxs("div",{style:t.field,children:[e.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,cursor:"pointer"},children:[e.jsx("input",{type:"checkbox",checked:a.mirrorOwnMessages,onChange:n=>d("mirrorOwnMessages",n.target.checked)}),e.jsx("span",{style:t.fieldLabel,children:"Mirror messages I send too"})]}),e.jsxs("span",{style:t.fieldDesc,children:["Capture your outgoing messages alongside incoming ones (logged as ",e.jsx("code",{children:"direction:outbound"}),"). Recommended for personal (xoxp-) tokens. Triggers do not fire on your own messages — that would loop."]})]}),e.jsxs("div",{style:t.field,children:[e.jsx("span",{style:t.fieldLabel,children:"Slack Token"}),e.jsx("input",{type:"password",style:t.input,placeholder:"xoxb-... or xoxp-...",value:a.SLACK_BOT_TOKEN,onChange:n=>d("SLACK_BOT_TOKEN",n.target.value)}),e.jsxs("span",{style:t.fieldDesc,children:["Bot token (xoxb-) → Socket Mode. User token (xoxp-) → Web API polling (~30-60s lag). Stored encrypted under a per-instance key; leave as ",e.jsx("code",{children:"********"})," to keep the existing token."]})]}),e.jsxs("div",{style:t.field,children:[e.jsx("span",{style:t.fieldLabel,children:"App Token (Socket Mode only)"}),e.jsx("input",{type:"password",style:t.input,placeholder:"xapp-...",value:a.SLACK_APP_TOKEN,onChange:n=>d("SLACK_APP_TOKEN",n.target.value)}),e.jsx("span",{style:t.fieldDesc,children:"Required for xoxb- only. Leave blank for xoxp- (polling mode)."})]}),e.jsxs("div",{style:t.rowGap,children:[e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Inbound Mode"}),e.jsxs("select",{style:t.input,value:a.authMode,onChange:n=>d("authMode",n.target.value),children:[e.jsx("option",{value:"auto",children:"Auto (from token prefix)"}),e.jsx("option",{value:"socket",children:"Socket Mode (xoxb-)"}),e.jsx("option",{value:"polling",children:"Polling (xoxp-)"})]})]}),e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Default Channel"}),e.jsx("input",{type:"text",style:t.input,placeholder:"C0123456789",value:a.defaultChannelId,onChange:n=>d("defaultChannelId",n.target.value)})]})]}),e.jsxs("div",{style:t.rowGap,children:[e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Polling Interval (s)"}),e.jsx("input",{type:"number",style:t.input,min:10,max:600,value:a.pollingIntervalSec,onChange:n=>d("pollingIntervalSec",Number(n.target.value))})]}),e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Concurrency"}),e.jsx("input",{type:"number",style:t.input,min:1,max:8,value:a.pollingConcurrency,onChange:n=>d("pollingConcurrency",Number(n.target.value))})]}),e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Backfill Cap (msgs)"}),e.jsx("input",{type:"number",style:t.input,min:1,max:1e3,value:a.pollingBackfillMessageCap,onChange:n=>d("pollingBackfillMessageCap",Number(n.target.value))})]}),e.jsxs("div",{style:{...t.field,flex:1},children:[e.jsx("span",{style:t.fieldLabel,children:"Min ms between calls"}),e.jsx("input",{type:"number",style:t.input,min:0,max:1e4,value:a.pollingMinMsBetweenCalls,onChange:n=>d("pollingMinMsBetweenCalls",Number(n.target.value))}),e.jsx("span",{style:{...t.fieldDesc,fontSize:11},children:"Throttle. 1500 ≈ 40 req/min. Set 0 to disable."})]})]}),e.jsxs("div",{style:t.field,children:[e.jsx("span",{style:t.fieldLabel,children:"Channel Types (poll all of these)"}),e.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:12,marginTop:4},children:C.map(n=>{const c=M(a.pollingChannelTypes).has(n);return e.jsxs("label",{style:{display:"flex",alignItems:"center",gap:6,cursor:"pointer",fontSize:13},children:[e.jsx("input",{type:"checkbox",checked:c,onChange:p=>{const h=new Set(M(a.pollingChannelTypes));p.target.checked?h.add(n):h.delete(n),d("pollingChannelTypes",N(h))}}),e.jsx("span",{children:O[n]})]},n)})}),e.jsx("span",{style:t.fieldDesc,children:"Determines which channel types are polled when the allowlist below is empty. Tick all four for full coverage. Heads-up: hundreds of channels at once can hit Slack's rate limit (~50 req/min) — use the allowlist to narrow down."})]}),e.jsxs("div",{style:t.field,children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between"},children:[e.jsx("span",{style:t.fieldLabel,children:"Channel Allowlist (optional)"}),a.pollingChannelAllowlist&&e.jsx("button",{type:"button",style:{...t.btnSecondary,padding:"4px 10px",fontSize:12},onClick:()=>d("pollingChannelAllowlist",""),title:"Clear the allowlist — fall back to polling all channels per the type checkboxes above.",children:"Include all (clear list)"})]}),e.jsx("textarea",{style:{...t.input,minHeight:60,fontFamily:"monospace",fontSize:12},placeholder:`C0123456789, G0987654321
2
- C9999999999`,value:a.pollingChannelAllowlist,onChange:n=>d("pollingChannelAllowlist",n.target.value)}),e.jsx("span",{style:t.fieldDesc,children:'Comma- or newline-separated channel IDs. When set, polling restricts to these channels (plus DMs if "Always include DMs" is on). The Channel Types checkboxes above are ignored while an allowlist is active. Leave blank to fall back to polling all channels per the type checkboxes.'})]}),e.jsxs("div",{style:t.field,children:[e.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,cursor:"pointer"},children:[e.jsx("input",{type:"checkbox",checked:a.pollingDmsAlways,onChange:n=>d("pollingDmsAlways",n.target.checked)}),e.jsx("span",{style:t.fieldLabel,children:"Always include DMs"})]}),e.jsx("span",{style:t.fieldDesc,children:"When the allowlist is set, still poll all 1:1 DMs (D-prefix). Default on. Turn off for strict allowlist-only mode."})]}),e.jsxs("div",{style:t.buttons,children:[e.jsx("button",{type:"button",style:t.btnPrimary,onClick:$,disabled:L,children:L?"Saving…":"Save & Reconnect"}),e.jsx("button",{type:"button",style:t.btnSecondary,onClick:i,children:"Close"}),o!=="default"&&e.jsx("button",{type:"button",style:{...t.btnDanger,marginLeft:"auto"},onClick:z,children:"Delete Instance"})]})]})]})]})]})};export{V as SlackMultiInstanceSetup,V as default};