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.
Files changed (149) hide show
  1. package/.windsurf/plans/persist-tasks-by-cwd.md +113 -0
  2. package/CHANGELOG.md +10 -0
  3. package/CLAUDE.md +67 -0
  4. package/README.md +124 -0
  5. package/build/config/timeouts.d.ts +12 -0
  6. package/build/config/timeouts.d.ts.map +1 -0
  7. package/build/config/timeouts.js +21 -0
  8. package/build/config/timeouts.js.map +1 -0
  9. package/build/index.d.ts +3 -0
  10. package/build/index.d.ts.map +1 -0
  11. package/build/index.js +116 -0
  12. package/build/index.js.map +1 -0
  13. package/build/models.d.ts +11 -0
  14. package/build/models.d.ts.map +1 -0
  15. package/build/models.js +22 -0
  16. package/build/models.js.map +1 -0
  17. package/build/services/client-context.d.ts +31 -0
  18. package/build/services/client-context.d.ts.map +1 -0
  19. package/build/services/client-context.js +44 -0
  20. package/build/services/client-context.js.map +1 -0
  21. package/build/services/copilot-switch.d.ts +36 -0
  22. package/build/services/copilot-switch.d.ts.map +1 -0
  23. package/build/services/copilot-switch.js +226 -0
  24. package/build/services/copilot-switch.js.map +1 -0
  25. package/build/services/process-spawner.d.ts +9 -0
  26. package/build/services/process-spawner.d.ts.map +1 -0
  27. package/build/services/process-spawner.js +475 -0
  28. package/build/services/process-spawner.js.map +1 -0
  29. package/build/services/retry-queue.d.ts +35 -0
  30. package/build/services/retry-queue.d.ts.map +1 -0
  31. package/build/services/retry-queue.js +125 -0
  32. package/build/services/retry-queue.js.map +1 -0
  33. package/build/services/task-manager.d.ts +124 -0
  34. package/build/services/task-manager.d.ts.map +1 -0
  35. package/build/services/task-manager.js +584 -0
  36. package/build/services/task-manager.js.map +1 -0
  37. package/build/services/task-persistence.d.ts +29 -0
  38. package/build/services/task-persistence.d.ts.map +1 -0
  39. package/build/services/task-persistence.js +158 -0
  40. package/build/services/task-persistence.js.map +1 -0
  41. package/build/templates/index.d.ts +11 -0
  42. package/build/templates/index.d.ts.map +1 -0
  43. package/build/templates/index.js +30 -0
  44. package/build/templates/index.js.map +1 -0
  45. package/build/tools/batch-spawn.d.ts +69 -0
  46. package/build/tools/batch-spawn.d.ts.map +1 -0
  47. package/build/tools/batch-spawn.js +150 -0
  48. package/build/tools/batch-spawn.js.map +1 -0
  49. package/build/tools/cancel-task.d.ts +21 -0
  50. package/build/tools/cancel-task.d.ts.map +1 -0
  51. package/build/tools/cancel-task.js +44 -0
  52. package/build/tools/cancel-task.js.map +1 -0
  53. package/build/tools/clear-tasks.d.ts +21 -0
  54. package/build/tools/clear-tasks.d.ts.map +1 -0
  55. package/build/tools/clear-tasks.js +43 -0
  56. package/build/tools/clear-tasks.js.map +1 -0
  57. package/build/tools/force-start.d.ts +21 -0
  58. package/build/tools/force-start.d.ts.map +1 -0
  59. package/build/tools/force-start.js +38 -0
  60. package/build/tools/force-start.js.map +1 -0
  61. package/build/tools/get-status.d.ts +31 -0
  62. package/build/tools/get-status.d.ts.map +1 -0
  63. package/build/tools/get-status.js +384 -0
  64. package/build/tools/get-status.js.map +1 -0
  65. package/build/tools/list-tasks.d.ts +26 -0
  66. package/build/tools/list-tasks.d.ts.map +1 -0
  67. package/build/tools/list-tasks.js +74 -0
  68. package/build/tools/list-tasks.js.map +1 -0
  69. package/build/tools/recover-task.d.ts +29 -0
  70. package/build/tools/recover-task.d.ts.map +1 -0
  71. package/build/tools/recover-task.js +91 -0
  72. package/build/tools/recover-task.js.map +1 -0
  73. package/build/tools/resume-task.d.ts +29 -0
  74. package/build/tools/resume-task.d.ts.map +1 -0
  75. package/build/tools/resume-task.js +43 -0
  76. package/build/tools/resume-task.js.map +1 -0
  77. package/build/tools/retry-task.d.ts +21 -0
  78. package/build/tools/retry-task.d.ts.map +1 -0
  79. package/build/tools/retry-task.js +52 -0
  80. package/build/tools/retry-task.js.map +1 -0
  81. package/build/tools/simulate-rate-limit.d.ts +25 -0
  82. package/build/tools/simulate-rate-limit.d.ts.map +1 -0
  83. package/build/tools/simulate-rate-limit.js +69 -0
  84. package/build/tools/simulate-rate-limit.js.map +1 -0
  85. package/build/tools/spawn-task.d.ts +57 -0
  86. package/build/tools/spawn-task.d.ts.map +1 -0
  87. package/build/tools/spawn-task.js +113 -0
  88. package/build/tools/spawn-task.js.map +1 -0
  89. package/build/tools/stream-output.d.ts +29 -0
  90. package/build/tools/stream-output.d.ts.map +1 -0
  91. package/build/tools/stream-output.js +96 -0
  92. package/build/tools/stream-output.js.map +1 -0
  93. package/build/types.d.ts +75 -0
  94. package/build/types.d.ts.map +1 -0
  95. package/build/types.js +12 -0
  96. package/build/types.js.map +1 -0
  97. package/build/utils/format.d.ts +29 -0
  98. package/build/utils/format.d.ts.map +1 -0
  99. package/build/utils/format.js +81 -0
  100. package/build/utils/format.js.map +1 -0
  101. package/build/utils/sanitize.d.ts +63 -0
  102. package/build/utils/sanitize.d.ts.map +1 -0
  103. package/build/utils/sanitize.js +28 -0
  104. package/build/utils/sanitize.js.map +1 -0
  105. package/build/utils/task-id-generator.d.ts +10 -0
  106. package/build/utils/task-id-generator.d.ts.map +1 -0
  107. package/build/utils/task-id-generator.js +22 -0
  108. package/build/utils/task-id-generator.js.map +1 -0
  109. package/docs/timeout-durability.md +28 -0
  110. package/package.json +39 -0
  111. package/plans/timeout-durability/00-overview.md +38 -0
  112. package/plans/timeout-durability/01-analysis.md +37 -0
  113. package/plans/timeout-durability/decisions.md +22 -0
  114. package/plans/timeout-durability/resources.md +24 -0
  115. package/plans/timeout-durability/step-01-timeout-flow.md +27 -0
  116. package/plans/timeout-durability/step-02-root-cause-map.md +26 -0
  117. package/plans/timeout-durability/step-03-state-schema.md +26 -0
  118. package/plans/timeout-durability/step-04-messaging-recovery.md +27 -0
  119. package/src/config/timeouts.ts +22 -0
  120. package/src/index.ts +129 -0
  121. package/src/models.ts +23 -0
  122. package/src/services/client-context.ts +49 -0
  123. package/src/services/copilot-switch.ts +269 -0
  124. package/src/services/process-spawner.ts +548 -0
  125. package/src/services/retry-queue.ts +151 -0
  126. package/src/services/task-manager.ts +667 -0
  127. package/src/services/task-persistence.ts +175 -0
  128. package/src/templates/index.ts +35 -0
  129. package/src/templates/super-coder.mdx +519 -0
  130. package/src/templates/super-planner.mdx +558 -0
  131. package/src/templates/super-researcher.mdx +394 -0
  132. package/src/templates/super-tester.mdx +688 -0
  133. package/src/tools/batch-spawn.ts +179 -0
  134. package/src/tools/cancel-task.ts +58 -0
  135. package/src/tools/clear-tasks.ts +52 -0
  136. package/src/tools/force-start.ts +48 -0
  137. package/src/tools/get-status.ts +480 -0
  138. package/src/tools/list-tasks.ts +83 -0
  139. package/src/tools/recover-task.ts +112 -0
  140. package/src/tools/resume-task.ts +51 -0
  141. package/src/tools/retry-task.ts +72 -0
  142. package/src/tools/simulate-rate-limit.ts +84 -0
  143. package/src/tools/spawn-task.ts +135 -0
  144. package/src/tools/stream-output.ts +101 -0
  145. package/src/types.ts +86 -0
  146. package/src/utils/format.ts +83 -0
  147. package/src/utils/sanitize.ts +35 -0
  148. package/src/utils/task-id-generator.ts +25 -0
  149. package/tsconfig.json +20 -0
