tide-commander 1.159.3 → 1.160.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 (43) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/assets/{BossLogsModal-DII7aJf5.js → BossLogsModal-COg0RBw_.js} +1 -1
  3. package/dist/assets/{BossSpawnModal-CQfEy11F.js → BossSpawnModal-Bvkk2uFi.js} +1 -1
  4. package/dist/assets/{ControlsModal-DFo7lwSp.js → ControlsModal-BWcWGs2x.js} +1 -1
  5. package/dist/assets/{DockerLogsModal-CXPYYhUg.js → DockerLogsModal-C4tJ59Pf.js} +1 -1
  6. package/dist/assets/{EmbeddedEditor-Dboxn7s4.js → EmbeddedEditor-DiDm5EvF.js} +1 -1
  7. package/dist/assets/{GmailOAuthSetup-BXsCPLsp.js → GmailOAuthSetup-GkYs6wUs.js} +1 -1
  8. package/dist/assets/{GoogleOAuthSetup-Bl-vieRg.js → GoogleOAuthSetup-KKwp2gEQ.js} +1 -1
  9. package/dist/assets/{IframeModal-BCRKWZQa.js → IframeModal-D0iTkxZB.js} +1 -1
  10. package/dist/assets/{IntegrationsPanel-C3Ia477x.js → IntegrationsPanel-CCKoizJa.js} +2 -2
  11. package/dist/assets/{LogViewerModal--Ij8llxK.js → LogViewerModal-CSGEkyhZ.js} +1 -1
  12. package/dist/assets/{MonitoringModal-OUrEUALC.js → MonitoringModal-Be6uEd7K.js} +1 -1
  13. package/dist/assets/{PM2LogsModal-BIS752lh.js → PM2LogsModal-DZG7Tcw7.js} +1 -1
  14. package/dist/assets/{RestoreArchivedAreaModal-07vSKn4W.js → RestoreArchivedAreaModal-CigBbBB_.js} +1 -1
  15. package/dist/assets/{Scene2DCanvas-JDJNFXK3.js → Scene2DCanvas-sJig3vJ4.js} +1 -1
  16. package/dist/assets/{SceneManager-CkUd1aHW.js → SceneManager-BG_0UVJc.js} +1 -1
  17. package/dist/assets/{SkillsPanel-DiLbHStJ.js → SkillsPanel-BnAf8uyn.js} +1 -1
  18. package/dist/assets/{SlackMultiInstanceSetup-F17-870l.js → SlackMultiInstanceSetup-DGuexHRz.js} +1 -1
  19. package/dist/assets/{SpawnModal-DLmbxM30.js → SpawnModal-FjDJZlIm.js} +1 -1
  20. package/dist/assets/{StatisticsModal-l6Ed7xxb.js → StatisticsModal-CbbdwSF0.js} +1 -1
  21. package/dist/assets/{SubordinateAssignmentModal-BNUrwWAx.js → SubordinateAssignmentModal-Dn2uuOcT.js} +1 -1
  22. package/dist/assets/{TriggerManagerPanel-DruR51gp.js → TriggerManagerPanel-Cj9pqf-r.js} +1 -1
  23. package/dist/assets/{WorkflowEditorPanel-D8O8NnFd.js → WorkflowEditorPanel-nucrx_0v.js} +1 -1
  24. package/dist/assets/{area-logos-Baka5-sr.js → area-logos-C93KZk3h.js} +1 -1
  25. package/dist/assets/{index-T8mnacEC.js → index-BkbKu66S.js} +1 -1
  26. package/dist/assets/{index-D_M5cgOI.js → index-CmmI2kZf.js} +2 -2
  27. package/dist/assets/{index-C2F5Uash.js → index-D7YoMagO.js} +1 -1
  28. package/dist/assets/{index-3mmNpr_o.js → index-DIOhr3im.js} +3 -3
  29. package/dist/assets/{index-CifRfrvD.js → index-DqM0QltS.js} +1 -1
  30. package/dist/assets/{index-D89rSdZ_.js → index-Gjc7NXlZ.js} +1 -1
  31. package/dist/assets/{index-LhjqVC1x.js → index-fh53j_4E.js} +1 -1
  32. package/dist/assets/{index-CGn4UG1-.js → index-iX9jPnEp.js} +1 -1
  33. package/dist/assets/{index-BEtUppej.js → index-ojmo-Cva.js} +1 -1
  34. package/dist/assets/{main-Cn0uJsZU.js → main-BFW0rGXU.js} +8 -8
  35. package/dist/assets/{web-BLnXgjVn.js → web-8gl2noUE.js} +1 -1
  36. package/dist/assets/{web-BjfQGXzj.js → web-D0uiHhnA.js} +1 -1
  37. package/dist/assets/{web-DY_H8hM_.js → web-M9cLwTrs.js} +1 -1
  38. package/dist/build-info.json +1 -1
  39. package/dist/index.html +1 -1
  40. package/dist/src/packages/server/codex/app-server/codex-app-server-runner.js +19 -4
  41. package/dist/src/packages/server/runtime/codex-runner-router.js +5 -1
  42. package/dist/src/packages/server/websocket/handlers/agent-handler.js +5 -6
  43. package/package.json +1 -1
