@xopcai/xopc 0.0.136 → 0.0.137

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 (120) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CER17NHM.js → agent-avatar-dicebear-BVGEvspi.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agents-Bv5R-N8Q.js → agents-Bmfl5l9o.js} +1 -1
  5. package/dist/gateway/static/root/assets/{app-management-settings-panel-B3Ap_wpX.js → app-management-settings-panel-BmdZifqk.js} +1 -1
  6. package/dist/gateway/static/root/assets/{appearance-settings-3kBO22Xd.js → appearance-settings-CI-Cony7.js} +1 -1
  7. package/dist/gateway/static/root/assets/{apps-page-BHYbGQcZ.js → apps-page-8yKgtRah.js} +1 -1
  8. package/dist/gateway/static/root/assets/{archive-plugin-D_vGeNB8.js → archive-plugin-hMye7wu9.js} +1 -1
  9. package/dist/gateway/static/root/assets/{attachment-load-hWV_8pHL.js → attachment-load-qKR5CPYj.js} +1 -1
  10. package/dist/gateway/static/root/assets/{automation-suggestion-card-DVKmVTIo.js → automation-suggestion-card-BrtqTkO2.js} +1 -1
  11. package/dist/gateway/static/root/assets/{automations-page-BCTXpOBp.js → automations-page-CTbY1_xq.js} +1 -1
  12. package/dist/gateway/static/root/assets/{binary-plugins-BuXIeSPc.js → binary-plugins-DURU6npf.js} +1 -1
  13. package/dist/gateway/static/root/assets/{block-editor-C1m0u-UU.js → block-editor-BQIHfg8Q.js} +58 -54
  14. package/dist/gateway/static/root/assets/{browser-settings-page-ChUF08V5.js → browser-settings-page-BTlEo9yH.js} +1 -1
  15. package/dist/gateway/static/root/assets/{capability-presets-api-B7WWYaEh.js → capability-presets-api-DowJXE85.js} +1 -1
  16. package/dist/gateway/static/root/assets/{capability-presets-settings-panel-D_Bh1PnA.js → capability-presets-settings-panel-CUBsiEWT.js} +1 -1
  17. package/dist/gateway/static/root/assets/{channel-recipient-api-sV06LCht.js → channel-recipient-api-BqbZNCJJ.js} +1 -1
  18. package/dist/gateway/static/root/assets/{channels-settings-BI2ChQc7.js → channels-settings-BzPicGm_.js} +1 -1
  19. package/dist/gateway/static/root/assets/channels-status-swr-BCkcagDP.js +1 -0
  20. package/dist/gateway/static/root/assets/{connectors-page-qgvEp09M.js → connectors-page-BryXzajG.js} +1 -1
  21. package/dist/gateway/static/root/assets/{desktop-pet-BxMJlvb-.js → desktop-pet-DxLTNBD2.js} +1 -1
  22. package/dist/gateway/static/root/assets/{desktop-pet-settings-DCvpDImn.js → desktop-pet-settings-D_EgKbEB.js} +1 -1
  23. package/dist/gateway/static/root/assets/{directory-picker-path-field-D1nxs9PA.js → directory-picker-path-field-DmzW9Mwg.js} +1 -1
  24. package/dist/gateway/static/root/assets/{dreaming-settings-EAWkpOgw.js → dreaming-settings-D3DNPePf.js} +1 -1
  25. package/dist/gateway/static/root/assets/{extension-debug-page-LUQ8dE8z.js → extension-debug-page-hUg0oHQR.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-page-B_mnhoRd.js → extension-page-Bl1aQuV_.js} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-settings-page-BWQsGmvW.js → extension-settings-page-BghvkAL8.js} +1 -1
  28. package/dist/gateway/static/root/assets/{fetch-BWXmBizE.js → fetch-hvbCiP2J.js} +1 -1
  29. package/dist/gateway/static/root/assets/{gateway-config-api-M9bzPASf.js → gateway-config-api-Dk4b3f7r.js} +1 -1
  30. package/dist/gateway/static/root/assets/{gateway-settings-CbgtpprN.js → gateway-settings-DKNhpqYg.js} +1 -1
  31. package/dist/gateway/static/root/assets/{gateway-startup-retry-BALL91S7.js → gateway-startup-retry-BzbrcQLJ.js} +1 -1
  32. package/dist/gateway/static/root/assets/{goal-create-dialog-CbP4t9aM.js → goal-create-dialog-Z_oEJXTZ.js} +1 -1
  33. package/dist/gateway/static/root/assets/{goal-detail-page-DlwI-MZZ.js → goal-detail-page-CIFnmZ2W.js} +1 -1
  34. package/dist/gateway/static/root/assets/{goals-config-api-BBhFVzBS.js → goals-config-api-DpQ3Hj8X.js} +1 -1
  35. package/dist/gateway/static/root/assets/{goals-page-D26r7knp.js → goals-page-BYWfLxSr.js} +1 -1
  36. package/dist/gateway/static/root/assets/{goals-settings-DdmVG_TR.js → goals-settings-DW6d-W79.js} +1 -1
  37. package/dist/gateway/static/root/assets/{heartbeat-settings-DZW2Xq-U.js → heartbeat-settings-CSGeVzW8.js} +1 -1
  38. package/dist/gateway/static/root/assets/index-B-SGXAZ7.js +262 -0
  39. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-1IWd88-T.js → keyboard-shortcuts-settings-Bh85DLbN.js} +1 -1
  40. package/dist/gateway/static/root/assets/{logs-page-DxoKJO7-.js → logs-page-BYG_JKr5.js} +1 -1
  41. package/dist/gateway/static/root/assets/{markdown-split-BtdBj32h.js → markdown-split-BLOUZPDJ.js} +1 -1
  42. package/dist/gateway/static/root/assets/{media-plugins-CpoPj3s8.js → media-plugins-vlqpbsN0.js} +1 -1
  43. package/dist/gateway/static/root/assets/messages-CD-qhazm.js +3 -0
  44. package/dist/gateway/static/root/assets/{models-hub-panel-D1Rp__dV.js → models-hub-panel-BihK16QP.js} +1 -1
  45. package/dist/gateway/static/root/assets/{notes-page-CgR1bO2W.js → notes-page-DJGOihcg.js} +1 -1
  46. package/dist/gateway/static/root/assets/{notes-workbench-ozsnmDTV.js → notes-workbench-CtdxRaAk.js} +2 -2
  47. package/dist/gateway/static/root/assets/{page-tabs-CVLqCfQB.js → page-tabs-BOKnavua.js} +1 -1
  48. package/dist/gateway/static/root/assets/{preview-open-alternatives-CKUXJk2t.js → preview-open-alternatives-07J39ZIq.js} +1 -1
  49. package/dist/gateway/static/root/assets/{project-detail-page-B4dqFAQF.js → project-detail-page-BC26Zx8C.js} +1 -1
  50. package/dist/gateway/static/root/assets/{projects-page-DlRGXv4a.js → projects-page-kQNhzpLr.js} +1 -1
  51. package/dist/gateway/static/root/assets/{remote-access-hub-rZEYQMZV.js → remote-access-hub-CN1ioJ0X.js} +1 -1
  52. package/dist/gateway/static/root/assets/{save-bar-controls-BtGni268.js → save-bar-controls-CDGmAkP7.js} +1 -1
  53. package/dist/gateway/static/root/assets/{schedule-field-BDGzKVWn.js → schedule-field-7Cvi7W5t.js} +1 -1
  54. package/dist/gateway/static/root/assets/{schema-form-DQJsKMCE.js → schema-form-xobSdD8a.js} +1 -1
  55. package/dist/gateway/static/root/assets/{sessions-page-DxGoCGU8.js → sessions-page-DEGTTMvU.js} +1 -1
  56. package/dist/gateway/static/root/assets/settings-advanced-gate-DgMxVBrX.js +1 -0
  57. package/dist/gateway/static/root/assets/{settings-collapsible-section-c8XGd4-8.js → settings-collapsible-section-CnqjZAfV.js} +1 -1
  58. package/dist/gateway/static/root/assets/{settings-form-section-By0YiDWo.js → settings-form-section-DRzUUAOA.js} +1 -1
  59. package/dist/gateway/static/root/assets/{settings-loading-skeleton-SYCPY-WM.js → settings-loading-skeleton-ke39n0bn.js} +1 -1
  60. package/dist/gateway/static/root/assets/{settings-page-D9NwvnBt.js → settings-page-BDP9GD1j.js} +1 -1
  61. package/dist/gateway/static/root/assets/{settings-page-layout-CrICyGob.js → settings-page-layout-CIf2rF-q.js} +1 -1
  62. package/dist/gateway/static/root/assets/{setup-status-panel-IjK-hDxf.js → setup-status-panel-CiiWlcKj.js} +1 -1
  63. package/dist/gateway/static/root/assets/{share-preview-page-Dfnk9M_m.js → share-preview-page-CwJ2tj2j.js} +1 -1
  64. package/dist/gateway/static/root/assets/{shares-settings-vQiRBra7.js → shares-settings-dm7VKGsi.js} +1 -1
  65. package/dist/gateway/static/root/assets/skill-reload-api-ZzOv59qM.js +1 -0
  66. package/dist/gateway/static/root/assets/{skills-page-CruV215G.js → skills-page-Bc0rxqmf.js} +1 -1
  67. package/dist/gateway/static/root/assets/{system-settings-panel-BBVbSDFD.js → system-settings-panel-1a3I3zIl.js} +1 -1
  68. package/dist/gateway/static/root/assets/{typed-models-lib-CwFayhxu.js → typed-models-lib-C3NCA3Nd.js} +1 -1
  69. package/dist/gateway/static/root/assets/{use-channel-catalog-BKtHOM50.js → use-channel-catalog-DUOMGhwc.js} +1 -1
  70. package/dist/gateway/static/root/assets/{user-profile-settings-panel-_KDWzagh.js → user-profile-settings-panel-dKptBh4U.js} +1 -1
  71. package/dist/gateway/static/root/assets/{utils-BiUjIHb4.js → utils-BqnHAm5O.js} +1 -1
  72. package/dist/gateway/static/root/assets/{voice-api-key-field-agJqlm4o.js → voice-api-key-field-D4dtA6k3.js} +1 -1
  73. package/dist/gateway/static/root/assets/{work-item-detail-page-Bdw4ATCb.js → work-item-detail-page-DpUYYeDf.js} +1 -1
  74. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-D-Dy6mTy.js → workflow-run-setup-panel-BQ8aBXA1.js} +1 -1
  75. package/dist/gateway/static/root/assets/{workflow-start-dialog-GammZ2GK.js → workflow-start-dialog-jHmIHxTR.js} +1 -1
  76. package/dist/gateway/static/root/assets/{workflows-page-Cw5zrqti.js → workflows-page-DzjPClwt.js} +1 -1
  77. package/dist/gateway/static/root/index.html +4 -4
  78. package/dist/package.js +1 -1
  79. package/dist/src/agent/session/session-inspector.d.ts +1 -0
  80. package/dist/src/agent/session/session-inspector.js +8 -2
  81. package/dist/src/agent/session/session-inspector.js.map +1 -1
  82. package/dist/src/cli/command-loaders.js +1 -0
  83. package/dist/src/cli/command-loaders.js.map +1 -1
  84. package/dist/src/cli/command-manifest.js +4 -0
  85. package/dist/src/cli/command-manifest.js.map +1 -1
  86. package/dist/src/cli/commands/resume.d.ts +1 -0
  87. package/dist/src/cli/commands/resume.js +31 -0
  88. package/dist/src/cli/commands/resume.js.map +1 -0
  89. package/dist/src/cli/commands/tui-runner.d.ts +9 -0
  90. package/dist/src/cli/commands/tui-runner.js +40 -0
  91. package/dist/src/cli/commands/tui-runner.js.map +1 -0
  92. package/dist/src/cli/commands/tui.js +4 -28
  93. package/dist/src/cli/commands/tui.js.map +1 -1
  94. package/dist/src/config/agent-profile.js +1 -1
  95. package/dist/src/gateway/agents-admin.js +1 -1
  96. package/dist/src/gateway/hono/routes/home.js +37 -2
  97. package/dist/src/gateway/hono/routes/home.js.map +1 -1
  98. package/dist/src/gateway/hono/routes/projects.js +16 -0
  99. package/dist/src/gateway/hono/routes/projects.js.map +1 -1
  100. package/dist/src/projects/project-kind.js +0 -1
  101. package/dist/src/projects/project-kind.js.map +1 -1
  102. package/dist/src/tui/tui-picker-overlay.d.ts +6 -1
  103. package/dist/src/tui/tui-picker-overlay.js +4 -1
  104. package/dist/src/tui/tui-picker-overlay.js.map +1 -1
  105. package/dist/src/tui/tui-types.d.ts +2 -0
  106. package/dist/src/tui/tui-types.js.map +1 -1
  107. package/dist/src/tui/tui.js +17 -2
  108. package/dist/src/tui/tui.js.map +1 -1
  109. package/dist/src/work-items/work-item-service.d.ts +1 -0
  110. package/dist/src/work-items/work-item-service.js +3 -0
  111. package/dist/src/work-items/work-item-service.js.map +1 -1
  112. package/dist/src/work-items/work-item-store.d.ts +1 -0
  113. package/dist/src/work-items/work-item-store.js +13 -0
  114. package/dist/src/work-items/work-item-store.js.map +1 -1
  115. package/package.json +1 -1
  116. package/dist/gateway/static/root/assets/channels-status-swr-MY4Xh4fM.js +0 -1
  117. package/dist/gateway/static/root/assets/index-DZOm5_ex.js +0 -262
  118. package/dist/gateway/static/root/assets/messages-CQ_k8RHj.js +0 -3
  119. package/dist/gateway/static/root/assets/settings-advanced-gate-4e8ZQwxr.js +0 -1
  120. package/dist/gateway/static/root/assets/skill-reload-api-BIWv778A.js +0 -1
