@hdwebsoft/hdcode-agent-team 0.2.1 → 0.2.2

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 (2) hide show
  1. package/dist/index.js +86 -71
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -236,36 +236,38 @@ function createTeamTools(directory) {
236
236
  description: tool.schema.string().describe("Team description")
237
237
  },
238
238
  async execute(args) {
239
- const dir = teamDir(directory, args.teamName);
240
- if (await exists(join4(dir, "config.json"))) {
241
- return `Error: Team "${args.teamName}" already exists`;
242
- }
243
- await ensureDir(join4(dir, "tasks"));
244
- await ensureDir(join4(dir, "inboxes"));
245
- await ensureDir(join4(dir, "reports"));
246
- const now = Date.now();
247
- const leadId = `team-lead@${args.teamName}`;
248
- const config = {
249
- name: args.teamName,
250
- description: args.description,
251
- createdAt: now,
252
- leadAgentId: leadId,
253
- members: [
254
- {
255
- agentId: leadId,
256
- name: "team-lead",
257
- agentType: "team-lead",
258
- model: "unknown",
259
- planModeRequired: false,
260
- joinedAt: now,
261
- cwd: directory,
262
- isActive: true
263
- }
264
- ]
265
- };
266
- await writeJsonAtomic(join4(dir, "config.json"), config);
267
- await writeJsonAtomic(join4(dir, "inboxes", "team-lead.json"), []);
268
- return JSON.stringify(config, null, 2);
239
+ return withTeamLock(directory, args.teamName, async () => {
240
+ const dir = teamDir(directory, args.teamName);
241
+ if (await exists(join4(dir, "config.json"))) {
242
+ return `Error: Team "${args.teamName}" already exists`;
243
+ }
244
+ await ensureDir(join4(dir, "tasks"));
245
+ await ensureDir(join4(dir, "inboxes"));
246
+ await ensureDir(join4(dir, "reports"));
247
+ const now = Date.now();
248
+ const leadId = `team-lead@${args.teamName}`;
249
+ const config = {
250
+ name: args.teamName,
251
+ description: args.description,
252
+ createdAt: now,
253
+ leadAgentId: leadId,
254
+ members: [
255
+ {
256
+ agentId: leadId,
257
+ name: "team-lead",
258
+ agentType: "team-lead",
259
+ model: "unknown",
260
+ planModeRequired: false,
261
+ joinedAt: now,
262
+ cwd: directory,
263
+ isActive: true
264
+ }
265
+ ]
266
+ };
267
+ await writeJsonAtomic(join4(dir, "config.json"), config);
268
+ await writeJsonAtomic(join4(dir, "inboxes", "team-lead.json"), []);
269
+ return JSON.stringify(config, null, 2);
270
+ });
269
271
  }
270
272
  }),
271
273
  team_delete: tool({
@@ -274,12 +276,14 @@ function createTeamTools(directory) {
274
276
  teamName: tool.schema.string().describe("Team name to delete")
275
277
  },
276
278
  async execute(args) {
277
- const dir = teamDir(directory, args.teamName);
278
- if (!await exists(join4(dir, "config.json"))) {
279
- return `Error: Team "${args.teamName}" not found`;
280
- }
281
- await rm2(dir, { recursive: true, force: true });
282
- return `Team "${args.teamName}" deleted successfully`;
279
+ return withTeamLock(directory, args.teamName, async () => {
280
+ const dir = teamDir(directory, args.teamName);
281
+ if (!await exists(join4(dir, "config.json"))) {
282
+ return `Error: Team "${args.teamName}" not found`;
283
+ }
284
+ await rm2(dir, { recursive: true, force: true });
285
+ return `Team "${args.teamName}" deleted successfully`;
286
+ });
283
287
  }
284
288
  }),