@@ -1 +1 @@
1
- import{df as a}from"./main-Cn0uJsZU.js";import{ImpactStyle as i,NotificationType as r}from"./index-D_M5cgOI.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{df as a}from"./main-BFW0rGXU.js";import{ImpactStyle as i,NotificationType as r}from"./index-CmmI2kZf.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{df as s}from"./main-Cn0uJsZU.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{df as s}from"./main-BFW0rGXU.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 +1 @@
1
- import{df as t}from"./main-Cn0uJsZU.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{df as t}from"./main-BFW0rGXU.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
- {"version":"1.159.3"}
1
+ {"version":"1.160.0"}
package/dist/index.html CHANGED
@@ -22,7 +22,7 @@
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-Cn0uJsZU.js"></script>
25
+ <script type="module" crossorigin src="/assets/main-BFW0rGXU.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
28
  <link rel="stylesheet" crossorigin href="/assets/main-BZcOdtO_.css">
@@ -233,7 +233,10 @@ export class CodexAppServerRunner {
233
233
  };
234
234
  this.agents.set(agentId, state);
235
235
  this.threadToAgent.set(threadId, agentId);
236
- agentService.updateAgent(agentId, { sessionId: threadId });
236
+ agentService.updateAgent(agentId, {
237
+ sessionId: threadId,
238
+ ...(request.forkSession ? { forkSourceSessionId: undefined } : {}),
239
+ });
237
240
  this.callbacks.onSessionId(agentId, threadId);
