@pixelbyte-software/pixcode 1.47.4 → 1.48.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 (113) hide show
  1. package/README.md +16 -30
  2. package/README.tr.md +1 -1
  3. package/dist/api-automation.html +1 -1
  4. package/dist/assets/index-DlAWSDTA.js +818 -0
  5. package/dist/assets/index-g9NMlzYt.css +32 -0
  6. package/dist/assets/{vendor-codemirror-CzSp4P1a.js → vendor-codemirror-CIYNS698.js} +8 -8
  7. package/dist/docs.html +10 -10
  8. package/dist/features.html +3 -3
  9. package/dist/index.html +3 -3
  10. package/dist/landing.html +21 -23
  11. package/dist/llms-full.txt +4 -8
  12. package/dist/llms.txt +5 -6
  13. package/dist/openapi.yaml +7 -7
  14. package/dist-server/server/index.js +4 -6
  15. package/dist-server/server/index.js.map +1 -1
  16. package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js +1 -1
  17. package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js.map +1 -1
  18. package/dist-server/server/modules/orchestration/a2a/adapters/codex.adapter.js +1 -1
  19. package/dist-server/server/modules/orchestration/a2a/adapters/codex.adapter.js.map +1 -1
  20. package/dist-server/server/modules/orchestration/a2a/adapters/cursor.adapter.js +1 -1
  21. package/dist-server/server/modules/orchestration/a2a/adapters/cursor.adapter.js.map +1 -1
  22. package/dist-server/server/modules/orchestration/a2a/adapters/gemini.adapter.js +1 -1
  23. package/dist-server/server/modules/orchestration/a2a/adapters/gemini.adapter.js.map +1 -1
  24. package/dist-server/server/modules/orchestration/a2a/adapters/opencode.adapter.js +1 -1
  25. package/dist-server/server/modules/orchestration/a2a/adapters/opencode.adapter.js.map +1 -1
  26. package/dist-server/server/modules/orchestration/a2a/adapters/qwen.adapter.js +1 -1
  27. package/dist-server/server/modules/orchestration/a2a/adapters/qwen.adapter.js.map +1 -1
  28. package/dist-server/server/modules/orchestration/a2a/agent-card.js +4 -4
  29. package/dist-server/server/modules/orchestration/a2a/agent-card.js.map +1 -1
  30. package/dist-server/server/modules/orchestration/a2a/routes.js +6 -2
  31. package/dist-server/server/modules/orchestration/a2a/routes.js.map +1 -1
  32. package/dist-server/server/modules/orchestration/hermes/hermes.routes.js +62 -0
  33. package/dist-server/server/modules/orchestration/hermes/hermes.routes.js.map +1 -0
  34. package/dist-server/server/modules/orchestration/index.js +2 -1
  35. package/dist-server/server/modules/orchestration/index.js.map +1 -1
  36. package/dist-server/server/modules/orchestration/tasks/orchestration-task-store.js +2 -5
  37. package/dist-server/server/modules/orchestration/tasks/orchestration-task-store.js.map +1 -1
  38. package/dist-server/server/modules/orchestration/tasks/orchestration-task.routes.js +1 -20
  39. package/dist-server/server/modules/orchestration/tasks/orchestration-task.routes.js.map +1 -1
  40. package/dist-server/server/modules/orchestration/tasks/orchestration-task.service.js +4 -37
  41. package/dist-server/server/modules/orchestration/tasks/orchestration-task.service.js.map +1 -1
  42. package/dist-server/server/modules/orchestration/tasks/task-run-graph.js +4 -62
  43. package/dist-server/server/modules/orchestration/tasks/task-run-graph.js.map +1 -1
  44. package/dist-server/server/modules/orchestration/workflows/workflow-runner.js +14 -14
  45. package/dist-server/server/modules/orchestration/workflows/workflow-runner.js.map +1 -1
  46. package/dist-server/server/modules/orchestration/workflows/workflow-trace.js +2 -2
  47. package/dist-server/server/modules/orchestration/workflows/workflow-trace.js.map +1 -1
  48. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +9 -1
  49. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -1
  50. package/dist-server/server/projects.js +0 -160
  51. package/dist-server/server/projects.js.map +1 -1
  52. package/dist-server/server/routes/mcp-utils.js +0 -18
  53. package/dist-server/server/routes/mcp-utils.js.map +1 -1
  54. package/dist-server/server/services/public-api-manifest.js +0 -5
  55. package/dist-server/server/services/public-api-manifest.js.map +1 -1
  56. package/dist-server/server/services/telegram/control-center.js +2 -144
  57. package/dist-server/server/services/telegram/control-center.js.map +1 -1
  58. package/dist-server/server/services/telegram/translations.js +2 -14
  59. package/dist-server/server/services/telegram/translations.js.map +1 -1
  60. package/package.json +1 -2
  61. package/scripts/smoke/default-landing-routing.mjs +7 -16
  62. package/scripts/smoke/{a2a-roundtrip.mjs → hermes-roundtrip.mjs} +23 -23
  63. package/scripts/smoke/mac-desktop-runtime.mjs +1 -7
  64. package/scripts/smoke/orchestration-live-run.mjs +1 -1
  65. package/scripts/smoke/orchestration-model-sync.mjs +2 -2
  66. package/scripts/smoke/orchestration-user-facing-output.mjs +2 -2
  67. package/scripts/smoke/pixcode-workbench-1-48.mjs +55 -0
  68. package/scripts/smoke/provider-selection-status.mjs +52 -0
  69. package/scripts/smoke/taskmaster-config.mjs +21 -56
  70. package/scripts/smoke/taskmaster-execution-telegram.mjs +1 -50
  71. package/scripts/smoke/taskmaster-onboarding.mjs +1 -50
  72. package/scripts/smoke/taskmaster-run-graph.mjs +1 -53
  73. package/scripts/smoke/vscode-workbench-layout.mjs +25 -62
  74. package/scripts/smoke/vscode-workbench-polish.mjs +19 -5
  75. package/server/index.js +5 -7
  76. package/server/modules/orchestration/a2a/adapters/claude-code.adapter.ts +1 -1
  77. package/server/modules/orchestration/a2a/adapters/codex.adapter.ts +1 -1
  78. package/server/modules/orchestration/a2a/adapters/cursor.adapter.ts +1 -1
  79. package/server/modules/orchestration/a2a/adapters/gemini.adapter.ts +1 -1
  80. package/server/modules/orchestration/a2a/adapters/opencode.adapter.ts +1 -1
  81. package/server/modules/orchestration/a2a/adapters/qwen.adapter.ts +1 -1
  82. package/server/modules/orchestration/a2a/agent-card.ts +4 -4
  83. package/server/modules/orchestration/a2a/routes.ts +7 -2
  84. package/server/modules/orchestration/hermes/hermes.routes.ts +69 -0
  85. package/server/modules/orchestration/index.ts +2 -1
  86. package/server/modules/orchestration/tasks/orchestration-task-store.ts +2 -6
  87. package/server/modules/orchestration/tasks/orchestration-task.routes.ts +1 -20
  88. package/server/modules/orchestration/tasks/orchestration-task.service.ts +4 -41
  89. package/server/modules/orchestration/tasks/orchestration-task.types.ts +2 -4
  90. package/server/modules/orchestration/tasks/task-run-graph.ts +6 -70
  91. package/server/modules/orchestration/workflows/workflow-runner.ts +14 -14
  92. package/server/modules/orchestration/workflows/workflow-trace.ts +2 -2
  93. package/server/modules/orchestration/workflows/workflow.types.ts +1 -1
  94. package/server/modules/providers/list/gemini/gemini-auth.provider.ts +10 -1
  95. package/server/projects.js +0 -170
  96. package/server/routes/mcp-utils.js +0 -19
  97. package/server/services/public-api-manifest.js +0 -5
  98. package/server/services/telegram/control-center.js +2 -153
  99. package/server/services/telegram/translations.js +2 -14
  100. package/dist/assets/index-BBdWwJi6.css +0 -32
  101. package/dist/assets/index-C7zmMv0b.js +0 -889
  102. package/dist-server/server/routes/taskmaster.js +0 -1793
  103. package/dist-server/server/routes/taskmaster.js.map +0 -1
  104. package/dist-server/server/services/taskmaster-config.js +0 -128
  105. package/dist-server/server/services/taskmaster-config.js.map +0 -1
  106. package/dist-server/server/utils/mcp-detector.js +0 -134
  107. package/dist-server/server/utils/mcp-detector.js.map +0 -1
  108. package/dist-server/server/utils/taskmaster-websocket.js +0 -118
  109. package/dist-server/server/utils/taskmaster-websocket.js.map +0 -1
  110. package/server/routes/taskmaster.js +0 -1918
  111. package/server/services/taskmaster-config.js +0 -146
  112. package/server/utils/mcp-detector.js +0 -147
  113. package/server/utils/taskmaster-websocket.js +0 -129