285
289
  team_status: tool({
@@ -791,6 +795,24 @@ function createTaskTools(directory) {
791
795
  return `Error: Task "${args.taskId}" not found in team "${args.teamName}"`;
792
796
  }
793
797
  const task = await readJson(tPath);
798
+ const originalOwner = task.owner;
799
+ if (args.subject !== undefined)
800
+ task.subject = args.subject;
801
+ if (args.description !== undefined)
802
+ task.description = args.description;
803
+ if (args.activeForm !== undefined)
804
+ task.activeForm = args.activeForm;
805
+ if (args.owner !== undefined)
806
+ task.owner = args.owner;
807
+ if (args.metadata) {
808
+ let newMeta;
809
+ try {
810
+ newMeta = JSON.parse(args.metadata);
811
+ } catch {
812
+ return "Error: Invalid metadata JSON";
813
+ }
814
+ task.metadata = { ...task.metadata, ...newMeta };
815
+ }
794
816
  if (args.status) {
795
817
  const validTransitions = {
796
818
  pending: ["in_progress"],
@@ -819,7 +841,7 @@ function createTaskTools(directory) {
819
841
  if (args.status === "in_progress") {
820
842
  const fileScope = task.metadata?.fileScope;
821
843
  if (fileScope) {
822
- const agentId = args.owner || task.owner || "unknown";
844
+ const agentId = task.owner || "unknown";
823
845
  const reserveResult = await reserveFiles(directory, args.teamName, {
824
846
  agentId,
825
847
  taskId: task.id,
@@ -832,36 +854,22 @@ function createTaskTools(directory) {
832
854
  }
833
855
  }
834
856
  if (args.status === "completed") {
835
- const agentId = args.owner || task.owner;
836
- if (agentId) {
837
- await releaseByTask(directory, args.teamName, agentId, task.id);
857
+ if (originalOwner) {
858
+ await releaseByTask(directory, args.teamName, originalOwner, task.id);
838
859
  }
839
860
  }
840
861
  task.status = args.status;
841
862
  }
842
- if (args.subject !== undefined)
843
- task.subject = args.subject;
844
- if (args.description !== undefined)
845
- task.description = args.description;
846
- if (args.activeForm !== undefined)
847
- task.activeForm = args.activeForm;
848
- if (args.owner !== undefined)
849
- task.owner = args.owner;
850
- if (args.metadata) {
851
- let newMeta;
852
- try {
853
- newMeta = JSON.parse(args.metadata);
854
- } catch {
855
- return "Error: Invalid metadata JSON";
856
- }
857
- task.metadata = { ...task.metadata, ...newMeta };
858
- }
859
863
  if (args.addBlocks) {
860
864
  const result = parseStringArray(args.addBlocks, "addBlocks");
861
865
  if (typeof result === "string")
862
866
  return result;
863
867
  const allTasks = await loadAllTasks(directory, args.teamName);
864
868
  const taskMap = new Map(allTasks.map((t) => [t.id, t]));
869
+ for (const targetId of result) {
870
+ if (!taskMap.has(targetId))
871
+ return `Error: Task "${targetId}" not found — cannot add to blocks`;
872
+ }
865
873
  if (hasCycleViaBlocks(task.id, result, task.blockedBy, taskMap)) {
866
874
  return `Error: Circular dependency detected — cannot add blocks`;
867
875
  }
@@ -870,12 +878,10 @@ function createTaskTools(directory) {
870
878
  task.blocks.push(targetId);
871
879
  }
872
880
  const targetPath = taskFilePath(directory, args.teamName, targetId);
873
- if (await exists(targetPath)) {
874
- const target = await readJson(targetPath);
875
- if (!target.blockedBy.includes(task.id)) {
876
- target.blockedBy.push(task.id);
877
- await writeJsonAtomic(targetPath, target);
878
- }
881
+ const target = await readJson(targetPath);
882
+ if (!target.blockedBy.includes(task.id)) {
883
+ target.blockedBy.push(task.id);
884
+ await writeJsonAtomic(targetPath, target);
879
885
  }
880
886
  }
881
887
  }
@@ -885,6 +891,10 @@ function createTaskTools(directory) {
885
891
  return result;
886
892
  const allTasks = await loadAllTasks(directory, args.teamName);
887
893
  const taskMap = new Map(allTasks.map((t) => [t.id, t]));
894
+ for (const targetId of result) {
895
+ if (!taskMap.has(targetId))
896
+ return `Error: Task "${targetId}" not found — cannot add to blockedBy`;
897
+ }
888
898
  if (hasCycle(task.id, result, taskMap)) {
889
899
  return `Error: Circular dependency detected — cannot add blockedBy`;
890
900
  }
@@ -893,12 +903,10 @@ function createTaskTools(directory) {
893
903
  task.blockedBy.push(targetId);
894
904
  }
895
905
  const targetPath = taskFilePath(directory, args.teamName, targetId);
896
- if (await exists(targetPath)) {
897
- const target = await readJson(targetPath);
898
- if (!target.blocks.includes(task.id)) {
899
- target.blocks.push(task.id);
900
- await writeJsonAtomic(targetPath, target);
901
- }
906
+ const target = await readJson(targetPath);
907
+ if (!target.blocks.includes(task.id)) {
908
+ target.blocks.push(task.id);
909
+ await writeJsonAtomic(targetPath, target);
902
910
  }
903
911
  }
904
912
  }
@@ -1015,6 +1023,7 @@ function createMessageTools(directory) {
1015
1023
  const inboxesDir = join7(dir, "inboxes");
1016
1024
  await ensureDir(inboxesDir);
1017
1025
  const message = {
1026
+ type: args.type,
1018
1027
  from: sender,
1019
1028
  text: args.content,
1020
1029
  ...args.summary && { summary: args.summary },
@@ -1061,11 +1070,17 @@ function createMessageTools(directory) {
1061
1070
  },
1062
1071
  async execute(args) {
1063
1072
  const dir = teamDir(directory, args.teamName);
1064
- if (!await exists(join7(dir, "config.json"))) {
1073
+ const configPath = join7(dir, "config.json");
1074
+ if (!await exists(configPath)) {
1065
1075
  return `Error: Team "${args.teamName}" not found`;
1066
1076
  }
1067
1077
  const agentName = args.agent.includes("@") ? args.agent.split("@")[0] : args.agent;
1068
- const inboxPath = join7(dir, "inboxes", `${agentName}.json`);
1078
+ const config = await readJson(configPath);
1079
+ const member = config.members.find((m) => m.name === agentName || m.agentId === args.agent);
1080
+ if (!member) {
1081
+ return `Error: Agent "${args.agent}" not found in team "${args.teamName}"`;
1082
+ }
1083
+ const inboxPath = join7(dir, "inboxes", `${member.name}.json`);
1069
1084
  if (args.markRead) {
1070
1085
  return withTeamLock(directory, args.teamName, async () => {
1071
1086
  const allMessages = await readInbox(inboxPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hdwebsoft/hdcode-agent-team",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "OpenCode plugin for multi-agent team coordination — per-agent inboxes, task management with dependency tracking, file reservation/locking, and atomic mkdir-based concurrency control.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",