mcp-copilot-cli 1.0.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 (79) hide show
  1. package/README.md +207 -0
  2. package/bin/mcp-copilot-cli.mjs +3 -0
  3. package/dist/src/app.d.ts +71 -0
  4. package/dist/src/app.js +303 -0
  5. package/dist/src/app.js.map +1 -0
  6. package/dist/src/cli/doctor.d.ts +2 -0
  7. package/dist/src/cli/doctor.js +99 -0
  8. package/dist/src/cli/doctor.js.map +1 -0
  9. package/dist/src/config/defaults.d.ts +3 -0
  10. package/dist/src/config/defaults.js +4 -0
  11. package/dist/src/config/defaults.js.map +1 -0
  12. package/dist/src/index.d.ts +2 -0
  13. package/dist/src/index.js +98 -0
  14. package/dist/src/index.js.map +1 -0
  15. package/dist/src/mcp/system-status.d.ts +19 -0
  16. package/dist/src/mcp/system-status.js +20 -0
  17. package/dist/src/mcp/system-status.js.map +1 -0
  18. package/dist/src/mcp/task-markdown.d.ts +3 -0
  19. package/dist/src/mcp/task-markdown.js +70 -0
  20. package/dist/src/mcp/task-markdown.js.map +1 -0
  21. package/dist/src/mcp/tool-banners.d.ts +4 -0
  22. package/dist/src/mcp/tool-banners.js +26 -0
  23. package/dist/src/mcp/tool-banners.js.map +1 -0
  24. package/dist/src/mcp/tool-definitions.d.ts +109 -0
  25. package/dist/src/mcp/tool-definitions.js +125 -0
  26. package/dist/src/mcp/tool-definitions.js.map +1 -0
  27. package/dist/src/services/copilot-runtime.d.ts +28 -0
  28. package/dist/src/services/copilot-runtime.js +194 -0
  29. package/dist/src/services/copilot-runtime.js.map +1 -0
  30. package/dist/src/services/output-log.d.ts +7 -0
  31. package/dist/src/services/output-log.js +59 -0
  32. package/dist/src/services/output-log.js.map +1 -0
  33. package/dist/src/services/profile-manager.d.ts +34 -0
  34. package/dist/src/services/profile-manager.js +113 -0
  35. package/dist/src/services/profile-manager.js.map +1 -0
  36. package/dist/src/services/question-registry.d.ts +29 -0
  37. package/dist/src/services/question-registry.js +115 -0
  38. package/dist/src/services/question-registry.js.map +1 -0
  39. package/dist/src/services/spawn-validation.d.ts +9 -0
  40. package/dist/src/services/spawn-validation.js +53 -0
  41. package/dist/src/services/spawn-validation.js.map +1 -0
  42. package/dist/src/services/task-manager.d.ts +34 -0
  43. package/dist/src/services/task-manager.js +107 -0
  44. package/dist/src/services/task-manager.js.map +1 -0
  45. package/dist/src/services/task-persistence.d.ts +20 -0
  46. package/dist/src/services/task-persistence.js +67 -0
  47. package/dist/src/services/task-persistence.js.map +1 -0
  48. package/dist/src/services/task-store.d.ts +12 -0
  49. package/dist/src/services/task-store.js +167 -0
  50. package/dist/src/services/task-store.js.map +1 -0
  51. package/dist/src/services/workspace-isolation.d.ts +13 -0
  52. package/dist/src/services/workspace-isolation.js +74 -0
  53. package/dist/src/services/workspace-isolation.js.map +1 -0
  54. package/dist/src/templates/agent-prompt.d.ts +6 -0
  55. package/dist/src/templates/agent-prompt.js +58 -0
  56. package/dist/src/templates/agent-prompt.js.map +1 -0
  57. package/dist/src/types/task.d.ts +79 -0
  58. package/dist/src/types/task.js +22 -0
  59. package/dist/src/types/task.js.map +1 -0
  60. package/package.json +63 -0
  61. package/src/app.ts +341 -0
  62. package/src/cli/doctor.ts +112 -0
  63. package/src/config/defaults.ts +3 -0
  64. package/src/index.ts +128 -0
  65. package/src/mcp/system-status.ts +41 -0
  66. package/src/mcp/task-markdown.ts +81 -0
  67. package/src/mcp/tool-banners.ts +32 -0
  68. package/src/mcp/tool-definitions.ts +151 -0
  69. package/src/services/copilot-runtime.ts +247 -0
  70. package/src/services/output-log.ts +68 -0
  71. package/src/services/profile-manager.ts +165 -0
  72. package/src/services/question-registry.ts +169 -0
  73. package/src/services/spawn-validation.ts +75 -0
  74. package/src/services/task-manager.ts +144 -0
  75. package/src/services/task-persistence.ts +100 -0
  76. package/src/services/task-store.ts +207 -0
  77. package/src/services/workspace-isolation.ts +100 -0
  78. package/src/templates/agent-prompt.ts +71 -0
  79. package/src/types/task.ts +95 -0
