super-subagents 1.0.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/.windsurf/plans/persist-tasks-by-cwd.md +113 -0
- package/CHANGELOG.md +10 -0
- package/CLAUDE.md +67 -0
- package/README.md +124 -0
- package/build/config/timeouts.d.ts +12 -0
- package/build/config/timeouts.d.ts.map +1 -0
- package/build/config/timeouts.js +21 -0
- package/build/config/timeouts.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +116 -0
- package/build/index.js.map +1 -0
- package/build/models.d.ts +11 -0
- package/build/models.d.ts.map +1 -0
- package/build/models.js +22 -0
- package/build/models.js.map +1 -0
- package/build/services/client-context.d.ts +31 -0
- package/build/services/client-context.d.ts.map +1 -0
- package/build/services/client-context.js +44 -0
- package/build/services/client-context.js.map +1 -0
- package/build/services/copilot-switch.d.ts +36 -0
- package/build/services/copilot-switch.d.ts.map +1 -0
- package/build/services/copilot-switch.js +226 -0
- package/build/services/copilot-switch.js.map +1 -0
- package/build/services/process-spawner.d.ts +9 -0
- package/build/services/process-spawner.d.ts.map +1 -0
- package/build/services/process-spawner.js +475 -0
- package/build/services/process-spawner.js.map +1 -0
- package/build/services/retry-queue.d.ts +35 -0
- package/build/services/retry-queue.d.ts.map +1 -0
- package/build/services/retry-queue.js +125 -0
- package/build/services/retry-queue.js.map +1 -0
- package/build/services/task-manager.d.ts +124 -0
- package/build/services/task-manager.d.ts.map +1 -0
- package/build/services/task-manager.js +584 -0
- package/build/services/task-manager.js.map +1 -0
- package/build/services/task-persistence.d.ts +29 -0
- package/build/services/task-persistence.d.ts.map +1 -0
- package/build/services/task-persistence.js +158 -0
- package/build/services/task-persistence.js.map +1 -0
- package/build/templates/index.d.ts +11 -0
- package/build/templates/index.d.ts.map +1 -0
- package/build/templates/index.js +30 -0
- package/build/templates/index.js.map +1 -0
- package/build/tools/batch-spawn.d.ts +69 -0
- package/build/tools/batch-spawn.d.ts.map +1 -0
- package/build/tools/batch-spawn.js +150 -0
- package/build/tools/batch-spawn.js.map +1 -0
- package/build/tools/cancel-task.d.ts +21 -0
- package/build/tools/cancel-task.d.ts.map +1 -0
- package/build/tools/cancel-task.js +44 -0
- package/build/tools/cancel-task.js.map +1 -0
- package/build/tools/clear-tasks.d.ts +21 -0
- package/build/tools/clear-tasks.d.ts.map +1 -0
- package/build/tools/clear-tasks.js +43 -0
- package/build/tools/clear-tasks.js.map +1 -0
- package/build/tools/force-start.d.ts +21 -0
- package/build/tools/force-start.d.ts.map +1 -0
- package/build/tools/force-start.js +38 -0
- package/build/tools/force-start.js.map +1 -0
- package/build/tools/get-status.d.ts +31 -0
- package/build/tools/get-status.d.ts.map +1 -0
- package/build/tools/get-status.js +384 -0
- package/build/tools/get-status.js.map +1 -0
- package/build/tools/list-tasks.d.ts +26 -0
- package/build/tools/list-tasks.d.ts.map +1 -0
- package/build/tools/list-tasks.js +74 -0
- package/build/tools/list-tasks.js.map +1 -0
- package/build/tools/recover-task.d.ts +29 -0
- package/build/tools/recover-task.d.ts.map +1 -0
- package/build/tools/recover-task.js +91 -0
- package/build/tools/recover-task.js.map +1 -0
- package/build/tools/resume-task.d.ts +29 -0
- package/build/tools/resume-task.d.ts.map +1 -0
- package/build/tools/resume-task.js +43 -0
- package/build/tools/resume-task.js.map +1 -0
- package/build/tools/retry-task.d.ts +21 -0
- package/build/tools/retry-task.d.ts.map +1 -0
- package/build/tools/retry-task.js +52 -0
- package/build/tools/retry-task.js.map +1 -0
- package/build/tools/simulate-rate-limit.d.ts +25 -0
- package/build/tools/simulate-rate-limit.d.ts.map +1 -0
- package/build/tools/simulate-rate-limit.js +69 -0
- package/build/tools/simulate-rate-limit.js.map +1 -0
- package/build/tools/spawn-task.d.ts +57 -0
- package/build/tools/spawn-task.d.ts.map +1 -0
- package/build/tools/spawn-task.js +113 -0
- package/build/tools/spawn-task.js.map +1 -0
- package/build/tools/stream-output.d.ts +29 -0
- package/build/tools/stream-output.d.ts.map +1 -0
- package/build/tools/stream-output.js +96 -0
- package/build/tools/stream-output.js.map +1 -0
- package/build/types.d.ts +75 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +12 -0
- package/build/types.js.map +1 -0
- package/build/utils/format.d.ts +29 -0
- package/build/utils/format.d.ts.map +1 -0
- package/build/utils/format.js +81 -0
- package/build/utils/format.js.map +1 -0
- package/build/utils/sanitize.d.ts +63 -0
- package/build/utils/sanitize.d.ts.map +1 -0
- package/build/utils/sanitize.js +28 -0
- package/build/utils/sanitize.js.map +1 -0
- package/build/utils/task-id-generator.d.ts +10 -0
- package/build/utils/task-id-generator.d.ts.map +1 -0
- package/build/utils/task-id-generator.js +22 -0
- package/build/utils/task-id-generator.js.map +1 -0
- package/docs/timeout-durability.md +28 -0
- package/package.json +39 -0
- package/plans/timeout-durability/00-overview.md +38 -0
- package/plans/timeout-durability/01-analysis.md +37 -0
- package/plans/timeout-durability/decisions.md +22 -0
- package/plans/timeout-durability/resources.md +24 -0
- package/plans/timeout-durability/step-01-timeout-flow.md +27 -0
- package/plans/timeout-durability/step-02-root-cause-map.md +26 -0
- package/plans/timeout-durability/step-03-state-schema.md +26 -0
- package/plans/timeout-durability/step-04-messaging-recovery.md +27 -0
- package/src/config/timeouts.ts +22 -0
- package/src/index.ts +129 -0
- package/src/models.ts +23 -0
- package/src/services/client-context.ts +49 -0
- package/src/services/copilot-switch.ts +269 -0
- package/src/services/process-spawner.ts +548 -0
- package/src/services/retry-queue.ts +151 -0
- package/src/services/task-manager.ts +667 -0
- package/src/services/task-persistence.ts +175 -0
- package/src/templates/index.ts +35 -0
- package/src/templates/super-coder.mdx +519 -0
- package/src/templates/super-planner.mdx +558 -0
- package/src/templates/super-researcher.mdx +394 -0
- package/src/templates/super-tester.mdx +688 -0
- package/src/tools/batch-spawn.ts +179 -0
- package/src/tools/cancel-task.ts +58 -0
- package/src/tools/clear-tasks.ts +52 -0
- package/src/tools/force-start.ts +48 -0
- package/src/tools/get-status.ts +480 -0
- package/src/tools/list-tasks.ts +83 -0
- package/src/tools/recover-task.ts +112 -0
- package/src/tools/resume-task.ts +51 -0
- package/src/tools/retry-task.ts +72 -0
- package/src/tools/simulate-rate-limit.ts +84 -0
- package/src/tools/spawn-task.ts +135 -0
- package/src/tools/stream-output.ts +101 -0
- package/src/types.ts +86 -0
- package/src/utils/format.ts +83 -0
- package/src/utils/sanitize.ts +35 -0
- package/src/utils/task-id-generator.ts +25 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { taskManager } from '../services/task-manager.js';
|
|
3
|
+
import { TaskStatus } from '../types.js';
|
|
4
|
+
import { mcpText, formatError, displayStatus, formatDuration, join } from '../utils/format.js';
|
|
5
|
+
import { TASK_STALL_WARN_MS } from '../config/timeouts.js';
|
|
6
|
+
const StreamOutputSchema = z.object({
|
|
7
|
+
task_id: z.string().min(1),
|
|
8
|
+
offset: z.number().int().min(0).optional().default(0),
|
|
9
|
+
limit: z.number().int().min(1).max(500).optional().default(100),
|
|
10
|
+
});
|
|
11
|
+
export const streamOutputTool = {
|
|
12
|
+
name: 'stream_output',
|
|
13
|
+
description: `Get incremental output from a task. Use offset to get new lines since last call. This is the preferred way to monitor task output -- unlike get_status, this tool is not throttled and returns only the new output lines you haven't seen yet.`,
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
task_id: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'Task ID to stream output from.',
|
|
20
|
+
},
|
|
21
|
+
offset: {
|
|
22
|
+
type: 'number',
|
|
23
|
+
description: 'Line offset to start from. Default: 0. Use next_offset from response.',
|
|
24
|
+
},
|
|
25
|
+
limit: {
|
|
26
|
+
type: 'number',
|
|
27
|
+
description: 'Max lines to return. Default: 100. Max: 500.',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
required: ['task_id'],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
export async function handleStreamOutput(args) {
|
|
34
|
+
try {
|
|
35
|
+
const parsed = StreamOutputSchema.parse(args || {});
|
|
36
|
+
const taskId = parsed.task_id.toLowerCase().trim();
|
|
37
|
+
const task = taskManager.getTask(taskId);
|
|
38
|
+
if (!task) {
|
|
39
|
+
return mcpText(formatError('Task not found', 'Use `list_tasks` to find valid task IDs.'));
|
|
40
|
+
}
|
|
41
|
+
const totalLines = task.output.length;
|
|
42
|
+
const offset = Math.min(parsed.offset, totalLines);
|
|
43
|
+
const outputLines = task.output.slice(offset, offset + parsed.limit);
|
|
44
|
+
const nextOffset = offset + outputLines.length;
|
|
45
|
+
const hasMore = nextOffset < totalLines;
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
const lastOutputAgeMs = task.lastOutputAt ? now - new Date(task.lastOutputAt).getTime() : undefined;
|
|
48
|
+
const isTerminal = [
|
|
49
|
+
TaskStatus.COMPLETED,
|
|
50
|
+
TaskStatus.FAILED,
|
|
51
|
+
TaskStatus.CANCELLED,
|
|
52
|
+
TaskStatus.TIMED_OUT,
|
|
53
|
+
].includes(task.status);
|
|
54
|
+
// Build headline
|
|
55
|
+
const statusStr = displayStatus(task.status);
|
|
56
|
+
let rangeStr;
|
|
57
|
+
if (outputLines.length > 0) {
|
|
58
|
+
rangeStr = `lines ${offset}-${nextOffset - 1} of ${totalLines}`;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
rangeStr = `${totalLines} lines`;
|
|
62
|
+
}
|
|
63
|
+
const exitInfo = isTerminal && task.exitCode !== undefined ? `, exit code: ${task.exitCode}` : '';
|
|
64
|
+
const headline = `**${task.id}** -- ${statusStr} (${rangeStr}${exitInfo})`;
|
|
65
|
+
// Build body
|
|
66
|
+
let body;
|
|
67
|
+
if (outputLines.length > 0) {
|
|
68
|
+
body = outputLines.map(l => `> ${l}`).join('\n');
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
body = 'No output yet.';
|
|
72
|
+
}
|
|
73
|
+
// Build footer
|
|
74
|
+
let footer;
|
|
75
|
+
if (hasMore) {
|
|
76
|
+
const remaining = totalLines - nextOffset;
|
|
77
|
+
footer = `${remaining} more lines available. Use offset \`${nextOffset}\` to continue.`;
|
|
78
|
+
}
|
|
79
|
+
else if (isTerminal) {
|
|
80
|
+
footer = 'All output retrieved.';
|
|
81
|
+
}
|
|
82
|
+
else if (lastOutputAgeMs !== undefined && lastOutputAgeMs >= TASK_STALL_WARN_MS) {
|
|
83
|
+
footer = `No output for ${formatDuration(lastOutputAgeMs)}. Task may be stalled.`;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
footer = 'Waiting for more output...';
|
|
87
|
+
}
|
|
88
|
+
// Add error if terminal and has error
|
|
89
|
+
const errorLine = task.error && isTerminal ? `**Error:** ${task.error}` : undefined;
|
|
90
|
+
return mcpText(join(headline, '', body, '', errorLine, footer));
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return mcpText(formatError(error instanceof Error ? error.message : 'Unknown error'));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=stream-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-output.js","sourceRoot":"","sources":["../../src/tools/stream-output.ts"],"names":[],"mappings":"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"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { ResultPromise } from 'execa';
|
|
2
|
+
export type Provider = 'copilot' | 'claude-cli';
|
|
3
|
+
export declare enum TaskStatus {
|
|
4
|
+
PENDING = "pending",
|
|
5
|
+
WAITING = "waiting",
|
|
6
|
+
RUNNING = "running",
|
|
7
|
+
COMPLETED = "completed",
|
|
8
|
+
FAILED = "failed",
|
|
9
|
+
CANCELLED = "cancelled",
|
|
10
|
+
RATE_LIMITED = "rate_limited",
|
|
11
|
+
TIMED_OUT = "timed_out"
|
|
12
|
+
}
|
|
13
|
+
export type TimeoutReason = 'hard_timeout' | 'stall' | 'process_dead' | 'server_restart' | 'unknown';
|
|
14
|
+
export interface TimeoutContext {
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
timeoutAt?: string;
|
|
17
|
+
elapsedMs?: number;
|
|
18
|
+
lastOutputAt?: string;
|
|
19
|
+
lastOutputAgeMs?: number;
|
|
20
|
+
lastHeartbeatAt?: string;
|
|
21
|
+
pidAlive?: boolean;
|
|
22
|
+
detectedBy?: 'execa' | 'health_check' | 'startup_recovery' | 'manual';
|
|
23
|
+
}
|
|
24
|
+
export interface RetryInfo {
|
|
25
|
+
reason: string;
|
|
26
|
+
retryCount: number;
|
|
27
|
+
nextRetryTime: string;
|
|
28
|
+
maxRetries: number;
|
|
29
|
+
originalTaskId?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface TaskState {
|
|
32
|
+
id: string;
|
|
33
|
+
status: TaskStatus;
|
|
34
|
+
prompt: string;
|
|
35
|
+
output: string[];
|
|
36
|
+
pid?: number;
|
|
37
|
+
sessionId?: string;
|
|
38
|
+
startTime: string;
|
|
39
|
+
lastOutputAt?: string;
|
|
40
|
+
lastHeartbeatAt?: string;
|
|
41
|
+
endTime?: string;
|
|
42
|
+
exitCode?: number;
|
|
43
|
+
error?: string;
|
|
44
|
+
cwd?: string;
|
|
45
|
+
model?: string;
|
|
46
|
+
autonomous?: boolean;
|
|
47
|
+
isResume?: boolean;
|
|
48
|
+
process?: ResultPromise;
|
|
49
|
+
retryInfo?: RetryInfo;
|
|
50
|
+
dependsOn?: string[];
|
|
51
|
+
timeout?: number;
|
|
52
|
+
timeoutAt?: string;
|
|
53
|
+
timeoutReason?: TimeoutReason;
|
|
54
|
+
timeoutContext?: TimeoutContext;
|
|
55
|
+
labels?: string[];
|
|
56
|
+
provider?: Provider;
|
|
57
|
+
fallbackAttempted?: boolean;
|
|
58
|
+
switchAttempted?: boolean;
|
|
59
|
+
recoveryAttempted?: boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface SpawnOptions {
|
|
62
|
+
prompt: string;
|
|
63
|
+
timeout?: number;
|
|
64
|
+
cwd?: string;
|
|
65
|
+
model?: string;
|
|
66
|
+
autonomous?: boolean;
|
|
67
|
+
resumeSessionId?: string;
|
|
68
|
+
retryInfo?: RetryInfo;
|
|
69
|
+
dependsOn?: string[];
|
|
70
|
+
labels?: string[];
|
|
71
|
+
provider?: Provider;
|
|
72
|
+
fallbackAttempted?: boolean;
|
|
73
|
+
switchAttempted?: boolean;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/build/types.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export var TaskStatus;
|
|
2
|
+
(function (TaskStatus) {
|
|
3
|
+
TaskStatus["PENDING"] = "pending";
|
|
4
|
+
TaskStatus["WAITING"] = "waiting";
|
|
5
|
+
TaskStatus["RUNNING"] = "running";
|
|
6
|
+
TaskStatus["COMPLETED"] = "completed";
|
|
7
|
+
TaskStatus["FAILED"] = "failed";
|
|
8
|
+
TaskStatus["CANCELLED"] = "cancelled";
|
|
9
|
+
TaskStatus["RATE_LIMITED"] = "rate_limited";
|
|
10
|
+
TaskStatus["TIMED_OUT"] = "timed_out";
|
|
11
|
+
})(TaskStatus || (TaskStatus = {}));
|
|
12
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,MAAM,CAAN,IAAY,UASX;AATD,WAAY,UAAU;IACpB,iCAAmB,CAAA;IACnB,iCAAmB,CAAA;IACnB,iCAAmB,CAAA;IACnB,qCAAuB,CAAA;IACvB,+BAAiB,CAAA;IACjB,qCAAuB,CAAA;IACvB,2CAA6B,CAAA;IAC7B,qCAAuB,CAAA;AACzB,CAAC,EATW,UAAU,KAAV,UAAU,QASrB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared formatting helpers for converting MCP tool responses to markdown.
|
|
3
|
+
*/
|
|
4
|
+
/** Wraps a markdown string in the MCP response shape. */
|
|
5
|
+
export declare function mcpText(markdown: string): {
|
|
6
|
+
content: Array<{
|
|
7
|
+
type: string;
|
|
8
|
+
text: string;
|
|
9
|
+
}>;
|
|
10
|
+
};
|
|
11
|
+
/** Display status in human-readable form: "rate_limited" -> "rate limited" */
|
|
12
|
+
export declare function displayStatus(status: string): string;
|
|
13
|
+
/** Format labels as inline code: "`label-a`, `label-b`". Returns empty string if none. */
|
|
14
|
+
export declare function formatLabels(labels?: string[]): string;
|
|
15
|
+
/** "Labels: `a`, `b`" or empty string. */
|
|
16
|
+
export declare function formatLabelsLine(labels?: string[]): string;
|
|
17
|
+
/** Milliseconds to human duration: 541364 -> "~9m" */
|
|
18
|
+
export declare function formatDuration(ms: number): string;
|
|
19
|
+
/** Format output as a blockquote with optional truncation. Returns empty string for empty output. */
|
|
20
|
+
export declare function formatOutputBlock(output: string, label?: string, maxLen?: number): string;
|
|
21
|
+
/** Standard error block with optional actionable hint. */
|
|
22
|
+
export declare function formatError(error: string, hint?: string): string;
|
|
23
|
+
/** "Run `sleep 120` then check again." or empty string. */
|
|
24
|
+
export declare function formatRetryHint(retryCommand?: string): string;
|
|
25
|
+
/** Render a markdown table from headers and rows. */
|
|
26
|
+
export declare function formatTable(headers: string[], rows: string[][]): string;
|
|
27
|
+
/** Join non-empty strings with newlines, filtering out falsy/empty values. */
|
|
28
|
+
export declare function join(...parts: (string | undefined | false | null)[]): string;
|
|
29
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,yDAAyD;AACzD,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAE5F;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAGtD;AAED,0CAA0C;AAC1C,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAG1D;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CASjD;AAED,qGAAqG;AACrG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAW,EAAE,MAAM,SAAO,GAAG,MAAM,CAYzF;AAED,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAIhE;AAED,2DAA2D;AAC3D,wBAAgB,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAG7D;AAOD,qDAAqD;AACrD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,CAKvE;AAED,8EAA8E;AAC9E,wBAAgB,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM,CAE5E"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared formatting helpers for converting MCP tool responses to markdown.
|
|
3
|
+
*/
|
|
4
|
+
/** Wraps a markdown string in the MCP response shape. */
|
|
5
|
+
export function mcpText(markdown) {
|
|
6
|
+
return { content: [{ type: 'text', text: markdown }] };
|
|
7
|
+
}
|
|
8
|
+
/** Display status in human-readable form: "rate_limited" -> "rate limited" */
|
|
9
|
+
export function displayStatus(status) {
|
|
10
|
+
return status.replace(/_/g, ' ');
|
|
11
|
+
}
|
|
12
|
+
/** Format labels as inline code: "`label-a`, `label-b`". Returns empty string if none. */
|
|
13
|
+
export function formatLabels(labels) {
|
|
14
|
+
if (!labels || labels.length === 0)
|
|
15
|
+
return '';
|
|
16
|
+
return labels.map(l => `\`${l}\``).join(', ');
|
|
17
|
+
}
|
|
18
|
+
/** "Labels: `a`, `b`" or empty string. */
|
|
19
|
+
export function formatLabelsLine(labels) {
|
|
20
|
+
const f = formatLabels(labels);
|
|
21
|
+
return f ? `Labels: ${f}` : '';
|
|
22
|
+
}
|
|
23
|
+
/** Milliseconds to human duration: 541364 -> "~9m" */
|
|
24
|
+
export function formatDuration(ms) {
|
|
25
|
+
if (ms <= 0)
|
|
26
|
+
return '0s';
|
|
27
|
+
const totalSec = Math.round(ms / 1000);
|
|
28
|
+
if (totalSec < 60)
|
|
29
|
+
return `~${totalSec}s`;
|
|
30
|
+
const min = Math.round(totalSec / 60);
|
|
31
|
+
if (min < 60)
|
|
32
|
+
return `~${min}m`;
|
|
33
|
+
const h = Math.floor(min / 60);
|
|
34
|
+
const rm = min % 60;
|
|
35
|
+
return rm === 0 ? `~${h}h` : `~${h}h ${rm}m`;
|
|
36
|
+
}
|
|
37
|
+
/** Format output as a blockquote with optional truncation. Returns empty string for empty output. */
|
|
38
|
+
export function formatOutputBlock(output, label = 'Output', maxLen = 2000) {
|
|
39
|
+
if (!output || !output.trim())
|
|
40
|
+
return '';
|
|
41
|
+
let text = output;
|
|
42
|
+
let truncated = false;
|
|
43
|
+
if (text.length > maxLen) {
|
|
44
|
+
text = text.slice(-maxLen);
|
|
45
|
+
truncated = true;
|
|
46
|
+
}
|
|
47
|
+
const quoted = text.split('\n').map(line => `> ${line}`).join('\n');
|
|
48
|
+
const parts = [`**${label}:**`, quoted];
|
|
49
|
+
if (truncated)
|
|
50
|
+
parts.push('*(truncated -- use `stream_output` for full output)*');
|
|
51
|
+
return parts.join('\n');
|
|
52
|
+
}
|
|
53
|
+
/** Standard error block with optional actionable hint. */
|
|
54
|
+
export function formatError(error, hint) {
|
|
55
|
+
const parts = [`**Error:** ${error}`];
|
|
56
|
+
if (hint)
|
|
57
|
+
parts.push('', hint);
|
|
58
|
+
return parts.join('\n');
|
|
59
|
+
}
|
|
60
|
+
/** "Run `sleep 120` then check again." or empty string. */
|
|
61
|
+
export function formatRetryHint(retryCommand) {
|
|
62
|
+
if (!retryCommand)
|
|
63
|
+
return '';
|
|
64
|
+
return `Run \`${retryCommand}\` then check again.`;
|
|
65
|
+
}
|
|
66
|
+
/** Escape pipe characters in table cell content. */
|
|
67
|
+
function escapeCell(value) {
|
|
68
|
+
return value.replace(/\|/g, '\\|');
|
|
69
|
+
}
|
|
70
|
+
/** Render a markdown table from headers and rows. */
|
|
71
|
+
export function formatTable(headers, rows) {
|
|
72
|
+
const headerRow = `| ${headers.map(escapeCell).join(' | ')} |`;
|
|
73
|
+
const separator = `|${headers.map(() => '------').join('|')}|`;
|
|
74
|
+
const dataRows = rows.map(r => `| ${r.map(escapeCell).join(' | ')} |`);
|
|
75
|
+
return [headerRow, separator, ...dataRows].join('\n');
|
|
76
|
+
}
|
|
77
|
+
/** Join non-empty strings with newlines, filtering out falsy/empty values. */
|
|
78
|
+
export function join(...parts) {
|
|
79
|
+
return parts.filter(p => typeof p === 'string' && p.length > 0).join('\n');
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const SpawnTaskSchema: z.ZodObject<{
|
|
3
|
+
prompt: z.ZodString;
|
|
4
|
+
timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
5
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
6
|
+
model: z.ZodOptional<z.ZodEnum<[string, ...string[]]>>;
|
|
7
|
+
task_type: z.ZodOptional<z.ZodEnum<[string, ...string[]]>>;
|
|
8
|
+
autonomous: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
9
|
+
depends_on: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
10
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
prompt: string;
|
|
13
|
+
timeout: number;
|
|
14
|
+
autonomous: boolean;
|
|
15
|
+
cwd?: string | undefined;
|
|
16
|
+
model?: string | undefined;
|
|
17
|
+
task_type?: string | undefined;
|
|
18
|
+
depends_on?: string[] | undefined;
|
|
19
|
+
labels?: string[] | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
prompt: string;
|
|
22
|
+
timeout?: number | undefined;
|
|
23
|
+
cwd?: string | undefined;
|
|
24
|
+
model?: string | undefined;
|
|
25
|
+
task_type?: string | undefined;
|
|
26
|
+
autonomous?: boolean | undefined;
|
|
27
|
+
depends_on?: string[] | undefined;
|
|
28
|
+
labels?: string[] | undefined;
|
|
29
|
+
}>;
|
|
30
|
+
export declare const ResumeTaskSchema: z.ZodObject<{
|
|
31
|
+
sessionId: z.ZodString;
|
|
32
|
+
timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
33
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
34
|
+
autonomous: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
35
|
+
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
timeout: number;
|
|
37
|
+
autonomous: boolean;
|
|
38
|
+
sessionId: string;
|
|
39
|
+
cwd?: string | undefined;
|
|
40
|
+
}, {
|
|
41
|
+
sessionId: string;
|
|
42
|
+
timeout?: number | undefined;
|
|
43
|
+
cwd?: string | undefined;
|
|
44
|
+
autonomous?: boolean | undefined;
|
|
45
|
+
}>;
|
|
46
|
+
export declare const GetTaskStatusSchema: z.ZodObject<{
|
|
47
|
+
taskId: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>;
|
|
48
|
+
}, "strip", z.ZodTypeAny, {
|
|
49
|
+
taskId: string | string[];
|
|
50
|
+
}, {
|
|
51
|
+
taskId: string | string[];
|
|
52
|
+
}>;
|
|
53
|
+
export declare const ListTasksSchema: z.ZodObject<{
|
|
54
|
+
status: z.ZodOptional<z.ZodEnum<["pending", "waiting", "running", "completed", "failed", "cancelled", "rate_limited", "timed_out"]>>;
|
|
55
|
+
label: z.ZodOptional<z.ZodString>;
|
|
56
|
+
}, "strip", z.ZodTypeAny, {
|
|
57
|
+
status?: "pending" | "waiting" | "running" | "completed" | "failed" | "cancelled" | "rate_limited" | "timed_out" | undefined;
|
|
58
|
+
label?: string | undefined;
|
|
59
|
+
}, {
|
|
60
|
+
status?: "pending" | "waiting" | "running" | "completed" | "failed" | "cancelled" | "rate_limited" | "timed_out" | undefined;
|
|
61
|
+
label?: string | undefined;
|
|
62
|
+
}>;
|
|
63
|
+
//# sourceMappingURL=sanitize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS1B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;EAK3B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;EAE9B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;EAG1B,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { MODEL_IDS } from '../models.js';
|
|
3
|
+
import { TASK_TYPE_IDS } from '../templates/index.js';
|
|
4
|
+
import { TASK_TIMEOUT_DEFAULT_MS, TASK_TIMEOUT_MAX_MS, TASK_TIMEOUT_MIN_MS, } from '../config/timeouts.js';
|
|
5
|
+
export const SpawnTaskSchema = z.object({
|
|
6
|
+
prompt: z.string().min(1).max(50000),
|
|
7
|
+
timeout: z.number().int().min(TASK_TIMEOUT_MIN_MS).max(TASK_TIMEOUT_MAX_MS).optional().default(TASK_TIMEOUT_DEFAULT_MS), // 10 minutes default
|
|
8
|
+
cwd: z.string().optional(),
|
|
9
|
+
model: z.enum(MODEL_IDS).optional(),
|
|
10
|
+
task_type: z.enum(TASK_TYPE_IDS).optional(),
|
|
11
|
+
autonomous: z.boolean().optional().default(true),
|
|
12
|
+
depends_on: z.array(z.string().min(1)).optional(),
|
|
13
|
+
labels: z.array(z.string().min(1).max(50)).max(10).optional(),
|
|
14
|
+
});
|
|
15
|
+
export const ResumeTaskSchema = z.object({
|
|
16
|
+
sessionId: z.string().min(1),
|
|
17
|
+
timeout: z.number().int().min(TASK_TIMEOUT_MIN_MS).max(TASK_TIMEOUT_MAX_MS).optional().default(TASK_TIMEOUT_DEFAULT_MS), // 10 minutes default
|
|
18
|
+
cwd: z.string().optional(),
|
|
19
|
+
autonomous: z.boolean().optional().default(true),
|
|
20
|
+
});
|
|
21
|
+
export const GetTaskStatusSchema = z.object({
|
|
22
|
+
taskId: z.union([z.string().min(1), z.array(z.string().min(1))]),
|
|
23
|
+
});
|
|
24
|
+
export const ListTasksSchema = z.object({
|
|
25
|
+
status: z.enum(['pending', 'waiting', 'running', 'completed', 'failed', 'cancelled', 'rate_limited', 'timed_out']).optional(),
|
|
26
|
+
label: z.string().min(1).optional(),
|
|
27
|
+
});
|
|
28
|
+
//# sourceMappingURL=sanitize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../src/utils/sanitize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;IACpC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,uBAAuB,CAAC,EAAE,qBAAqB;IAC9I,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,SAAkC,CAAC,CAAC,QAAQ,EAAE;IAC5D,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,aAAsC,CAAC,CAAC,QAAQ,EAAE;IACpE,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAChD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACjD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;CAC9D,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,uBAAuB,CAAC,EAAE,qBAAqB;IAC9I,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;CACjD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACjE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC7H,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates human-readable task IDs like "brave-tiger-42" or "cosmic-falcon-17"
|
|
3
|
+
* Much easier to remember and communicate than UUIDs or random strings
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateTaskId(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Normalizes task ID for case-insensitive lookups
|
|
8
|
+
*/
|
|
9
|
+
export declare function normalizeTaskId(taskId: string): string;
|
|
10
|
+
//# sourceMappingURL=task-id-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-id-generator.d.ts","sourceRoot":"","sources":["../../src/utils/task-id-generator.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAWvC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { uniqueNamesGenerator, adjectives, animals } from 'unique-names-generator';
|
|
2
|
+
/**
|
|
3
|
+
* Generates human-readable task IDs like "brave-tiger-42" or "cosmic-falcon-17"
|
|
4
|
+
* Much easier to remember and communicate than UUIDs or random strings
|
|
5
|
+
*/
|
|
6
|
+
export function generateTaskId() {
|
|
7
|
+
const randomNumber = Math.floor(Math.random() * 100);
|
|
8
|
+
const name = uniqueNamesGenerator({
|
|
9
|
+
dictionaries: [adjectives, animals],
|
|
10
|
+
separator: '-',
|
|
11
|
+
length: 2,
|
|
12
|
+
style: 'lowerCase',
|
|
13
|
+
});
|
|
14
|
+
return `${name}-${randomNumber}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Normalizes task ID for case-insensitive lookups
|
|
18
|
+
*/
|
|
19
|
+
export function normalizeTaskId(taskId) {
|
|
20
|
+
return taskId.toLowerCase().trim();
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=task-id-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-id-generator.js","sourceRoot":"","sources":["../../src/utils/task-id-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAU,OAAO,EAAS,MAAM,wBAAwB,CAAC;AAElG;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;IAErD,MAAM,IAAI,GAAG,oBAAoB,CAAC;QAChC,YAAY,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC;QACnC,SAAS,EAAE,GAAG;QACd,MAAM,EAAE,CAAC;QACT,KAAK,EAAE,WAAW;KACnB,CAAC,CAAC;IAEH,OAAO,GAAG,IAAI,IAAI,YAAY,EAAE,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Timeout Durability Notes
|
|
2
|
+
|
|
3
|
+
## What changed
|
|
4
|
+
- Task state now records last output and heartbeat timestamps.
|
|
5
|
+
- Timeout events record a reason and context for diagnosis.
|
|
6
|
+
- `get_status` and `stream_output` provide stall-aware guidance.
|
|
7
|
+
- `recover_task` can resume timed_out tasks when a session is available.
|
|
8
|
+
|
|
9
|
+
## Timeout reasons
|
|
10
|
+
- hard_timeout: Task exceeded configured timeout.
|
|
11
|
+
- stall: No output for a long interval before timeout.
|
|
12
|
+
- process_dead: Process died unexpectedly.
|
|
13
|
+
- server_restart: Server restarted while task was running.
|
|
14
|
+
|
|
15
|
+
## Recovery workflow
|
|
16
|
+
1. Run `get_status` to see timeout reason and session availability.
|
|
17
|
+
2. If session_id is present, use `recover_task` or `resume_task`.
|
|
18
|
+
3. If no session_id, re-run with `spawn_task` (optionally with a higher timeout).
|
|
19
|
+
4. If the process is still alive after timeout, `recover_task` will attempt cleanup.
|
|
20
|
+
|
|
21
|
+
## Manual verification checklist
|
|
22
|
+
- Spawn a task with a very small timeout and confirm status becomes timed_out.
|
|
23
|
+
- Verify `get_status` shows timeout reason and suggested action.
|
|
24
|
+
- Confirm `stream_output` shows stall warning if no output for a while.
|
|
25
|
+
- If a session_id is present, call `recover_task` and verify a new task starts.
|
|
26
|
+
|
|
27
|
+
## Notes
|
|
28
|
+
- Timed out tasks are removed after the task TTL window; recover before expiration.
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "super-subagents",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "MCP server for spawning and managing GitHub Copilot CLI tasks",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "build/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"copilot-mcp-server": "build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsx watch src/index.ts",
|
|
13
|
+
"start": "node build/index.js",
|
|
14
|
+
"clean": "rm -rf build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mcp",
|
|
18
|
+
"copilot",
|
|
19
|
+
"github",
|
|
20
|
+
"cli",
|
|
21
|
+
"agent"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
26
|
+
"execa": "^9.5.2",
|
|
27
|
+
"nanoid": "^5.0.9",
|
|
28
|
+
"unique-names-generator": "^4.7.1",
|
|
29
|
+
"zod": "^3.24.1"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.10.5",
|
|
33
|
+
"tsx": "^4.19.2",
|
|
34
|
+
"typescript": "^5.7.2"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Plan: Timeout Durability
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-02-01
|
|
4
|
+
**Goal:** Identify timeout root causes in the MCP task system and design durable handling with clear diagnostics, recovery, and user guidance.
|
|
5
|
+
**Complexity:** medium
|
|
6
|
+
|
|
7
|
+
## Scope
|
|
8
|
+
**In:** Task lifecycle, timeout config/enforcement, process health checks, persistence schema, get_status messaging, recovery/resume flows, diagnostic logging.
|
|
9
|
+
**Out:** Changes to Copilot CLI itself, external service behavior, UI/UX outside MCP tool responses.
|
|
10
|
+
|
|
11
|
+
## Phases
|
|
12
|
+
### Phase 1: Evidence and Root Causes (Steps 1-2)
|
|
13
|
+
- Step 1: Document current timeout flow and gaps
|
|
14
|
+
- Step 2: Distinguish root cause categories and signals
|
|
15
|
+
**Goal:** Evidence-backed root cause map | **Estimate:** 1-2 hours
|
|
16
|
+
|
|
17
|
+
### Phase 2: State and Diagnostics Design (Steps 3-4)
|
|
18
|
+
- Step 3: Define state fields for heartbeat/output/timeout reason
|
|
19
|
+
- Step 4: Design diagnostics and recovery actions per cause
|
|
20
|
+
**Goal:** Durable architecture for timeouts | **Estimate:** 2-3 hours
|
|
21
|
+
|
|
22
|
+
### Phase 3: Messaging and Recovery UX (Steps 5-6)
|
|
23
|
+
- Step 5: Improve get_status and stream_output guidance
|
|
24
|
+
- Step 6: Resume/retry/cleanup guidance for timed_out cases
|
|
25
|
+
**Goal:** Actionable feedback for operators | **Estimate:** 1-2 hours
|
|
26
|
+
|
|
27
|
+
## Approach
|
|
28
|
+
Ground the design in existing task lifecycle code, add minimal state fields needed for diagnosis, and surface recovery paths (resume_task, retry_task) when available. Prioritize persistence correctness before feature expansion.
|
|
29
|
+
|
|
30
|
+
## Risks
|
|
31
|
+
1. **Misclassification of timeouts** — Mitigation: add explicit timeout_reason and last_activity timestamps.
|
|
32
|
+
2. **State incompatibility** — Mitigation: backward-compatible persistence and schema defaults.
|
|
33
|
+
3. **Noisy logs** — Mitigation: throttle diagnostic logging and focus on actionable data.
|
|
34
|
+
|
|
35
|
+
## Success Metrics
|
|
36
|
+
- Timed_out tasks show a specific reason and a next step.
|
|
37
|
+
- Operators can resume or retry without manual log digging.
|
|
38
|
+
- No loss of task state across server restarts.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Analysis
|
|
2
|
+
|
|
3
|
+
## Current State (Evidence)
|
|
4
|
+
- Tasks are created in memory with generated IDs and persisted to JSON under the user home directory per workspace.
|
|
5
|
+
- Timeout defaults to 600000 ms for spawn and resume; execa enforces the timeout and sets status to timed_out.
|
|
6
|
+
- Health checks only verify process liveness; no heartbeat or last-activity timestamps exist.
|
|
7
|
+
- get_status provides timeout remaining for running tasks but no timed_out-specific guidance.
|
|
8
|
+
- Session IDs can be captured from output and used by resume_task, but timed_out does not surface that hint.
|
|
9
|
+
- Server restarts mark running or pending tasks as failed with a generic interruption error.
|
|
10
|
+
|
|
11
|
+
## Root Cause Categories and Signals
|
|
12
|
+
1. **Hard timeout exceeded**
|
|
13
|
+
- Signal: TaskStatus timed_out with error text “timed out after X ms”.
|
|
14
|
+
- Distinguish from: server restart and dead process via error text and endTime source.
|
|
15
|
+
2. **Process died (zombie or crash)**
|
|
16
|
+
- Signal: health check or get_status liveness check marks task failed with “process exited unexpectedly”.
|
|
17
|
+
3. **Stall or no-output hang**
|
|
18
|
+
- Signal: process still alive, but output and activity do not change for a long period.
|
|
19
|
+
- Currently indistinguishable due to missing last-activity tracking.
|
|
20
|
+
4. **Server restart interruption**
|
|
21
|
+
- Signal: load-time recovery marks running or pending tasks as failed with “server restarted” error.
|
|
22
|
+
5. **Rate-limit backoff**
|
|
23
|
+
- Signal: rate_limited status with retryInfo; already handled by retry queue.
|
|
24
|
+
|
|
25
|
+
## Options
|
|
26
|
+
- **Option A: Increase timeout only**
|
|
27
|
+
- Pros: minimal change.
|
|
28
|
+
- Cons: hides root causes, doesn’t improve reliability.
|
|
29
|
+
- **Option B: Add diagnostics + recovery guidance (preferred)**
|
|
30
|
+
- Pros: actionable feedback, durable state, clearer recovery paths.
|
|
31
|
+
- Cons: requires schema and message updates.
|
|
32
|
+
- **Option C: Separate watchdog service**
|
|
33
|
+
- Pros: robust.
|
|
34
|
+
- Cons: more complexity than needed.
|
|
35
|
+
|
|
36
|
+
## Decision
|
|
37
|
+
Proceed with Option B: extend task state for activity and timeout reasons, improve messaging, and add recovery actions aligned with existing tools.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Key Decisions
|
|
2
|
+
|
|
3
|
+
## Decision 1: Add activity timestamps to TaskState
|
|
4
|
+
**Context:** Need to distinguish stall vs slow but healthy.
|
|
5
|
+
**Options:** A=No change, B=Track lastOutputAt and lastHeartbeatAt, C=External watchdog.
|
|
6
|
+
**Chosen:** B
|
|
7
|
+
**Rationale:** Minimal change with strong diagnostic value.
|
|
8
|
+
**Tradeoffs:** Requires updating persistence and runtime updates.
|
|
9
|
+
|
|
10
|
+
## Decision 2: Introduce timeout_reason taxonomy
|
|
11
|
+
**Context:** timed_out status is too generic for recovery guidance.
|
|
12
|
+
**Options:** A=Free-form error string only, B=Structured reason enum, C=Separate status values.
|
|
13
|
+
**Chosen:** B
|
|
14
|
+
**Rationale:** Keeps status stable while enabling precise messaging.
|
|
15
|
+
**Tradeoffs:** Requires mapping logic and migration defaults.
|
|
16
|
+
|
|
17
|
+
## Decision 3: Surface resume guidance for timed_out
|
|
18
|
+
**Context:** Session IDs are captured but not shown for timed_out tasks.
|
|
19
|
+
**Options:** A=No change, B=Show resume_task hint whenever sessionId exists, C=Auto-resume.
|
|
20
|
+
**Chosen:** B
|
|
21
|
+
**Rationale:** Actionable guidance without automatic behavior changes.
|
|
22
|
+
**Tradeoffs:** Must ensure hints are accurate and not misleading.
|