@ycodium-ai/plugin-team 0.2.3306 → 0.2.3317

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 +65 -6
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -6872,6 +6872,13 @@ function findGoalMember(members, identity2) {
6872
6872
  (member) => "threadId" in identity2 ? "threadId" in member && member.threadId === identity2.threadId : "principalId" in member && member.principalId === identity2.principalId
6873
6873
  );
6874
6874
  }
6875
+ function assignedToGoalMember(goal, assignees) {
6876
+ const execution = goalExecution(goal);
6877
+ const members = execution.members.filter((member) => member.memberId !== execution.leadMemberId);
6878
+ return assignees.some(
6879
+ (assignee) => assignee.kind === "agent" ? findGoalMember(members, { threadId: assignee.threadId }) !== void 0 : assignee.kind === "remote-agent" ? findGoalMember(members, { principalId: assignee.principalId }) !== void 0 : false
6880
+ );
6881
+ }
6875
6882
 
6876
6883
  // src/domain/goalItem.ts
6877
6884
  var teamGoalItemId = (projectId, goalId) => `team-goal:${projectId}:${goalId}`;
@@ -7190,6 +7197,8 @@ var memberStuckRule = (leadThreadId) => {
7190
7197
  };
7191
7198
  var LEAD_STUCK_RULE = "When a member is stuck, answer in that item's comments before you next look in on members: give a concrete direction, split the item, or reassign it. A member is stuck when they mention you because they are stuck, and also when a comment of theirs reports a blocker, such as a test or error they cannot get past, even if it does not mention you. Do not just note it.";
7192
7199
  var LEAD_REPEATED_BLOCKER_RULE = "If, when you look in, a blocker a member reported is still there and their branch has no new commit since your last look-in, do not just ask for a work-in-progress commit: ask what they have tried and which exact line fails, then give a direction, or split or reassign the item.";
7200
+ var LEAD_CLAIM_CHECK_RULE = "Each time you look in on members, also check that every item you assigned has been moved to In Progress by the member it is assigned to, and that no two members are working on the same item; if an item has not been started or is being worked on twice, ask about it in its comments or reassign it.";
7201
+ var LEAD_SCHEDULE_CHECKIN_RULE = "Before you end a turn while any item of this goal is not done, including items still in Backlog and items assigned but not started, make sure your next look-in is scheduled: call list_wakes, and if no wake-up is waiting for you, call schedule_wake with delaySeconds of at most 900 and a note saying to look in on members. Nothing else wakes you while nobody has started an item.";
7193
7202
  var LEAD_SPLIT_RULE = "Use work_create_item to split the goal into a few work items: one item per task, with a clear action in the title. Members do not see this conversation or your goal, so put everything a member needs into the description: the deliverable, the constraints, and how to hand the work in. Create them without assignees.";
7194
7203
  var LEAD_OWN_ITEM_RULE = "If a work item for this goal is assigned to you, also record it as blocked by every item you create. Each time a member marks an item done you will be told, so check it then; when they are all done, mark that item done with work_update_item.";
7195
7204
  var LEAD_REBALANCE_RULE = "When a member has nothing in progress while another member has an item waiting in line that is not blocked, move one waiting item to the idle member with work_update_item.";
