@pixelbyte-software/pixcode 1.47.5 → 1.48.1
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.
- package/README.md +16 -30
- package/README.tr.md +1 -1
- package/dist/api-automation.html +1 -1
- package/dist/assets/index-By2TVdoL.css +32 -0
- package/dist/assets/index-rGiqd0D-.js +818 -0
- package/dist/assets/{vendor-codemirror-CzSp4P1a.js → vendor-codemirror-CIYNS698.js} +8 -8
- package/dist/docs.html +10 -10
- package/dist/features.html +3 -3
- package/dist/index.html +3 -3
- package/dist/landing.html +21 -23
- package/dist/llms-full.txt +4 -8
- package/dist/llms.txt +5 -6
- package/dist/openapi.yaml +7 -7
- package/dist-server/server/index.js +4 -6
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/codex.adapter.js +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/codex.adapter.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/cursor.adapter.js +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/cursor.adapter.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/gemini.adapter.js +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/gemini.adapter.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/opencode.adapter.js +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/opencode.adapter.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/qwen.adapter.js +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/qwen.adapter.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/agent-card.js +4 -4
- package/dist-server/server/modules/orchestration/a2a/agent-card.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/routes.js +6 -2
- package/dist-server/server/modules/orchestration/a2a/routes.js.map +1 -1
- package/dist-server/server/modules/orchestration/hermes/hermes.routes.js +62 -0
- package/dist-server/server/modules/orchestration/hermes/hermes.routes.js.map +1 -0
- package/dist-server/server/modules/orchestration/index.js +2 -1
- package/dist-server/server/modules/orchestration/index.js.map +1 -1
- package/dist-server/server/modules/orchestration/tasks/orchestration-task-store.js +2 -5
- package/dist-server/server/modules/orchestration/tasks/orchestration-task-store.js.map +1 -1
- package/dist-server/server/modules/orchestration/tasks/orchestration-task.routes.js +1 -20
- package/dist-server/server/modules/orchestration/tasks/orchestration-task.routes.js.map +1 -1
- package/dist-server/server/modules/orchestration/tasks/orchestration-task.service.js +4 -37
- package/dist-server/server/modules/orchestration/tasks/orchestration-task.service.js.map +1 -1
- package/dist-server/server/modules/orchestration/tasks/task-run-graph.js +4 -62
- package/dist-server/server/modules/orchestration/tasks/task-run-graph.js.map +1 -1
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js +14 -14
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js.map +1 -1
- package/dist-server/server/modules/orchestration/workflows/workflow-trace.js +2 -2
- package/dist-server/server/modules/orchestration/workflows/workflow-trace.js.map +1 -1
- package/dist-server/server/projects.js +0 -160
- package/dist-server/server/projects.js.map +1 -1
- package/dist-server/server/routes/mcp-utils.js +0 -18
- package/dist-server/server/routes/mcp-utils.js.map +1 -1
- package/dist-server/server/services/public-api-manifest.js +0 -5
- package/dist-server/server/services/public-api-manifest.js.map +1 -1
- package/dist-server/server/services/telegram/control-center.js +2 -144
- package/dist-server/server/services/telegram/control-center.js.map +1 -1
- package/dist-server/server/services/telegram/translations.js +2 -14
- package/dist-server/server/services/telegram/translations.js.map +1 -1
- package/package.json +1 -2
- package/scripts/smoke/default-landing-routing.mjs +7 -16
- package/scripts/smoke/{a2a-roundtrip.mjs → hermes-roundtrip.mjs} +23 -23
- package/scripts/smoke/mac-desktop-runtime.mjs +1 -7
- package/scripts/smoke/orchestration-live-run.mjs +1 -1
- package/scripts/smoke/orchestration-model-sync.mjs +2 -2
- package/scripts/smoke/orchestration-user-facing-output.mjs +2 -2
- package/scripts/smoke/pixcode-workbench-1-48.mjs +55 -0
- package/scripts/smoke/taskmaster-config.mjs +21 -56
- package/scripts/smoke/taskmaster-execution-telegram.mjs +1 -50
- package/scripts/smoke/taskmaster-onboarding.mjs +1 -50
- package/scripts/smoke/taskmaster-run-graph.mjs +1 -53
- package/scripts/smoke/vscode-workbench-layout.mjs +25 -62
- package/scripts/smoke/vscode-workbench-polish.mjs +77 -5
- package/server/index.js +5 -7
- package/server/modules/orchestration/a2a/adapters/claude-code.adapter.ts +1 -1
- package/server/modules/orchestration/a2a/adapters/codex.adapter.ts +1 -1
- package/server/modules/orchestration/a2a/adapters/cursor.adapter.ts +1 -1
- package/server/modules/orchestration/a2a/adapters/gemini.adapter.ts +1 -1
- package/server/modules/orchestration/a2a/adapters/opencode.adapter.ts +1 -1
- package/server/modules/orchestration/a2a/adapters/qwen.adapter.ts +1 -1
- package/server/modules/orchestration/a2a/agent-card.ts +4 -4
- package/server/modules/orchestration/a2a/routes.ts +7 -2
- package/server/modules/orchestration/hermes/hermes.routes.ts +69 -0
- package/server/modules/orchestration/index.ts +2 -1
- package/server/modules/orchestration/tasks/orchestration-task-store.ts +2 -6
- package/server/modules/orchestration/tasks/orchestration-task.routes.ts +1 -20
- package/server/modules/orchestration/tasks/orchestration-task.service.ts +4 -41
- package/server/modules/orchestration/tasks/orchestration-task.types.ts +2 -4
- package/server/modules/orchestration/tasks/task-run-graph.ts +6 -70
- package/server/modules/orchestration/workflows/workflow-runner.ts +14 -14
- package/server/modules/orchestration/workflows/workflow-trace.ts +2 -2
- package/server/modules/orchestration/workflows/workflow.types.ts +1 -1
- package/server/projects.js +0 -170
- package/server/routes/mcp-utils.js +0 -19
- package/server/services/public-api-manifest.js +0 -5
- package/server/services/telegram/control-center.js +2 -153
- package/server/services/telegram/translations.js +2 -14
- package/dist/assets/index-BBdWwJi6.css +0 -32
- package/dist/assets/index-DfqcgNYJ.js +0 -889
- package/dist-server/server/routes/taskmaster.js +0 -1793
- package/dist-server/server/routes/taskmaster.js.map +0 -1
- package/dist-server/server/services/taskmaster-config.js +0 -128
- package/dist-server/server/services/taskmaster-config.js.map +0 -1
- package/dist-server/server/utils/mcp-detector.js +0 -134
- package/dist-server/server/utils/mcp-detector.js.map +0 -1
- package/dist-server/server/utils/taskmaster-websocket.js +0 -118
- package/dist-server/server/utils/taskmaster-websocket.js.map +0 -1
- package/server/routes/taskmaster.js +0 -1918
- package/server/services/taskmaster-config.js +0 -146
- package/server/utils/mcp-detector.js +0 -147
- package/server/utils/taskmaster-websocket.js +0 -129
|
@@ -11,7 +11,7 @@ export interface TaskRunGraphCriterion {
|
|
|
11
11
|
id: string;
|
|
12
12
|
label: string;
|
|
13
13
|
status: TaskRunGraphCriterionStatus;
|
|
14
|
-
source: '
|
|
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
|
|
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
|
-
|
|
174
|
-
taskmasterTask,
|
|
115
|
+
orchestrationTaskId,
|
|
175
116
|
}: {
|
|
176
117
|
projectId: string;
|
|
177
|
-
|
|
178
|
-
taskmasterTask?: Record<string, unknown>;
|
|
118
|
+
orchestrationTaskId?: string;
|
|
179
119
|
}): TaskRunGraph {
|
|
180
|
-
const orchestrationTask =
|
|
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
|
|
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,
|
|
@@ -101,8 +101,8 @@ function newId(prefix: string): string {
|
|
|
101
101
|
return `${prefix}_${crypto.randomBytes(8).toString('hex')}`;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
function
|
|
105
|
-
return `http://127.0.0.1:${process.env.SERVER_PORT ?? process.env.PORT ?? '3001'}/
|
|
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
|
|
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
|
|
1106
|
-
await fetch(`${
|
|
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(`${
|
|
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.
|
|
1311
|
-
.map((node) => node.
|
|
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) =>
|
|
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(`${
|
|
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.
|
|
1913
|
+
nodeRun.hermesTaskId = body.id;
|
|
1914
1914
|
workflowStore.setRun(run);
|
|
1915
1915
|
|
|
1916
1916
|
if (this.isCanceling(run.id)) {
|
|
1917
|
-
await
|
|
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
|
|
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 ?? `
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
61
|
+
hermesTaskId?: string;
|
|
62
62
|
startedAt?: number;
|
|
63
63
|
finishedAt?: number;
|
|
64
64
|
error?: string;
|
package/server/projects.js
CHANGED
|
@@ -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`,
|