238
241
  this.pipeline.emitStandardEvent(agentId, {
239
242
  type: 'init',
@@ -261,17 +264,29 @@ export class CodexAppServerRunner {
261
264
  baseParams.config = { model_reasoning_effort: effort };
262
265
  try {
263
266
  if (!wantNew && request.sessionId) {
264
- const result = (await proc.request('thread/resume', {
267
+ const method = request.forkSession ? 'thread/fork' : 'thread/resume';
268
+ const result = (await proc.request(method, {
265
269
  ...baseParams,
266
270
  threadId: request.sessionId,
267
271
  }));
268
- const id = result?.thread?.id || request.sessionId;
269
- log.log(`🔄 Resumed thread ${id.slice(0, 8)} for agent ${agentId.slice(0, 8)}`);
272
+ // A fork must always return its own id. Falling back to the source id
273
+ // would make both agents write to the same conversation.
274
+ const id = result?.thread?.id || (request.forkSession ? undefined : request.sessionId);
275
+ if (!id)
276
+ throw new Error(`${method} returned no thread id`);
277
+ log.log(`${request.forkSession ? '🌿 Forked' : '🔄 Resumed'} thread ${id.slice(0, 8)} for agent ${agentId.slice(0, 8)}`);
270
278
  return id;
271
279
  }
272
280
  }
273
281
  catch (err) {
274
282
  const msg = err instanceof Error ? err.message : String(err);
283
+ if (request.forkSession) {
284
+ // Do not silently create an empty thread: keep forkSourceSessionId in
285
+ // place so the user can retry after upgrading/fixing Codex.
286
+ log.error(`thread/fork failed for ${agentId.slice(0, 8)}: ${msg}`);
287
+ this.callbacks.onError(agentId, `Codex session fork failed: ${msg}`);
288
+ return null;
289
+ }
275
290
  log.warn(`thread/resume failed for ${agentId.slice(0, 8)} (${msg}) — starting a fresh thread`);
276
291
  }
277
292
  try {
@@ -48,7 +48,11 @@ export class CodexRunnerRouter {
48
48
  this.appServer.start?.();
49
49
  }
50
50
  async run(request) {
51
- const mode = this.currentMode();
51
+ // `codex exec` can resume threads but has no headless fork command. The
52
+ // app-server does (`thread/fork`), so route the first turn of a fork through
53
+ // it regardless of the streaming preference. Later turns may switch back
54
+ // to exec and resume the newly-created thread normally.
55
+ const mode = request.forkSession ? 'app-server' : this.currentMode();
52
56
  const prev = this.ownerOf(request.agentId);
53
57
  if (prev && prev !== mode) {
54
58
  log.log(`Agent ${request.agentId.slice(0, 8)} switching ${prev} → ${mode}; stopping old runner first`);
@@ -135,10 +135,9 @@ async function duplicateAgentConfig(source, name, position) {
135
135
  function duplicateOffset(source) {
136
136
  return { x: source.position.x + 2, y: 0, z: source.position.z + 2 };
137
137
  }
138
- // Providers whose conversation history can be forked (resume + native fork flag).
139
- // Codex is intentionally excluded for now (no headless fork; would need rollout
140
- // duplication) forking a Codex agent gracefully degrades to a plain clone.
141
- const FORKABLE_PROVIDERS = new Set(['claude', 'opencode', 'grok']);
138
+ // Providers whose conversation history can be forked. Codex forks through the
139
+ // app-server `thread/fork` method even when regular turns use `codex exec`.
140
+ const FORKABLE_PROVIDERS = new Set(['claude', 'codex', 'opencode', 'grok']);
142
141
  /**
143
142
  * Handle clone_agent message - duplicates an existing agent's configuration
144
143
  * into a brand-new agent (fresh session, no inherited context/memory).
@@ -168,9 +167,9 @@ export async function handleCloneAgent(ctx, payload) {
168
167
  * Handle fork_agent message - like clone, but the new agent also CONTINUES the
169
168
  * source's conversation history. On the new agent's first run the backend
170
169
  * resumes the source session and forks it into a fresh one (Claude
171
- * --fork-session / OpenCode --fork); the new session id is then captured and
170
+ * --fork-session / Codex thread/fork / OpenCode --fork); the new session id is then captured and
172
171
  * forkSourceSessionId is cleared. If the source has no session or its provider
173
- * isn't forkable (e.g. Codex), this degrades to a plain clone (fresh session).
172
+ * isn't forkable, this degrades to a plain clone (fresh session).
174
173
  */
175
174
  export async function handleForkAgent(ctx, payload) {
176
175
  const source = agentService.getAgent(payload.sourceAgentId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tide-commander",
3
- "version": "1.159.3",
3
+ "version": "1.160.0",
4
4
  "description": "Visual multi-agent orchestrator and manager for Claude Code with 3D/2D interface",
5
5
  "repository": {
6
6
  "type": "git",