@@ -7226,6 +7235,7 @@ function leadBrief(goal, roster) {
7226
7235
  LEAD_STUCK_RULE,
7227
7236
  LEAD_CHECKPOINT_RULE,
7228
7237
  LEAD_REPEATED_BLOCKER_RULE,
7238
+ LEAD_CLAIM_CHECK_RULE,
7229
7239
  `Only after all dependencies are recorded, assign each item to exactly one member with work_update_item. For local members use assignees: [{ "kind": "agent", "threadId": "<threadId from the table>" }]. Assign work to members with no item in progress first; do not give one member two items while another is idle. An item assigned to a local member who already has work waits in line and wakes them after their current item is finished. Record dependencies before assigning so blocked work waits until it can start. ${LEAD_NO_MEMBER_TASKS}`,
7230
7240
  LEAD_REBALANCE_RULE,
7231
7241
  ...remoteMembers.length === 0 ? [] : [
@@ -7233,6 +7243,7 @@ function leadBrief(goal, roster) {
7233
7243
  "A comment that mentions a remote member, or replies to one of their comments, wakes them on their machine, so you can ask or answer them in work item comments. Once they mark an item done they stop working on it, so to send work back to a remote member you still reopen the item as described above."
7234
7244
  ],
7235
7245
  "Use work_list_items to check progress. When all work is complete, summarize the results here in one or two sentences.",
7246
+ LEAD_SCHEDULE_CHECKIN_RULE,
7236
7247
  "Members' worktrees and branches remain after the goal ends. After their work is merged into the main line, they can be deleted from the source control panel.",
7237
7248
  PERSON_MESSAGE_RULE,
7238
7249
  "If the work item tools are unavailable, tell the user directly that this project needs the board and project memory switches turned on first."
@@ -9838,6 +9849,58 @@ function startRecoveryRuntime(ctx, goals, state, worktrees) {
9838
9849
  return { ready, flush };
9839
9850
  }
9840
9851
 
9852
+ // src/runtime/leadCheckin.ts
9853
+ var LEAD_CHECKIN_REMINDER = `Your turn ended while work on this goal is still open, and no wake-up is scheduled for you. ${LEAD_SCHEDULE_CHECKIN_RULE}`;
9854
+ var OPEN_GROUPS = ["backlog", "unstarted", "started"];
9855
+ var settledThreadOf = (payload) => {
9856
+ const value = payload;
9857
+ return typeof value?.threadId === "string" && (value.session?.status === "ready" || value.session?.status === "idle") && value.session.activeTurnId === null ? value.threadId : null;
9858
+ };
9859
+ function startLeadCheckinRuntime(ctx, state, goals) {
9860
+ const check = async (threadId) => {
9861
+ const projects = await state.get();
9862
+ for (const [projectId, project2] of Object.entries(projects)) {
9863
+ if (!(project2.leadThreads ?? []).includes(threadId)) continue;
9864
+ const goal = await goals.read(projectId);
9865
+ if (goal === null) continue;
9866
+ const summary = await ctx.threads.execution.summary({ threadId, limit: 1 });
9867
+ if (summary.queue.length > 0 || summary.latestTurn?.state !== "completed") continue;
9868
+ const scheduled = await ctx.wakes.list({ threadId, state: "scheduled" });
9869
+ if (scheduled.wakes.length > 0) continue;
9870
+ const { items } = await readPages(
9871
+ Number.POSITIVE_INFINITY,
9872
+ (page) => ctx.work.items.list({ projectId, stateGroups: [...OPEN_GROUPS], ...page })
9873
+ );
9874
+ const open = items.filter(
9875
+ (item) => item.assignees.length === 0 ? item.createdBy.kind === "agent" && item.createdBy.threadId === threadId : assignedToGoalMember(goal, item.assignees)
9876
+ ).map((item) => `${item.workItemId}:${item.revision}`).sort();
9877
+ if (open.length === 0) continue;
9878
+ const fired = await ctx.wakes.list({ threadId, state: "fired" });
9879
+ const key = stableHash(`${projectId}
9880
+ ${open.join("\n")}
9881
+ fired:${fired.wakes.length}`);
9882
+ await deliverWake(ctx, {
9883
+ projectId,
9884
+ recipient: { threadId },
9885
+ requestId: `team-lead-checkin:${threadId}:${key}`,
9886
+ messageId: `team-lead-checkin-message:${threadId}:${key}`,
9887
+ text: LEAD_CHECKIN_REMINDER
9888
+ });
9889
+ }
9890
+ };
9891
+ ctx.reactor({
9892
+ name: "team-lead-checkin",
9893
+ events: ["thread.session-set"],
9894
+ handle: (event) => {
9895
+ const threadId = settledThreadOf(event.payload);
9896
+ if (threadId === null) return Promise.resolve();
9897
+ return check(threadId).catch((error) => {
9898
+ ctx.log.warn("team lead check-in reminder failed", { threadId, error });
9899
+ });
9900
+ }
9901
+ });
9902
+ }
9903
+
9841
9904
  // src/handbook/content.ts
9842
9905
  async function releaseRefs(memory, projectId, release) {
9843
9906
  return release === 0 ? [] : (await memory.handbook.releases.get({ projectId, release })).pages;
@@ -9891,12 +9954,7 @@ async function publicationRequiresAck(memory, projectId, input) {
9891
9954
  // src/handbook/waitingWork.ts
9892
9955
  async function hasUnassignedWork(items, projectId, goal) {
9893
9956
  const goalItemId = teamGoalItemId(projectId, goal.goalId);
9894
- const members = goalExecution(goal).members.filter(
9895
- (member) => member.memberId !== goal.leadMemberId
9896
- );
9897
- const waiting = (item) => item.workItemId !== goalItemId && !isClosed({ stateGroup: item.state.group }) && !item.assignees.some(
9898
- (assignee) => assignee.kind === "agent" ? findGoalMember(members, { threadId: assignee.threadId }) !== void 0 : assignee.kind === "remote-agent" ? findGoalMember(members, { principalId: assignee.principalId }) !== void 0 : false
9899
- );
9957
+ const waiting = (item) => item.workItemId !== goalItemId && !isClosed({ stateGroup: item.state.group }) && !assignedToGoalMember(goal, item.assignees);
9900
9958
  let cursor = null;
9901
9959
  do {
9902
9960
  const page = await items.list({
@@ -10666,6 +10724,7 @@ var index_default = definePlugin({
10666
10724
  registerBoardCommands(ctx, goals, rosters, wakes.state);
10667
10725
  registerDetailCommands(ctx, goals);
10668
10726
  startRecoveryRuntime(ctx, goals, wakes.state, wakes.worktrees);
10727
+ startLeadCheckinRuntime(ctx, wakes.state, goals);
10669
10728
  const handbook = startHandbookRuntime(ctx, { lane: wakes.worktrees, goals });
10670
10729
  registerHandbook(ctx, handbook);
10671
10730
  registerHandbookPanel(ctx, handbook);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/plugin-team",
3
- "version": "0.2.3306",
3
+ "version": "0.2.3317",
4
4
  "description": "A project team roster with members, a lead, and goals.",
5
5
  "keywords": [
6
6
  "teams",
@@ -34,7 +34,7 @@
34
34
  "tailwindcss": "^4.0.0",
35
35
  "typescript": "~6.0.3",
36
36
  "vite-plus": "0.2.2",
37
- "@ycodium-ai/plugin-api": "0.2.3306"
37
+ "@ycodium-ai/plugin-api": "0.2.0"
38
38
  },
39
39
  "ycodium": {
40
40
  "plugin": "./dist/index.js",