@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
@@ -41,6 +41,18 @@ assert.match(
41
41
  'Projects activity should use a dedicated project-directory panel.',
42
42
  );
43
43
 
44
+ assert.match(
45
+ workbench,
46
+ /function WorkbenchProjectLanding/,
47
+ 'Workbench center should show a project landing page instead of a blank editor when no project is selected.',
48
+ );
49
+
50
+ assert.match(
51
+ workbench,
52
+ /function WorkbenchCliPanel/,
53
+ 'Right workbench pane should use a terminal-only CLI panel.',
54
+ );
55
+
44
56
  assert.doesNotMatch(
45
57
  workbench,
46
58
  /return <Sidebar \{\.\.\.sidebarProps\} isMobile=\{false\} \/>/,
@@ -59,6 +71,12 @@ assert.match(
59
71
  'Projects panel should show file counts.',
60
72
  );
61
73
 
74
+ assert.match(
75
+ workbench,
76
+ /Work in this folder/,
77
+ 'Project cards should make the folder binding explicit.',
78
+ );
79
+
62
80
  assert.match(projectType, /fileCount\?: number/, 'Project type should expose optional fileCount metadata.');
63
81
  assert.match(projectsServer, /async function countProjectFiles/, 'Backend should count project files for the workbench project list.');
64
82
 
@@ -74,11 +92,7 @@ assert.doesNotMatch(
74
92
  'Workbench center panel should be allowed to shrink with narrow three-pane layouts.',
75
93
  );
76
94
 
77
- assert.match(
78
- workbench,
79
- /compactComposer/,
80
- 'Workbench should request compact composer behavior in the right CLI pane.',
81
- );
95
+ assert.doesNotMatch(workbench, /<ChatInterface/, 'Workbench should not embed the chat composer in the right CLI pane.');
82
96
 
83
97
  assert.match(
84
98
  workbench,
package/server/index.js CHANGED
@@ -58,7 +58,6 @@ import sessionManager from './sessionManager.js';
58
58
  import gitRoutes from './routes/git.js';
59
59
  import authRoutes from './routes/auth.js';
60
60
  import cursorRoutes from './routes/cursor.js';
61
- import taskmasterRoutes from './routes/taskmaster.js';
62
61
  import mcpUtilsRoutes from './routes/mcp-utils.js';
63
62
  import commandsRoutes from './routes/commands.js';
64
63
  import settingsRoutes from './routes/settings.js';
@@ -84,7 +83,7 @@ import platformizationRoutes from './routes/platformization.js';
84
83
  import liveViewRoutes, { createLiveViewPublicRouter } from './routes/live-view.js';
85
84
  import providerRoutes from './modules/providers/provider.routes.js';
86
85
  import {
87
- createA2ARouter,
86
+ createHermesTaskRouter,
88
87
  adapterRegistry,
89
88
  ClaudeCodeA2AAdapter,
90
89
  CodexA2AAdapter,
@@ -94,6 +93,7 @@ import {
94
93
  QwenA2AAdapter,
95
94
  createPreviewProxyRouter,
96
95
  createOrchestrationTaskRouter,
96
+ createHermesRouter,
97
97
  createWorkflowRouter,
98
98
  } from './modules/orchestration/index.js';
99
99
  import networkRoutes from './routes/network.js';
@@ -370,9 +370,6 @@ app.use('/api/git', authenticateToken, gitRoutes);
370
370
  // Cursor API Routes (protected)
371
371
  app.use('/api/cursor', authenticateToken, cursorRoutes);
372
372
 
373
- // TaskMaster API Routes (protected)
374
- app.use('/api/taskmaster', authenticateToken, taskmasterRoutes);
375
-
376
373
  // MCP utilities
377
374
  app.use('/api/mcp-utils', authenticateToken, mcpUtilsRoutes);
378
375
 
@@ -424,16 +421,17 @@ app.use('/api/live-view', authenticateToken, liveViewRoutes);
424
421
  // Unified provider MCP routes (protected)
425
422
  app.use('/api/providers', authenticateToken, providerRoutes);
426
423
 
427
- // A2A protocol router has its own auth middleware, do NOT wrap with authenticateToken
424
+ // Hermes internal task router has its own localhost/auth middleware; do not wrap with authenticateToken.
428
425
  adapterRegistry.register(new ClaudeCodeA2AAdapter());
429
426
  adapterRegistry.register(new CodexA2AAdapter());
430
427
  adapterRegistry.register(new CursorA2AAdapter());
431
428
  adapterRegistry.register(new GeminiA2AAdapter());
432
429
  adapterRegistry.register(new QwenA2AAdapter());
433
430
  adapterRegistry.register(new OpenCodeA2AAdapter());
434
- app.use('/a2a', createA2ARouter());
431
+ app.use('/hermes', createHermesTaskRouter());
435
432
  app.use('/preview', authenticateToken, createPreviewProxyRouter());
436
433
  app.use('/api/orchestration', authenticateToken, createOrchestrationTaskRouter());
434
+ app.use('/api/orchestration/hermes', authenticateToken, createHermesRouter());
437
435
  app.use('/api/orchestration', authenticateToken, createWorkflowRouter());
438
436
  app.use('/live', createLiveViewPublicRouter());
439
437
 
@@ -49,7 +49,7 @@ export class ClaudeCodeA2AAdapter extends AbstractA2AAdapter {
49
49
  readonly agentCard: AgentCard = {
50
50
  name: 'pixcode-claude-code',
51
51
  description: 'Anthropic Claude Code, accessed via Pixcode',
52
- url: '/a2a/agents/claude-code',
52
+ url: '/hermes/agents/claude-code',
53
53
  version: '1.0.0',
54
54
  capabilities: ['streaming', 'fileEdit', 'commandExec', 'mcp'],
55
55
  skills: [
@@ -40,7 +40,7 @@ export class CodexA2AAdapter extends AbstractA2AAdapter {
40
40
  readonly agentCard: AgentCard = {
41
41
  name: 'pixcode-codex',
42
42
  description: 'OpenAI Codex, accessed via Pixcode',
43
- url: '/a2a/agents/codex',
43
+ url: '/hermes/agents/codex',
44
44
  version: '1.0.0',
45
45
  capabilities: ['streaming', 'fileEdit', 'commandExec', 'webSearch', 'mcp'],
46
46
  skills: [
@@ -40,7 +40,7 @@ export class CursorA2AAdapter extends AbstractA2AAdapter {
40
40
  readonly agentCard: AgentCard = {
41
41
  name: 'pixcode-cursor',
42
42
  description: 'Cursor CLI, accessed via Pixcode',
43
- url: '/a2a/agents/cursor',
43
+ url: '/hermes/agents/cursor',
44
44
  version: '1.0.0',
45
45
  capabilities: ['streaming', 'fileEdit', 'commandExec'],
46
46
  skills: [
@@ -40,7 +40,7 @@ export class GeminiA2AAdapter extends AbstractA2AAdapter {
40
40
  readonly agentCard: AgentCard = {
41
41
  name: 'pixcode-gemini',
42
42
  description: 'Google Gemini CLI, accessed via Pixcode',
43
- url: '/a2a/agents/gemini',
43
+ url: '/hermes/agents/gemini',
44
44
  version: '1.0.0',
45
45
  capabilities: ['streaming', 'fileEdit', 'commandExec', 'mcp'],
46
46
  skills: [
@@ -40,7 +40,7 @@ export class OpenCodeA2AAdapter extends AbstractA2AAdapter {
40
40
  readonly agentCard: AgentCard = {
41
41
  name: 'pixcode-opencode',
42
42
  description: 'OpenCode CLI, accessed via Pixcode',
43
- url: '/a2a/agents/opencode',
43
+ url: '/hermes/agents/opencode',
44
44
  version: '1.0.0',
45
45
  capabilities: ['streaming', 'fileEdit', 'commandExec', 'multiProvider'],
46
46
  skills: [
@@ -40,7 +40,7 @@ export class QwenA2AAdapter extends AbstractA2AAdapter {
40
40
  readonly agentCard: AgentCard = {
41
41
  name: 'pixcode-qwen',
42
42
  description: 'Qwen Code CLI, accessed via Pixcode',
43
- url: '/a2a/agents/qwen',
43
+ url: '/hermes/agents/qwen',
44
44
  version: '1.0.0',
45
45
  capabilities: ['streaming', 'fileEdit', 'commandExec', 'mcp'],
46
46
  skills: [
@@ -1,6 +1,6 @@
1
1
  // server/modules/orchestration/a2a/agent-card.ts
2
- // Pixcode advertises itself as one A2A agent at /a2a/.well-known/agent-card.json.
3
- // Per-CLI adapters publish their own cards under /a2a/agents/:id/agent-card.
2
+ // Pixcode advertises Hermes as one local control agent at /hermes/.well-known/agent-card.json.
3
+ // Per-CLI adapters publish their own cards under /hermes/agents/:id/agent-card.
4
4
 
5
5
  import { readFileSync } from 'node:fs';
6
6
  import { dirname, resolve } from 'node:path';
@@ -44,9 +44,9 @@ export function buildPixcodeAgentCard(baseUrl: string): AgentCard {
44
44
  return {
45
45
  name: 'pixcode',
46
46
  description:
47
- 'Pixcode multi-CLI orchestration platform. Routes A2A tasks to ' +
47
+ 'Pixcode Hermes multi-CLI orchestration platform. Routes Hermes tasks to ' +
48
48
  'Claude Code, Codex, Cursor, Gemini, Qwen, or OpenCode adapters.',
49
- url: `${baseUrl.replace(/\/$/, '')}/a2a`,
49
+ url: `${baseUrl.replace(/\/$/, '')}/hermes`,
50
50
  version: VERSION,
51
51
  capabilities: ['streaming', 'taskRouting'],
52
52
  skills,
@@ -1,5 +1,6 @@
1
1
  // server/modules/orchestration/a2a/routes.ts
2
- // HTTP surface for A2A v0.2. Mounted at /a2a in server/index.js.
2
+ // Internal Hermes task router. The adapter primitives still live in this legacy
3
+ // folder, but the public mount is /hermes.
3
4
 
4
5
  import crypto from 'node:crypto';
5
6
 
@@ -257,7 +258,7 @@ for (const task of taskStore.values()) {
257
258
  }
258
259
  }
259
260
 
260
- export function createA2ARouter(): Router {
261
+ function createA2ARouter(): Router {
261
262
  const router: Router = express.Router();
262
263
 
263
264
  router.use(express.json({ limit: '5mb' }));
@@ -583,3 +584,7 @@ export function createA2ARouter(): Router {
583
584
 
584
585
  return router;
585
586
  }
587
+
588
+ export function createHermesTaskRouter(): Router {
589
+ return createA2ARouter();
590
+ }
@@ -0,0 +1,69 @@
1
+ import os from 'node:os';
2
+
3
+ import express, { type Router } from 'express';
4
+
5
+ import { adapterRegistry } from '@/modules/orchestration/a2a/adapter-registry.js';
6
+ import { a2aTaskStore as hermesTaskStore } from '@/modules/orchestration/a2a/task-store.js';
7
+
8
+ export function createHermesRouter(): Router {
9
+ const router = express.Router();
10
+
11
+ router.get('/status', (_req, res) => {
12
+ res.json({
13
+ id: 'hermes',
14
+ name: 'Hermes Agent',
15
+ product: 'Pixcode',
16
+ runtime: {
17
+ mode: process.env.PIXCODE_MANAGED_PLATFORM === '1' ? 'managed' : 'local',
18
+ host: os.hostname(),
19
+ node: process.version,
20
+ pid: process.pid,
21
+ },
22
+ capabilities: [
23
+ 'project-aware CLI orchestration',
24
+ 'background checks and tests',
25
+ 'workspace-scoped terminal operations',
26
+ 'run history and artifact review',
27
+ ],
28
+ });
29
+ });
30
+
31
+ router.get('/context', (req, res) => {
32
+ const project = typeof req.query.project === 'string' ? req.query.project : null;
33
+ const cwd = typeof req.query.cwd === 'string' ? req.query.cwd : process.cwd();
34
+ res.json({
35
+ agent: 'Hermes Agent',
36
+ product: 'Pixcode',
37
+ project,
38
+ cwd,
39
+ local: true,
40
+ message: project
41
+ ? `Hermes is operating inside Pixcode for ${project}.`
42
+ : 'Hermes is operating inside Pixcode.',
43
+ });
44
+ });
45
+
46
+ router.get('/agents', (_req, res) => {
47
+ res.json({
48
+ agent: 'hermes',
49
+ agents: adapterRegistry.agentCards().map((agent) => ({
50
+ ...agent,
51
+ coordinator: 'hermes',
52
+ })),
53
+ });
54
+ });
55
+
56
+ router.get('/tasks/:id', (req, res) => {
57
+ const task = hermesTaskStore.get(req.params.id);
58
+ if (!task) {
59
+ res.status(404).json({ error: { code: 'HERMES_TASK_NOT_FOUND', message: req.params.id } });
60
+ return;
61
+ }
62
+ res.json({
63
+ ...task,
64
+ hermesTaskId: task.id,
65
+ });
66
+ });
67
+
68
+ return router;
69
+ }
@@ -3,7 +3,7 @@
3
3
  // All cross-module consumers must import from here per
4
4
  // eslint.config.js boundaries rules.
5
5
 
6
- export { createA2ARouter } from './a2a/routes.js';
6
+ export { createHermesTaskRouter } from './a2a/routes.js';
7
7
  export { adapterRegistry } from './a2a/adapter-registry.js';
8
8
  export { ClaudeCodeA2AAdapter } from './a2a/adapters/claude-code.adapter.js';
9
9
  export { CodexA2AAdapter } from './a2a/adapters/codex.adapter.js';
@@ -30,6 +30,7 @@ export {
30
30
  } from './security/permission-policy.js';
31
31
  export { createOrchestrationTaskRouter } from './tasks/orchestration-task.routes.js';
32
32
  export { orchestrationTaskService } from './tasks/orchestration-task.service.js';
33
+ export { createHermesRouter } from './hermes/hermes.routes.js';
33
34
  export { createWorkflowRouter } from './workflows/workflow.routes.js';
34
35
  export {
35
36
  listPendingApprovals,
@@ -20,12 +20,8 @@ export class OrchestrationTaskStore {
20
20
  return this.store.findWhere('orchestration_tasks', (r: OrchestrationTask) => r.id === id) ?? undefined;
21
21
  }
22
22
 
23
- getByA2ATaskId(a2aTaskId: string): OrchestrationTask | undefined {
24
- return this.store.findWhere('orchestration_tasks', (r: OrchestrationTask) => r.a2aTaskId === a2aTaskId) ?? undefined;
25
- }
26
-
27
- getByTaskMasterId(taskmasterId: string): OrchestrationTask | undefined {
28
- return this.store.findWhere('orchestration_tasks', (r: OrchestrationTask) => r.taskmasterId === taskmasterId) ?? undefined;
23
+ getByHermesTaskId(hermesTaskId: string): OrchestrationTask | undefined {
24
+ return this.store.findWhere('orchestration_tasks', (r: OrchestrationTask) => r.hermesTaskId === hermesTaskId) ?? undefined;
29
25
  }
30
26
 
31
27
  list(projectId?: string): OrchestrationTask[] {
@@ -15,35 +15,16 @@ export function createOrchestrationTaskRouter(): Router {
15
15
  const projectId = typeof req.body?.projectId === 'string' ? req.body.projectId : 'default';
16
16
  const title = typeof req.body?.title === 'string' ? req.body.title.trim() : '';
17
17
  const description = typeof req.body?.description === 'string' ? req.body.description : undefined;
18
- const taskmasterId = typeof req.body?.taskmasterId === 'string' ? req.body.taskmasterId : undefined;
19
18
 
20
19
  if (!title) {
21
20
  res.status(400).json({ error: { code: 'TITLE_REQUIRED', message: 'title is required' } });
22
21
  return;
23
22
  }
24
23
 
25
- const task = orchestrationTaskService.create({ projectId, title, description, taskmasterId });
24
+ const task = orchestrationTaskService.create({ projectId, title, description });
26
25
  res.status(201).json(task);
27
26
  });
28
27
 
29
- router.post('/tasks/import-taskmaster', (req, res) => {
30
- const projectId = typeof req.body?.projectId === 'string' ? req.body.projectId : 'default';
31
- const entries = Array.isArray(req.body?.tasks) ? req.body.tasks : [];
32
- const imported = entries
33
- .map((entry: unknown) => {
34
- if (!entry || typeof entry !== 'object') return null;
35
- const record = entry as Record<string, unknown>;
36
- const taskmasterId = typeof record.id === 'string' ? record.id : undefined;
37
- const title = typeof record.title === 'string' ? record.title : undefined;
38
- const description = typeof record.description === 'string' ? record.description : undefined;
39
- if (!taskmasterId || !title) return null;
40
- return orchestrationTaskService.upsertFromTaskMaster({ projectId, title, description, taskmasterId });
41
- })
42
- .filter(Boolean);
43
-
44
- res.json({ tasks: imported, count: imported.length });
45
- });
46
-
47
28
  router.post('/tasks/:id/dispatch', async (req, res) => {
48
29
  try {
49
30
  const adapterId = typeof req.body?.adapterId === 'string' ? req.body.adapterId : '';
@@ -79,7 +79,6 @@ class OrchestrationTaskService {
79
79
  projectId: input.projectId,
80
80
  title: input.title,
81
81
  description: input.description,
82
- taskmasterId: input.taskmasterId,
83
82
  acceptanceCriteria: input.acceptanceCriteria,
84
83
  changedFiles: input.changedFiles,
85
84
  state: 'todo',
@@ -90,27 +89,11 @@ class OrchestrationTaskService {
90
89
  return task;
91
90
  }
92
91
 
93
- upsertFromTaskMaster(input: CreateOrchestrationTaskInput): OrchestrationTask {
94
- const existing = this.store.list(input.projectId).find((task) =>
95
- task.taskmasterId === input.taskmasterId,
96
- );
97
- if (existing) {
98
- existing.title = input.title;
99
- existing.description = input.description;
100
- existing.acceptanceCriteria = input.acceptanceCriteria ?? existing.acceptanceCriteria;
101
- existing.changedFiles = uniqueStrings([...(existing.changedFiles ?? []), ...(input.changedFiles ?? [])]);
102
- existing.updatedAt = Date.now();
103
- this.store.set(existing);
104
- return existing;
105
- }
106
- return this.create(input);
107
- }
108
-
109
92
  async dispatch(taskId: string, input: DispatchOrchestrationTaskInput): Promise<OrchestrationTask> {
110
93
  const task = this.store.get(taskId);
111
94
  if (!task) throw new Error('TASK_NOT_FOUND');
112
95
 
113
- const a2aResponse = await fetch(`http://127.0.0.1:${process.env.SERVER_PORT ?? '3001'}/a2a/tasks`, {
96
+ const a2aResponse = await fetch(`http://127.0.0.1:${process.env.SERVER_PORT ?? '3001'}/hermes/tasks`, {
114
97
  method: 'POST',
115
98
  headers: { 'Content-Type': 'application/json' },
116
99
  body: JSON.stringify({
@@ -129,7 +112,6 @@ class OrchestrationTaskService {
129
112
  projectPath: input.projectPath,
130
113
  },
131
114
  orchestrationTaskId: task.id,
132
- taskmasterId: task.taskmasterId,
133
115
  },
134
116
  }),
135
117
  });
@@ -139,7 +121,7 @@ class OrchestrationTaskService {
139
121
  throw new Error(body?.error?.message ?? 'DISPATCH_FAILED');
140
122
  }
141
123
 
142
- task.a2aTaskId = body.id;
124
+ task.hermesTaskId = body.id;
143
125
  task.adapterId = input.adapterId;
144
126
  task.adapterSelector = input.adapterId;
145
127
  task.workspaceKind = input.isolation ?? 'worktree';
@@ -163,12 +145,7 @@ class OrchestrationTaskService {
163
145
  updateFromWorkflowRun(run: WorkflowRun): OrchestrationTask | undefined {
164
146
  const metadata = run.metadata ?? {};
165
147
  const taskId = readString(metadata.orchestrationTaskId);
166
- const taskmasterId = readString(metadata.taskmasterId);
167
- const task = taskId
168
- ? this.store.get(taskId)
169
- : taskmasterId
170
- ? this.store.list(readString(metadata.projectId)).find((candidate) => candidate.taskmasterId === taskmasterId)
171
- : undefined;
148
+ const task = taskId ? this.store.get(taskId) : undefined;
172
149
  if (!task) return undefined;
173
150
 
174
151
  const changedFiles = changedFilesFromWorkflowRun(run);
@@ -187,9 +164,6 @@ class OrchestrationTaskService {
187
164
  task.updatedAt = Date.now();
188
165
  this.store.set(task);
189
166
 
190
- if (task.taskmasterId && task.state === 'done') {
191
- this.syncTaskMasterStatus(task.taskmasterId, 'done');
192
- }
193
167
  return task;
194
168
  }
195
169
 
@@ -207,7 +181,7 @@ class OrchestrationTaskService {
207
181
  if (event.kind !== 'task-state') return;
208
182
  if (!TERMINAL_A2A_STATES.includes(event.state)) return;
209
183
 
210
- const orchTask = this.store.getByA2ATaskId(event.taskId);
184
+ const orchTask = this.store.getByHermesTaskId(event.taskId);
211
185
  if (!orchTask) return;
212
186
  if (orchTask.state === 'done' || orchTask.state === 'failed' || orchTask.state === 'canceled') return;
213
187
 
@@ -219,20 +193,9 @@ class OrchestrationTaskService {
219
193
  orchTask.updatedAt = Date.now();
220
194
  this.store.set(orchTask);
221
195
 
222
- if (orchTask.taskmasterId && mapped === 'done') {
223
- this.syncTaskMasterStatus(orchTask.taskmasterId, 'done');
224
- }
225
196
  });
226
197
  }
227
198
 
228
- private syncTaskMasterStatus(taskmasterId: string, status: string): void {
229
- const { spawn } = require('node:child_process') as typeof import('node:child_process');
230
- spawn('task-master', ['set-status', '--id', taskmasterId, '--status', status], {
231
- stdio: 'ignore',
232
- detached: true,
233
- }).unref();
234
- }
235
-
236
199
  cancel(taskId: string): OrchestrationTask {
237
200
  const task = this.store.get(taskId);
238
201
  if (!task) throw new Error('TASK_NOT_FOUND');
@@ -2,9 +2,8 @@ export type OrchestrationTaskState = 'todo' | 'in_progress' | 'in_review' | 'don
2
2
 
3
3
  export interface OrchestrationTask {
4
4
  id: string;
5
- a2aTaskId?: string;
5
+ hermesTaskId?: string;
6
6
  workflowRunIds?: string[];
7
- taskmasterId?: string;
8
7
  projectId: string;
9
8
  title: string;
10
9
  description?: string;
@@ -13,7 +12,7 @@ export interface OrchestrationTask {
13
12
  id: string;
14
13
  label: string;
15
14
  status: 'pending' | 'passed' | 'failed';
16
- source: 'taskmaster' | 'workflow';
15
+ source: 'workflow' | 'hermes';
17
16
  }>;
18
17
  changedFiles?: string[];
19
18
  adapterId?: string;
@@ -28,7 +27,6 @@ export interface CreateOrchestrationTaskInput {
28
27
  projectId: string;
29
28
  title: string;
30
29
  description?: string;
31
- taskmasterId?: string;
32
30
  acceptanceCriteria?: OrchestrationTask['acceptanceCriteria'];
33
31
  changedFiles?: string[];
34
32
  }
@@ -11,7 +11,7 @@ export interface TaskRunGraphCriterion {
11
11
  id: string;
12
12
  label: string;
13
13
  status: TaskRunGraphCriterionStatus;
14
- source: 'taskmaster' | 'workflow';
14
+ source: 'workflow' | 'hermes';
15
15
  }
16
16
 
17
17
  export interface TaskRunGraphRunSummary {
@@ -20,7 +20,6 @@ export interface TaskRunGraphRunSummary {
20
20
  status: WorkflowRun['status'];
21
21
  startedAt: number;
22
22
  finishedAt?: number;
23
- taskmasterId?: string;
24
23
  orchestrationTaskId?: string;
25
24
  changedFiles: string[];
26
25
  }
@@ -28,7 +27,6 @@ export interface TaskRunGraphRunSummary {
28
27
  export interface TaskRunGraph {
29
28
  protocol: typeof PIXCODE_TASK_RUN_GRAPH_PROTOCOL;
30
29
  projectId: string;
31
- taskmasterId?: string;
32
30
  orchestrationTaskId?: string;
33
31
  workflowRuns: TaskRunGraphRunSummary[];
34
32
  changedFiles: string[];
@@ -55,59 +53,6 @@ function uniqueStrings(values: Array<string | undefined>): string[] {
55
53
  .sort((a, b) => a.localeCompare(b));
56
54
  }
57
55
 
58
- function taskStatusPassed(status: unknown): boolean {
59
- const normalized = String(status ?? '').toLocaleLowerCase('en');
60
- return normalized === 'done' || normalized === 'completed';
61
- }
62
-
63
- function taskStatusFailed(status: unknown): boolean {
64
- const normalized = String(status ?? '').toLocaleLowerCase('en');
65
- return normalized === 'failed' || normalized === 'blocked' || normalized === 'cancelled' || normalized === 'canceled';
66
- }
67
-
68
- function criterionStatus(status: unknown): TaskRunGraphCriterionStatus {
69
- if (taskStatusPassed(status)) return 'passed';
70
- if (taskStatusFailed(status)) return 'failed';
71
- return 'pending';
72
- }
73
-
74
- function taskmasterAcceptanceCriteria(taskmasterTask: Record<string, unknown> | undefined): TaskRunGraphCriterion[] {
75
- if (!taskmasterTask) return [];
76
-
77
- const criteria: TaskRunGraphCriterion[] = [];
78
- const testStrategy = readString(taskmasterTask.testStrategy) ?? readString(taskmasterTask.test_strategy);
79
- if (testStrategy) {
80
- criteria.push({
81
- id: 'test-strategy',
82
- label: testStrategy,
83
- status: criterionStatus(taskmasterTask.status),
84
- source: 'taskmaster',
85
- });
86
- }
87
-
88
- const subtasks = Array.isArray(taskmasterTask.subtasks) ? taskmasterTask.subtasks : [];
89
- subtasks.forEach((subtask, index) => {
90
- const record = readRecord(subtask);
91
- if (!record) return;
92
- const title = readString(record.title);
93
- if (!title) return;
94
- criteria.push({
95
- id: `subtask-${readString(record.id) ?? index + 1}`,
96
- label: title,
97
- status: criterionStatus(record.status),
98
- source: 'taskmaster',
99
- });
100
- });
101
-
102
- return criteria;
103
- }
104
-
105
- function metadataTaskmasterId(run: WorkflowRun): string | undefined {
106
- return readString(run.metadata?.taskmasterId)
107
- ?? readString(readRecord(run.metadata?.taskGraph)?.taskmasterId)
108
- ?? readString(readRecord(run.metadata?.replay)?.taskmasterId);
109
- }
110
-
111
56
  function metadataOrchestrationTaskId(run: WorkflowRun): string | undefined {
112
57
  return readString(run.metadata?.orchestrationTaskId)
113
58
  ?? readString(readRecord(run.metadata?.taskGraph)?.orchestrationTaskId);
@@ -146,10 +91,8 @@ export function changedFilesFromWorkflowRun(run: WorkflowRun): string[] {
146
91
  return uniqueStrings(run.nodeRuns.flatMap((node) => artifactChangedFiles(node)));
147
92
  }
148
93
 
149
- function workflowRunMatchesTask(run: WorkflowRun, task: OrchestrationTask | undefined, taskmasterId: string | undefined): boolean {
150
- const runTaskmasterId = metadataTaskmasterId(run);
94
+ function workflowRunMatchesTask(run: WorkflowRun, task: OrchestrationTask | undefined): boolean {
151
95
  const runOrchestrationTaskId = metadataOrchestrationTaskId(run);
152
- if (taskmasterId && runTaskmasterId === taskmasterId) return true;
153
96
  if (task?.id && runOrchestrationTaskId === task.id) return true;
154
97
  if (task?.workflowRunIds?.includes(run.id)) return true;
155
98
  return false;
@@ -162,7 +105,6 @@ function runSummary(run: WorkflowRun): TaskRunGraphRunSummary {
162
105
  status: run.status,
163
106
  startedAt: run.startedAt,
164
107
  finishedAt: run.finishedAt,
165
- taskmasterId: metadataTaskmasterId(run),
166
108
  orchestrationTaskId: metadataOrchestrationTaskId(run),
167
109
  changedFiles: changedFilesFromWorkflowRun(run),
168
110
  };
@@ -170,19 +112,15 @@ function runSummary(run: WorkflowRun): TaskRunGraphRunSummary {
170
112
 
171
113
  export function buildTaskRunGraph({
172
114
  projectId,
173
- taskmasterId,
174
- taskmasterTask,
115
+ orchestrationTaskId,
175
116
  }: {
176
117
  projectId: string;
177
- taskmasterId?: string;
178
- taskmasterTask?: Record<string, unknown>;
118
+ orchestrationTaskId?: string;
179
119
  }): TaskRunGraph {
180
- const orchestrationTask = taskmasterId
181
- ? orchestrationTaskService.list(projectId).find((task) => task.taskmasterId === taskmasterId)
182
- : undefined;
120
+ const orchestrationTask = orchestrationTaskId ? orchestrationTaskService.get(orchestrationTaskId) : undefined;
183
121
  const workflowRuns = workflowStore
184
122
  .listRuns()
185
- .filter((run) => workflowRunMatchesTask(run, orchestrationTask, taskmasterId))
123
+ .filter((run) => workflowRunMatchesTask(run, orchestrationTask))
186
124
  .map(runSummary);
187
125
  const workflowCriteria: TaskRunGraphCriterion[] = workflowRuns.map((run) => ({
188
126
  id: `run-${run.id}`,
@@ -191,7 +129,6 @@ export function buildTaskRunGraph({
191
129
  source: 'workflow',
192
130
  }));
193
131
  const acceptanceCriteria = [
194
- ...taskmasterAcceptanceCriteria(taskmasterTask),
195
132
  ...(orchestrationTask?.acceptanceCriteria ?? []),
196
133
  ...workflowCriteria,
197
134
  ];
@@ -203,7 +140,6 @@ export function buildTaskRunGraph({
203
140
  return {
204
141
  protocol: PIXCODE_TASK_RUN_GRAPH_PROTOCOL,
205
142
  projectId,
206
- taskmasterId,
207
143
  orchestrationTaskId: orchestrationTask?.id,
208
144
  workflowRuns,
209
145
  changedFiles,