@@ -101,8 +101,8 @@ function newId(prefix: string): string {
101
101
  return `${prefix}_${crypto.randomBytes(8).toString('hex')}`;
102
102
  }
103
103
 
104
- function localA2ABaseUrl(): string {
105
- return `http://127.0.0.1:${process.env.SERVER_PORT ?? process.env.PORT ?? '3001'}/a2a`;
104
+ function localHermesBaseUrl(): string {
105
+ return `http://127.0.0.1:${process.env.SERVER_PORT ?? process.env.PORT ?? '3001'}/hermes`;
106
106
  }
107
107
 
108
108
  function validateWorkflow(workflow: Workflow): void {
@@ -505,7 +505,7 @@ function handoffPrompt(agent: AgentAssignment, role: AgentRole): string {
505
505
  return [
506
506
  `You are ${agent.label} in a Pixcode CLI team.`,
507
507
  `Your inferred stage is: ${role}.`,
508
- 'This is a bounded A2A handoff task, not the full implementation.',
508
+ 'This is a bounded Hermes handoff task, not the full implementation.',
509
509
  'Read the original user goal and coordinator plan, then publish a compact contract for downstream agents.',
510
510
  agent.instruction ? `Your explicit assignment from the user is: ${agent.instruction}` : '',
511
511
  handoffArtifactInstructions('ready'),
@@ -1102,8 +1102,8 @@ function expandWorkflowForRun(workflow: Workflow, metadata?: Record<string, unkn
1102
1102
  };
1103
1103
  }
1104
1104
 
1105
- async function cancelA2ATask(taskId: string): Promise<void> {
1106
- await fetch(`${localA2ABaseUrl()}/tasks/${taskId}/cancel`, { method: 'POST' }).catch(() => undefined);
1105
+ async function cancelHermesTask(taskId: string): Promise<void> {
1106
+ await fetch(`${localHermesBaseUrl()}/tasks/${taskId}/cancel`, { method: 'POST' }).catch(() => undefined);
1107
1107
  }
1108
1108
 
1109
1109
  function readTaskResult(task: RawTask): TaskResult {
@@ -1156,7 +1156,7 @@ async function waitForTask(
1156
1156
  if (deadline && Date.now() >= deadline) {
1157
1157
  throw new WorkflowNodeTimeoutError(timeout ?? 0);
1158
1158
  }
1159
- const response = await fetch(`${localA2ABaseUrl()}/tasks/${taskId}`);
1159
+ const response = await fetch(`${localHermesBaseUrl()}/tasks/${taskId}`);
1160
1160
  const task = await response.json() as RawTask;
1161
1161
  const snapshot = readTaskResult(task);
1162
1162
  onSnapshot?.(snapshot);
@@ -1307,13 +1307,13 @@ class WorkflowRunner {
1307
1307
 
1308
1308
  this.cancelingRuns.add(run.id);
1309
1309
  const taskIds = run.nodeRuns
1310
- .filter((node) => node.a2aTaskId && (node.status === 'running' || node.status === 'queued'))
1311
- .map((node) => node.a2aTaskId as string);
1310
+ .filter((node) => node.hermesTaskId && (node.status === 'running' || node.status === 'queued'))
1311
+ .map((node) => node.hermesTaskId as string);
1312
1312
 
1313
1313
  this.markCanceled(run);
1314
1314
  workflowStore.setRun(run);
1315
1315
 
1316
- await Promise.all(taskIds.map((taskId) => cancelA2ATask(taskId)));
1316
+ await Promise.all(taskIds.map((taskId) => cancelHermesTask(taskId)));
1317
1317
 
1318
1318
  return workflowStore.getRun(run.id) ?? run;
1319
1319
  }
@@ -1838,7 +1838,7 @@ class WorkflowRunner {
1838
1838
  }
1839
1839
  let body: { id?: string; error?: { message?: string } };
1840
1840
  try {
1841
- const submit = await fetch(`${localA2ABaseUrl()}/tasks`, {
1841
+ const submit = await fetch(`${localHermesBaseUrl()}/tasks`, {
1842
1842
  method: 'POST',
1843
1843
  headers: { 'content-type': 'application/json' },
1844
1844
  body: JSON.stringify({
@@ -1910,11 +1910,11 @@ class WorkflowRunner {
1910
1910
  }
1911
1911
  throw error;
1912
1912
  }
1913
- nodeRun.a2aTaskId = body.id;
1913
+ nodeRun.hermesTaskId = body.id;
1914
1914
  workflowStore.setRun(run);
1915
1915
 
1916
1916
  if (this.isCanceling(run.id)) {
1917
- await cancelA2ATask(body.id);
1917
+ await cancelHermesTask(body.id);
1918
1918
  nodeRun.status = 'canceled';
1919
1919
  nodeRun.finishedAt = Date.now();
1920
1920
  workflowStore.setRun(run);
@@ -1940,7 +1940,7 @@ class WorkflowRunner {
1940
1940
  throw error;
1941
1941
  }
1942
1942
 
1943
- await cancelA2ATask(body.id);
1943
+ await cancelHermesTask(body.id);
1944
1944
  nodeRun.finishedAt = Date.now();
1945
1945
  nodeRun.status = 'failed';
1946
1946
  nodeRun.error = error.message;
@@ -2037,7 +2037,7 @@ class WorkflowRunner {
2037
2037
  }
2038
2038
 
2039
2039
  nodeRun.status = 'failed';
2040
- nodeRun.error = result.error ?? `A2A task ended with ${result.state}`;
2040
+ nodeRun.error = result.error ?? `Hermes task ended with ${result.state}`;
2041
2041
  workflowStore.setRun(run);
2042
2042
  if (isExternalDirectoryPermissionError(`${nodeRun.error}\n${nodeRun.outputText ?? ''}`)) {
2043
2043
  completeNodeWithPermissionFallback(nodeRun, node, outputs, completed, nodeRun.error, workspaceTarget);
@@ -333,7 +333,7 @@ export function buildWorkflowTrace(run: WorkflowRun): WorkflowTraceEvent[] {
333
333
  id: traceId([run.id, node.nodeId, 'provider']),
334
334
  type: 'provider',
335
335
  severity: node.status === 'failed' ? 'error' : 'info',
336
- status: node.a2aTaskId ? 'submitted' : node.status,
336
+ status: node.hermesTaskId ? 'submitted' : node.status,
337
337
  timestamp: timestamp + 2,
338
338
  durationMs: nodeDuration,
339
339
  ...base,
@@ -341,7 +341,7 @@ export function buildWorkflowTrace(run: WorkflowRun): WorkflowTraceEvent[] {
341
341
  titleKey: 'workflow.trace.providerCall',
342
342
  summary: [node.adapterId, node.model].filter(Boolean).join(' / '),
343
343
  metadata: {
344
- a2aTaskId: node.a2aTaskId,
344
+ hermesTaskId: node.hermesTaskId,
345
345
  permissionMode: node.permissionMode,
346
346
  timeoutMs: node.timeoutMs,
347
347
  },
@@ -58,7 +58,7 @@ export interface WorkflowNodeRun {
58
58
  fallbackTrigger?: WorkflowFallbackTrigger;
59
59
  fallbackSourceNodeId?: string;
60
60
  status: WorkflowNodeStatus;
61
- a2aTaskId?: string;
61
+ hermesTaskId?: string;
62
62
  startedAt?: number;
63
63
  finishedAt?: number;
64
64
  error?: string;
@@ -19,6 +19,8 @@ type GeminiCredentialsStatus = {
19
19
  error?: string;
20
20
  };
21
21
 
22
+ const GEMINI_TOKEN_INFO_TIMEOUT_MS = 5_000;
23
+
22
24
  export class GeminiProviderAuth implements IProviderAuth {
23
25
  /**
24
26
  * Checks whether the Gemini CLI is available on this host.
@@ -132,8 +134,13 @@ export class GeminiProviderAuth implements IProviderAuth {
132
134
  * Validates a Gemini OAuth access token and returns an email when Google reports one.
133
135
  */
134
136
  private async getTokenInfoEmail(accessToken: string): Promise<{ valid: boolean; email: string | null }> {
137
+ const controller = new AbortController();
138
+ const timeout = setTimeout(() => controller.abort(), GEMINI_TOKEN_INFO_TIMEOUT_MS);
139
+
135
140
  try {
136
- const tokenRes = await fetch(`https://oauth2.googleapis.com/tokeninfo?access_token=${accessToken}`);
141
+ const tokenRes = await fetch(`https://oauth2.googleapis.com/tokeninfo?access_token=${accessToken}`, {
142
+ signal: controller.signal,
143
+ });
137
144
  if (!tokenRes.ok) {
138
145
  return { valid: false, email: null };
139
146
  }
@@ -145,6 +152,8 @@ export class GeminiProviderAuth implements IProviderAuth {
145
152
  };
146
153
  } catch {
147
154
  return { valid: false, email: null };
155
+ } finally {
156
+ clearTimeout(timeout);
148
157
  }
149
158
  }
150
159
 
@@ -136,134 +136,6 @@ async function countProjectFiles(projectPath, maxFiles = FILE_COUNT_LIMIT) {
136
136
  return count;
137
137
  }
138
138
 
139
- // Import TaskMaster detection functions
140
- async function detectTaskMasterFolder(projectPath) {
141
- try {
142
- const taskMasterPath = path.join(projectPath, '.taskmaster');
143
-
144
- // Check if .taskmaster directory exists
145
- try {
146
- const stats = await fs.stat(taskMasterPath);
147
- if (!stats.isDirectory()) {
148
- return {
149
- hasTaskmaster: false,
150
- reason: '.taskmaster exists but is not a directory'
151
- };
152
- }
153
- } catch (error) {
154
- if (error.code === 'ENOENT') {
155
- return {
156
- hasTaskmaster: false,
157
- reason: '.taskmaster directory not found'
158
- };
159
- }
160
- throw error;
161
- }
162
-
163
- // Check for key TaskMaster files
164
- const keyFiles = [
165
- 'tasks/tasks.json',
166
- 'config.json'
167
- ];
168
-
169
- const fileStatus = {};
170
- let hasEssentialFiles = true;
171
-
172
- for (const file of keyFiles) {
173
- const filePath = path.join(taskMasterPath, file);
174
- try {
175
- await fs.access(filePath);
176
- fileStatus[file] = true;
177
- } catch (error) {
178
- fileStatus[file] = false;
179
- if (file === 'tasks/tasks.json') {
180
- hasEssentialFiles = false;
181
- }
182
- }
183
- }
184
-
185
- // Parse tasks.json if it exists for metadata
186
- let taskMetadata = null;
187
- if (fileStatus['tasks/tasks.json']) {
188
- try {
189
- const tasksPath = path.join(taskMasterPath, 'tasks/tasks.json');
190
- const tasksContent = await fs.readFile(tasksPath, 'utf8');
191
- const tasksData = JSON.parse(tasksContent);
192
-
193
- // Handle both tagged and legacy formats
194
- let tasks = [];
195
- if (tasksData.tasks) {
196
- // Legacy format
197
- tasks = tasksData.tasks;
198
- } else {
199
- // Tagged format - get tasks from all tags
200
- Object.values(tasksData).forEach(tagData => {
201
- if (tagData.tasks) {
202
- tasks = tasks.concat(tagData.tasks);
203
- }
204
- });
205
- }
206
-
207
- // Calculate task statistics
208
- const stats = tasks.reduce((acc, task) => {
209
- acc.total++;
210
- acc[task.status] = (acc[task.status] || 0) + 1;
211
-
212
- // Count subtasks
213
- if (task.subtasks) {
214
- task.subtasks.forEach(subtask => {
215
- acc.subtotalTasks++;
216
- acc.subtasks = acc.subtasks || {};
217
- acc.subtasks[subtask.status] = (acc.subtasks[subtask.status] || 0) + 1;
218
- });
219
- }
220
-
221
- return acc;
222
- }, {
223
- total: 0,
224
- subtotalTasks: 0,
225
- pending: 0,
226
- 'in-progress': 0,
227
- done: 0,
228
- review: 0,
229
- deferred: 0,
230
- cancelled: 0,
231
- subtasks: {}
232
- });
233
-
234
- taskMetadata = {
235
- taskCount: stats.total,
236
- subtaskCount: stats.subtotalTasks,
237
- completed: stats.done || 0,
238
- pending: stats.pending || 0,
239
- inProgress: stats['in-progress'] || 0,
240
- review: stats.review || 0,
241
- completionPercentage: stats.total > 0 ? Math.round((stats.done / stats.total) * 100) : 0,
242
- lastModified: (await fs.stat(tasksPath)).mtime.toISOString()
243
- };
244
- } catch (parseError) {
245
- console.warn('Failed to parse tasks.json:', parseError.message);
246
- taskMetadata = { error: 'Failed to parse tasks.json' };
247
- }
248
- }
249
-
250
- return {
251
- hasTaskmaster: true,
252
- hasEssentialFiles,
253
- files: fileStatus,
254
- metadata: taskMetadata,
255
- path: taskMasterPath
256
- };
257
-
258
- } catch (error) {
259
- console.error('Error detecting TaskMaster folder:', error);
260
- return {
261
- hasTaskmaster: false,
262
- reason: `Error checking directory: ${error.message}`
263
- };
264
- }
265
- }
266
-
267
139
  // Cache for extracted project directories
268
140
  const projectDirectoryCache = new Map();
269
141
  let hasWarnedDiscoveredPersistenceFailure = false;
@@ -847,24 +719,6 @@ async function getProjects(progressCallback = null) {
847
719
  }
848
720
  applyCustomSessionNames(project.opencodeSessions, 'opencode');
849
721
 
850
- try {
851
- const taskMasterResult = await detectTaskMasterFolder(actualProjectDir);
852
- project.taskmaster = {
853
- hasTaskmaster: taskMasterResult.hasTaskmaster,
854
- hasEssentialFiles: taskMasterResult.hasEssentialFiles,
855
- metadata: taskMasterResult.metadata,
856
- status: taskMasterResult.hasTaskmaster && taskMasterResult.hasEssentialFiles ? 'configured' : 'not-configured'
857
- };
858
- } catch (e) {
859
- console.warn(`Could not detect TaskMaster for project ${entry.name}:`, e.message);
860
- project.taskmaster = {
861
- hasTaskmaster: false,
862
- hasEssentialFiles: false,
863
- metadata: null,
864
- status: 'error'
865
- };
866
- }
867
-
868
722
  projects.push(project);
869
723
  }
870
724
 
@@ -964,30 +818,6 @@ async function getProjects(progressCallback = null) {
964
818
  }
965
819
  applyCustomSessionNames(project.opencodeSessions, 'opencode');
966
820
 
967
- try {
968
- const taskMasterResult = await detectTaskMasterFolder(actualProjectDir);
969
-
970
- let taskMasterStatus = 'not-configured';
971
- if (taskMasterResult.hasTaskmaster && taskMasterResult.hasEssentialFiles) {
972
- taskMasterStatus = 'taskmaster-only';
973
- }
974
-
975
- project.taskmaster = {
976
- status: taskMasterStatus,
977
- hasTaskmaster: taskMasterResult.hasTaskmaster,
978
- hasEssentialFiles: taskMasterResult.hasEssentialFiles,
979
- metadata: taskMasterResult.metadata
980
- };
981
- } catch (error) {
982
- console.warn(`TaskMaster detection failed for tracked project ${projectName}:`, error.message);
983
- project.taskmaster = {
984
- status: 'error',
985
- hasTaskmaster: false,
986
- hasEssentialFiles: false,
987
- error: error.message
988
- };
989
- }
990
-
991
821
  projects.push(project);
992
822
  }
993
823
  }
@@ -8,25 +8,6 @@
8
8
 
9
9
  import express from 'express';
10
10
 
11
- import { detectTaskMasterMCPServer } from '../utils/mcp-detector.js';
12
-
13
11
  const router = express.Router();
14
12
 
15
- /**
16
- * GET /api/mcp-utils/taskmaster-server
17
- * Check if TaskMaster MCP server is configured
18
- */
19
- router.get('/taskmaster-server', async (req, res) => {
20
- try {
21
- const result = await detectTaskMasterMCPServer();
22
- res.json(result);
23
- } catch (error) {
24
- console.error('TaskMaster MCP detection error:', error);
25
- res.status(500).json({
26
- error: 'Failed to detect TaskMaster MCP server',
27
- message: error.message
28
- });
29
- }
30
- });
31
-
32
13
  export default router;
@@ -4,7 +4,6 @@ const API_GROUPS = [
4
4
  { id: 'sessions', title: 'Sessions and messages', basePath: '/api/sessions', scopes: ['sessions:read', 'sessions:write'] },
5
5
  { id: 'providers', title: 'CLI providers', basePath: '/api/providers', scopes: ['providers:read', 'providers:write'] },
6
6
  { id: 'orchestration', title: 'Orchestration runs', basePath: '/api/orchestration', scopes: ['orchestration:read', 'orchestration:write'] },
7
- { id: 'taskmaster', title: 'Taskmaster queue', basePath: '/api/taskmaster', scopes: ['taskmaster:read', 'taskmaster:write'] },
8
7
  { id: 'notifications', title: 'Notifications', basePath: '/api/settings/notifications', scopes: ['notifications:read', 'notifications:write'] },
9
8
  { id: 'files', title: 'Files', basePath: '/api/projects/:projectName/files', scopes: ['files:read', 'files:write'] },
10
9
  { id: 'git', title: 'Source control', basePath: '/api/git', scopes: ['git:read', 'git:write'] },
@@ -41,10 +40,6 @@ export function buildPublicApiManifest({ baseUrl = '' } = {}) {
41
40
  title: 'List projects',
42
41
  curl: `curl -H "X-API-Key: px_your_key" ${origin || 'http://127.0.0.1:3001'}/api/projects`,
43
42
  },
44
- {
45
- title: 'Start a Taskmaster task with a model',
46
- curl: `curl -X POST -H "Content-Type: application/json" -H "X-API-Key: px_your_key" -d '{"provider":"opencode","model":"minimax/minimax-m2"}' ${origin || 'http://127.0.0.1:3001'}/api/taskmaster/execute/my-project/1`,
47
- },
48
43
  {
49
44
  title: 'Fetch diagnostics bundle',
50
45
  curl: `curl -H "X-API-Key: px_your_key" ${origin || 'http://127.0.0.1:3001'}/api/diagnostics/bundle`,
@@ -43,8 +43,6 @@ const CONTROL_COMMANDS = new Set([
43
43
  '/webhooks',
44
44
  '/sessions',
45
45
  '/newchat',
46
- '/tasks',
47
- '/task',
48
46
  '/settings',
49
47
  '/install',
50
48
  '/auth',
@@ -206,9 +204,8 @@ function mainMenuKeyboard(lang) {
206
204
  return [
207
205
  [button(t(lang, 'control.button.projects'), 'projects'), button(t(lang, 'control.button.provider'), 'providers')],
208
206
  [button(t(lang, 'control.button.models'), 'models'), button(t(lang, 'control.button.workflows'), 'workflows')],
209
- [button(t(lang, 'control.button.tasks'), 'tasks'), button(t(lang, 'control.button.runs'), 'runs')],
210
- [button(t(lang, 'control.button.approvals'), 'approvals'), button(t(lang, 'control.button.controlRoom'), 'control_room')],
211
- [button(t(lang, 'control.button.webhooks'), 'webhooks')],
207
+ [button(t(lang, 'control.button.runs'), 'runs'), button(t(lang, 'control.button.approvals'), 'approvals')],
208
+ [button(t(lang, 'control.button.controlRoom'), 'control_room'), button(t(lang, 'control.button.webhooks'), 'webhooks')],
212
209
  [button(t(lang, 'control.button.sessions'), 'sessions'), button(t(lang, 'control.button.newChat'), 'new_chat')],
213
210
  [button(t(lang, 'control.button.install'), 'install_menu'), button(t(lang, 'control.button.auth'), 'auth_menu')],
214
211
  [button(t(lang, 'control.button.settings'), 'settings')],
@@ -458,37 +455,6 @@ async function startNewChat({ bot, chatId, link, editMessageId }) {
458
455
  });
459
456
  }
460
457
 
461
- async function showTaskMasterTasks({ bot, chatId, link, editMessageId }) {
462
- const lang = languageFor(link);
463
- const state = getState(link.user_id);
464
- if (!state.selectedProjectName) {
465
- await send(bot, chatId, t(lang, 'control.selectProjectFirst'), { editMessageId });
466
- await showProjectMenu({ bot, chatId, link });
467
- return;
468
- }
469
-
470
- const data = await localApi(link.user_id, `/api/taskmaster/tasks/${encodeURIComponent(state.selectedProjectName)}`);
471
- const tasks = Array.isArray(data?.tasks) ? data.tasks : [];
472
- const activeTasks = tasks.filter((task) => !['done', 'completed', 'cancelled', 'canceled'].includes(String(task.status || '').toLowerCase()));
473
- if (activeTasks.length === 0) {
474
- await send(bot, chatId, t(lang, 'control.noTaskMasterTasks'), {
475
- editMessageId,
476
- reply_markup: { inline_keyboard: [[button(t(lang, 'control.button.mainMenu'), 'menu')]] },
477
- });
478
- return;
479
- }
480
-
481
- const buttons = activeTasks.slice(0, 12).map((task) => button(
482
- `#${task.id} ${compact(task.title, 38)}`,
483
- 'task_run',
484
- { taskId: String(task.id) },
485
- ));
486
- await send(bot, chatId, t(lang, 'control.pickTaskMasterTask'), {
487
- editMessageId,
488
- reply_markup: { inline_keyboard: rows(buttons, 1) },
489
- });
490
- }
491
-
492
458
  function extractAssistantText(response) {
493
459
  const messages = Array.isArray(response?.messages) ? response.messages : [];
494
460
  const chunks = [];
@@ -582,10 +548,6 @@ async function fetchRun(userId, runId) {
582
548
  return localApi(userId, `/api/orchestration/workflows/runs/${runId}`);
583
549
  }
584
550
 
585
- async function fetchA2ATask(userId, taskId) {
586
- return localApi(userId, `/a2a/tasks/${encodeURIComponent(taskId)}`);
587
- }
588
-
589
551
  function summarizeRun(run, mode) {
590
552
  const lines = [
591
553
  `Run ${run.id}`,
@@ -646,100 +608,6 @@ async function monitorWorkflowRun({ bot, chatId, link, runId }) {
646
608
  }
647
609
  }
648
610
 
649
- function extractA2ATaskText(task) {
650
- const chunks = [];
651
- const artifacts = Array.isArray(task?.artifacts) ? task.artifacts : [];
652
- for (const artifact of artifacts) {
653
- for (const part of Array.isArray(artifact?.parts) ? artifact.parts : []) {
654
- if (part?.kind === 'text' && typeof part.text === 'string') chunks.push(part.text);
655
- if (part?.type === 'text' && typeof part.text === 'string') chunks.push(part.text);
656
- }
657
- }
658
- const history = Array.isArray(task?.history) ? task.history : [];
659
- for (const message of history) {
660
- if (message?.role !== 'assistant') continue;
661
- for (const part of Array.isArray(message?.parts) ? message.parts : []) {
662
- if (part?.kind === 'text' && typeof part.text === 'string') chunks.push(part.text);
663
- if (part?.type === 'text' && typeof part.text === 'string') chunks.push(part.text);
664
- }
665
- }
666
- return chunks.join('\n\n').trim();
667
- }
668
-
669
- function summarizeA2ATask(task) {
670
- const text = extractA2ATaskText(task);
671
- const error = task?.error?.message || task?.metadata?.error?.message || '';
672
- return truncate([
673
- `Task ${task?.id || ''}`,
674
- `Status: ${task?.state || 'unknown'}`,
675
- error ? `Error: ${error}` : '',
676
- text,
677
- ].filter(Boolean).join('\n\n'));
678
- }
679
-
680
- async function monitorA2ATask({ bot, chatId, link, taskId }) {
681
- const key = `a2a:${taskId}`;
682
- if (runMonitors.has(key)) return;
683
- runMonitors.set(key, true);
684
- const lang = languageFor(link);
685
- try {
686
- for (;;) {
687
- await new Promise((resolve) => setTimeout(resolve, 5000));
688
- const task = await fetchA2ATask(link.user_id, taskId);
689
- if (TERMINAL_RUN_STATES.has(task?.state)) {
690
- await send(bot, chatId, t(lang, 'control.taskFinished', {
691
- taskId,
692
- status: task.state,
693
- summary: summarizeA2ATask(task),
694
- }));
695
- return;
696
- }
697
- }
698
- } finally {
699
- runMonitors.delete(key);
700
- }
701
- }
702
-
703
- async function runTaskMasterTask({ bot, chatId, link, taskId }) {
704
- const lang = languageFor(link);
705
- const state = getState(link.user_id);
706
- if (!state.remoteControlEnabled) {
707
- await send(bot, chatId, t(lang, 'control.disabled'));
708
- return;
709
- }
710
- if (!state.selectedProjectName) {
711
- await send(bot, chatId, t(lang, 'control.selectProjectFirst'));
712
- await showProjectMenu({ bot, chatId, link });
713
- return;
714
- }
715
-
716
- const result = await localApi(
717
- link.user_id,
718
- `/api/taskmaster/execute/${encodeURIComponent(state.selectedProjectName)}/${encodeURIComponent(taskId)}`,
719
- {
720
- method: 'POST',
721
- body: {
722
- projectId: state.selectedProjectName,
723
- adapterId: state.selectedProvider,
724
- model: state.selectedModel || undefined,
725
- isolation: 'worktree',
726
- },
727
- },
728
- );
729
- const a2aTaskId = result?.task?.a2aTaskId;
730
- await send(bot, chatId, t(lang, 'control.taskStarted', {
731
- taskId,
732
- provider: state.selectedProvider,
733
- a2aTaskId: a2aTaskId || result?.task?.id || 'unknown',
734
- }));
735
-
736
- if (a2aTaskId) {
737
- monitorA2ATask({ bot, chatId, link, taskId: a2aTaskId }).catch((error) => {
738
- console.warn('[telegram-control] task monitor failed:', error?.message || error);
739
- });
740
- }
741
- }
742
-
743
611
  export async function startCliInstall({ bot, chatId, link, provider }) {
744
612
  const lang = languageFor(link);
745
613
  const data = await localApi(link.user_id, `/api/providers/${provider}/install`, { method: 'POST' });
@@ -824,10 +692,6 @@ async function handleAwaitingInput({ bot, chatId, link, text }) {
824
692
  await runWorkflow({ bot, chatId, link, input: text });
825
693
  return true;
826
694
  }
827
- if (awaiting.type === 'task_id') {
828
- await runTaskMasterTask({ bot, chatId, link, taskId: text });
829
- return true;
830
- }
831
695
  return false;
832
696
  }
833
697
 
@@ -885,19 +749,6 @@ async function handleCommand({ bot, chatId, link, text }) {
885
749
  await startNewChat({ bot, chatId, link });
886
750
  return true;
887
751
  }
888
- if (command === '/tasks') {
889
- await showTaskMasterTasks({ bot, chatId, link });
890
- return true;
891
- }
892
- if (command === '/task') {
893
- if (!argText) {
894
- updateTelegramControlState(link.user_id, { awaiting: { type: 'task_id' } });
895
- await send(bot, chatId, t(lang, 'control.sendTaskId'));
896
- return true;
897
- }
898
- await runTaskMasterTask({ bot, chatId, link, taskId: argText });
899
- return true;
900
- }
901
752
  if (command === '/settings') {
902
753
  await showSettings({ bot, chatId, link });
903
754
  return true;
@@ -1026,7 +877,6 @@ export async function handleTelegramControlCallback({ bot, query, link }) {
1026
877
  if (action === 'webhooks') return showWebhookMenu({ bot, chatId, link, editMessageId });
1027
878
  if (action === 'sessions') return showSessions({ bot, chatId, link, editMessageId });
1028
879
  if (action === 'new_chat') return startNewChat({ bot, chatId, link, editMessageId });
1029
- if (action === 'tasks') return showTaskMasterTasks({ bot, chatId, link, editMessageId });
1030
880
  if (action === 'install_menu') return showInstallMenu({ bot, chatId, link, editMessageId });
1031
881
  if (action === 'auth_menu') return showAuthMenu({ bot, chatId, link, editMessageId });
1032
882
  if (action === 'settings') return showSettings({ bot, chatId, link, editMessageId });
@@ -1102,7 +952,6 @@ export async function handleTelegramControlCallback({ bot, query, link }) {
1102
952
  }), { editMessageId });
1103
953
  return showApprovalQueue({ bot, chatId, link });
1104
954
  }
1105
- if (action === 'task_run') return runTaskMasterTask({ bot, chatId, link, taskId: payload.taskId });
1106
955
  if (action === 'install_provider') return startCliInstall({ bot, chatId, link, provider: payload.provider });
1107
956
  if (action === 'auth_provider') {
1108
957
  await send(bot, chatId, `${payload.provider} login:\n${AUTH_HELP[payload.provider] || t(languageFor(link), 'control.providerAuthFallback')}`, { editMessageId });