indus-swarms 0.1.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 (52) hide show
  1. package/AGENTS.md +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +119 -0
  4. package/docs/claude-parity.md +151 -0
  5. package/docs/field-notes-teams-setup.md +107 -0
  6. package/docs/smoke-test-plan.md +146 -0
  7. package/eslint.config.js +74 -0
  8. package/extensions/teams/README.md +23 -0
  9. package/extensions/teams/activity-tracker.ts +234 -0
  10. package/extensions/teams/cleanup.ts +31 -0
  11. package/extensions/teams/fs-lock.ts +87 -0
  12. package/extensions/teams/hooks.ts +363 -0
  13. package/extensions/teams/index.ts +18 -0
  14. package/extensions/teams/leader-attach-commands.ts +221 -0
  15. package/extensions/teams/leader-inbox.ts +214 -0
  16. package/extensions/teams/leader-info-commands.ts +140 -0
  17. package/extensions/teams/leader-lifecycle-commands.ts +559 -0
  18. package/extensions/teams/leader-messaging-commands.ts +148 -0
  19. package/extensions/teams/leader-plan-commands.ts +95 -0
  20. package/extensions/teams/leader-spawn-command.ts +149 -0
  21. package/extensions/teams/leader-task-commands.ts +435 -0
  22. package/extensions/teams/leader-team-command.ts +382 -0
  23. package/extensions/teams/leader-teams-tool.ts +1075 -0
  24. package/extensions/teams/leader.ts +925 -0
  25. package/extensions/teams/mailbox.ts +131 -0
  26. package/extensions/teams/model-policy.ts +142 -0
  27. package/extensions/teams/names.ts +121 -0
  28. package/extensions/teams/paths.ts +37 -0
  29. package/extensions/teams/protocol.ts +241 -0
  30. package/extensions/teams/spawn-types.ts +36 -0
  31. package/extensions/teams/task-store.ts +544 -0
  32. package/extensions/teams/team-attach-claim.ts +205 -0
  33. package/extensions/teams/team-config.ts +335 -0
  34. package/extensions/teams/team-discovery.ts +59 -0
  35. package/extensions/teams/teammate-rpc.ts +261 -0
  36. package/extensions/teams/teams-panel.ts +1186 -0
  37. package/extensions/teams/teams-style.ts +322 -0
  38. package/extensions/teams/teams-ui-shared.ts +89 -0
  39. package/extensions/teams/teams-widget.ts +212 -0
  40. package/extensions/teams/worker.ts +605 -0
  41. package/extensions/teams/worktree.ts +103 -0
  42. package/package.json +53 -0
  43. package/scripts/e2e-rpc-test.mjs +277 -0
  44. package/scripts/integration-claim-test.mts +157 -0
  45. package/scripts/integration-hooks-remediation-test.mts +382 -0
  46. package/scripts/integration-spawn-overrides-test.mts +398 -0
  47. package/scripts/integration-todo-test.mts +533 -0
  48. package/scripts/lib/pi-workers.ts +105 -0
  49. package/scripts/smoke-test.mts +764 -0
  50. package/scripts/start-tmux-team.sh +91 -0
  51. package/skills/agent-teams/SKILL.md +180 -0
  52. package/tsconfig.strict.json +22 -0
