openbot 0.4.7 → 0.5.4

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 (130) hide show
  1. package/.claude/agents/runtime-security-reviewer.md +32 -0
  2. package/.claude/hooks/format.sh +18 -0
  3. package/.claude/hooks/protect-secrets.sh +23 -0
  4. package/.claude/settings.json +26 -0
  5. package/.claude/skills/deploy/SKILL.md +26 -0
  6. package/.claude/skills/new-plugin/SKILL.md +46 -0
  7. package/.dockerignore +9 -0
  8. package/.mcp.json +8 -0
  9. package/AGENTS.md +2 -2
  10. package/CLAUDE.md +50 -0
  11. package/Dockerfile +41 -0
  12. package/deploy/README.md +61 -0
  13. package/deploy/entrypoint.sh +6 -0
  14. package/deploy/fly.toml +36 -0
  15. package/dist/app/bootstrap.js +29 -0
  16. package/dist/app/cli.js +3 -1
  17. package/dist/app/cloud-mode.js +26 -0
  18. package/dist/app/config.js +61 -16
  19. package/dist/app/server.js +38 -6
  20. package/dist/plugins/approval/index.js +1 -1
  21. package/dist/plugins/bash/index.js +386 -164
  22. package/dist/plugins/memory/service.js +2 -5
  23. package/dist/plugins/openbot/context.js +17 -1
  24. package/dist/plugins/openbot/index.js +23 -8
  25. package/dist/plugins/openbot/model.js +59 -0
  26. package/dist/plugins/openbot/runtime.js +39 -56
  27. package/dist/plugins/openbot/system-prompt.js +43 -8
  28. package/dist/plugins/preview/index.js +267 -0
  29. package/dist/plugins/storage/index.js +3 -3
  30. package/dist/plugins/storage/service.js +58 -12
  31. package/dist/plugins/todo/index.js +131 -38
  32. package/dist/plugins/todo/service.js +93 -0
  33. package/dist/plugins/ui/index.js +8 -1
  34. package/dist/services/plugins/model-registry.js +101 -0
  35. package/dist/services/plugins/registry.js +6 -4
  36. package/dist/services/plugins/service.js +2 -6
  37. package/docs/agents.md +20 -2
  38. package/docs/architecture.md +1 -1
  39. package/docs/plugins.md +13 -3
  40. package/docs/templates/AGENT.example.md +1 -1
  41. package/package.json +5 -2
  42. package/pnpm-workspace.yaml +2 -0
  43. package/src/app/bootstrap.ts +43 -0
  44. package/src/app/cli.ts +3 -1
  45. package/src/app/cloud-mode.ts +41 -0
  46. package/src/app/config.ts +71 -19
  47. package/src/app/server.ts +45 -6
  48. package/src/app/types.ts +162 -31
  49. package/src/plugins/approval/index.ts +1 -1
  50. package/src/plugins/bash/index.ts +498 -185
  51. package/src/plugins/memory/service.ts +2 -5
  52. package/src/plugins/openbot/context.ts +17 -1
  53. package/src/plugins/openbot/index.ts +25 -10
  54. package/src/plugins/openbot/model.ts +76 -0
  55. package/src/plugins/openbot/runtime.ts +47 -69
  56. package/src/plugins/openbot/system-prompt.ts +43 -8
  57. package/src/plugins/preview/index.ts +323 -0
  58. package/src/plugins/storage/index.ts +5 -8
  59. package/src/plugins/storage/service.ts +79 -15
  60. package/src/plugins/todo/index.ts +166 -0
  61. package/src/plugins/todo/service.ts +123 -0
  62. package/src/plugins/ui/index.ts +8 -1
  63. package/src/services/plugins/domain.ts +2 -0
  64. package/src/services/plugins/model-registry.ts +146 -0
  65. package/src/services/plugins/registry.ts +6 -4
  66. package/src/services/plugins/service.ts +2 -6
  67. package/dist/agents/openbot/index.js +0 -76
  68. package/dist/agents/openbot/middleware/approval.js +0 -132
  69. package/dist/agents/openbot/runtime.js +0 -289
  70. package/dist/agents/openbot/system-prompt.js +0 -32
  71. package/dist/agents/openbot/tools/delegation.js +0 -78
  72. package/dist/agents/openbot/tools/mcp.js +0 -99
  73. package/dist/agents/openbot/tools/shell.js +0 -91
  74. package/dist/agents/openbot/tools/storage.js +0 -75
  75. package/dist/agents/openbot/tools/ui.js +0 -176
  76. package/dist/agents/system.js +0 -33
  77. package/dist/bus/agent-package.js +0 -1
  78. package/dist/bus/plugin.js +0 -1
  79. package/dist/bus/services.js +0 -754
  80. package/dist/bus/types.js +0 -1
  81. package/dist/harness/agent-harness.js +0 -45
  82. package/dist/harness/agent-invoke-run.js +0 -44
  83. package/dist/harness/agent-turn.js +0 -99
  84. package/dist/harness/channel-participants.js +0 -40
  85. package/dist/harness/constants.js +0 -2
  86. package/dist/harness/context-meter.js +0 -97
  87. package/dist/harness/context.js +0 -363
  88. package/dist/harness/dispatch.js +0 -144
  89. package/dist/harness/dispatcher.js +0 -156
  90. package/dist/harness/event-normalizer.js +0 -59
  91. package/dist/harness/history.js +0 -177
  92. package/dist/harness/mcp.js +0 -61
  93. package/dist/harness/orchestration.js +0 -88
  94. package/dist/harness/orchestrator.js +0 -149
  95. package/dist/harness/participants.js +0 -22
  96. package/dist/harness/process.js +0 -29
  97. package/dist/harness/queue-processor.js +0 -187
  98. package/dist/harness/run-harness.js +0 -154
  99. package/dist/harness/run.js +0 -98
  100. package/dist/harness/runtime-factory.js +0 -73
  101. package/dist/harness/runtime.js +0 -57
  102. package/dist/harness/todo-advance.js +0 -93
  103. package/dist/harness/todo-dispatch.js +0 -51
  104. package/dist/harness/todos.js +0 -5
  105. package/dist/harness/turn.js +0 -79
  106. package/dist/harness/types.js +0 -1
  107. package/dist/plugins/ai-sdk/index.js +0 -34
  108. package/dist/plugins/ai-sdk/runtime.js +0 -395
  109. package/dist/plugins/ai-sdk/system-prompt.js +0 -18
  110. package/dist/plugins/ai-sdk.js +0 -331
  111. package/dist/plugins/approval.js +0 -163
  112. package/dist/plugins/delegation.js +0 -108
  113. package/dist/plugins/mcp/index.js +0 -108
  114. package/dist/plugins/mcp.js +0 -140
  115. package/dist/plugins/shell/index.js +0 -100
  116. package/dist/plugins/shell.js +0 -123
  117. package/dist/plugins/storage-tools/index.js +0 -76
  118. package/dist/plugins/storage.js +0 -737
  119. package/dist/plugins/thread-namer/index.js +0 -72
  120. package/dist/plugins/threads/index.js +0 -114
  121. package/dist/plugins/ui.js +0 -211
  122. package/dist/plugins/workflow/index.js +0 -65
  123. package/dist/registry/agents.js +0 -138
  124. package/dist/registry/plugins.js +0 -110
  125. package/dist/services/agent-packages.js +0 -103
  126. package/dist/services/memory.js +0 -152
  127. package/dist/services/plugins.js +0 -98
  128. package/dist/services/storage.js +0 -1028
  129. package/dist/workflow/service.js +0 -106
  130. package/dist/workflow/types.js +0 -3