@@ -0,0 +1,53 @@
1
+ import { stat } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ const MAX_CONTEXT_FILES = 20;
4
+ const MAX_CONTEXT_FILE_BYTES = 200 * 1024;
5
+ const MAX_TOTAL_CONTEXT_BYTES = 500 * 1024;
6
+ const MIN_PROMPT_LENGTH = {
7
+ coder: 1000,
8
+ planner: 300,
9
+ researcher: 200,
10
+ tester: 300,
11
+ general: 200,
12
+ };
13
+ export async function validateSpawnAgentInput(args) {
14
+ const minimum = MIN_PROMPT_LENGTH[args.input.agent_type];
15
+ if (args.input.prompt.trim().length < minimum) {
16
+ throw new Error(`${args.input.agent_type} tasks require a prompt of at least ${minimum} characters`);
17
+ }
18
+ const inputFiles = args.input.context_files;
19
+ if (args.input.agent_type === 'coder' && (inputFiles?.length ?? 0) < 1) {
20
+ throw new Error('coder tasks require at least one context_files entry');
21
+ }
22
+ if (!inputFiles || inputFiles.length === 0) {
23
+ return { contextFiles: undefined };
24
+ }
25
+ if (inputFiles.length > MAX_CONTEXT_FILES) {
26
+ throw new Error(`context_files may contain at most ${MAX_CONTEXT_FILES} files`);
27
+ }
28
+ const normalized = [];
29
+ let totalBytes = 0;
30
+ for (const file of inputFiles) {
31
+ const absolutePath = resolve(args.baseCwd, file.path);
32
+ const info = await stat(absolutePath).catch(() => null);
33
+ if (!info) {
34
+ throw new Error(`Context file not found: ${file.path}`);
35
+ }
36
+ if (!info.isFile()) {
37
+ throw new Error(`Context file is not a regular file: ${file.path}`);
38
+ }
39
+ if (info.size > MAX_CONTEXT_FILE_BYTES) {
40
+ throw new Error(`Context file exceeds 200KB: ${file.path}`);
41
+ }
42
+ totalBytes += info.size;
43
+ if (totalBytes > MAX_TOTAL_CONTEXT_BYTES) {
44
+ throw new Error('Combined context_files size exceeds 500KB');
45
+ }
46
+ normalized.push({
47
+ path: absolutePath,
48
+ description: file.description,
49
+ });
50
+ }
51
+ return { contextFiles: normalized };
52
+ }
53
+ //# sourceMappingURL=spawn-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn-validation.js","sourceRoot":"","sources":["../../../src/services/spawn-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,sBAAsB,GAAG,GAAG,GAAG,IAAI,CAAC;AAC1C,MAAM,uBAAuB,GAAG,GAAG,GAAG,IAAI,CAAC;AAE3C,MAAM,iBAAiB,GAAkD;IACvE,KAAK,EAAE,IAAI;IACX,OAAO,EAAE,GAAG;IACZ,UAAU,EAAE,GAAG;IACf,MAAM,EAAE,GAAG;IACX,OAAO,EAAE,GAAG;CACb,CAAC;AAOF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,IAAiC;IAEjC,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,uCAAuC,OAAO,aAAa,CACpF,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;IAC5C,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,KAAK,OAAO,IAAI,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;IACrC,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,GAAG,iBAAiB,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,qCAAqC,iBAAiB,QAAQ,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,UAAU,GAAkB,EAAE,CAAC;IACrC,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,uCAAuC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,GAAG,sBAAsB,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC;QACxB,IAAI,UAAU,GAAG,uBAAuB,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AACtC,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { PersistedProfileState } from '../types/task.js';
2
+ import type { OutputLogService } from './output-log.js';
3
+ import { type LoadedWorkspaceState } from './task-persistence.js';
4
+ import type { CreateTaskInput, TaskRecord } from '../types/task.js';
5
+ export interface TaskManagerOptions {
6
+ storageRoot?: string | undefined;
7
+ outputLog: OutputLogService;
8
+ getProfiles?: (() => PersistedProfileState[]) | undefined;
9
+ }
10
+ type ExecutionBinding = {
11
+ abort?: () => Promise<void>;
12
+ cleanup?: () => Promise<void>;
13
+ };
14
+ export declare class TaskManager {
15
+ private readonly store;
16
+ private readonly storageRoot;
17
+ private readonly outputLog;
18
+ private readonly getProfiles;
19
+ private readonly executionBindings;
20
+ constructor(options: TaskManagerOptions);
21
+ load(cwd: string): Promise<LoadedWorkspaceState>;
22
+ getTask(taskId: string): TaskRecord | undefined;
23
+ getAllTasks(): TaskRecord[];
24
+ createTask(input: CreateTaskInput): Promise<TaskRecord>;
25
+ updateTask(taskId: string, updates: Partial<TaskRecord>): Promise<TaskRecord | undefined>;
26
+ appendOutput(taskId: string, line: string): Promise<void>;
27
+ releaseReadyTasks(): Promise<TaskRecord[]>;
28
+ registerExecution(taskId: string, binding: ExecutionBinding): Promise<void>;
29
+ clearExecution(taskId: string): Promise<void>;
30
+ cancelTask(taskId: string): Promise<boolean>;
31
+ clearAllTasks(): Promise<number>;
32
+ private persist;
33
+ }
34
+ export {};
@@ -0,0 +1,107 @@
1
+ import { TaskStore } from './task-store.js';
2
+ import { loadWorkspaceState, saveWorkspaceState, } from './task-persistence.js';
3
+ import { TaskStatus, isTerminalStatus } from '../types/task.js';
4
+ export class TaskManager {
5
+ store = new TaskStore();
6
+ storageRoot;
7
+ outputLog;
8
+ getProfiles;
9
+ executionBindings = new Map();
10
+ constructor(options) {
11
+ this.storageRoot = options.storageRoot;
12
+ this.outputLog = options.outputLog;
13
+ this.getProfiles = options.getProfiles;
14
+ }
15
+ async load(cwd) {
16
+ const restored = await loadWorkspaceState({ cwd, storageRoot: this.storageRoot });
17
+ for (const task of restored.tasks) {
18
+ this.store.importTask(task);
19
+ }
20
+ return restored;
21
+ }
22
+ getTask(taskId) {
23
+ return this.store.getTask(taskId);
24
+ }
25
+ getAllTasks() {
26
+ return this.store.getAllTasks();
27
+ }
28
+ async createTask(input) {
29
+ const task = this.store.createTask(input);
30
+ task.outputFilePath = await this.outputLog.create(task.cwd, task.id);
31
+ await this.persist(task.cwd);
32
+ return task;
33
+ }
34
+ async updateTask(taskId, updates) {
35
+ const task = this.store.updateTask(taskId, updates);
36
+ if (!task) {
37
+ return undefined;
38
+ }
39
+ if (task.outputFilePath && updates.status && isTerminalStatus(updates.status)) {
40
+ await this.outputLog.finalize(task.cwd, task.id, task.status, task.error);
41
+ }
42
+ await this.persist(task.cwd);
43
+ return task;
44
+ }
45
+ async appendOutput(taskId, line) {
46
+ const task = this.store.getTask(taskId);
47
+ if (!task) {
48
+ return;
49
+ }
50
+ task.output.push(line);
51
+ task.updatedAt = new Date().toISOString();
52
+ await this.outputLog.append(task.cwd, task.id, line);
53
+ await this.persist(task.cwd);
54
+ }
55
+ async releaseReadyTasks() {
56
+ const tasks = this.store.releaseReadyTasks();
57
+ if (tasks.length > 0) {
58
+ await this.persist(tasks[0].cwd);
59
+ }
60
+ return tasks;
61
+ }
62
+ async registerExecution(taskId, binding) {
63
+ this.executionBindings.set(taskId, binding);
64
+ }
65
+ async clearExecution(taskId) {
66
+ const binding = this.executionBindings.get(taskId);
67
+ if (!binding) {
68
+ return;
69
+ }
70
+ await binding.cleanup?.();
71
+ this.executionBindings.delete(taskId);
72
+ }
73
+ async cancelTask(taskId) {
74
+ const task = this.store.getTask(taskId);
75
+ if (!task || isTerminalStatus(task.status)) {
76
+ return false;
77
+ }
78
+ const binding = this.executionBindings.get(taskId);
79
+ await binding?.abort?.();
80
+ await this.clearExecution(taskId);
81
+ await this.updateTask(taskId, {
82
+ status: TaskStatus.CANCELLED,
83
+ endTime: new Date().toISOString(),
84
+ });
85
+ return true;
86
+ }
87
+ async clearAllTasks() {
88
+ const tasks = this.store.getAllTasks();
89
+ for (const task of tasks) {
90
+ await this.cancelTask(task.id).catch(() => { });
91
+ }
92
+ this.store.clear();
93
+ if (tasks[0]) {
94
+ await this.persist(tasks[0].cwd);
95
+ }
96
+ return tasks.length;
97
+ }
98
+ async persist(cwd) {
99
+ await saveWorkspaceState({
100
+ cwd,
101
+ storageRoot: this.storageRoot,
102
+ tasks: this.store.getAllTasks(),
103
+ profiles: this.getProfiles?.() ?? [],
104
+ });
105
+ }
106
+ }
107
+ //# sourceMappingURL=task-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-manager.js","sourceRoot":"","sources":["../../../src/services/task-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { PersistedProfileState, TaskRecord } from '../types/task.js';
2
+ export interface SaveWorkspaceStateInput {
3
+ cwd: string;
4
+ storageRoot?: string | undefined;
5
+ tasks: TaskRecord[];
6
+ profiles: PersistedProfileState[];
7
+ }
8
+ export interface LoadWorkspaceStateInput {
9
+ cwd: string;
10
+ storageRoot?: string | undefined;
11
+ }
12
+ export interface LoadedWorkspaceState {
13
+ tasks: TaskRecord[];
14
+ profiles: PersistedProfileState[];
15
+ }
16
+ export declare function defaultStorageRoot(): string;
17
+ export declare function getWorkspaceStatePath(cwd: string, storageRoot?: string): string;
18
+ export declare function saveWorkspaceState(input: SaveWorkspaceStateInput): Promise<void>;
19
+ export declare function loadWorkspaceState(input: LoadWorkspaceStateInput): Promise<LoadedWorkspaceState>;
20
+ export declare function deleteWorkspaceState(cwd: string, storageRoot?: string): Promise<void>;
@@ -0,0 +1,67 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { TaskStatus } from '../types/task.js';
6
+ const STORAGE_DIR_NAME = '.super-agents';
7
+ export function defaultStorageRoot() {
8
+ return join(homedir(), STORAGE_DIR_NAME);
9
+ }
10
+ export function getWorkspaceStatePath(cwd, storageRoot = defaultStorageRoot()) {
11
+ const digest = createHash('md5').update(cwd).digest('hex');
12
+ return join(storageRoot, `${digest}.json`);
13
+ }
14
+ function recoverTask(task) {
15
+ if (task.status === TaskStatus.RATE_LIMITED) {
16
+ return task;
17
+ }
18
+ if (task.status === TaskStatus.RUNNING ||
19
+ task.status === TaskStatus.PENDING ||
20
+ task.status === TaskStatus.WAITING ||
21
+ task.status === TaskStatus.WAITING_ANSWER) {
22
+ return {
23
+ ...task,
24
+ status: TaskStatus.FAILED,
25
+ error: 'Server restarted while task was active',
26
+ endTime: new Date().toISOString(),
27
+ updatedAt: new Date().toISOString(),
28
+ };
29
+ }
30
+ return task;
31
+ }
32
+ export async function saveWorkspaceState(input) {
33
+ const storageRoot = input.storageRoot ?? defaultStorageRoot();
34
+ const path = getWorkspaceStatePath(input.cwd, storageRoot);
35
+ const tempPath = `${path}.${Date.now().toString(36)}.${Math.random().toString(36).slice(2, 8)}.tmp`;
36
+ await mkdir(storageRoot, { recursive: true });
37
+ const payload = {
38
+ version: 1,
39
+ tasks: input.tasks,
40
+ profiles: input.profiles,
41
+ };
42
+ await writeFile(tempPath, JSON.stringify(payload, null, 2), 'utf8');
43
+ await rename(tempPath, path);
44
+ }
45
+ export async function loadWorkspaceState(input) {
46
+ const storageRoot = input.storageRoot ?? defaultStorageRoot();
47
+ const path = getWorkspaceStatePath(input.cwd, storageRoot);
48
+ try {
49
+ const raw = await readFile(path, 'utf8');
50
+ const parsed = JSON.parse(raw);
51
+ return {
52
+ tasks: parsed.tasks.map(recoverTask),
53
+ profiles: parsed.profiles ?? [],
54
+ };
55
+ }
56
+ catch {
57
+ return {
58
+ tasks: [],
59
+ profiles: [],
60
+ };
61
+ }
62
+ }
63
+ export async function deleteWorkspaceState(cwd, storageRoot) {
64
+ const path = getWorkspaceStatePath(cwd, storageRoot ?? defaultStorageRoot());
65
+ await unlink(path).catch(() => { });
66
+ }
67
+ //# sourceMappingURL=task-persistence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-persistence.js","sourceRoot":"","sources":["../../../src/services/task-persistence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { CreateTaskInput, TaskRecord } from '../types/task.js';
2
+ export declare class TaskStore {
3
+ private readonly tasks;
4
+ createTask(input: CreateTaskInput): TaskRecord;
5
+ getTask(taskId: string): TaskRecord | undefined;
6
+ getAllTasks(): TaskRecord[];
7
+ importTask(task: TaskRecord): void;
8
+ validateDependencies(dependsOn: string[], newTaskId?: string): string | null;
9
+ updateTask(taskId: string, updates: Partial<TaskRecord>): TaskRecord | undefined;
10
+ releaseReadyTasks(): TaskRecord[];
11
+ clear(): void;
12
+ }
@@ -0,0 +1,167 @@
1
+ import { uniqueNamesGenerator, adjectives, animals, NumberDictionary } from 'unique-names-generator';
2
+ import { TaskStatus, isTerminalStatus } from '../types/task.js';
3
+ const numberDictionary = NumberDictionary.generate({ min: 1, max: 9999 });
4
+ const VALID_TRANSITIONS = {
5
+ [TaskStatus.PENDING]: new Set([TaskStatus.RUNNING, TaskStatus.WAITING, TaskStatus.WAITING_ANSWER, TaskStatus.COMPLETED, TaskStatus.CANCELLED, TaskStatus.FAILED, TaskStatus.TIMED_OUT]),
6
+ [TaskStatus.WAITING]: new Set([TaskStatus.PENDING, TaskStatus.WAITING_ANSWER, TaskStatus.COMPLETED, TaskStatus.CANCELLED, TaskStatus.FAILED, TaskStatus.TIMED_OUT]),
7
+ [TaskStatus.RUNNING]: new Set([TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.CANCELLED, TaskStatus.RATE_LIMITED, TaskStatus.WAITING_ANSWER, TaskStatus.TIMED_OUT]),
8
+ [TaskStatus.WAITING_ANSWER]: new Set([TaskStatus.RUNNING, TaskStatus.FAILED, TaskStatus.CANCELLED, TaskStatus.TIMED_OUT]),
9
+ [TaskStatus.COMPLETED]: new Set(),
10
+ [TaskStatus.FAILED]: new Set(),
11
+ [TaskStatus.CANCELLED]: new Set(),
12
+ [TaskStatus.RATE_LIMITED]: new Set([TaskStatus.RUNNING, TaskStatus.FAILED, TaskStatus.CANCELLED, TaskStatus.TIMED_OUT]),
13
+ [TaskStatus.TIMED_OUT]: new Set(),
14
+ };
15
+ function generateTaskId(existingIds) {
16
+ let next = uniqueNamesGenerator({
17
+ dictionaries: [adjectives, animals, numberDictionary],
18
+ separator: '-',
19
+ style: 'lowerCase',
20
+ });
21
+ while (existingIds.has(next)) {
22
+ next = uniqueNamesGenerator({
23
+ dictionaries: [adjectives, animals, numberDictionary],
24
+ separator: '-',
25
+ style: 'lowerCase',
26
+ });
27
+ }
28
+ return next;
29
+ }
30
+ function dependenciesSatisfied(task, tasks) {
31
+ return (task.dependsOn ?? []).every((dependencyId) => tasks.get(dependencyId)?.status === TaskStatus.COMPLETED);
32
+ }
33
+ function circularDependencyPath(tasks, startId, newDependsOn) {
34
+ const visiting = new Set();
35
+ const visited = new Set();
36
+ const trail = [];
37
+ const visit = (taskId) => {
38
+ if (visiting.has(taskId)) {
39
+ const index = trail.indexOf(taskId);
40
+ return [...trail.slice(index), taskId];
41
+ }
42
+ if (visited.has(taskId)) {
43
+ return null;
44
+ }
45
+ visiting.add(taskId);
46
+ trail.push(taskId);
47
+ const dependsOn = taskId === startId && newDependsOn !== undefined
48
+ ? newDependsOn
49
+ : tasks.get(taskId)?.dependsOn ?? [];
50
+ for (const dependencyId of dependsOn) {
51
+ const cycle = visit(dependencyId);
52
+ if (cycle) {
53
+ return cycle;
54
+ }
55
+ }
56
+ trail.pop();
57
+ visiting.delete(taskId);
58
+ visited.add(taskId);
59
+ return null;
60
+ };
61
+ return visit(startId);
62
+ }
63
+ export class TaskStore {
64
+ tasks = new Map();
65
+ createTask(input) {
66
+ const id = generateTaskId(new Set(this.tasks.keys()));
67
+ const dependencyError = this.validateDependencies(input.dependsOn ?? [], id);
68
+ if (dependencyError) {
69
+ throw new Error(dependencyError);
70
+ }
71
+ const now = new Date().toISOString();
72
+ const task = {
73
+ id,
74
+ status: (input.dependsOn?.length ?? 0) > 0 ? TaskStatus.WAITING : TaskStatus.PENDING,
75
+ prompt: input.prompt,
76
+ cwd: input.cwd,
77
+ model: input.model,
78
+ agentType: input.agentType,
79
+ output: [],
80
+ startTime: now,
81
+ createdAt: now,
82
+ updatedAt: now,
83
+ labels: input.labels ?? [],
84
+ contextFiles: input.contextFiles ?? [],
85
+ dependsOn: input.dependsOn?.length ? [...input.dependsOn] : undefined,
86
+ timeoutMs: input.timeoutMs,
87
+ sessionId: input.sessionId,
88
+ parentTaskId: input.parentTaskId,
89
+ profileId: input.profileId,
90
+ profileConfigDir: input.profileConfigDir,
91
+ isolationMode: input.isolationMode,
92
+ baseCwd: input.baseCwd,
93
+ };
94
+ if (task.status === TaskStatus.WAITING && dependenciesSatisfied(task, this.tasks)) {
95
+ task.status = TaskStatus.PENDING;
96
+ }
97
+ this.tasks.set(task.id, task);
98
+ return task;
99
+ }
100
+ getTask(taskId) {
101
+ return this.tasks.get(taskId);
102
+ }
103
+ getAllTasks() {
104
+ return [...this.tasks.values()];
105
+ }
106
+ importTask(task) {
107
+ this.tasks.set(task.id, task);
108
+ }
109
+ validateDependencies(dependsOn, newTaskId) {
110
+ if (dependsOn.length === 0) {
111
+ return null;
112
+ }
113
+ if (new Set(dependsOn).size !== dependsOn.length) {
114
+ return 'Duplicate dependency IDs are not allowed';
115
+ }
116
+ if (newTaskId && dependsOn.includes(newTaskId)) {
117
+ return `Task '${newTaskId}' cannot depend on itself`;
118
+ }
119
+ for (const dependencyId of dependsOn) {
120
+ if (!this.tasks.has(dependencyId)) {
121
+ return `Dependency task '${dependencyId}' not found`;
122
+ }
123
+ }
124
+ if (newTaskId) {
125
+ const cycle = circularDependencyPath(this.tasks, newTaskId, dependsOn);
126
+ if (cycle) {
127
+ return `Circular dependency detected: ${cycle.join(' -> ')}`;
128
+ }
129
+ }
130
+ return null;
131
+ }
132
+ updateTask(taskId, updates) {
133
+ const task = this.tasks.get(taskId);
134
+ if (!task) {
135
+ return undefined;
136
+ }
137
+ if (updates.status && updates.status !== task.status) {
138
+ if (isTerminalStatus(task.status)) {
139
+ return task;
140
+ }
141
+ const allowed = VALID_TRANSITIONS[task.status];
142
+ if (!allowed.has(updates.status)) {
143
+ return task;
144
+ }
145
+ }
146
+ Object.assign(task, updates, { updatedAt: new Date().toISOString() });
147
+ return task;
148
+ }
149
+ releaseReadyTasks() {
150
+ const released = [];
151
+ for (const task of this.tasks.values()) {
152
+ if (task.status !== TaskStatus.WAITING) {
153
+ continue;
154
+ }
155
+ if (dependenciesSatisfied(task, this.tasks)) {
156
+ task.status = TaskStatus.PENDING;
157
+ task.updatedAt = new Date().toISOString();
158
+ released.push(task);
159
+ }
160
+ }
161
+ return released;
162
+ }
163
+ clear() {
164
+ this.tasks.clear();
165
+ }
166
+ }
167
+ //# sourceMappingURL=task-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-store.js","sourceRoot":"","sources":["../../../src/services/task-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export type IsolationMode = 'shared' | 'isolated';
2
+ export interface PreparedWorkspace {
3
+ cwd: string;
4
+ cleanupRequired: boolean;
5
+ mode: 'shared' | 'copy' | 'worktree';
6
+ }
7
+ export interface PrepareTaskWorkspaceInput {
8
+ baseCwd: string;
9
+ taskId: string;
10
+ isolationMode: IsolationMode;
11
+ }
12
+ export declare function prepareTaskWorkspace(input: PrepareTaskWorkspaceInput): Promise<PreparedWorkspace>;
13
+ export declare function cleanupPreparedWorkspace(workspace: PreparedWorkspace): Promise<void>;
@@ -0,0 +1,74 @@
1
+ import { cp, mkdir, readdir, rm } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ import { execFile } from 'node:child_process';
4
+ import { promisify } from 'node:util';
5
+ const execFileAsync = promisify(execFile);
6
+ const SKIP_NAMES = new Set(['.git', 'node_modules', '.super-agents', '.worktrees', 'worktrees', 'dist']);
7
+ export async function prepareTaskWorkspace(input) {
8
+ if (input.isolationMode === 'shared') {
9
+ return {
10
+ cwd: input.baseCwd,
11
+ cleanupRequired: false,
12
+ mode: 'shared',
13
+ };
14
+ }
15
+ const worktree = await tryCreateGitWorktree(input);
16
+ if (worktree) {
17
+ return worktree;
18
+ }
19
+ const copyRoot = join(input.baseCwd, '.super-agents', 'workspaces', input.taskId);
20
+ await mkdir(dirname(copyRoot), { recursive: true });
21
+ await rm(copyRoot, { recursive: true, force: true });
22
+ await mkdir(copyRoot, { recursive: true });
23
+ const topLevelEntries = await readdir(input.baseCwd);
24
+ for (const entry of topLevelEntries) {
25
+ if (SKIP_NAMES.has(entry)) {
26
+ continue;
27
+ }
28
+ await cp(join(input.baseCwd, entry), join(copyRoot, entry), {
29
+ recursive: true,
30
+ filter(source) {
31
+ return !SKIP_NAMES.has(source.split('/').pop() ?? '');
32
+ },
33
+ });
34
+ }
35
+ return {
36
+ cwd: copyRoot,
37
+ cleanupRequired: true,
38
+ mode: 'copy',
39
+ };
40
+ }
41
+ export async function cleanupPreparedWorkspace(workspace) {
42
+ if (!workspace.cleanupRequired || workspace.mode === 'shared') {
43
+ return;
44
+ }
45
+ await rm(workspace.cwd, { recursive: true, force: true });
46
+ }
47
+ async function tryCreateGitWorktree(input) {
48
+ try {
49
+ const { stdout: rootStdout } = await execFileAsync('git', ['rev-parse', '--show-toplevel'], {
50
+ cwd: input.baseCwd,
51
+ });
52
+ const gitRoot = rootStdout.trim();
53
+ if (!gitRoot) {
54
+ return null;
55
+ }
56
+ await execFileAsync('git', ['rev-parse', '--verify', 'HEAD'], {
57
+ cwd: gitRoot,
58
+ });
59
+ const worktreePath = join(gitRoot, '.worktrees', input.taskId);
60
+ await mkdir(dirname(worktreePath), { recursive: true });
61
+ await execFileAsync('git', ['worktree', 'add', '--detach', worktreePath, 'HEAD'], {
62
+ cwd: gitRoot,
63
+ });
64
+ return {
65
+ cwd: worktreePath,
66
+ cleanupRequired: true,
67
+ mode: 'worktree',
68
+ };
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ //# sourceMappingURL=workspace-isolation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-isolation.js","sourceRoot":"","sources":["../../../src/services/workspace-isolation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { AgentType, ContextFile } from '../types/task.js';
2
+ export declare function buildAgentPrompt(input: {
3
+ agentType: AgentType;
4
+ prompt: string;
5
+ contextFiles: ContextFile[];
6
+ }): Promise<string>;