@@ -0,0 +1,175 @@
1
+ import { createHash } from 'crypto';
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync } from 'fs';
3
+ import { homedir } from 'os';
4
+ import { join } from 'path';
5
+ import { TaskState, TaskStatus } from '../types.js';
6
+
7
+ const STORAGE_DIR_NAME = '.super-agents';
8
+
9
+ /**
10
+ * Get the storage directory path (~/.super-agents/)
11
+ */
12
+ export function getStorageDir(): string {
13
+ return join(homedir(), STORAGE_DIR_NAME);
14
+ }
15
+
16
+ /**
17
+ * Get MD5 hash of a string
18
+ */
19
+ export function hashCwd(cwd: string): string {
20
+ return createHash('md5').update(cwd).digest('hex');
21
+ }
22
+
23
+ /**
24
+ * Get the storage file path for a given cwd
25
+ * Returns: ~/.super-agents/{md5(cwd)}.json
26
+ */
27
+ export function getStoragePath(cwd: string): string {
28
+ return join(getStorageDir(), `${hashCwd(cwd)}.json`);
29
+ }
30
+
31
+ /**
32
+ * Ensure storage directory exists
33
+ */
34
+ function ensureStorageDir(): boolean {
35
+ try {
36
+ const dir = getStorageDir();
37
+ if (!existsSync(dir)) {
38
+ mkdirSync(dir, { recursive: true });
39
+ }
40
+ return true;
41
+ } catch (error) {
42
+ console.error(`[task-persistence] Failed to create storage directory: ${error}`);
43
+ return false;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Serialize tasks for persistence (excludes non-serializable fields)
49
+ */
50
+ function serializeTasks(tasks: TaskState[]): string {
51
+ const serializable = tasks.map(task => {
52
+ const { process, ...rest } = task as TaskState & { process?: unknown };
53
+ return rest;
54
+ });
55
+ return JSON.stringify(serializable, null, 2);
56
+ }
57
+
58
+ /**
59
+ * Mark orphaned running/pending tasks as failed (server crashed)
60
+ * Note: RATE_LIMITED tasks are preserved for auto-retry
61
+ */
62
+ function applyTaskDefaults(task: TaskState): TaskState {
63
+ const startTime = task.startTime || new Date().toISOString();
64
+ return {
65
+ ...task,
66
+ startTime,
67
+ lastHeartbeatAt: task.lastHeartbeatAt ?? startTime,
68
+ };
69
+ }
70
+
71
+ function recoverOrphanedTasks(tasks: TaskState[]): TaskState[] {
72
+ return tasks.map(task => {
73
+ // Keep rate-limited tasks as-is for auto-retry
74
+ if (task.status === TaskStatus.RATE_LIMITED) {
75
+ return applyTaskDefaults(task);
76
+ }
77
+
78
+ // Mark running/pending as failed (server crashed)
79
+ if (task.status === TaskStatus.RUNNING || task.status === TaskStatus.PENDING) {
80
+ const updated: TaskState = {
81
+ ...task,
82
+ status: TaskStatus.FAILED,
83
+ endTime: new Date().toISOString(),
84
+ error: 'Server restarted - task was interrupted',
85
+ timeoutReason: 'server_restart',
86
+ timeoutContext: {
87
+ detectedBy: 'startup_recovery',
88
+ },
89
+ };
90
+ return applyTaskDefaults(updated);
91
+ }
92
+ return applyTaskDefaults(task);
93
+ });
94
+ }
95
+
96
+ /**
97
+ * Save tasks to disk with atomic write
98
+ */
99
+ export function saveTasks(cwd: string, tasks: TaskState[]): boolean {
100
+ if (!ensureStorageDir()) {
101
+ return false;
102
+ }
103
+
104
+ const filePath = getStoragePath(cwd);
105
+ const tempPath = `${filePath}.tmp`;
106
+
107
+ try {
108
+ const data = serializeTasks(tasks);
109
+
110
+ // Atomic write: write to temp file, then rename
111
+ writeFileSync(tempPath, data, 'utf-8');
112
+ renameSync(tempPath, filePath);
113
+
114
+ return true;
115
+ } catch (error) {
116
+ console.error(`[task-persistence] Failed to save tasks: ${error}`);
117
+
118
+ // Clean up temp file if it exists
119
+ try {
120
+ if (existsSync(tempPath)) {
121
+ unlinkSync(tempPath);
122
+ }
123
+ } catch {
124
+ // Ignore cleanup errors
125
+ }
126
+
127
+ return false;
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Load tasks from disk
133
+ * Returns empty array if file doesn't exist or is corrupted
134
+ * Marks orphaned running tasks as failed
135
+ */
136
+ export function loadTasks(cwd: string): TaskState[] {
137
+ const filePath = getStoragePath(cwd);
138
+
139
+ if (!existsSync(filePath)) {
140
+ return [];
141
+ }
142
+
143
+ try {
144
+ const data = readFileSync(filePath, 'utf-8');
145
+ const tasks = JSON.parse(data) as TaskState[];
146
+
147
+ if (!Array.isArray(tasks)) {
148
+ console.error('[task-persistence] Invalid tasks file format, starting fresh');
149
+ return [];
150
+ }
151
+
152
+ // Recover orphaned tasks (server crashed while they were running)
153
+ return recoverOrphanedTasks(tasks);
154
+ } catch (error) {
155
+ console.error(`[task-persistence] Failed to load tasks (corrupted?), starting fresh: ${error}`);
156
+ return [];
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Delete storage file for a cwd (for testing/cleanup)
162
+ */
163
+ export function deleteStorage(cwd: string): boolean {
164
+ const filePath = getStoragePath(cwd);
165
+
166
+ try {
167
+ if (existsSync(filePath)) {
168
+ unlinkSync(filePath);
169
+ }
170
+ return true;
171
+ } catch (error) {
172
+ console.error(`[task-persistence] Failed to delete storage: ${error}`);
173
+ return false;
174
+ }
175
+ }
@@ -0,0 +1,35 @@
1
+ import { readFileSync } from 'fs';
2
+ import { fileURLToPath } from 'url';
3
+ import { dirname, join } from 'path';
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+
7
+ export const TASK_TYPES = {
8
+ 'super-coder': 'super coder for all coding tasks',
9
+ 'super-planner': 'super planner for all planning tasks',
10
+ 'super-researcher': 'super researcher for answering any question',
11
+ 'super-tester': 'super tester to test stuff properly',
12
+ } as const;
13
+
14
+ export type TaskType = keyof typeof TASK_TYPES;
15
+ export const TASK_TYPE_IDS = Object.keys(TASK_TYPES) as TaskType[];
16
+
17
+ const cache = new Map<TaskType, string>();
18
+
19
+ export function isValidTaskType(type: string): type is TaskType {
20
+ return type in TASK_TYPES;
21
+ }
22
+
23
+ export function applyTemplate(taskType: TaskType, userPrompt: string): string {
24
+ if (!cache.has(taskType)) {
25
+ try {
26
+ cache.set(taskType, readFileSync(join(__dirname, `${taskType}.mdx`), 'utf8'));
27
+ } catch {
28
+ return userPrompt;
29
+ }
30
+ }
31
+ const template = cache.get(taskType)!;
32
+ return template.includes('{{user_prompt}}')
33
+ ? template.replace('{{user_prompt}}', userPrompt)
34
+ : `${template}\n\n---\n\n${userPrompt}`;
35
+ }