tide-commander 0.52.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 (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +364 -0
  3. package/dist/assets/characters/Textures/colormap.png +0 -0
  4. package/dist/assets/characters/character-female-a.glb +0 -0
  5. package/dist/assets/characters/character-female-b.glb +0 -0
  6. package/dist/assets/characters/character-female-c.glb +0 -0
  7. package/dist/assets/characters/character-female-d.glb +0 -0
  8. package/dist/assets/characters/character-female-e.glb +0 -0
  9. package/dist/assets/characters/character-female-f.glb +0 -0
  10. package/dist/assets/characters/character-male-a-processed.gltf +11862 -0
  11. package/dist/assets/characters/character-male-a.glb +0 -0
  12. package/dist/assets/characters/character-male-b.glb +0 -0
  13. package/dist/assets/characters/character-male-c.glb +0 -0
  14. package/dist/assets/characters/character-male-d.glb +0 -0
  15. package/dist/assets/characters/character-male-e.glb +0 -0
  16. package/dist/assets/characters/character-male-f.glb +0 -0
  17. package/dist/assets/icons/icon-192.png +0 -0
  18. package/dist/assets/icons/icon-512.png +0 -0
  19. package/dist/assets/landing-Cc0MDBAK.css +1 -0
  20. package/dist/assets/main-BIpLsrUu.css +1 -0
  21. package/dist/assets/main-DMTRw3br.js +276 -0
  22. package/dist/assets/textures/concrete_floor_worn_001_diff_1k.jpg +0 -0
  23. package/dist/assets/textures/logo-blanco.png +0 -0
  24. package/dist/assets/vendor-react-uS-d4TUT.js +17 -0
  25. package/dist/assets/vendor-three-4iQNXcoo.js +3828 -0
  26. package/dist/assets/web-BZdi2lG9.js +1 -0
  27. package/dist/assets/web-yHsOO1Qb.js +1 -0
  28. package/dist/index.html +38 -0
  29. package/dist/manifest.json +39 -0
  30. package/dist/src/packages/landing/index.html +463 -0
  31. package/dist/src/packages/server/app.js +87 -0
  32. package/dist/src/packages/server/auth/index.js +121 -0
  33. package/dist/src/packages/server/claude/backend.js +578 -0
  34. package/dist/src/packages/server/claude/index.js +8 -0
  35. package/dist/src/packages/server/claude/runner/internal-events.js +22 -0
  36. package/dist/src/packages/server/claude/runner/process-lifecycle.js +208 -0
  37. package/dist/src/packages/server/claude/runner/recovery-store.js +72 -0
  38. package/dist/src/packages/server/claude/runner/resource-monitor.js +51 -0
  39. package/dist/src/packages/server/claude/runner/restart-policy.js +69 -0
  40. package/dist/src/packages/server/claude/runner/stdout-pipeline.js +153 -0
  41. package/dist/src/packages/server/claude/runner/watchdog.js +114 -0
  42. package/dist/src/packages/server/claude/runner.js +310 -0
  43. package/dist/src/packages/server/claude/session-loader.js +898 -0
  44. package/dist/src/packages/server/claude/types.js +5 -0
  45. package/dist/src/packages/server/cli.js +113 -0
  46. package/dist/src/packages/server/codex/backend.js +119 -0
  47. package/dist/src/packages/server/codex/index.js +2 -0
  48. package/dist/src/packages/server/codex/json-event-parser.js +612 -0
  49. package/dist/src/packages/server/data/builtin-skills/bitbucket-pr.js +298 -0
  50. package/dist/src/packages/server/data/builtin-skills/full-notifications.js +49 -0
  51. package/dist/src/packages/server/data/builtin-skills/git-captain.js +304 -0
  52. package/dist/src/packages/server/data/builtin-skills/index.js +61 -0
  53. package/dist/src/packages/server/data/builtin-skills/pm2-logs.js +354 -0
  54. package/dist/src/packages/server/data/builtin-skills/send-message-to-agent.js +51 -0
  55. package/dist/src/packages/server/data/builtin-skills/server-logs.js +124 -0
  56. package/dist/src/packages/server/data/builtin-skills/streaming-exec.js +94 -0
  57. package/dist/src/packages/server/data/builtin-skills/types.js +4 -0
  58. package/dist/src/packages/server/data/builtin-skills.js +6 -0
  59. package/dist/src/packages/server/data/index.js +890 -0
  60. package/dist/src/packages/server/data/snapshots.js +371 -0
  61. package/dist/src/packages/server/index.js +96 -0
  62. package/dist/src/packages/server/prompts/tide-commander.js +13 -0
  63. package/dist/src/packages/server/routes/agents.js +406 -0
  64. package/dist/src/packages/server/routes/config.js +347 -0
  65. package/dist/src/packages/server/routes/custom-models.js +170 -0
  66. package/dist/src/packages/server/routes/exec.js +269 -0
  67. package/dist/src/packages/server/routes/files.js +995 -0
  68. package/dist/src/packages/server/routes/index.js +38 -0
  69. package/dist/src/packages/server/routes/notifications.js +81 -0
  70. package/dist/src/packages/server/routes/permissions.js +115 -0
  71. package/dist/src/packages/server/routes/snapshots.js +224 -0
  72. package/dist/src/packages/server/routes/stt.js +99 -0
  73. package/dist/src/packages/server/routes/tts.js +166 -0
  74. package/dist/src/packages/server/routes/voice-assistant.js +310 -0
  75. package/dist/src/packages/server/runtime/claude-runtime-provider.js +10 -0
  76. package/dist/src/packages/server/runtime/codex-runtime-provider.js +11 -0
  77. package/dist/src/packages/server/runtime/index.js +2 -0
  78. package/dist/src/packages/server/runtime/types.js +6 -0
  79. package/dist/src/packages/server/services/agent-lifecycle-service.js +82 -0
  80. package/dist/src/packages/server/services/agent-service.js +410 -0
  81. package/dist/src/packages/server/services/boss-message-service.js +430 -0
  82. package/dist/src/packages/server/services/boss-service.js +553 -0
  83. package/dist/src/packages/server/services/building-service.js +867 -0
  84. package/dist/src/packages/server/services/claude-service.js +5 -0
  85. package/dist/src/packages/server/services/custom-class-service.js +323 -0
  86. package/dist/src/packages/server/services/database-service.js +914 -0
  87. package/dist/src/packages/server/services/docker-service.js +865 -0
  88. package/dist/src/packages/server/services/fileTracker.js +242 -0
  89. package/dist/src/packages/server/services/index.js +21 -0
  90. package/dist/src/packages/server/services/permission-service.js +258 -0
  91. package/dist/src/packages/server/services/pm2-service.js +435 -0
  92. package/dist/src/packages/server/services/runtime-command-execution.js +168 -0
  93. package/dist/src/packages/server/services/runtime-events.js +357 -0
  94. package/dist/src/packages/server/services/runtime-service.js +308 -0
  95. package/dist/src/packages/server/services/runtime-status-sync.js +104 -0
  96. package/dist/src/packages/server/services/runtime-subagents.js +50 -0
  97. package/dist/src/packages/server/services/runtime-watchdog.js +74 -0
  98. package/dist/src/packages/server/services/secrets-service.js +206 -0
  99. package/dist/src/packages/server/services/skill-service.js +508 -0
  100. package/dist/src/packages/server/services/subordinate-context-service.js +223 -0
  101. package/dist/src/packages/server/services/supervisor-claude.js +132 -0
  102. package/dist/src/packages/server/services/supervisor-prompts.js +80 -0
  103. package/dist/src/packages/server/services/supervisor-service.js +659 -0
  104. package/dist/src/packages/server/services/work-plan-service.js +476 -0
  105. package/dist/src/packages/server/setup.js +86 -0
  106. package/dist/src/packages/server/utils/index.js +4 -0
  107. package/dist/src/packages/server/utils/logger.js +302 -0
  108. package/dist/src/packages/server/utils/string.js +39 -0
  109. package/dist/src/packages/server/utils/tool-formatting.js +139 -0
  110. package/dist/src/packages/server/utils/unicode.js +46 -0
  111. package/dist/src/packages/server/websocket/handler.js +290 -0
  112. package/dist/src/packages/server/websocket/handlers/agent-handler.js +515 -0
  113. package/dist/src/packages/server/websocket/handlers/boss-handler.js +116 -0
  114. package/dist/src/packages/server/websocket/handlers/boss-response-handler.js +250 -0
  115. package/dist/src/packages/server/websocket/handlers/building-handler.js +298 -0
  116. package/dist/src/packages/server/websocket/handlers/command-handler.js +217 -0
  117. package/dist/src/packages/server/websocket/handlers/custom-class-handler.js +68 -0
  118. package/dist/src/packages/server/websocket/handlers/database-handler.js +223 -0
  119. package/dist/src/packages/server/websocket/handlers/notification-handler.js +25 -0
  120. package/dist/src/packages/server/websocket/handlers/permission-handler.js +21 -0
  121. package/dist/src/packages/server/websocket/handlers/secrets-handler.js +61 -0
  122. package/dist/src/packages/server/websocket/handlers/skill-handler.js +148 -0
  123. package/dist/src/packages/server/websocket/handlers/supervisor-handler.js +44 -0
  124. package/dist/src/packages/server/websocket/handlers/sync-handler.js +19 -0
  125. package/dist/src/packages/server/websocket/handlers/types.js +4 -0
  126. package/dist/src/packages/server/websocket/listeners/boss-listeners.js +21 -0
  127. package/dist/src/packages/server/websocket/listeners/index.js +32 -0
  128. package/dist/src/packages/server/websocket/listeners/permission-listeners.js +19 -0
  129. package/dist/src/packages/server/websocket/listeners/runtime-listeners.js +196 -0
  130. package/dist/src/packages/server/websocket/listeners/skill-listeners.js +51 -0
  131. package/dist/src/packages/server/websocket/listeners/supervisor-listeners.js +37 -0
  132. package/dist/src/packages/shared/agent-types.js +54 -0
  133. package/dist/src/packages/shared/building-types.js +43 -0
  134. package/dist/src/packages/shared/common-types.js +1 -0
  135. package/dist/src/packages/shared/database-types.js +8 -0
  136. package/dist/src/packages/shared/types/snapshot.js +7 -0
  137. package/dist/src/packages/shared/types.js +12 -0
  138. package/dist/src/packages/shared/websocket-messages.js +1 -0
  139. package/dist/sw.js +37 -0
  140. package/package.json +90 -0
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Skill Handler
3
+ * Handles skill CRUD operations and assignment to agents
4
+ */
5
+ import { agentService, skillService } from '../../services/index.js';
6
+ import { createLogger } from '../../utils/index.js';
7
+ const log = createLogger('SkillHandler');
8
+ /**
9
+ * Handle create_skill message
10
+ */
11
+ export function handleCreateSkill(ctx, payload) {
12
+ try {
13
+ const skill = skillService.createSkill(payload);
14
+ ctx.broadcast({
15
+ type: 'skill_created',
16
+ payload: skill,
17
+ });
18
+ log.log(` Created skill: ${skill.name} (${skill.id})`);
19
+ }
20
+ catch (err) {
21
+ log.error(' Failed to create skill:', err);
22
+ ctx.sendError(err.message);
23
+ }
24
+ }
25
+ /**
26
+ * Handle update_skill message
27
+ */
28
+ export function handleUpdateSkill(ctx, payload) {
29
+ try {
30
+ // Check if trying to modify a builtin skill's protected fields
31
+ const existingSkill = skillService.getSkill(payload.id);
32
+ if (existingSkill?.builtin) {
33
+ const allowedKeys = ['assignedAgentIds', 'assignedAgentClasses', 'enabled'];
34
+ const attemptedKeys = Object.keys(payload.updates);
35
+ const disallowedKeys = attemptedKeys.filter(k => !allowedKeys.includes(k));
36
+ if (disallowedKeys.length > 0) {
37
+ ctx.sendError(`Cannot modify built-in skill "${existingSkill.name}". Only assignments and enabled status can be changed.`);
38
+ return;
39
+ }
40
+ }
41
+ const skill = skillService.updateSkill(payload.id, payload.updates);
42
+ if (skill) {
43
+ ctx.broadcast({
44
+ type: 'skill_updated',
45
+ payload: skill,
46
+ });
47
+ log.log(` Updated skill: ${skill.name} (${skill.id})`);
48
+ }
49
+ else {
50
+ ctx.sendError(`Skill not found: ${payload.id}`);
51
+ }
52
+ }
53
+ catch (err) {
54
+ log.error(' Failed to update skill:', err);
55
+ ctx.sendError(err.message);
56
+ }
57
+ }
58
+ /**
59
+ * Handle delete_skill message
60
+ */
61
+ export function handleDeleteSkill(ctx, payload) {
62
+ try {
63
+ // Check if trying to delete a builtin skill
64
+ const existingSkill = skillService.getSkill(payload.id);
65
+ if (existingSkill?.builtin) {
66
+ ctx.sendError(`Cannot delete built-in skill "${existingSkill.name}". Built-in skills are part of Tide Commander.`);
67
+ return;
68
+ }
69
+ const deleted = skillService.deleteSkill(payload.id);
70
+ if (deleted) {
71
+ ctx.broadcast({
72
+ type: 'skill_deleted',
73
+ payload: { id: payload.id },
74
+ });
75
+ log.log(` Deleted skill: ${payload.id}`);
76
+ }
77
+ else {
78
+ ctx.sendError(`Skill not found: ${payload.id}`);
79
+ }
80
+ }
81
+ catch (err) {
82
+ log.error(' Failed to delete skill:', err);
83
+ ctx.sendError(err.message);
84
+ }
85
+ }
86
+ /**
87
+ * Handle assign_skill message
88
+ */
89
+ export function handleAssignSkill(ctx, payload) {
90
+ try {
91
+ const skill = skillService.assignSkillToAgent(payload.skillId, payload.agentId);
92
+ if (skill) {
93
+ ctx.broadcast({
94
+ type: 'skill_updated',
95
+ payload: skill,
96
+ });
97
+ log.log(` Assigned skill ${skill.name} to agent ${payload.agentId}`);
98
+ }
99
+ else {
100
+ ctx.sendError(`Skill not found: ${payload.skillId}`);
101
+ }
102
+ }
103
+ catch (err) {
104
+ log.error(' Failed to assign skill:', err);
105
+ ctx.sendError(err.message);
106
+ }
107
+ }
108
+ /**
109
+ * Handle unassign_skill message
110
+ */
111
+ export function handleUnassignSkill(ctx, payload) {
112
+ try {
113
+ const skill = skillService.unassignSkillFromAgent(payload.skillId, payload.agentId);
114
+ if (skill) {
115
+ ctx.broadcast({
116
+ type: 'skill_updated',
117
+ payload: skill,
118
+ });
119
+ log.log(` Unassigned skill ${skill.name} from agent ${payload.agentId}`);
120
+ }
121
+ else {
122
+ ctx.sendError(`Skill not found: ${payload.skillId}`);
123
+ }
124
+ }
125
+ catch (err) {
126
+ log.error(' Failed to unassign skill:', err);
127
+ ctx.sendError(err.message);
128
+ }
129
+ }
130
+ /**
131
+ * Handle request_agent_skills message
132
+ */
133
+ export function handleRequestAgentSkills(ctx, payload) {
134
+ const agent = agentService.getAgent(payload.agentId);
135
+ if (agent) {
136
+ const skills = skillService.getSkillsForAgent(agent.id, agent.class);
137
+ ctx.sendToClient({
138
+ type: 'agent_skills',
139
+ payload: {
140
+ agentId: payload.agentId,
141
+ skills,
142
+ },
143
+ });
144
+ }
145
+ else {
146
+ ctx.sendError(`Agent not found: ${payload.agentId}`);
147
+ }
148
+ }
@@ -0,0 +1,44 @@
1
+ import { supervisorService } from '../../services/index.js';
2
+ import { createLogger, logger } from '../../utils/index.js';
3
+ const log = logger.ws;
4
+ const supervisorLog = createLogger('Supervisor');
5
+ export function handleSetSupervisorConfig(_ctx, payload) {
6
+ supervisorService.setConfig(payload);
7
+ }
8
+ export async function handleRequestSupervisorReport(ctx, _payload) {
9
+ supervisorLog.log('Report requested by frontend');
10
+ try {
11
+ const report = await supervisorService.generateReport();
12
+ ctx.sendToClient({
13
+ type: 'supervisor_report',
14
+ payload: report,
15
+ });
16
+ }
17
+ catch (err) {
18
+ log.error(' Supervisor report failed:', err);
19
+ ctx.sendError(`Supervisor report failed: ${err.message}`);
20
+ }
21
+ }
22
+ export function handleRequestAgentSupervisorHistory(ctx, payload) {
23
+ const history = supervisorService.getAgentSupervisorHistory(payload.agentId);
24
+ ctx.sendToClient({
25
+ type: 'agent_supervisor_history',
26
+ payload: history,
27
+ });
28
+ }
29
+ export async function handleRequestGlobalUsage(ctx, _payload) {
30
+ const cachedUsage = supervisorService.getGlobalUsage();
31
+ if (cachedUsage) {
32
+ ctx.sendToClient({
33
+ type: 'global_usage',
34
+ payload: cachedUsage,
35
+ });
36
+ }
37
+ const agentId = await supervisorService.requestUsageRefresh();
38
+ if (!agentId && !cachedUsage) {
39
+ ctx.sendToClient({
40
+ type: 'global_usage',
41
+ payload: null,
42
+ });
43
+ }
44
+ }
@@ -0,0 +1,19 @@
1
+ import { saveAreas, saveBuildings } from '../../data/index.js';
2
+ import { buildingService } from '../../services/index.js';
3
+ import { logger } from '../../utils/index.js';
4
+ const log = logger.ws;
5
+ function handleSyncMessage(ctx, payload, entityName, saveFn, updateType) {
6
+ saveFn(payload);
7
+ log.log(` Saved ${payload.length} ${entityName}`);
8
+ ctx.broadcastToOthers({
9
+ type: updateType,
10
+ payload,
11
+ });
12
+ }
13
+ export function handleSyncAreas(ctx, payload) {
14
+ handleSyncMessage(ctx, payload, 'areas', saveAreas, 'areas_update');
15
+ }
16
+ export async function handleSyncBuildings(ctx, payload) {
17
+ await buildingService.handleBuildingSync(payload, ctx.broadcast);
18
+ handleSyncMessage(ctx, payload, 'buildings', saveBuildings, 'buildings_update');
19
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Shared types for WebSocket handlers
3
+ */
4
+ export {};
@@ -0,0 +1,21 @@
1
+ import { bossService } from '../../services/index.js';
2
+ export function setupBossListeners(ctx) {
3
+ bossService.subscribe((event, data) => {
4
+ switch (event) {
5
+ case 'delegation_decision':
6
+ ctx.broadcast({
7
+ type: 'delegation_decision',
8
+ payload: data,
9
+ });
10
+ break;
11
+ case 'subordinates_updated': {
12
+ const { bossId, subordinateIds } = data;
13
+ ctx.broadcast({
14
+ type: 'boss_subordinates_updated',
15
+ payload: { bossId, subordinateIds },
16
+ });
17
+ break;
18
+ }
19
+ }
20
+ });
21
+ }
@@ -0,0 +1,32 @@
1
+ import { agentService } from '../../services/index.js';
2
+ import { setupBossListeners } from './boss-listeners.js';
3
+ import { setupPermissionListeners } from './permission-listeners.js';
4
+ import { setupRuntimeListeners } from './runtime-listeners.js';
5
+ import { setupSkillListeners } from './skill-listeners.js';
6
+ import { setupSupervisorListeners } from './supervisor-listeners.js';
7
+ export function setupServiceListeners(ctx) {
8
+ agentService.subscribe((event, data) => {
9
+ switch (event) {
10
+ case 'created':
11
+ break;
12
+ case 'updated':
13
+ ctx.broadcast({
14
+ type: 'agent_updated',
15
+ payload: data,
16
+ });
17
+ break;
18
+ case 'deleted':
19
+ ctx.broadcast({
20
+ type: 'agent_deleted',
21
+ payload: { id: data },
22
+ });
23
+ ctx.sendActivity(data, 'Agent terminated');
24
+ break;
25
+ }
26
+ });
27
+ setupRuntimeListeners(ctx);
28
+ setupPermissionListeners(ctx);
29
+ setupSupervisorListeners(ctx);
30
+ setupBossListeners(ctx);
31
+ setupSkillListeners(ctx);
32
+ }
@@ -0,0 +1,19 @@
1
+ import { agentService, permissionService } from '../../services/index.js';
2
+ import { logger } from '../../utils/index.js';
3
+ const log = logger.ws;
4
+ export function setupPermissionListeners(ctx) {
5
+ permissionService.subscribe((request) => {
6
+ log.log(` Broadcasting permission_request: ${request.id} for tool ${request.tool}`);
7
+ ctx.broadcast({
8
+ type: 'permission_request',
9
+ payload: request,
10
+ });
11
+ const agent = agentService.getAgent(request.agentId);
12
+ if (agent) {
13
+ agentService.updateAgent(request.agentId, {
14
+ status: 'waiting',
15
+ currentTask: `Waiting for permission: ${request.tool}`,
16
+ });
17
+ }
18
+ });
19
+ }
@@ -0,0 +1,196 @@
1
+ import { parseContextOutput } from '../../claude/backend.js';
2
+ import { agentService, runtimeService } from '../../services/index.js';
3
+ import { logger, formatToolActivity } from '../../utils/index.js';
4
+ import { parseBossDelegation, parseBossSpawn, getBossForSubordinate, clearDelegation } from '../handlers/boss-response-handler.js';
5
+ const log = logger.ws;
6
+ export function setupRuntimeListeners(ctx) {
7
+ runtimeService.on('event', (agentId, event) => {
8
+ if (event.type === 'init') {
9
+ ctx.sendActivity(agentId, `Session initialized (${event.model})`);
10
+ }
11
+ else if (event.type === 'tool_start') {
12
+ const details = formatToolActivity(event.toolName, event.toolInput);
13
+ ctx.sendActivity(agentId, details);
14
+ if (event.toolName === 'Task' && event.toolUseId && event.subagentName) {
15
+ const subagent = runtimeService.getActiveSubagentByToolUseId(event.toolUseId);
16
+ if (subagent) {
17
+ const parentAgent = agentService.getAgent(agentId);
18
+ const parentPos = parentAgent?.position || { x: 0, y: 0, z: 0 };
19
+ const activeSubagents = runtimeService.getActiveSubagentsForAgent(agentId);
20
+ const angle = (activeSubagents.length - 1) * (Math.PI * 2 / Math.max(activeSubagents.length, 3));
21
+ const radius = 3;
22
+ const subagentPayload = {
23
+ id: subagent.id,
24
+ parentAgentId: agentId,
25
+ toolUseId: subagent.toolUseId,
26
+ name: subagent.name,
27
+ description: subagent.description,
28
+ subagentType: subagent.subagentType,
29
+ model: subagent.model,
30
+ status: 'working',
31
+ startedAt: subagent.startedAt,
32
+ position: {
33
+ x: parentPos.x + Math.cos(angle) * radius,
34
+ y: parentPos.y,
35
+ z: parentPos.z + Math.sin(angle) * radius,
36
+ },
37
+ };
38
+ ctx.broadcast({
39
+ type: 'subagent_started',
40
+ payload: subagentPayload,
41
+ });
42
+ ctx.sendActivity(agentId, `Spawned subagent: ${subagent.name} (${subagent.subagentType})`);
43
+ log.log(`[Subagent] Broadcast subagent_started: ${subagent.name} (${subagent.id})`);
44
+ }
45
+ }
46
+ }
47
+ else if (event.type === 'tool_result' && event.toolName === 'Task' && event.toolUseId) {
48
+ let cleanPreview;
49
+ if (event.toolOutput) {
50
+ try {
51
+ const parsed = JSON.parse(event.toolOutput);
52
+ if (Array.isArray(parsed)) {
53
+ cleanPreview = parsed
54
+ .filter((b) => b.type === 'text' && b.text)
55
+ .map((b) => b.text)
56
+ .join(' ')
57
+ .slice(0, 200);
58
+ }
59
+ else {
60
+ cleanPreview = event.toolOutput.slice(0, 200);
61
+ }
62
+ }
63
+ catch {
64
+ cleanPreview = event.toolOutput.slice(0, 200);
65
+ }
66
+ }
67
+ ctx.broadcast({
68
+ type: 'subagent_completed',
69
+ payload: {
70
+ subagentId: event.toolUseId,
71
+ parentAgentId: agentId,
72
+ success: true,
73
+ resultPreview: cleanPreview,
74
+ subagentName: event.subagentName,
75
+ },
76
+ });
77
+ log.log(`[Subagent] Broadcast subagent_completed for toolUseId=${event.toolUseId}, name=${event.subagentName || 'unknown'}`);
78
+ }
79
+ else if (event.type === 'error') {
80
+ ctx.sendActivity(agentId, `Error: ${event.errorMessage}`);
81
+ }
82
+ if (event.type === 'step_complete' && event.resultText) {
83
+ const agent = agentService.getAgent(agentId);
84
+ if (agent?.isBoss || agent?.class === 'boss') {
85
+ parseBossDelegation(agentId, agent.name, event.resultText, ctx.broadcast);
86
+ parseBossSpawn(agentId, agent.name, event.resultText, ctx.broadcast, ctx.sendActivity);
87
+ }
88
+ }
89
+ if (event.type === 'context_stats' && event.contextStatsRaw) {
90
+ log.log(`[context_stats] Received for agent ${agentId}, raw length: ${event.contextStatsRaw.length}`);
91
+ const stats = parseContextOutput(event.contextStatsRaw);
92
+ if (stats) {
93
+ log.log(`[context_stats] Parsed: ${stats.usedPercent}% used, ${stats.totalTokens}/${stats.contextWindow} tokens`);
94
+ agentService.updateAgent(agentId, {
95
+ contextStats: stats,
96
+ contextUsed: stats.totalTokens,
97
+ contextLimit: stats.contextWindow,
98
+ }, false);
99
+ ctx.broadcast({
100
+ type: 'context_stats',
101
+ payload: { agentId, stats },
102
+ });
103
+ }
104
+ else {
105
+ log.log(`[context_stats] Failed to parse context output for agent ${agentId}`);
106
+ }
107
+ }
108
+ ctx.broadcast({
109
+ type: 'event',
110
+ payload: { ...event, agentId },
111
+ });
112
+ });
113
+ runtimeService.on('output', (agentId, text, isStreaming, subagentName, uuid, toolMeta) => {
114
+ const textPreview = text.slice(0, 80).replace(/\n/g, '\\n');
115
+ log.log(`[OUTPUT] agent=${agentId.slice(0, 4)} streaming=${isStreaming} text="${textPreview}" uuid=${uuid || 'none'}`);
116
+ const payload = {
117
+ agentId,
118
+ text,
119
+ isStreaming: isStreaming || false,
120
+ timestamp: Date.now(),
121
+ ...(subagentName ? { subagentName } : {}),
122
+ ...(uuid ? { uuid } : {}),
123
+ };
124
+ if (toolMeta?.toolName) {
125
+ payload.toolName = toolMeta.toolName;
126
+ }
127
+ if (toolMeta?.toolInput) {
128
+ payload.toolInput = toolMeta.toolInput;
129
+ }
130
+ if (text.startsWith('Using tool:') && !payload.toolName) {
131
+ payload.toolName = text.replace('Using tool:', '').trim();
132
+ }
133
+ else if (text.startsWith('Tool input:')) {
134
+ try {
135
+ const jsonStr = text.replace('Tool input:', '').trim();
136
+ payload.toolInput = JSON.parse(jsonStr);
137
+ }
138
+ catch {
139
+ payload.toolInputRaw = text.replace('Tool input:', '').trim();
140
+ }
141
+ }
142
+ else if (text.startsWith('Bash output:')) {
143
+ payload.toolOutput = text.replace('Bash output:', '').trim();
144
+ }
145
+ else if (text.startsWith('Tool result:')) {
146
+ payload.toolOutput = text.replace('Tool result:', '').trim();
147
+ }
148
+ ctx.broadcast({
149
+ type: 'output',
150
+ payload,
151
+ });
152
+ const delegation = getBossForSubordinate(agentId);
153
+ if (delegation) {
154
+ ctx.broadcast({
155
+ type: 'agent_task_output',
156
+ payload: {
157
+ bossId: delegation.bossId,
158
+ subordinateId: agentId,
159
+ output: text.slice(0, 500),
160
+ },
161
+ });
162
+ }
163
+ });
164
+ runtimeService.on('complete', (agentId, success) => {
165
+ ctx.sendActivity(agentId, success ? 'Task completed' : 'Task failed');
166
+ const delegation = getBossForSubordinate(agentId);
167
+ log.log(`[COMPLETE] Agent ${agentId} completed (success=${success}), delegation=${delegation ? `bossId=${delegation.bossId}` : 'none'}`);
168
+ if (delegation) {
169
+ log.log(`[COMPLETE] Broadcasting agent_task_completed for subordinate ${agentId} to boss ${delegation.bossId}`);
170
+ ctx.broadcast({
171
+ type: 'agent_task_completed',
172
+ payload: {
173
+ bossId: delegation.bossId,
174
+ subordinateId: agentId,
175
+ success,
176
+ },
177
+ });
178
+ clearDelegation(agentId);
179
+ }
180
+ });
181
+ runtimeService.on('error', (agentId, error) => {
182
+ ctx.sendActivity(agentId, `Error: ${error}`);
183
+ });
184
+ runtimeService.setCommandStartedCallback((agentId, command) => {
185
+ ctx.broadcast({
186
+ type: 'command_started',
187
+ payload: { agentId, command },
188
+ });
189
+ });
190
+ runtimeService.setSessionUpdateCallback((agentId) => {
191
+ ctx.broadcast({
192
+ type: 'session_updated',
193
+ payload: { agentId },
194
+ });
195
+ });
196
+ }
@@ -0,0 +1,51 @@
1
+ import { agentLifecycleService, customClassService, skillService } from '../../services/index.js';
2
+ export function setupSkillListeners(ctx) {
3
+ skillService.subscribe((event, data) => {
4
+ switch (event) {
5
+ case 'created':
6
+ ctx.broadcast({
7
+ type: 'skill_created',
8
+ payload: data,
9
+ });
10
+ break;
11
+ case 'updated':
12
+ ctx.broadcast({
13
+ type: 'skill_updated',
14
+ payload: data,
15
+ });
16
+ agentLifecycleService.restartAgentsWithSkill(data, ctx.sendActivity);
17
+ break;
18
+ case 'deleted':
19
+ ctx.broadcast({
20
+ type: 'skill_deleted',
21
+ payload: { id: data },
22
+ });
23
+ break;
24
+ case 'assigned':
25
+ ctx.broadcast({
26
+ type: 'skill_updated',
27
+ payload: data,
28
+ });
29
+ break;
30
+ }
31
+ });
32
+ customClassService.customClassEvents.on('created', (customClass) => {
33
+ ctx.broadcast({
34
+ type: 'custom_agent_class_created',
35
+ payload: customClass,
36
+ });
37
+ });
38
+ customClassService.customClassEvents.on('updated', (customClass) => {
39
+ ctx.broadcast({
40
+ type: 'custom_agent_class_updated',
41
+ payload: customClass,
42
+ });
43
+ agentLifecycleService.restartAgentsWithClass(customClass.id, ctx.sendActivity);
44
+ });
45
+ customClassService.customClassEvents.on('deleted', (id) => {
46
+ ctx.broadcast({
47
+ type: 'custom_agent_class_deleted',
48
+ payload: { id },
49
+ });
50
+ });
51
+ }
@@ -0,0 +1,37 @@
1
+ import { supervisorService } from '../../services/index.js';
2
+ export function setupSupervisorListeners(ctx) {
3
+ supervisorService.subscribe((event, data) => {
4
+ switch (event) {
5
+ case 'report':
6
+ ctx.broadcast({
7
+ type: 'supervisor_report',
8
+ payload: data,
9
+ });
10
+ break;
11
+ case 'agent_analysis':
12
+ ctx.broadcast({
13
+ type: 'agent_analysis',
14
+ payload: data,
15
+ });
16
+ break;
17
+ case 'narrative':
18
+ ctx.broadcast({
19
+ type: 'narrative_update',
20
+ payload: data,
21
+ });
22
+ break;
23
+ case 'config_changed':
24
+ ctx.broadcast({
25
+ type: 'supervisor_status',
26
+ payload: supervisorService.getStatus(),
27
+ });
28
+ break;
29
+ case 'global_usage':
30
+ ctx.broadcast({
31
+ type: 'global_usage',
32
+ payload: data,
33
+ });
34
+ break;
35
+ }
36
+ });
37
+ }
@@ -0,0 +1,54 @@
1
+ // ============================================================================
2
+ // Agent Classes - built-in types
3
+ // ============================================================================
4
+ export const BUILT_IN_AGENT_CLASSES = {
5
+ scout: { icon: '🔍', color: '#4a9eff', description: 'Codebase exploration, file discovery' },
6
+ builder: { icon: '🔨', color: '#ff9e4a', description: 'Feature implementation, writing code' },
7
+ debugger: { icon: '🐛', color: '#ff4a4a', description: 'Bug hunting, fixing issues' },
8
+ architect: { icon: '📐', color: '#9e4aff', description: 'Planning, design decisions' },
9
+ warrior: { icon: '⚔️', color: '#ff4a9e', description: 'Aggressive refactoring, migrations' },
10
+ support: { icon: '💚', color: '#4aff9e', description: 'Documentation, tests, cleanup' },
11
+ boss: { icon: '👑', color: '#ffd700', description: 'Team leader, delegates tasks to subordinates' },
12
+ };
13
+ // For backwards compatibility
14
+ export const AGENT_CLASSES = BUILT_IN_AGENT_CLASSES;
15
+ export const PERMISSION_MODES = {
16
+ bypass: { label: 'Permissionless', description: 'Skip all permission prompts (less safe, faster)' },
17
+ interactive: { label: 'Interactive', description: 'Ask for approval before sensitive operations' },
18
+ };
19
+ export const CODEX_MODELS = {
20
+ 'gpt-5.3-codex': {
21
+ label: 'GPT-5.3 Codex',
22
+ description: 'Latest frontier agentic coding model',
23
+ icon: '⚙️',
24
+ },
25
+ 'gpt-5.2-codex': {
26
+ label: 'GPT-5.2 Codex',
27
+ description: 'Frontier agentic coding model',
28
+ icon: '🧠',
29
+ },
30
+ 'gpt-5.1-codex-max': {
31
+ label: 'GPT-5.1 Codex Max',
32
+ description: 'Codex-optimized flagship for deep and fast reasoning',
33
+ icon: '🚀',
34
+ },
35
+ 'gpt-5.1-codex-mini': {
36
+ label: 'GPT-5.1 Codex Mini',
37
+ description: 'Optimized for codex, cheaper and faster',
38
+ icon: '⚡',
39
+ },
40
+ 'gpt-5.2': {
41
+ label: 'GPT-5.2',
42
+ description: 'General frontier model with strong reasoning and coding',
43
+ icon: '🧩',
44
+ },
45
+ };
46
+ export const CLAUDE_MODELS = {
47
+ sonnet: { label: 'Sonnet', description: 'Balanced performance and cost (recommended)', icon: '⚡' },
48
+ opus: { label: 'Opus', description: 'Most capable, higher cost', icon: '🧠' },
49
+ haiku: { label: 'Haiku', description: 'Fast and economical', icon: '🚀' },
50
+ };
51
+ // Boss context delimiters - used to inject subordinate context at the beginning of user messages
52
+ // The frontend detects these to collapse/hide the context section in the UI
53
+ export const BOSS_CONTEXT_START = '<<<BOSS_CONTEXT_START>>>';
54
+ export const BOSS_CONTEXT_END = '<<<BOSS_CONTEXT_END>>>';