@@ -55,6 +55,10 @@ const ROOT_HELP_COMMANDS = [
55
55
  name: "tui [options]",
56
56
  description: "Interactive terminal UI (pi-tui)"
57
57
  },
58
+ {
59
+ name: "resume [options] [sessionKey]",
60
+ description: "Resume a previous TUI session"
61
+ },
58
62
  {
59
63
  name: "tunnel",
60
64
  description: "Manage FRP remote access tunnel"
@@ -1 +1 @@
1
- {"version":3,"file":"command-manifest.js","names":[],"sources":["../../../src/cli/command-manifest.ts"],"sourcesContent":["export type RootHelpOption = {\n flags: string;\n description: string;\n};\n\nexport type RootHelpCommand = {\n name: string;\n description: string;\n};\n\nexport const ROOT_COMMAND_DESCRIPTION = 'Ultra-Lightweight Personal AI Assistant. Run `xopc` with no command to open the local TUI.';\n\nexport const ROOT_HELP_OPTIONS: RootHelpOption[] = [\n { flags: '-V, --version', description: 'output the version number' },\n { flags: '--verbose', description: 'Enable verbose logging (default: false)' },\n { flags: '--config <path>', description: 'Config file path' },\n { flags: '--workspace <path>', description: 'Workspace directory' },\n { flags: '-h, --help', description: 'display help for command' },\n];\n\nexport const ROOT_HELP_COMMANDS: RootHelpCommand[] = [\n { name: 'init [options]', description: 'Initialize xopc state directories, config, and agent workspace' },\n { name: 'setup [options]', description: 'Initialize config file and workspace directory' },\n { name: 'profile', description: 'Manage xopc state profiles (~/.xopc vs ~/.xopc-<name>)' },\n { name: 'onboard [options]', description: 'Interactive setup wizard for xopc (gateway uses schema defaults)' },\n { name: 'channels', description: 'Messaging channel configuration' },\n { name: 'auth', description: 'Manage authentication credentials' },\n { name: 'agent [options]', description: 'Chat with the AI agent' },\n { name: 'tui [options]', description: 'Interactive terminal UI (pi-tui)' },\n { name: 'tunnel', description: 'Manage FRP remote access tunnel' },\n { name: 'gateway [options]', description: 'Start the xopc gateway server' },\n { name: 'session', description: 'Session management commands' },\n { name: 'project', description: 'Manage long-running projects' },\n { name: 'doctor [options]', description: 'Check xopc installation health and diagnose common issues' },\n { name: 'update [options]', description: 'Check for and install xopc updates' },\n { name: 'logs', description: 'Manage and query logs' },\n { name: 'goal', description: 'Manage durable goals' },\n { name: 'config [options]', description: 'View and edit configuration' },\n { name: 'image', description: 'Inspect image provider availability' },\n { name: 'models [options]', description: 'List and manage models and model auth' },\n { name: 'providers', description: 'Manage LLM provider credentials (user-friendly hub over `xopc auth`)' },\n { name: 'voice', description: 'Configure text-to-speech (TTS) output' },\n { name: 'search', description: 'Manage web-search providers (brave / tavily / bing / searxng)' },\n { name: 'skills', description: 'Manage skills' },\n { name: 'connectors', description: 'Browse and install verified connector capabilities from xopc-store' },\n { name: 'tailscale', description: 'Tailscale status for gateway remote access' },\n { name: 'browser', description: 'Browser automation commands (uses Playwright)' },\n { name: 'agents', description: 'Manage agents (config + workspace)' },\n { name: 'extensions', description: 'Manage extensions' },\n { name: 'help [command]', description: 'display help for command' },\n];\n\nfunction formatRows(rows: Array<{ label: string; description: string }>): string {\n const labelWidth = Math.max(...rows.map((row) => row.label.length)) + 2;\n return rows.map((row) => ` ${row.label.padEnd(labelWidth)}${row.description}`).join('\\n');\n}\n\nexport function formatRootHelp(): string {\n const options = formatRows(ROOT_HELP_OPTIONS.map((option) => ({ label: option.flags, description: option.description })));\n const commands = formatRows(\n ROOT_HELP_COMMANDS.map((command) => ({ label: command.name, description: command.description })),\n );\n return `Usage: xopc [options] [command]\n\n${ROOT_COMMAND_DESCRIPTION}\n\nOptions:\n${options}\n\nCommands:\n${commands}`;\n}\n"],"mappings":";AAUA,MAAa,2BAA2B;AAExC,MAAa,oBAAsC;CACjD;EAAE,OAAO;EAAiB,aAAa;EAA6B;CACpE;EAAE,OAAO;EAAa,aAAa;EAA2C;CAC9E;EAAE,OAAO;EAAmB,aAAa;EAAoB;CAC7D;EAAE,OAAO;EAAsB,aAAa;EAAuB;CACnE;EAAE,OAAO;EAAc,aAAa;EAA4B;CACjE;AAED,MAAa,qBAAwC;CACnD;EAAE,MAAM;EAAkB,aAAa;EAAkE;CACzG;EAAE,MAAM;EAAmB,aAAa;EAAkD;CAC1F;EAAE,MAAM;EAAW,aAAa;EAA0D;CAC1F;EAAE,MAAM;EAAqB,aAAa;EAAoE;CAC9G;EAAE,MAAM;EAAY,aAAa;EAAmC;CACpE;EAAE,MAAM;EAAQ,aAAa;EAAqC;CAClE;EAAE,MAAM;EAAmB,aAAa;EAA0B;CAClE;EAAE,MAAM;EAAiB,aAAa;EAAoC;CAC1E;EAAE,MAAM;EAAU,aAAa;EAAmC;CAClE;EAAE,MAAM;EAAqB,aAAa;EAAiC;CAC3E;EAAE,MAAM;EAAW,aAAa;EAA+B;CAC/D;EAAE,MAAM;EAAW,aAAa;EAAgC;CAChE;EAAE,MAAM;EAAoB,aAAa;EAA6D;CACtG;EAAE,MAAM;EAAoB,aAAa;EAAsC;CAC/E;EAAE,MAAM;EAAQ,aAAa;EAAyB;CACtD;EAAE,MAAM;EAAQ,aAAa;EAAwB;CACrD;EAAE,MAAM;EAAoB,aAAa;EAA+B;CACxE;EAAE,MAAM;EAAS,aAAa;EAAuC;CACrE;EAAE,MAAM;EAAoB,aAAa;EAAyC;CAClF;EAAE,MAAM;EAAa,aAAa;EAAwE;CAC1G;EAAE,MAAM;EAAS,aAAa;EAAyC;CACvE;EAAE,MAAM;EAAU,aAAa;EAAiE;CAChG;EAAE,MAAM;EAAU,aAAa;EAAiB;CAChD;EAAE,MAAM;EAAc,aAAa;EAAsE;CACzG;EAAE,MAAM;EAAa,aAAa;EAA8C;CAChF;EAAE,MAAM;EAAW,aAAa;EAAiD;CACjF;EAAE,MAAM;EAAU,aAAa;EAAsC;CACrE;EAAE,MAAM;EAAc,aAAa;EAAqB;CACxD;EAAE,MAAM;EAAkB,aAAa;EAA4B;CACpE;AAED,SAAS,WAAW,MAA6D;CAC/E,MAAM,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,MAAM,OAAO,CAAC,GAAG;AACtE,QAAO,KAAK,KAAK,QAAQ,KAAK,IAAI,MAAM,OAAO,WAAW,GAAG,IAAI,cAAc,CAAC,KAAK,KAAK;;AAG5F,SAAgB,iBAAyB;AAKvC,QAAO;;EAEP,yBAAyB;;;EANT,WAAW,kBAAkB,KAAK,YAAY;EAAE,OAAO,OAAO;EAAO,aAAa,OAAO;EAAa,EAAE,CASjH,CAAC;;;EARS,WACf,mBAAmB,KAAK,aAAa;EAAE,OAAO,QAAQ;EAAM,aAAa,QAAQ;EAAa,EAAE,CAU1F"}
1
+ {"version":3,"file":"command-manifest.js","names":[],"sources":["../../../src/cli/command-manifest.ts"],"sourcesContent":["export type RootHelpOption = {\n flags: string;\n description: string;\n};\n\nexport type RootHelpCommand = {\n name: string;\n description: string;\n};\n\nexport const ROOT_COMMAND_DESCRIPTION = 'Ultra-Lightweight Personal AI Assistant. Run `xopc` with no command to open the local TUI.';\n\nexport const ROOT_HELP_OPTIONS: RootHelpOption[] = [\n { flags: '-V, --version', description: 'output the version number' },\n { flags: '--verbose', description: 'Enable verbose logging (default: false)' },\n { flags: '--config <path>', description: 'Config file path' },\n { flags: '--workspace <path>', description: 'Workspace directory' },\n { flags: '-h, --help', description: 'display help for command' },\n];\n\nexport const ROOT_HELP_COMMANDS: RootHelpCommand[] = [\n { name: 'init [options]', description: 'Initialize xopc state directories, config, and agent workspace' },\n { name: 'setup [options]', description: 'Initialize config file and workspace directory' },\n { name: 'profile', description: 'Manage xopc state profiles (~/.xopc vs ~/.xopc-<name>)' },\n { name: 'onboard [options]', description: 'Interactive setup wizard for xopc (gateway uses schema defaults)' },\n { name: 'channels', description: 'Messaging channel configuration' },\n { name: 'auth', description: 'Manage authentication credentials' },\n { name: 'agent [options]', description: 'Chat with the AI agent' },\n { name: 'tui [options]', description: 'Interactive terminal UI (pi-tui)' },\n { name: 'resume [options] [sessionKey]', description: 'Resume a previous TUI session' },\n { name: 'tunnel', description: 'Manage FRP remote access tunnel' },\n { name: 'gateway [options]', description: 'Start the xopc gateway server' },\n { name: 'session', description: 'Session management commands' },\n { name: 'project', description: 'Manage long-running projects' },\n { name: 'doctor [options]', description: 'Check xopc installation health and diagnose common issues' },\n { name: 'update [options]', description: 'Check for and install xopc updates' },\n { name: 'logs', description: 'Manage and query logs' },\n { name: 'goal', description: 'Manage durable goals' },\n { name: 'config [options]', description: 'View and edit configuration' },\n { name: 'image', description: 'Inspect image provider availability' },\n { name: 'models [options]', description: 'List and manage models and model auth' },\n { name: 'providers', description: 'Manage LLM provider credentials (user-friendly hub over `xopc auth`)' },\n { name: 'voice', description: 'Configure text-to-speech (TTS) output' },\n { name: 'search', description: 'Manage web-search providers (brave / tavily / bing / searxng)' },\n { name: 'skills', description: 'Manage skills' },\n { name: 'connectors', description: 'Browse and install verified connector capabilities from xopc-store' },\n { name: 'tailscale', description: 'Tailscale status for gateway remote access' },\n { name: 'browser', description: 'Browser automation commands (uses Playwright)' },\n { name: 'agents', description: 'Manage agents (config + workspace)' },\n { name: 'extensions', description: 'Manage extensions' },\n { name: 'help [command]', description: 'display help for command' },\n];\n\nfunction formatRows(rows: Array<{ label: string; description: string }>): string {\n const labelWidth = Math.max(...rows.map((row) => row.label.length)) + 2;\n return rows.map((row) => ` ${row.label.padEnd(labelWidth)}${row.description}`).join('\\n');\n}\n\nexport function formatRootHelp(): string {\n const options = formatRows(ROOT_HELP_OPTIONS.map((option) => ({ label: option.flags, description: option.description })));\n const commands = formatRows(\n ROOT_HELP_COMMANDS.map((command) => ({ label: command.name, description: command.description })),\n );\n return `Usage: xopc [options] [command]\n\n${ROOT_COMMAND_DESCRIPTION}\n\nOptions:\n${options}\n\nCommands:\n${commands}`;\n}\n"],"mappings":";AAUA,MAAa,2BAA2B;AAExC,MAAa,oBAAsC;CACjD;EAAE,OAAO;EAAiB,aAAa;EAA6B;CACpE;EAAE,OAAO;EAAa,aAAa;EAA2C;CAC9E;EAAE,OAAO;EAAmB,aAAa;EAAoB;CAC7D;EAAE,OAAO;EAAsB,aAAa;EAAuB;CACnE;EAAE,OAAO;EAAc,aAAa;EAA4B;CACjE;AAED,MAAa,qBAAwC;CACnD;EAAE,MAAM;EAAkB,aAAa;EAAkE;CACzG;EAAE,MAAM;EAAmB,aAAa;EAAkD;CAC1F;EAAE,MAAM;EAAW,aAAa;EAA0D;CAC1F;EAAE,MAAM;EAAqB,aAAa;EAAoE;CAC9G;EAAE,MAAM;EAAY,aAAa;EAAmC;CACpE;EAAE,MAAM;EAAQ,aAAa;EAAqC;CAClE;EAAE,MAAM;EAAmB,aAAa;EAA0B;CAClE;EAAE,MAAM;EAAiB,aAAa;EAAoC;CAC1E;EAAE,MAAM;EAAiC,aAAa;EAAiC;CACvF;EAAE,MAAM;EAAU,aAAa;EAAmC;CAClE;EAAE,MAAM;EAAqB,aAAa;EAAiC;CAC3E;EAAE,MAAM;EAAW,aAAa;EAA+B;CAC/D;EAAE,MAAM;EAAW,aAAa;EAAgC;CAChE;EAAE,MAAM;EAAoB,aAAa;EAA6D;CACtG;EAAE,MAAM;EAAoB,aAAa;EAAsC;CAC/E;EAAE,MAAM;EAAQ,aAAa;EAAyB;CACtD;EAAE,MAAM;EAAQ,aAAa;EAAwB;CACrD;EAAE,MAAM;EAAoB,aAAa;EAA+B;CACxE;EAAE,MAAM;EAAS,aAAa;EAAuC;CACrE;EAAE,MAAM;EAAoB,aAAa;EAAyC;CAClF;EAAE,MAAM;EAAa,aAAa;EAAwE;CAC1G;EAAE,MAAM;EAAS,aAAa;EAAyC;CACvE;EAAE,MAAM;EAAU,aAAa;EAAiE;CAChG;EAAE,MAAM;EAAU,aAAa;EAAiB;CAChD;EAAE,MAAM;EAAc,aAAa;EAAsE;CACzG;EAAE,MAAM;EAAa,aAAa;EAA8C;CAChF;EAAE,MAAM;EAAW,aAAa;EAAiD;CACjF;EAAE,MAAM;EAAU,aAAa;EAAsC;CACrE;EAAE,MAAM;EAAc,aAAa;EAAqB;CACxD;EAAE,MAAM;EAAkB,aAAa;EAA4B;CACpE;AAED,SAAS,WAAW,MAA6D;CAC/E,MAAM,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,MAAM,OAAO,CAAC,GAAG;AACtE,QAAO,KAAK,KAAK,QAAQ,KAAK,IAAI,MAAM,OAAO,WAAW,GAAG,IAAI,cAAc,CAAC,KAAK,KAAK;;AAG5F,SAAgB,iBAAyB;AAKvC,QAAO;;EAEP,yBAAyB;;;EANT,WAAW,kBAAkB,KAAK,YAAY;EAAE,OAAO,OAAO;EAAO,aAAa,OAAO;EAAa,EAAE,CASjH,CAAC;;;EARS,WACf,mBAAmB,KAAK,aAAa;EAAE,OAAO,QAAQ;EAAM,aAAa,QAAQ;EAAa,EAAE,CAU1F"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ import { formatExamples, register } from "../registry.js";
2
+ import { prepareTuiStartup, runTuiFromCliOptions } from "./tui-runner.js";
3
+ import { Command } from "commander";
4
+ //#region src/cli/commands/resume.ts
5
+ function createResumeCommand(ctx) {
6
+ return new Command("resume").description("Resume a previous TUI session").argument("[sessionKey]", "Session key to resume directly").addHelpText("after", formatExamples([
7
+ "xopc resume # Choose a session interactively",
8
+ "xopc resume agent:main:tui-... # Resume a specific session",
9
+ "xopc resume --gateway --url http://host:3120 # Choose a remote session"
10
+ ])).option("--url <url>", "Gateway URL (default: http://localhost:3120)").option("--token <token>", "Gateway bearer token").option("--password-env <name>", "Environment variable holding the gateway password").option("--workdir <dir>", "Workspace directory for the resumed TUI session").option("--no-cwd", "Do not use the launch directory as the resumed TUI session workspace").option("--local", "Run in embedded mode (no gateway required)").option("--gateway", "Force gateway mode even without an explicit URL or credential").option("--theme <name>", "Theme: auto, dark, light, or custom name from ~/.xopc/themes/").option("--thinking <level>", "Thinking level override").action(async (sessionKey, options) => {
11
+ prepareTuiStartup(ctx.configPath);
12
+ await runTuiFromCliOptions(options, {
13
+ session: sessionKey,
14
+ openSessionPickerOnStart: sessionKey === void 0
15
+ });
16
+ });
17
+ }
18
+ register({
19
+ id: "resume",
20
+ name: "resume",
21
+ description: "Resume a previous TUI session",
22
+ factory: createResumeCommand,
23
+ metadata: {
24
+ category: "runtime",
25
+ examples: ["xopc resume", "xopc resume agent:main:tui-..."]
26
+ }
27
+ });
28
+ //#endregion
29
+ export {};
30
+
31
+ //# sourceMappingURL=resume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.js","names":[],"sources":["../../../../src/cli/commands/resume.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { register, formatExamples, type CLIContext } from '../registry.js';\nimport { prepareTuiStartup, runTuiFromCliOptions, type TuiCliOptions } from './tui-runner.js';\n\nfunction createResumeCommand(ctx: CLIContext): Command {\n return new Command('resume')\n .description('Resume a previous TUI session')\n .argument('[sessionKey]', 'Session key to resume directly')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc resume # Choose a session interactively',\n 'xopc resume agent:main:tui-... # Resume a specific session',\n 'xopc resume --gateway --url http://host:3120 # Choose a remote session',\n ]),\n )\n .option('--url <url>', 'Gateway URL (default: http://localhost:3120)')\n .option('--token <token>', 'Gateway bearer token')\n .option('--password-env <name>', 'Environment variable holding the gateway password')\n .option('--workdir <dir>', 'Workspace directory for the resumed TUI session')\n .option('--no-cwd', 'Do not use the launch directory as the resumed TUI session workspace')\n .option('--local', 'Run in embedded mode (no gateway required)')\n .option('--gateway', 'Force gateway mode even without an explicit URL or credential')\n .option('--theme <name>', 'Theme: auto, dark, light, or custom name from ~/.xopc/themes/')\n .option('--thinking <level>', 'Thinking level override')\n .action(async (sessionKey: string | undefined, options: TuiCliOptions) => {\n prepareTuiStartup(ctx.configPath);\n await runTuiFromCliOptions(options, {\n session: sessionKey,\n openSessionPickerOnStart: sessionKey === undefined,\n });\n });\n}\n\nregister({\n id: 'resume',\n name: 'resume',\n description: 'Resume a previous TUI session',\n factory: createResumeCommand,\n metadata: {\n category: 'runtime',\n examples: ['xopc resume', 'xopc resume agent:main:tui-...'],\n },\n});\n"],"mappings":";;;;AAKA,SAAS,oBAAoB,KAA0B;AACrD,QAAO,IAAI,QAAQ,SAAS,CACzB,YAAY,gCAAgC,CAC5C,SAAS,gBAAgB,iCAAiC,CAC1D,YACC,SACA,eAAe;EACb;EACA;EACA;EACD,CAAC,CACH,CACA,OAAO,eAAe,+CAA+C,CACrE,OAAO,mBAAmB,uBAAuB,CACjD,OAAO,yBAAyB,oDAAoD,CACpF,OAAO,mBAAmB,kDAAkD,CAC5E,OAAO,YAAY,uEAAuE,CAC1F,OAAO,WAAW,6CAA6C,CAC/D,OAAO,aAAa,gEAAgE,CACpF,OAAO,kBAAkB,gEAAgE,CACzF,OAAO,sBAAsB,0BAA0B,CACvD,OAAO,OAAO,YAAgC,YAA2B;AACxE,oBAAkB,IAAI,WAAW;AACjC,QAAM,qBAAqB,SAAS;GAClC,SAAS;GACT,0BAA0B,eAAe,KAAA;GAC1C,CAAC;GACF;;AAGN,SAAS;CACP,IAAI;CACJ,MAAM;CACN,aAAa;CACb,SAAS;CACT,UAAU;EACR,UAAU;EACV,UAAU,CAAC,eAAe,iCAAiC;EAC5D;CACF,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { TuiOptions } from '../../tui/tui-types.js';
2
+ export type TuiCliOptions = Record<string, string | boolean | undefined>;
3
+ export interface TuiLaunchOverrides {
4
+ session?: string;
5
+ openSessionPickerOnStart?: boolean;
6
+ }
7
+ export declare function prepareTuiStartup(configPath: string): void;
8
+ export declare function resolveTuiOptions(options: TuiCliOptions, overrides?: TuiLaunchOverrides): TuiOptions;
9
+ export declare function runTuiFromCliOptions(options: TuiCliOptions, overrides?: TuiLaunchOverrides): Promise<void>;
@@ -0,0 +1,40 @@
1
+ import { createGatewayCredential } from "../../gateway/credential.js";
2
+ import { detectMigrations, runBootstrapMigrationsSync } from "../../migrations/runner.js";
3
+ //#region src/cli/commands/tui-runner.ts
4
+ function prepareTuiStartup(configPath) {
5
+ runBootstrapMigrationsSync(configPath);
6
+ const pendingMigrations = detectMigrations(configPath);
7
+ if (pendingMigrations.length > 0) console.warn(`xopc has ${pendingMigrations.length} pending migration(s). Run \`xopc doctor --fix\` or open Settings → App management.`);
8
+ }
9
+ function resolveTuiOptions(options, overrides = {}) {
10
+ const token = typeof options.token === "string" ? options.token : void 0;
11
+ const passwordEnv = typeof options.passwordEnv === "string" ? options.passwordEnv.trim() : void 0;
12
+ if (token && passwordEnv) throw new Error("Use either --token or --password-env, not both.");
13
+ const password = passwordEnv ? process.env[passwordEnv] : void 0;
14
+ if (passwordEnv && !password) throw new Error(`Gateway password environment variable ${passwordEnv} is not set.`);
15
+ const credential = token ? createGatewayCredential("token", token) : createGatewayCredential("password", password);
16
+ const useLocal = options.local === true;
17
+ const useGateway = options.gateway === true || typeof options.url === "string" || credential !== void 0;
18
+ if (useLocal && useGateway) console.log("`--local` and gateway flags both set. Using local mode.");
19
+ return {
20
+ url: typeof options.url === "string" ? options.url : void 0,
21
+ credential,
22
+ session: overrides.session ?? (typeof options.session === "string" ? options.session : void 0),
23
+ agentId: typeof options.agent === "string" ? options.agent : void 0,
24
+ message: typeof options.message === "string" ? options.message : void 0,
25
+ workdir: typeof options.workdir === "string" ? options.workdir : void 0,
26
+ useStartupCwd: options.cwd !== false,
27
+ local: useLocal || !useGateway,
28
+ thinking: typeof options.thinking === "string" ? options.thinking : void 0,
29
+ theme: typeof options.theme === "string" ? options.theme : void 0,
30
+ openSessionPickerOnStart: overrides.openSessionPickerOnStart
31
+ };
32
+ }
33
+ async function runTuiFromCliOptions(options, overrides) {
34
+ const { runTui } = await import("../../tui/tui.js");
35
+ await runTui(resolveTuiOptions(options, overrides));
36
+ }
37
+ //#endregion
38
+ export { prepareTuiStartup, resolveTuiOptions, runTuiFromCliOptions };
39
+
40
+ //# sourceMappingURL=tui-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-runner.js","names":[],"sources":["../../../../src/cli/commands/tui-runner.ts"],"sourcesContent":["import { createGatewayCredential } from '../../gateway/credential.js';\nimport { detectMigrations, runBootstrapMigrationsSync } from '../../migrations/runner.js';\nimport type { TuiOptions } from '../../tui/tui-types.js';\n\nexport type TuiCliOptions = Record<string, string | boolean | undefined>;\n\nexport interface TuiLaunchOverrides {\n session?: string;\n openSessionPickerOnStart?: boolean;\n}\n\nexport function prepareTuiStartup(configPath: string): void {\n runBootstrapMigrationsSync(configPath);\n const pendingMigrations = detectMigrations(configPath);\n if (pendingMigrations.length > 0) {\n console.warn(\n `xopc has ${pendingMigrations.length} pending migration(s). Run \\`xopc doctor --fix\\` or open Settings → App management.`,\n );\n }\n}\n\nexport function resolveTuiOptions(\n options: TuiCliOptions,\n overrides: TuiLaunchOverrides = {},\n): TuiOptions {\n const token = typeof options.token === 'string' ? options.token : undefined;\n const passwordEnv = typeof options.passwordEnv === 'string' ? options.passwordEnv.trim() : undefined;\n if (token && passwordEnv) {\n throw new Error('Use either --token or --password-env, not both.');\n }\n\n const password = passwordEnv ? process.env[passwordEnv] : undefined;\n if (passwordEnv && !password) {\n throw new Error(`Gateway password environment variable ${passwordEnv} is not set.`);\n }\n\n const credential = token\n ? createGatewayCredential('token', token)\n : createGatewayCredential('password', password);\n const useLocal = options.local === true;\n const useGateway = options.gateway === true || typeof options.url === 'string' || credential !== undefined;\n if (useLocal && useGateway) {\n console.log('`--local` and gateway flags both set. Using local mode.');\n }\n\n return {\n url: typeof options.url === 'string' ? options.url : undefined,\n credential,\n session: overrides.session ?? (typeof options.session === 'string' ? options.session : undefined),\n agentId: typeof options.agent === 'string' ? options.agent : undefined,\n message: typeof options.message === 'string' ? options.message : undefined,\n workdir: typeof options.workdir === 'string' ? options.workdir : undefined,\n useStartupCwd: options.cwd !== false,\n local: useLocal || !useGateway,\n thinking: typeof options.thinking === 'string' ? options.thinking : undefined,\n theme: typeof options.theme === 'string' ? options.theme : undefined,\n openSessionPickerOnStart: overrides.openSessionPickerOnStart,\n };\n}\n\nexport async function runTuiFromCliOptions(\n options: TuiCliOptions,\n overrides?: TuiLaunchOverrides,\n): Promise<void> {\n const { runTui } = await import('../../tui/tui.js');\n await runTui(resolveTuiOptions(options, overrides));\n}\n"],"mappings":";;;AAWA,SAAgB,kBAAkB,YAA0B;AAC1D,4BAA2B,WAAW;CACtC,MAAM,oBAAoB,iBAAiB,WAAW;AACtD,KAAI,kBAAkB,SAAS,EAC7B,SAAQ,KACN,YAAY,kBAAkB,OAAO,qFACtC;;AAIL,SAAgB,kBACd,SACA,YAAgC,EAAE,EACtB;CACZ,MAAM,QAAQ,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,KAAA;CAClE,MAAM,cAAc,OAAO,QAAQ,gBAAgB,WAAW,QAAQ,YAAY,MAAM,GAAG,KAAA;AAC3F,KAAI,SAAS,YACX,OAAM,IAAI,MAAM,kDAAkD;CAGpE,MAAM,WAAW,cAAc,QAAQ,IAAI,eAAe,KAAA;AAC1D,KAAI,eAAe,CAAC,SAClB,OAAM,IAAI,MAAM,yCAAyC,YAAY,cAAc;CAGrF,MAAM,aAAa,QACf,wBAAwB,SAAS,MAAM,GACvC,wBAAwB,YAAY,SAAS;CACjD,MAAM,WAAW,QAAQ,UAAU;CACnC,MAAM,aAAa,QAAQ,YAAY,QAAQ,OAAO,QAAQ,QAAQ,YAAY,eAAe,KAAA;AACjG,KAAI,YAAY,WACd,SAAQ,IAAI,0DAA0D;AAGxE,QAAO;EACL,KAAK,OAAO,QAAQ,QAAQ,WAAW,QAAQ,MAAM,KAAA;EACrD;EACA,SAAS,UAAU,YAAY,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,KAAA;EACvF,SAAS,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,KAAA;EAC7D,SAAS,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,KAAA;EACjE,SAAS,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,KAAA;EACjE,eAAe,QAAQ,QAAQ;EAC/B,OAAO,YAAY,CAAC;EACpB,UAAU,OAAO,QAAQ,aAAa,WAAW,QAAQ,WAAW,KAAA;EACpE,OAAO,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,KAAA;EAC3D,0BAA0B,UAAU;EACrC;;AAGH,eAAsB,qBACpB,SACA,WACe;CACf,MAAM,EAAE,WAAW,MAAM,OAAO;AAChC,OAAM,OAAO,kBAAkB,SAAS,UAAU,CAAC"}
@@ -1,8 +1,7 @@
1
1
  import { init_loader, loadConfig, saveConfig } from "../../config/loader.js";
2
2
  import { setTuiDefaultAgentConfig } from "../../commands/agents.config.js";
3
3
  import { formatExamples, register } from "../registry.js";
4
- import { createGatewayCredential } from "../../gateway/credential.js";
5
- import { detectMigrations, runBootstrapMigrationsSync } from "../../migrations/runner.js";
4
+ import { prepareTuiStartup, runTuiFromCliOptions } from "./tui-runner.js";
6
5
  import { Command } from "commander";
7
6
  //#region src/cli/commands/tui.ts
8
7
  init_loader();
@@ -10,6 +9,7 @@ function createTuiCommand(ctx) {
10
9
  return new Command("tui").description("Interactive terminal UI (pi-tui)").addHelpText("after", formatExamples([
11
10
  "xopc # Open embedded TUI (default command)",
12
11
  "xopc tui # Embedded mode (default)",
12
+ "xopc resume # Choose a session to resume",
13
13
  "xopc tui --gateway # Force gateway mode",
14
14
  "XOPC_GATEWAY_PASSWORD=xxx xopc tui --url http://host:3120 --password-env XOPC_GATEWAY_PASSWORD",
15
15
  "xopc tui -s agent:main:tui-... # Resume a session",
@@ -17,9 +17,7 @@ function createTuiCommand(ctx) {
17
17
  "xopc tui --set-default-agent coder # Persist default agent for new TUI sessions",
18
18
  "xopc tui -m \"Summarize my inbox\" # Send a message on launch"
19
19
  ])).option("--url <url>", "Gateway URL (default: http://localhost:3120)").option("--token <token>", "Gateway bearer token").option("--password-env <name>", "Environment variable holding the gateway password").option("-s, --session <key>", "Session key to resume (omitted: start a fresh TUI session)").option("--agent <id>", "Agent id for a fresh TUI session").option("--set-default-agent <id>", "Persist default agent for new TUI sessions and exit").option("-m, --message <text>", "Send a message on launch").option("--workdir <dir>", "Workspace directory for the new TUI session").option("--no-cwd", "Do not use the launch directory as the new TUI session workspace").option("--local", "Run in embedded mode (no gateway required)").option("--gateway", "Force gateway mode even without an explicit URL or credential").option("--theme <name>", "Theme: auto, dark, light, or custom name from ~/.xopc/themes/").option("--thinking <level>", "Thinking level override").action(async (options) => {
20
- runBootstrapMigrationsSync(ctx.configPath);
21
- const pendingMigrations = detectMigrations(ctx.configPath);
22
- if (pendingMigrations.length > 0) console.warn(`xopc has ${pendingMigrations.length} pending migration(s). Run \`xopc doctor --fix\` or open Settings → App management.`);
20
+ prepareTuiStartup(ctx.configPath);
23
21
  if (typeof options.setDefaultAgent === "string") {
24
22
  const result = setTuiDefaultAgentConfig(loadConfig(ctx.configPath), options.setDefaultAgent);
25
23
  if (result.ok === false) {
@@ -30,29 +28,7 @@ function createTuiCommand(ctx) {
30
28
  console.log(`TUI default agent set to "${result.agentId}".`);
31
29
  return;
32
30
  }
33
- const { runTui } = await import("../../tui/tui.js");
34
- const token = typeof options.token === "string" ? options.token : void 0;
35
- const passwordEnv = typeof options.passwordEnv === "string" ? options.passwordEnv.trim() : void 0;
36
- if (token && passwordEnv) throw new Error("Use either --token or --password-env, not both.");
37
- const password = passwordEnv ? process.env[passwordEnv] : void 0;
38
- if (passwordEnv && !password) throw new Error(`Gateway password environment variable ${passwordEnv} is not set.`);
39
- const credential = token ? createGatewayCredential("token", token) : createGatewayCredential("password", password);
40
- const useLocal = options.local === true;
41
- const useGateway = options.gateway === true || typeof options.url === "string" || credential !== void 0;
42
- if (useLocal && useGateway) console.log("`--local` and gateway flags both set. Using local mode.");
43
- const localMode = useLocal || !useGateway;
44
- await runTui({
45
- url: typeof options.url === "string" ? options.url : void 0,
46
- credential,
47
- session: typeof options.session === "string" ? options.session : void 0,
48
- agentId: typeof options.agent === "string" ? options.agent : void 0,
49
- message: typeof options.message === "string" ? options.message : void 0,
50
- workdir: typeof options.workdir === "string" ? options.workdir : void 0,
51
- useStartupCwd: options.cwd !== false,
52
- local: localMode,
53
- thinking: typeof options.thinking === "string" ? options.thinking : void 0,
54
- theme: typeof options.theme === "string" ? options.theme : void 0
55
- });
31
+ await runTuiFromCliOptions(options);
56
32
  });
57
33
  }
58
34
  register({
@@ -1 +1 @@
1
- {"version":3,"file":"tui.js","names":[],"sources":["../../../../src/cli/commands/tui.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { setTuiDefaultAgentConfig } from '../../commands/agents.config.js';\nimport { loadConfig, saveConfig } from '../../config/loader.js';\nimport { createGatewayCredential } from '../../gateway/credential.js';\nimport { detectMigrations, runBootstrapMigrationsSync } from '../../migrations/runner.js';\nimport { register, formatExamples, type CLIContext } from '../registry.js';\n\nfunction createTuiCommand(ctx: CLIContext): Command {\n const cmd = new Command('tui')\n .description('Interactive terminal UI (pi-tui)')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc # Open embedded TUI (default command)',\n 'xopc tui # Embedded mode (default)',\n 'xopc tui --gateway # Force gateway mode',\n 'XOPC_GATEWAY_PASSWORD=xxx xopc tui --url http://host:3120 --password-env XOPC_GATEWAY_PASSWORD',\n 'xopc tui -s agent:main:tui-... # Resume a session',\n 'xopc tui --agent coder # Start with a specific agent',\n 'xopc tui --set-default-agent coder # Persist default agent for new TUI sessions',\n 'xopc tui -m \"Summarize my inbox\" # Send a message on launch',\n ]),\n )\n .option('--url <url>', 'Gateway URL (default: http://localhost:3120)')\n .option('--token <token>', 'Gateway bearer token')\n .option('--password-env <name>', 'Environment variable holding the gateway password')\n .option('-s, --session <key>', 'Session key to resume (omitted: start a fresh TUI session)')\n .option('--agent <id>', 'Agent id for a fresh TUI session')\n .option('--set-default-agent <id>', 'Persist default agent for new TUI sessions and exit')\n .option('-m, --message <text>', 'Send a message on launch')\n .option('--workdir <dir>', 'Workspace directory for the new TUI session')\n .option('--no-cwd', 'Do not use the launch directory as the new TUI session workspace')\n .option('--local', 'Run in embedded mode (no gateway required)')\n .option('--gateway', 'Force gateway mode even without an explicit URL or credential')\n .option('--theme <name>', 'Theme: auto, dark, light, or custom name from ~/.xopc/themes/')\n .option('--thinking <level>', 'Thinking level override')\n .action(async (options: Record<string, string | boolean | undefined>) => {\n runBootstrapMigrationsSync(ctx.configPath);\n const pendingMigrations = detectMigrations(ctx.configPath);\n if (pendingMigrations.length > 0) {\n console.warn(\n `xopc has ${pendingMigrations.length} pending migration(s). Run \\`xopc doctor --fix\\` or open Settings → App management.`,\n );\n }\n if (typeof options.setDefaultAgent === 'string') {\n const cfg = loadConfig(ctx.configPath);\n const result = setTuiDefaultAgentConfig(cfg, options.setDefaultAgent);\n if (result.ok === false) {\n console.error(`Error: ${result.message}`);\n process.exit(1);\n }\n await saveConfig(result.config, ctx.configPath);\n console.log(`TUI default agent set to \"${result.agentId}\".`);\n return;\n }\n const { runTui } = await import('../../tui/tui.js');\n const token = typeof options.token === 'string' ? options.token : undefined;\n const passwordEnv = typeof options.passwordEnv === 'string' ? options.passwordEnv.trim() : undefined;\n if (token && passwordEnv) {\n throw new Error('Use either --token or --password-env, not both.');\n }\n const password = passwordEnv ? process.env[passwordEnv] : undefined;\n if (passwordEnv && !password) {\n throw new Error(`Gateway password environment variable ${passwordEnv} is not set.`);\n }\n const credential = token\n ? createGatewayCredential('token', token)\n : createGatewayCredential('password', password);\n const useLocal = options.local === true;\n const useGateway = options.gateway === true || typeof options.url === 'string' || credential !== undefined;\n if (useLocal && useGateway) {\n console.log('`--local` and gateway flags both set. Using local mode.');\n }\n const localMode = useLocal || !useGateway;\n await runTui({\n url: typeof options.url === 'string' ? options.url : undefined,\n credential,\n session: typeof options.session === 'string' ? options.session : undefined,\n agentId: typeof options.agent === 'string' ? options.agent : undefined,\n message: typeof options.message === 'string' ? options.message : undefined,\n workdir: typeof options.workdir === 'string' ? options.workdir : undefined,\n useStartupCwd: options.cwd !== false,\n local: localMode,\n thinking: typeof options.thinking === 'string' ? options.thinking : undefined,\n theme: typeof options.theme === 'string' ? options.theme : undefined,\n });\n });\n\n return cmd;\n}\n\nregister({\n id: 'tui',\n name: 'tui',\n description: 'Interactive terminal UI (pi-tui)',\n factory: createTuiCommand,\n metadata: {\n category: 'runtime',\n examples: [\n 'xopc',\n 'xopc tui',\n 'xopc tui --agent coder',\n 'xopc tui --set-default-agent coder',\n 'xopc tui --gateway',\n 'xopc tui --url http://host:3120',\n ],\n },\n});\n"],"mappings":";;;;;;;aAGgE;AAKhE,SAAS,iBAAiB,KAA0B;AAiFlD,QAhFY,IAAI,QAAQ,MAAM,CAC3B,YAAY,mCAAmC,CAC/C,YACC,SACA,eAAe;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,CACH,CACA,OAAO,eAAe,+CAA+C,CACrE,OAAO,mBAAmB,uBAAuB,CACjD,OAAO,yBAAyB,oDAAoD,CACpF,OAAO,uBAAuB,6DAA6D,CAC3F,OAAO,gBAAgB,mCAAmC,CAC1D,OAAO,4BAA4B,sDAAsD,CACzF,OAAO,wBAAwB,2BAA2B,CAC1D,OAAO,mBAAmB,8CAA8C,CACxE,OAAO,YAAY,mEAAmE,CACtF,OAAO,WAAW,6CAA6C,CAC/D,OAAO,aAAa,gEAAgE,CACpF,OAAO,kBAAkB,gEAAgE,CACzF,OAAO,sBAAsB,0BAA0B,CACvD,OAAO,OAAO,YAA0D;AACvE,6BAA2B,IAAI,WAAW;EAC1C,MAAM,oBAAoB,iBAAiB,IAAI,WAAW;AAC1D,MAAI,kBAAkB,SAAS,EAC7B,SAAQ,KACN,YAAY,kBAAkB,OAAO,qFACtC;AAEH,MAAI,OAAO,QAAQ,oBAAoB,UAAU;GAE/C,MAAM,SAAS,yBADH,WAAW,IAAI,WACgB,EAAE,QAAQ,gBAAgB;AACrE,OAAI,OAAO,OAAO,OAAO;AACvB,YAAQ,MAAM,UAAU,OAAO,UAAU;AACzC,YAAQ,KAAK,EAAE;;AAEjB,SAAM,WAAW,OAAO,QAAQ,IAAI,WAAW;AAC/C,WAAQ,IAAI,6BAA6B,OAAO,QAAQ,IAAI;AAC5D;;EAEF,MAAM,EAAE,WAAW,MAAM,OAAO;EAChC,MAAM,QAAQ,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,KAAA;EAClE,MAAM,cAAc,OAAO,QAAQ,gBAAgB,WAAW,QAAQ,YAAY,MAAM,GAAG,KAAA;AAC3F,MAAI,SAAS,YACX,OAAM,IAAI,MAAM,kDAAkD;EAEpE,MAAM,WAAW,cAAc,QAAQ,IAAI,eAAe,KAAA;AAC1D,MAAI,eAAe,CAAC,SAClB,OAAM,IAAI,MAAM,yCAAyC,YAAY,cAAc;EAErF,MAAM,aAAa,QACf,wBAAwB,SAAS,MAAM,GACvC,wBAAwB,YAAY,SAAS;EACjD,MAAM,WAAW,QAAQ,UAAU;EACnC,MAAM,aAAa,QAAQ,YAAY,QAAQ,OAAO,QAAQ,QAAQ,YAAY,eAAe,KAAA;AACjG,MAAI,YAAY,WACd,SAAQ,IAAI,0DAA0D;EAExE,MAAM,YAAY,YAAY,CAAC;AAC/B,QAAM,OAAO;GACX,KAAK,OAAO,QAAQ,QAAQ,WAAW,QAAQ,MAAM,KAAA;GACrD;GACA,SAAS,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,KAAA;GACjE,SAAS,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,KAAA;GAC7D,SAAS,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,KAAA;GACjE,SAAS,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,KAAA;GACjE,eAAe,QAAQ,QAAQ;GAC/B,OAAO;GACP,UAAU,OAAO,QAAQ,aAAa,WAAW,QAAQ,WAAW,KAAA;GACpE,OAAO,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,KAAA;GAC5D,CAAC;GAGI;;AAGZ,SAAS;CACP,IAAI;CACJ,MAAM;CACN,aAAa;CACb,SAAS;CACT,UAAU;EACR,UAAU;EACV,UAAU;GACR;GACA;GACA;GACA;GACA;GACA;GACD;EACF;CACF,CAAC"}
1
+ {"version":3,"file":"tui.js","names":[],"sources":["../../../../src/cli/commands/tui.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { setTuiDefaultAgentConfig } from '../../commands/agents.config.js';\nimport { loadConfig, saveConfig } from '../../config/loader.js';\nimport { register, formatExamples, type CLIContext } from '../registry.js';\nimport { prepareTuiStartup, runTuiFromCliOptions, type TuiCliOptions } from './tui-runner.js';\n\nfunction createTuiCommand(ctx: CLIContext): Command {\n const cmd = new Command('tui')\n .description('Interactive terminal UI (pi-tui)')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc # Open embedded TUI (default command)',\n 'xopc tui # Embedded mode (default)',\n 'xopc resume # Choose a session to resume',\n 'xopc tui --gateway # Force gateway mode',\n 'XOPC_GATEWAY_PASSWORD=xxx xopc tui --url http://host:3120 --password-env XOPC_GATEWAY_PASSWORD',\n 'xopc tui -s agent:main:tui-... # Resume a session',\n 'xopc tui --agent coder # Start with a specific agent',\n 'xopc tui --set-default-agent coder # Persist default agent for new TUI sessions',\n 'xopc tui -m \"Summarize my inbox\" # Send a message on launch',\n ]),\n )\n .option('--url <url>', 'Gateway URL (default: http://localhost:3120)')\n .option('--token <token>', 'Gateway bearer token')\n .option('--password-env <name>', 'Environment variable holding the gateway password')\n .option('-s, --session <key>', 'Session key to resume (omitted: start a fresh TUI session)')\n .option('--agent <id>', 'Agent id for a fresh TUI session')\n .option('--set-default-agent <id>', 'Persist default agent for new TUI sessions and exit')\n .option('-m, --message <text>', 'Send a message on launch')\n .option('--workdir <dir>', 'Workspace directory for the new TUI session')\n .option('--no-cwd', 'Do not use the launch directory as the new TUI session workspace')\n .option('--local', 'Run in embedded mode (no gateway required)')\n .option('--gateway', 'Force gateway mode even without an explicit URL or credential')\n .option('--theme <name>', 'Theme: auto, dark, light, or custom name from ~/.xopc/themes/')\n .option('--thinking <level>', 'Thinking level override')\n .action(async (options: TuiCliOptions) => {\n prepareTuiStartup(ctx.configPath);\n if (typeof options.setDefaultAgent === 'string') {\n const cfg = loadConfig(ctx.configPath);\n const result = setTuiDefaultAgentConfig(cfg, options.setDefaultAgent);\n if (result.ok === false) {\n console.error(`Error: ${result.message}`);\n process.exit(1);\n }\n await saveConfig(result.config, ctx.configPath);\n console.log(`TUI default agent set to \"${result.agentId}\".`);\n return;\n }\n await runTuiFromCliOptions(options);\n });\n\n return cmd;\n}\n\nregister({\n id: 'tui',\n name: 'tui',\n description: 'Interactive terminal UI (pi-tui)',\n factory: createTuiCommand,\n metadata: {\n category: 'runtime',\n examples: [\n 'xopc',\n 'xopc tui',\n 'xopc tui --agent coder',\n 'xopc tui --set-default-agent coder',\n 'xopc tui --gateway',\n 'xopc tui --url http://host:3120',\n ],\n },\n});\n"],"mappings":";;;;;;aAGgE;AAIhE,SAAS,iBAAiB,KAA0B;AA8ClD,QA7CY,IAAI,QAAQ,MAAM,CAC3B,YAAY,mCAAmC,CAC/C,YACC,SACA,eAAe;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,CACH,CACA,OAAO,eAAe,+CAA+C,CACrE,OAAO,mBAAmB,uBAAuB,CACjD,OAAO,yBAAyB,oDAAoD,CACpF,OAAO,uBAAuB,6DAA6D,CAC3F,OAAO,gBAAgB,mCAAmC,CAC1D,OAAO,4BAA4B,sDAAsD,CACzF,OAAO,wBAAwB,2BAA2B,CAC1D,OAAO,mBAAmB,8CAA8C,CACxE,OAAO,YAAY,mEAAmE,CACtF,OAAO,WAAW,6CAA6C,CAC/D,OAAO,aAAa,gEAAgE,CACpF,OAAO,kBAAkB,gEAAgE,CACzF,OAAO,sBAAsB,0BAA0B,CACvD,OAAO,OAAO,YAA2B;AACxC,oBAAkB,IAAI,WAAW;AACjC,MAAI,OAAO,QAAQ,oBAAoB,UAAU;GAE/C,MAAM,SAAS,yBADH,WAAW,IAAI,WACgB,EAAE,QAAQ,gBAAgB;AACrE,OAAI,OAAO,OAAO,OAAO;AACvB,YAAQ,MAAM,UAAU,OAAO,UAAU;AACzC,YAAQ,KAAK,EAAE;;AAEjB,SAAM,WAAW,OAAO,QAAQ,IAAI,WAAW;AAC/C,WAAQ,IAAI,6BAA6B,OAAO,QAAQ,IAAI;AAC5D;;AAEF,QAAM,qBAAqB,QAAQ;GAG7B;;AAGZ,SAAS;CACP,IAAI;CACJ,MAAM;CACN,aAAa;CACb,SAAS;CACT,UAAU;EACR,UAAU;EACV,UAAU;GACR;GACA;GACA;GACA;GACA;GACA;GACD;EACF;CACF,CAAC"}
@@ -1,6 +1,6 @@
1
+ import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
1
2
  import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
2
3
  import "../agent-manifest/index.js";
3
- import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
4
4
  import { init_session_key, parseSessionKey } from "../routing/session-key.js";
5
5
  import { agentExists, getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
6
6
  //#region src/config/agent-profile.ts
@@ -1,5 +1,5 @@
1
- import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
2
1
  import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
2
+ import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
3
3
  import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
4
4
  import { WORKSPACE_FILES, init_paths, resolveUserProfilePath } from "../config/paths.js";
5
5
  import { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES, REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET } from "../agent/context/workspace.js";
@@ -1,7 +1,16 @@
1
1
  import { listGatewayAgents } from "../../agents-admin.js";
2
+ import { WorkItemService } from "../../../work-items/work-item-service.js";
3
+ import "../../../work-items/index.js";
2
4
  import { getTunnelService } from "../../../tunnel/tunnel-service.js";
3
5
  import "../../../tunnel/index.js";
4
6
  //#region src/gateway/hono/routes/home.ts
7
+ function workItemAttentionRank(item, nowMs) {
8
+ if (item.status === "needs_input" || item.status === "blocked") return 0;
9
+ if (item.dueAt != null && item.dueAt < nowMs) return 1;
10
+ if (item.dueAt != null && item.dueAt < nowMs + 1440 * 60 * 1e3) return 2;
11
+ if (item.priority === "urgent") return 3;
12
+ return 4;
13
+ }
5
14
  function toHomeWorkflowRun(run) {
6
15
  return {
7
16
  id: run.id,
@@ -78,7 +87,9 @@ function registerHomeRoutes(authenticated, deps) {
78
87
  const workflowRunStore = service.createWorkflowRunService().createRunStore(defaultAgent?.id ?? agents.defaultId);
79
88
  const tunnel = getTunnelService().getStatus();
80
89
  const health = service.getHealth();
81
- const [recentlyOpened, inbox, pendingTasks, recentSessions, workflowRuns, automations, automationRuns] = await Promise.all([
90
+ const workItems = new WorkItemService();
91
+ const nowMs = Date.now();
92
+ const [recentlyOpened, inbox, pendingTasks, recentSessions, workflowRuns, automations, automationRuns, projects, allWorkItems] = await Promise.all([
82
93
  notes.listNotes({
83
94
  sortBy: "lastOpenedAt",
84
95
  sortOrder: "desc",
@@ -101,8 +112,26 @@ function registerHomeRoutes(authenticated, deps) {
101
112
  }),
102
113
  workflowRunStore.listRunSummaries(20),
103
114
  service.automationServiceInstance.list(),
104
- service.automationServiceInstance.listRuns({ limit: 10 })
115
+ service.automationServiceInstance.listRuns({ limit: 10 }),
116
+ service.projects.list({ limit: 500 }),
117
+ Promise.resolve(workItems.listWorkItems({ limit: 100 }))
105
118
  ]);
119
+ const projectsById = new Map(projects.items.map((project) => [project.id, project]));
120
+ const activeWorkItems = allWorkItems.items.filter((item) => item.status !== "done" && item.status !== "cancelled").sort((left, right) => {
121
+ return workItemAttentionRank(left, nowMs) - workItemAttentionRank(right, nowMs) || right.updatedAt - left.updatedAt;
122
+ });
123
+ const attentionWorkItems = activeWorkItems.slice(0, 6).map((item) => ({
124
+ id: item.id,
125
+ projectId: item.projectId,
126
+ projectName: projectsById.get(item.projectId)?.name ?? "Project",
127
+ title: item.title,
128
+ status: item.status,
129
+ priority: item.priority,
130
+ nextAction: item.nextAction,
131
+ blockedReason: item.blockedReason,
132
+ dueAt: item.dueAt,
133
+ updatedAt: item.updatedAt
134
+ }));
106
135
  const activeWorkflowRuns = workflowRuns.filter((run) => run.status === "queued" || run.status === "running").slice(0, 5).map(toHomeWorkflowRun);
107
136
  const attentionWorkflowRuns = workflowRuns.filter((run) => run.status === "failed" || run.status === "timeout").slice(0, 5).map(toHomeWorkflowRun);
108
137
  const recentWorkflowRuns = workflowRuns.slice(0, 5).map(toHomeWorkflowRun);
@@ -135,6 +164,12 @@ function registerHomeRoutes(authenticated, deps) {
135
164
  attention: attentionWorkflowRuns,
136
165
  recent: recentWorkflowRuns
137
166
  },
167
+ work: {
168
+ attentionCount: activeWorkItems.filter((item) => workItemAttentionRank(item, nowMs) < 3).length,
169
+ overdueCount: activeWorkItems.filter((item) => item.dueAt != null && item.dueAt < nowMs).length,
170
+ todayCount: activeWorkItems.filter((item) => item.dueAt != null && item.dueAt >= nowMs && item.dueAt < nowMs + 1440 * 60 * 1e3).length,
171
+ items: attentionWorkItems
172
+ },
138
173
  upcomingAutomations,
139
174
  recentAutomationRuns: automationRuns.slice(0, 5).map(toHomeAutomationRun)
140
175
  });
@@ -1 +1 @@
1
- {"version":3,"file":"home.js","names":[],"sources":["../../../../../src/gateway/hono/routes/home.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { listGatewayAgents } from '../../agents-admin.js';\nimport { getTunnelService } from '../../../tunnel/index.js';\nimport type { Automation, AutomationRun } from '../../../automations/index.js';\nimport type { WorkflowRunSummary } from '../../../workflows/domain/index.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\ntype HomeWorkflowRun = {\n id: string;\n definitionId: string;\n title: string;\n status: WorkflowRunSummary['status'];\n sessionKey?: string;\n createdAtMs: number;\n startedAtMs?: number;\n completedAtMs?: number;\n metrics: WorkflowRunSummary['metrics'];\n};\n\ntype HomeAutomation = {\n id: string;\n name?: string;\n trigger: string;\n action: string;\n nextRunAt: string;\n};\n\ntype HomeAutomationRun = {\n id: string;\n automationId: string;\n automationName?: string;\n status: AutomationRun['status'];\n createdAtMs: number;\n startedAtMs?: number;\n endedAtMs?: number;\n error?: string;\n summary?: string;\n sessionKey?: string;\n workflowRunId?: string;\n};\n\nfunction toHomeWorkflowRun(run: WorkflowRunSummary): HomeWorkflowRun {\n return {\n id: run.id,\n definitionId: run.definitionId,\n title: run.title,\n status: run.status,\n sessionKey: run.metadata?.sessionKey,\n createdAtMs: run.createdAtMs,\n startedAtMs: run.startedAtMs,\n completedAtMs: run.completedAtMs,\n metrics: run.metrics,\n };\n}\n\nfunction triggerLabel(automation: Automation): string {\n const trigger = automation.trigger;\n if (trigger.kind === 'manual') return 'manual';\n if (trigger.kind === 'webhook') return 'webhook';\n if (trigger.kind === 'event') return `event:${trigger.eventType}`;\n const schedule = trigger.schedule;\n if (schedule.kind === 'once') return schedule.at;\n if (schedule.kind === 'interval') return `every ${Math.round(schedule.everyMs / 60000)} minutes`;\n return schedule.expr;\n}\n\nfunction actionLabel(automation: Automation): string {\n if (automation.action.kind === 'workflow') return `workflow:${automation.action.workflowId}`;\n return automation.action.agentId ? `agent:${automation.action.agentId}` : 'agent';\n}\n\nfunction toHomeAutomation(automation: Automation): HomeAutomation | null {\n if (!automation.enabled || !automation.state.nextRunAtMs) return null;\n return {\n id: automation.id,\n name: automation.name,\n trigger: triggerLabel(automation),\n action: actionLabel(automation),\n nextRunAt: new Date(automation.state.nextRunAtMs).toISOString(),\n };\n}\n\nfunction toHomeAutomationRun(run: AutomationRun): HomeAutomationRun {\n return {\n id: run.id,\n automationId: run.automationId,\n automationName: run.automationName,\n status: run.status,\n createdAtMs: run.createdAtMs,\n startedAtMs: run.startedAtMs,\n endedAtMs: run.endedAtMs,\n error: run.error,\n summary: run.summary,\n sessionKey: run.sessionKey,\n workflowRunId: run.workflowRunId,\n };\n}\n\n/**\n * GET /api/home — Aggregated home screen data for the mobile app.\n *\n * Returns:\n * - recentlyOpened: notes sorted by lastOpenedAt (continue rail)\n * - inboxCount: number of notes with status === 'inbox'\n * - pendingTasks: task notes where done === false\n * - recentSessions: last 5 active AI sessions (threads)\n * - activeAgent: default agent identity for this gateway\n * - gateway: readiness + public tunnel status\n * - workflowRuns: active / attention / recent workflow runs\n * - upcomingAutomations: upcoming enabled automations\n * - recentAutomationRuns: latest automation executions\n */\nexport function registerHomeRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n authenticated.get('/api/home', async (c) => {\n const notes = service.notesServiceInstance;\n const sessions = service.sessions;\n const agents = await listGatewayAgents(service.currentConfig);\n const defaultAgent = agents.agents.find((agent) => agent.id === agents.defaultId) ?? agents.agents[0];\n const workflowRunService = service.createWorkflowRunService();\n const workflowRunStore = workflowRunService.createRunStore(defaultAgent?.id ?? agents.defaultId);\n const tunnel = getTunnelService().getStatus();\n const health = service.getHealth();\n\n const [\n recentlyOpened,\n inbox,\n pendingTasks,\n recentSessions,\n workflowRuns,\n automations,\n automationRuns,\n ] = await Promise.all([\n notes.listNotes({ sortBy: 'lastOpenedAt', sortOrder: 'desc', limit: 10 }),\n notes.listNotes({ status: 'inbox', limit: 0 }),\n notes.listNotes({ pendingTasksOnly: true, sortBy: 'createdAt', sortOrder: 'desc', limit: 10 }),\n sessions.listSessions({ sortBy: 'updatedAt', sortOrder: 'desc', limit: 5 }),\n workflowRunStore.listRunSummaries(20),\n service.automationServiceInstance.list(),\n service.automationServiceInstance.listRuns({ limit: 10 }),\n ]);\n\n const activeWorkflowRuns = workflowRuns\n .filter((run) => run.status === 'queued' || run.status === 'running')\n .slice(0, 5)\n .map(toHomeWorkflowRun);\n const attentionWorkflowRuns = workflowRuns\n .filter((run) => run.status === 'failed' || run.status === 'timeout')\n .slice(0, 5)\n .map(toHomeWorkflowRun);\n const recentWorkflowRuns = workflowRuns.slice(0, 5).map(toHomeWorkflowRun);\n const upcomingAutomations = automations\n .map(toHomeAutomation)\n .filter((automation): automation is HomeAutomation => Boolean(automation))\n .sort((a, b) => Date.parse(a.nextRunAt) - Date.parse(b.nextRunAt))\n .slice(0, 5);\n\n return c.json({\n recentlyOpened: recentlyOpened.items.filter((n) => n.lastOpenedAt),\n inboxCount: inbox.total,\n pendingTasks: pendingTasks.items,\n pendingTaskCount: pendingTasks.total,\n recentSessions: recentSessions.items,\n activeAgent: defaultAgent\n ? {\n id: defaultAgent.id,\n name: defaultAgent.name,\n description: defaultAgent.description,\n }\n : { id: agents.defaultId },\n gateway: {\n status: health.status,\n ready: health.ready,\n httpListening: health.httpListening,\n version: health.version,\n uptime: health.uptime,\n tunnel: {\n state: tunnel.state,\n publicUrl: tunnel.publicUrl,\n connected: tunnel.state === 'connected',\n },\n },\n workflowRuns: {\n active: activeWorkflowRuns,\n attention: attentionWorkflowRuns,\n recent: recentWorkflowRuns,\n },\n upcomingAutomations,\n recentAutomationRuns: automationRuns.slice(0, 5).map(toHomeAutomationRun),\n });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"home.js","names":[],"sources":["../../../../../src/gateway/hono/routes/home.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { listGatewayAgents } from '../../agents-admin.js';\nimport { getTunnelService } from '../../../tunnel/index.js';\nimport type { Automation, AutomationRun } from '../../../automations/index.js';\nimport type { WorkflowRunSummary } from '../../../workflows/domain/index.js';\nimport { WorkItemService } from '../../../work-items/index.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\ntype HomeWorkflowRun = {\n id: string;\n definitionId: string;\n title: string;\n status: WorkflowRunSummary['status'];\n sessionKey?: string;\n createdAtMs: number;\n startedAtMs?: number;\n completedAtMs?: number;\n metrics: WorkflowRunSummary['metrics'];\n};\n\ntype HomeAutomation = {\n id: string;\n name?: string;\n trigger: string;\n action: string;\n nextRunAt: string;\n};\n\ntype HomeAutomationRun = {\n id: string;\n automationId: string;\n automationName?: string;\n status: AutomationRun['status'];\n createdAtMs: number;\n startedAtMs?: number;\n endedAtMs?: number;\n error?: string;\n summary?: string;\n sessionKey?: string;\n workflowRunId?: string;\n};\n\nfunction workItemAttentionRank(item: { status: string; dueAt?: number; priority: string; updatedAt: number }, nowMs: number): number {\n if (item.status === 'needs_input' || item.status === 'blocked') return 0;\n if (item.dueAt != null && item.dueAt < nowMs) return 1;\n if (item.dueAt != null && item.dueAt < nowMs + 24 * 60 * 60 * 1000) return 2;\n if (item.priority === 'urgent') return 3;\n return 4;\n}\n\nfunction toHomeWorkflowRun(run: WorkflowRunSummary): HomeWorkflowRun {\n return {\n id: run.id,\n definitionId: run.definitionId,\n title: run.title,\n status: run.status,\n sessionKey: run.metadata?.sessionKey,\n createdAtMs: run.createdAtMs,\n startedAtMs: run.startedAtMs,\n completedAtMs: run.completedAtMs,\n metrics: run.metrics,\n };\n}\n\nfunction triggerLabel(automation: Automation): string {\n const trigger = automation.trigger;\n if (trigger.kind === 'manual') return 'manual';\n if (trigger.kind === 'webhook') return 'webhook';\n if (trigger.kind === 'event') return `event:${trigger.eventType}`;\n const schedule = trigger.schedule;\n if (schedule.kind === 'once') return schedule.at;\n if (schedule.kind === 'interval') return `every ${Math.round(schedule.everyMs / 60000)} minutes`;\n return schedule.expr;\n}\n\nfunction actionLabel(automation: Automation): string {\n if (automation.action.kind === 'workflow') return `workflow:${automation.action.workflowId}`;\n return automation.action.agentId ? `agent:${automation.action.agentId}` : 'agent';\n}\n\nfunction toHomeAutomation(automation: Automation): HomeAutomation | null {\n if (!automation.enabled || !automation.state.nextRunAtMs) return null;\n return {\n id: automation.id,\n name: automation.name,\n trigger: triggerLabel(automation),\n action: actionLabel(automation),\n nextRunAt: new Date(automation.state.nextRunAtMs).toISOString(),\n };\n}\n\nfunction toHomeAutomationRun(run: AutomationRun): HomeAutomationRun {\n return {\n id: run.id,\n automationId: run.automationId,\n automationName: run.automationName,\n status: run.status,\n createdAtMs: run.createdAtMs,\n startedAtMs: run.startedAtMs,\n endedAtMs: run.endedAtMs,\n error: run.error,\n summary: run.summary,\n sessionKey: run.sessionKey,\n workflowRunId: run.workflowRunId,\n };\n}\n\n/**\n * GET /api/home — Aggregated home screen data for the mobile app.\n *\n * Returns:\n * - recentlyOpened: notes sorted by lastOpenedAt (continue rail)\n * - inboxCount: number of notes with status === 'inbox'\n * - pendingTasks: task notes where done === false\n * - recentSessions: last 5 active AI sessions (threads)\n * - activeAgent: default agent identity for this gateway\n * - gateway: readiness + public tunnel status\n * - workflowRuns: active / attention / recent workflow runs\n * - upcomingAutomations: upcoming enabled automations\n * - recentAutomationRuns: latest automation executions\n */\nexport function registerHomeRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n authenticated.get('/api/home', async (c) => {\n const notes = service.notesServiceInstance;\n const sessions = service.sessions;\n const agents = await listGatewayAgents(service.currentConfig);\n const defaultAgent = agents.agents.find((agent) => agent.id === agents.defaultId) ?? agents.agents[0];\n const workflowRunService = service.createWorkflowRunService();\n const workflowRunStore = workflowRunService.createRunStore(defaultAgent?.id ?? agents.defaultId);\n const tunnel = getTunnelService().getStatus();\n const health = service.getHealth();\n const workItems = new WorkItemService();\n const nowMs = Date.now();\n\n const [\n recentlyOpened,\n inbox,\n pendingTasks,\n recentSessions,\n workflowRuns,\n automations,\n automationRuns,\n projects,\n allWorkItems,\n ] = await Promise.all([\n notes.listNotes({ sortBy: 'lastOpenedAt', sortOrder: 'desc', limit: 10 }),\n notes.listNotes({ status: 'inbox', limit: 0 }),\n notes.listNotes({ pendingTasksOnly: true, sortBy: 'createdAt', sortOrder: 'desc', limit: 10 }),\n sessions.listSessions({ sortBy: 'updatedAt', sortOrder: 'desc', limit: 5 }),\n workflowRunStore.listRunSummaries(20),\n service.automationServiceInstance.list(),\n service.automationServiceInstance.listRuns({ limit: 10 }),\n service.projects.list({ limit: 500 }),\n Promise.resolve(workItems.listWorkItems({ limit: 100 })),\n ]);\n const projectsById = new Map(projects.items.map((project) => [project.id, project]));\n const activeWorkItems = allWorkItems.items\n .filter((item) => item.status !== 'done' && item.status !== 'cancelled')\n .sort((left, right) => {\n const rank = workItemAttentionRank(left, nowMs) - workItemAttentionRank(right, nowMs);\n return rank || right.updatedAt - left.updatedAt;\n });\n const attentionWorkItems = activeWorkItems.slice(0, 6).map((item) => ({\n id: item.id,\n projectId: item.projectId,\n projectName: projectsById.get(item.projectId)?.name ?? 'Project',\n title: item.title,\n status: item.status,\n priority: item.priority,\n nextAction: item.nextAction,\n blockedReason: item.blockedReason,\n dueAt: item.dueAt,\n updatedAt: item.updatedAt,\n }));\n\n const activeWorkflowRuns = workflowRuns\n .filter((run) => run.status === 'queued' || run.status === 'running')\n .slice(0, 5)\n .map(toHomeWorkflowRun);\n const attentionWorkflowRuns = workflowRuns\n .filter((run) => run.status === 'failed' || run.status === 'timeout')\n .slice(0, 5)\n .map(toHomeWorkflowRun);\n const recentWorkflowRuns = workflowRuns.slice(0, 5).map(toHomeWorkflowRun);\n const upcomingAutomations = automations\n .map(toHomeAutomation)\n .filter((automation): automation is HomeAutomation => Boolean(automation))\n .sort((a, b) => Date.parse(a.nextRunAt) - Date.parse(b.nextRunAt))\n .slice(0, 5);\n\n return c.json({\n recentlyOpened: recentlyOpened.items.filter((n) => n.lastOpenedAt),\n inboxCount: inbox.total,\n pendingTasks: pendingTasks.items,\n pendingTaskCount: pendingTasks.total,\n recentSessions: recentSessions.items,\n activeAgent: defaultAgent\n ? {\n id: defaultAgent.id,\n name: defaultAgent.name,\n description: defaultAgent.description,\n }\n : { id: agents.defaultId },\n gateway: {\n status: health.status,\n ready: health.ready,\n httpListening: health.httpListening,\n version: health.version,\n uptime: health.uptime,\n tunnel: {\n state: tunnel.state,\n publicUrl: tunnel.publicUrl,\n connected: tunnel.state === 'connected',\n },\n },\n workflowRuns: {\n active: activeWorkflowRuns,\n attention: attentionWorkflowRuns,\n recent: recentWorkflowRuns,\n },\n work: {\n attentionCount: activeWorkItems.filter((item) => workItemAttentionRank(item, nowMs) < 3).length,\n overdueCount: activeWorkItems.filter((item) => item.dueAt != null && item.dueAt < nowMs).length,\n todayCount: activeWorkItems.filter((item) => item.dueAt != null && item.dueAt >= nowMs && item.dueAt < nowMs + 24 * 60 * 60 * 1000).length,\n items: attentionWorkItems,\n },\n upcomingAutomations,\n recentAutomationRuns: automationRuns.slice(0, 5).map(toHomeAutomationRun),\n });\n });\n}\n"],"mappings":"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"}
@@ -673,6 +673,22 @@ function registerProjectsRoutes(authenticated, deps) {
673
673
  item: created
674
674
  }, 201);
675
675
  });
676
+ authenticated.get("/api/work-items", (c) => {
677
+ const result = workItems.listWorkItems({
678
+ status: parseCsvEnum(c.req.query("status"), WORK_ITEM_STATUSES),
679
+ priority: parseCsvEnum(c.req.query("priority"), WORK_ITEM_PRIORITIES),
680
+ includeArchived: c.req.query("includeArchived") === "true",
681
+ search: c.req.query("search"),
682
+ sortBy: c.req.query("sortBy"),
683
+ sortOrder: c.req.query("sortOrder"),
684
+ limit: parseLimit(c.req.query("limit")),
685
+ offset: c.req.query("offset") ? Math.max(0, Number.parseInt(c.req.query("offset"), 10) || 0) : void 0
686
+ });
687
+ return c.json({
688
+ ok: true,
689
+ ...result
690
+ });
691
+ });
676
692
  authenticated.get("/api/work-items/:id", async (c) => {
677
693
  const item = workItems.getWorkItem(c.req.param("id"));
678
694
  if (!item) return c.json({