@@ -0,0 +1,382 @@
1
+ import type { ExtensionCommandContext, ExtensionContext } from "indusagi-coding-agent";
2
+ import { getTeamDir } from "./paths.js";
3
+ import {
4
+ handleTeamEnvCommand,
5
+ handleTeamIdCommand,
6
+ handleTeamListCommand,
7
+ } from "./leader-info-commands.js";
8
+ import { handleTeamAttachCommand, handleTeamDetachCommand } from "./leader-attach-commands.js";
9
+ import {
10
+ handleTeamCleanupCommand,
11
+ handleTeamDelegateCommand,
12
+ handleTeamKillCommand,
13
+ handleTeamPruneCommand,
14
+ handleTeamShutdownCommand,
15
+ handleTeamStopCommand,
16
+ handleTeamStyleCommand,
17
+ } from "./leader-lifecycle-commands.js";
18
+ import {
19
+ handleTeamBroadcastCommand,
20
+ handleTeamDmCommand,
21
+ handleTeamSendCommand,
22
+ handleTeamSteerCommand,
23
+ } from "./leader-messaging-commands.js";
24
+ import { handleTeamPlanCommand } from "./leader-plan-commands.js";
25
+ import { handleTeamSpawnCommand } from "./leader-spawn-command.js";
26
+ import { handleTeamTaskCommand } from "./leader-task-commands.js";
27
+ import type { SpawnTeammateFn } from "./spawn-types.js";
28
+ import type { TeamConfig } from "./team-config.js";
29
+ import type { TeamTask } from "./task-store.js";
30
+ import type { TeammateRpc } from "./teammate-rpc.js";
31
+ import type { TeamsStyle } from "./teams-style.js";
32
+
33
+ const TEAM_HELP_TEXT = [
34
+ "Usage:",
35
+ " /team id",
36
+ " /team env <name>",
37
+ " /team attach list",
38
+ " /team attach <teamId> [--claim]",
39
+ " /team detach",
40
+ " /team spawn <name> [fresh|branch] [shared|worktree] [plan] [--model <provider>/<modelId>] [--thinking <level>]",
41
+ " /team panel",
42
+ " /team send <name> <msg...>",
43
+ " /team dm <name> <msg...>",
44
+ " /team broadcast <msg...>",
45
+ " /team steer <name> <msg...>",
46
+ " /team stop <name> [reason...]",
47
+ " /team kill <name>",
48
+ " /team shutdown",
49
+ " /team shutdown <name> [reason...]",
50
+ " /team delegate [on|off]",
51
+ " /team style",
52
+ " /team style list",
53
+ " /team style <name>",
54
+ " /team style init <name> [extends <base>]",
55
+ " /team plan approve <name>",
56
+ " /team plan reject <name> [feedback...]",
57
+ " /team cleanup [--force]",
58
+ " /team prune [--all] # hide stale manual teammates (mark offline)",
59
+ " /team task add <text...>",
60
+ " /team task assign <id> <agent>",
61
+ " /team task unassign <id>",
62
+ " /team task list",
63
+ " /team task clear [completed|all] [--force]",
64
+ " /team task show <id>",
65
+ " /team task dep add <id> <depId>",
66
+ " /team task dep rm <id> <depId>",
67
+ " /team task dep ls <id>",
68
+ " /team task use <taskListId>",
69
+ ].join("\n");
70
+
71
+ export function getTeamHelpText(): string {
72
+ return TEAM_HELP_TEXT;
73
+ }
74
+
75
+ export async function handleTeamCommand(opts: {
76
+ args: string;
77
+ ctx: ExtensionCommandContext;
78
+ teammates: Map<string, TeammateRpc>;
79
+ getTeamConfig: () => TeamConfig | null;
80
+ getTasks: () => TeamTask[];
81
+ refreshTasks: () => Promise<void>;
82
+ renderWidget: () => void;
83
+ getTaskListId: () => string | null;
84
+ setTaskListId: (id: string) => void;
85
+ getActiveTeamId: () => string;
86
+ setActiveTeamId: (teamId: string) => void;
87
+ pendingPlanApprovals: Map<string, { requestId: string; name: string; taskId?: string }>;
88
+ getDelegateMode: () => boolean;
89
+ setDelegateMode: (next: boolean) => void;
90
+ getStyle: () => TeamsStyle;
91
+ setStyle: (next: TeamsStyle) => void;
92
+ spawnTeammate: SpawnTeammateFn;
93
+ openWidget: (ctx: ExtensionCommandContext) => Promise<void>;
94
+ getTeamsExtensionEntryPath: () => string | null;
95
+ shellQuote: (v: string) => string;
96
+ getCurrentCtx: () => ExtensionContext | null;
97
+ stopAllTeammates: (ctx: ExtensionContext, reason: string) => Promise<void>;
98
+ }): Promise<void> {
99
+ const {
100
+ args,
101
+ ctx,
102
+ teammates,
103
+ getTeamConfig,
104
+ getTasks,
105
+ refreshTasks,
106
+ renderWidget,
107
+ getTaskListId,
108
+ setTaskListId,
109
+ getActiveTeamId,
110
+ setActiveTeamId,
111
+ pendingPlanApprovals,
112
+ getDelegateMode,
113
+ setDelegateMode,
114
+ getStyle,
115
+ setStyle,
116
+ spawnTeammate,
117
+ openWidget,
118
+ getTeamsExtensionEntryPath,
119
+ shellQuote,
120
+ getCurrentCtx,
121
+ stopAllTeammates,
122
+ } = opts;
123
+
124
+ const style = getStyle();
125
+ const activeTeamId = getActiveTeamId();
126
+ const leadName = getTeamConfig()?.leadName ?? "team-lead";
127
+ const taskListId = getTaskListId();
128
+
129
+ const parts = args.trim().split(/\s+/).filter((p) => p.length > 0);
130
+ const [sub, ...rest] = parts;
131
+ if (!sub || sub === "help") {
132
+ ctx.ui.notify(getTeamHelpText(), "info");
133
+ return;
134
+ }
135
+
136
+ type TeamSubcommandHandler = () => Promise<void>;
137
+ const handlers: Record<string, TeamSubcommandHandler> = {
138
+ list: async () => {
139
+ await handleTeamListCommand({
140
+ ctx,
141
+ teammates,
142
+ getTeamConfig,
143
+ style,
144
+ refreshTasks,
145
+ renderWidget,
146
+ });
147
+ },
148
+
149
+ id: async () => {
150
+ await handleTeamIdCommand({
151
+ ctx,
152
+ teamId: activeTeamId,
153
+ taskListId,
154
+ leadName,
155
+ style,
156
+ });
157
+ },
158
+
159
+ env: async () => {
160
+ await handleTeamEnvCommand({
161
+ ctx,
162
+ rest,
163
+ teamId: activeTeamId,
164
+ taskListId,
165
+ leadName,
166
+ style,
167
+ getTeamsExtensionEntryPath,
168
+ shellQuote,
169
+ });
170
+ },
171
+
172
+ attach: async () => {
173
+ await handleTeamAttachCommand({
174
+ ctx,
175
+ rest,
176
+ defaultTeamId: ctx.sessionManager.getSessionId(),
177
+ teammates,
178
+ getActiveTeamId,
179
+ setActiveTeamId,
180
+ setStyle,
181
+ setTaskListId,
182
+ refreshTasks,
183
+ renderWidget,
184
+ });
185
+ },
186
+
187
+ detach: async () => {
188
+ await handleTeamDetachCommand({
189
+ ctx,
190
+ defaultTeamId: ctx.sessionManager.getSessionId(),
191
+ teammates,
192
+ getActiveTeamId,
193
+ setActiveTeamId,
194
+ setTaskListId,
195
+ refreshTasks,
196
+ renderWidget,
197
+ });
198
+ },
199
+
200
+ cleanup: async () => {
201
+ await handleTeamCleanupCommand({
202
+ ctx,
203
+ rest,
204
+ teamId: activeTeamId,
205
+ teammates,
206
+ refreshTasks,
207
+ getTasks,
208
+ renderWidget,
209
+ style,
210
+ });
211
+ },
212
+
213
+ prune: async () => {
214
+ await handleTeamPruneCommand({
215
+ ctx,
216
+ rest,
217
+ teamId: activeTeamId,
218
+ teammates,
219
+ getTeamConfig,
220
+ refreshTasks,
221
+ getTasks,
222
+ style,
223
+ renderWidget,
224
+ });
225
+ },
226
+
227
+ delegate: async () => {
228
+ await handleTeamDelegateCommand({
229
+ ctx,
230
+ rest,
231
+ getDelegateMode,
232
+ setDelegateMode,
233
+ renderWidget,
234
+ });
235
+ },
236
+
237
+ shutdown: async () => {
238
+ await handleTeamShutdownCommand({
239
+ ctx,
240
+ rest,
241
+ teamId: activeTeamId,
242
+ teammates,
243
+ getTeamConfig,
244
+ leadName,
245
+ style,
246
+ getCurrentCtx,
247
+ getActiveTeamId,
248
+ stopAllTeammates,
249
+ refreshTasks,
250
+ getTasks,
251
+ renderWidget,
252
+ });
253
+ },
254
+
255
+ spawn: async () => {
256
+ await handleTeamSpawnCommand({ ctx, rest, teammates, style, spawnTeammate });
257
+ },
258
+
259
+ style: async () => {
260
+ const teamDir = getTeamDir(activeTeamId);
261
+ await handleTeamStyleCommand({
262
+ ctx,
263
+ rest,
264
+ teamDir,
265
+ getStyle,
266
+ setStyle,
267
+ refreshTasks,
268
+ renderWidget,
269
+ });
270
+ },
271
+
272
+ panel: async () => {
273
+ await openWidget(ctx);
274
+ },
275
+
276
+ send: async () => {
277
+ await handleTeamSendCommand({
278
+ ctx,
279
+ rest,
280
+ teammates,
281
+ style,
282
+ renderWidget,
283
+ });
284
+ },
285
+
286
+ steer: async () => {
287
+ await handleTeamSteerCommand({
288
+ ctx,
289
+ rest,
290
+ teammates,
291
+ style,
292
+ renderWidget,
293
+ });
294
+ },
295
+
296
+ stop: async () => {
297
+ await handleTeamStopCommand({
298
+ ctx,
299
+ rest,
300
+ teamId: activeTeamId,
301
+ teammates,
302
+ leadName,
303
+ style,
304
+ refreshTasks,
305
+ getTasks,
306
+ renderWidget,
307
+ });
308
+ },
309
+
310
+ kill: async () => {
311
+ await handleTeamKillCommand({
312
+ ctx,
313
+ rest,
314
+ teamId: activeTeamId,
315
+ teammates,
316
+ leadName,
317
+ style,
318
+ taskListId,
319
+ refreshTasks,
320
+ renderWidget,
321
+ });
322
+ },
323
+
324
+ dm: async () => {
325
+ await handleTeamDmCommand({
326
+ ctx,
327
+ rest,
328
+ teamId: activeTeamId,
329
+ leadName,
330
+ style,
331
+ });
332
+ },
333
+
334
+ broadcast: async () => {
335
+ await handleTeamBroadcastCommand({
336
+ ctx,
337
+ rest,
338
+ teamId: activeTeamId,
339
+ teammates,
340
+ leadName,
341
+ style,
342
+ refreshTasks,
343
+ getTasks,
344
+ getTaskListId,
345
+ });
346
+ },
347
+
348
+ task: async () => {
349
+ await handleTeamTaskCommand({
350
+ ctx,
351
+ rest,
352
+ teamId: activeTeamId,
353
+ leadName,
354
+ style,
355
+ getTaskListId,
356
+ setTaskListId,
357
+ getTasks,
358
+ refreshTasks,
359
+ renderWidget,
360
+ });
361
+ },
362
+
363
+ plan: async () => {
364
+ await handleTeamPlanCommand({
365
+ ctx,
366
+ rest,
367
+ teamId: activeTeamId,
368
+ leadName,
369
+ style,
370
+ pendingPlanApprovals,
371
+ });
372
+ },
373
+ };
374
+
375
+ const normalizedSub = sub === "widget" ? "panel" : sub === "join" ? "attach" : sub;
376
+ const handler = handlers[normalizedSub];
377
+ if (!handler) {
378
+ ctx.ui.notify(`Unknown subcommand: ${sub}`, "error");
379
+ return;
380
+ }
381
+ await handler();
382
+ }