package/src/app/server.ts CHANGED
@@ -8,7 +8,8 @@ import { createRequire } from 'module';
8
8
  const require = createRequire(import.meta.url);
9
9
  const pkg = require('../../package.json');
10
10
  import { generateId } from 'melony';
11
- import { DEFAULT_BASE_DIR, loadConfig, resolvePath } from '../app/config.js';
11
+ import { getBaseDir, loadConfig } from '../app/config.js';
12
+ import { isCloudMode, getCloudIntegrationsConfig } from './cloud-mode.js';
12
13
  import { ActiveRunsSnapshotEvent, OpenBotEvent, OpenBotState } from './types.js';
13
14
  import { processService } from '../services/process.js';
14
15
  import { runAgent, STATE_AGENT_ID, ORCHESTRATOR_AGENT_ID } from '../harness/index.js';
@@ -46,8 +47,14 @@ export async function startServer(options: ServerOptions = {}) {
46
47
  const config = loadConfig();
47
48
  processService.syncWorkspaceVariablesToProcessEnv();
48
49
 
49
- const baseDir = config.baseDir || DEFAULT_BASE_DIR;
50
- const openBotDir = resolvePath(baseDir);
50
+ if (isCloudMode()) {
51
+ const integrations = getCloudIntegrationsConfig();
52
+ console.log(
53
+ `[server] Cloud mode enabled${integrations ? '' : ' (integrations proxy env not set)'}`,
54
+ );
55
+ }
56
+
57
+ const openBotDir = getBaseDir();
51
58
  const PORT = Number(options.port ?? config.port ?? process.env.PORT ?? 4132);
52
59
  const app = express();
53
60
  const clients: Map<string, express.Response[]> = new Map();
@@ -247,6 +254,23 @@ export async function startServer(options: ServerOptions = {}) {
247
254
 
248
255
  app.use(cors());
249
256
 
257
+ const gatewayToken = process.env.OPENBOT_GATEWAY_TOKEN?.trim();
258
+ if (gatewayToken) {
259
+ app.use((req, res, next) => {
260
+ if (req.path === '/api/health' || req.method === 'OPTIONS') {
261
+ next();
262
+ return;
263
+ }
264
+
265
+ const got = req.get('x-openbot-gateway-token');
266
+ if (got !== gatewayToken) {
267
+ res.status(401).json({ error: 'unauthorized' });
268
+ return;
269
+ }
270
+ next();
271
+ });
272
+ }
273
+
250
274
  const resolvePublicBaseUrl = () => getPublicBaseUrl(PORT, config.publicUrl);
251
275
 
252
276
  app.use((req, res, next) => {
@@ -264,7 +288,7 @@ export async function startServer(options: ServerOptions = {}) {
264
288
  });
265
289
 
266
290
  app.get('/api/health', (req, res) => {
267
- res.json({ status: 'ok', version: pkg.version });
291
+ res.json({ status: 'ok', version: pkg.version, apiVersion: 1 });
268
292
  });
269
293
 
270
294
  app.get('/api/events', (req, res) => {
@@ -683,10 +707,25 @@ export async function startServer(options: ServerOptions = {}) {
683
707
  }
684
708
  });
685
709
 
686
- app.listen(PORT, () => {
687
- console.log(`\x1b[32mOpenBot server listening at http://localhost:${PORT}\x1b[0m`);
710
+ const HOST = process.env.HOST || '0.0.0.0';
711
+ const server = app.listen(PORT, HOST, () => {
712
+ console.log(`\x1b[32mOpenBot server listening at http://${HOST}:${PORT}\x1b[0m`);
688
713
  console.log(
689
714
  `🌐 Visit \x1b[96m\x1b[1mhttps://openbot.one\x1b[0m to connect to this runtime and manage everything from there. ✨`,
690
715
  );
691
716
  });
717
+
718
+ const shutdown = (signal: string) => {
719
+ console.log(`\n[server] Received ${signal}, shutting down...`);
720
+ server.close(() => {
721
+ process.exit(0);
722
+ });
723
+ setTimeout(() => {
724
+ console.error('[server] Forced shutdown after timeout');
725
+ process.exit(1);
726
+ }, 10_000).unref();
727
+ };
728
+
729
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
730
+ process.on('SIGINT', () => shutdown('SIGINT'));
692
731
  }
package/src/app/types.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  } from '../services/plugins/domain.js';
10
10
  import type { PluginRef } from '../services/plugins/types.js';
11
11
  import type { MemoryRecord } from '../plugins/memory/service.js';
12
+ import type { TodoList } from '../plugins/todo/service.js';
12
13
 
13
14
  export interface OpenBotState {
14
15
  agentId: string;
@@ -657,11 +658,21 @@ export type UIWidgetField = {
657
658
  defaultValue?: unknown;
658
659
  };
659
660
 
661
+ export type UIWidgetListItemStatusVariant =
662
+ | 'default'
663
+ | 'success'
664
+ | 'warning'
665
+ | 'danger'
666
+ | 'info';
667
+
660
668
  export type UIWidgetListItem = {
661
669
  id: string;
662
670
  label: string;
663
671
  description?: string;
664
- status?: 'pending' | 'in_progress' | 'done' | 'error' | 'cancelled';
672
+ /** Optional status label shown on the item (e.g. "Pending", "Shipped") */
673
+ status?: string;
674
+ /** Optional semantic hint for status coloring in the client */
675
+ statusVariant?: UIWidgetListItemStatusVariant;
665
676
  metadata?: Record<string, unknown>;
666
677
  };
667
678
 
@@ -737,11 +748,12 @@ export type UIWidgetResponseEvent = BaseEvent & {
737
748
  };
738
749
  };
739
750
 
740
- export type BashEvent = BaseEvent & {
741
- type: 'action:bash';
751
+ export type ShellExecEvent = BaseEvent & {
752
+ type: 'action:shell_exec';
742
753
  data: {
754
+ id: string;
755
+ exec_dir: string;
743
756
  command: string;
744
- restart?: boolean;
745
757
  };
746
758
  meta?: {
747
759
  toolCallId?: string;
@@ -751,47 +763,116 @@ export type BashEvent = BaseEvent & {
751
763
  };
752
764
  };
753
765
 
754
- export type BashResultEvent = BaseEvent & {
755
- type: 'action:bash:result';
766
+ export type ShellExecResultEvent = BaseEvent & {
767
+ type: 'action:shell_exec:result';
756
768
  data: {
757
769
  success: boolean;
758
770
  approved?: boolean;
759
- exitCode: number | null;
760
- stdout: string;
761
- stderr: string;
762
- timedOut: boolean;
771
+ exitCode?: number;
763
772
  error?: string;
773
+ output?: string;
764
774
  };
765
775
  };
766
776
 
767
- export type BashStopEvent = BaseEvent & {
768
- type: 'action:bash_stop';
777
+ export type ShellViewEvent = BaseEvent & {
778
+ type: 'action:shell_view';
769
779
  data: {
770
- channelId?: string;
780
+ id: string;
771
781
  };
772
782
  };
773
783
 
774
- export type BashStopResultEvent = BaseEvent & {
775
- type: 'action:bash_stop:result';
784
+ export type ShellViewResultEvent = BaseEvent & {
785
+ type: 'action:shell_view:result';
776
786
  data: {
777
787
  success: boolean;
788
+ output?: string;
778
789
  };
779
790
  };
780
791
 
781
- export type BashListSessionsEvent = BaseEvent & {
782
- type: 'action:bash_list_sessions';
783
- data: {};
792
+ export type ShellWaitEvent = BaseEvent & {
793
+ type: 'action:shell_wait';
794
+ data: {
795
+ id: string;
796
+ seconds: number;
797
+ };
784
798
  };
785
799
 
786
- export type BashListSessionsResultEvent = BaseEvent & {
787
- type: 'action:bash_list_sessions:result';
800
+ export type ShellWaitResultEvent = BaseEvent & {
801
+ type: 'action:shell_wait:result';
788
802
  data: {
789
803
  success: boolean;
790
- sessions: Array<{
791
- channelId: string;
792
- cwd: string;
793
- lastActivity: number;
794
- }>;
804
+ waitedSeconds?: number;
805
+ output?: string;
806
+ };
807
+ };
808
+
809
+ export type ShellWriteToProcessEvent = BaseEvent & {
810
+ type: 'action:shell_write_to_process';
811
+ data: {
812
+ id: string;
813
+ input: string;
814
+ press_enter: boolean;
815
+ };
816
+ };
817
+
818
+ export type ShellWriteToProcessResultEvent = BaseEvent & {
819
+ type: 'action:shell_write_to_process:result';
820
+ data: {
821
+ success: boolean;
822
+ output?: string;
823
+ };
824
+ };
825
+
826
+ export type ShellKillProcessEvent = BaseEvent & {
827
+ type: 'action:shell_kill_process';
828
+ data: {
829
+ id: string;
830
+ };
831
+ };
832
+
833
+ export type ShellKillProcessResultEvent = BaseEvent & {
834
+ type: 'action:shell_kill_process:result';
835
+ data: {
836
+ success: boolean;
837
+ output?: string;
838
+ };
839
+ };
840
+
841
+ export type ExposePortEvent = BaseEvent & {
842
+ type: 'action:expose_port';
843
+ data: {
844
+ port: number;
845
+ };
846
+ meta?: {
847
+ toolCallId?: string;
848
+ approvalId?: string;
849
+ approvalStatus?: 'approved' | 'denied';
850
+ [key: string]: unknown;
851
+ };
852
+ };
853
+
854
+ export type ExposePortResultEvent = BaseEvent & {
855
+ type: 'action:expose_port:result';
856
+ data: {
857
+ success: boolean;
858
+ previewUrl?: string;
859
+ port?: number;
860
+ temporary?: boolean;
861
+ error?: string;
862
+ output?: string;
863
+ };
864
+ };
865
+
866
+ export type UnexposePortEvent = BaseEvent & {
867
+ type: 'action:unexpose_port';
868
+ data?: Record<string, never>;
869
+ };
870
+
871
+ export type UnexposePortResultEvent = BaseEvent & {
872
+ type: 'action:unexpose_port:result';
873
+ data: {
874
+ success: boolean;
875
+ output?: string;
795
876
  };
796
877
  };
797
878
 
@@ -968,6 +1049,44 @@ export type ForgetResultEvent = BaseEvent & {
968
1049
  };
969
1050
  };
970
1051
 
1052
+ export type TodoWriteEvent = BaseEvent & {
1053
+ type: 'action:todo_write';
1054
+ data: {
1055
+ items: Array<{
1056
+ id: string;
1057
+ content: string;
1058
+ status: 'pending' | 'in_progress' | 'completed' | 'cancelled';
1059
+ }>;
1060
+ };
1061
+ };
1062
+
1063
+ export type TodoWriteResultEvent = BaseEvent & {
1064
+ type: 'action:todo_write:result';
1065
+ data: {
1066
+ success: boolean;
1067
+ list?: TodoList;
1068
+ /** Text fed back to the model via history (`data.output`). */
1069
+ output: string;
1070
+ error?: string;
1071
+ };
1072
+ };
1073
+
1074
+ export type TodoReadEvent = BaseEvent & {
1075
+ type: 'action:todo_read';
1076
+ data: Record<string, never>;
1077
+ };
1078
+
1079
+ export type TodoReadResultEvent = BaseEvent & {
1080
+ type: 'action:todo_read:result';
1081
+ data: {
1082
+ success: boolean;
1083
+ list?: TodoList;
1084
+ /** Text fed back to the model via history (`data.output`). */
1085
+ output: string;
1086
+ error?: string;
1087
+ };
1088
+ };
1089
+
971
1090
  export type DelegateTaskEvent = BaseEvent & {
972
1091
  type: 'action:delegate_task';
973
1092
  data: {
@@ -1101,12 +1220,20 @@ export type OpenBotEvent =
1101
1220
  | DeleteChannelToolResultEvent
1102
1221
  | UIWidgetEvent
1103
1222
  | UIWidgetResponseEvent
1104
- | BashEvent
1105
- | BashResultEvent
1106
- | BashStopEvent
1107
- | BashStopResultEvent
1108
- | BashListSessionsEvent
1109
- | BashListSessionsResultEvent
1223
+ | ShellExecEvent
1224
+ | ShellExecResultEvent
1225
+ | ShellViewEvent
1226
+ | ShellViewResultEvent
1227
+ | ShellWaitEvent
1228
+ | ShellWaitResultEvent
1229
+ | ShellWriteToProcessEvent
1230
+ | ShellWriteToProcessResultEvent
1231
+ | ShellKillProcessEvent
1232
+ | ShellKillProcessResultEvent
1233
+ | ExposePortEvent
1234
+ | ExposePortResultEvent
1235
+ | UnexposePortEvent
1236
+ | UnexposePortResultEvent
1110
1237
  | InstallPluginEvent
1111
1238
  | InstallPluginResultEvent
1112
1239
  | UninstallPluginEvent
@@ -1123,6 +1250,10 @@ export type OpenBotEvent =
1123
1250
  | RecallResultEvent
1124
1251
  | ForgetEvent
1125
1252
  | ForgetResultEvent
1253
+ | TodoWriteEvent
1254
+ | TodoWriteResultEvent
1255
+ | TodoReadEvent
1256
+ | TodoReadResultEvent
1126
1257
  | DelegateTaskEvent
1127
1258
  | DelegateTaskResultEvent
1128
1259
  | RenderWidgetEvent
@@ -19,7 +19,7 @@ export const approvalPlugin: Plugin = {
19
19
  description: 'Gate protected tool calls behind a UI confirmation widget.',
20
20
  factory: ({ config, storage }) => (builder) => {
21
21
  // Actions that require approval. Defaults to bash.
22
- const actionsToApprove = (config.actions as string[]) || ['action:bash'];
22
+ const actionsToApprove = (config.actions as string[]) || ['action:shell_exec'];
23
23
 
24
24
  for (const action of actionsToApprove) {
25
25
  builder.intercept(action as OpenBotEvent['type'], (event, context) => {