@ycodium-ai/plugin-team 0.2.4160 → 0.2.4162

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.
package/README.md CHANGED
@@ -50,8 +50,9 @@ on a remote seat; the release check was not exercised, and the other providers h
50
50
  provider-by-provider table is in the [team plugin](../../docs/internals/team-plugin.md#trial-run) page.
51
51
 
52
52
  Starting a goal also puts the goal on the board as a work item assigned to the lead, recorded
53
- with this plugin as its author. The lead does no item itself, merging and pushing included; when
54
- everything the goal waits on is finished, it checks the results and marks the goal item done,
53
+ with this plugin as its author. The lead does no item itself, merging and pushing included. While the
54
+ goal is open, a member's completed item wakes the lead for review without requiring a dependency on
55
+ the goal item. When all work is finished, it checks the results and marks the goal item done,
55
56
  and the team's Board view shows that item's state.
56
57
 
57
58
  Member conversations start without messages; each gets its first one when work is assigned to its member.
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ var __export = (target, all3) => {
8
8
  import { definePlugin } from "@ycodium-ai/plugin-api";
9
9
 
10
10
  // ../../packages/plugin-api/src/version.ts
11
- var PLUGIN_API_VERSION = 97;
11
+ var PLUGIN_API_VERSION = 99;
12
12
 
13
13
  // ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Pipeable.js
14
14
  var pipeArguments = (self, args2) => {
@@ -10932,6 +10932,12 @@ var decodeCompletion = decodeUnknownOption2(
10932
10932
  var openLeadItemsBlockedBy = (project2, workItemId, lead) => lead === void 0 ? [] : Object.entries(project2.items).filter(
10933
10933
  ([id]) => isAssignedOpen(project2, id, lead) && readFact(project2.blockers, id)?.includes(workItemId) === true
10934
10934
  );
10935
+ var hasOpenTeamGoal = (project2, review) => {
10936
+ const item = readFact(project2.items, review.workItemId);
10937
+ if (item === null) return false;
10938
+ const scope2 = scopeOfRecipient(project2, review.by, item.workLineId);
10939
+ return scope2 !== void 0 && scope2 === scopeForLine(project2, item.workLineId) && scope2.goalId !== void 0 && scope2.leadThreads?.includes(review.threadId) === true && isAssignedOpen(project2, teamGoalItemId(review.projectId, scope2.goalId), review.threadId);
10940
+ };
10935
10941
  function reviewOnUpdate(previous, next, event) {
10936
10942
  const decoded = decodeCompletion(event.payload);
10937
10943
  if (isNone2(decoded) || decoded.value.state.group !== "completed") return null;
@@ -10942,16 +10948,18 @@ function reviewOnUpdate(previous, next, event) {
10942
10948
  if (lead === void 0) return null;
10943
10949
  if (!isMember(next, by) || "threadId" in by && isLeadThread(next, by.threadId)) return null;
10944
10950
  const goals = openLeadItemsBlockedBy(next, workItemId, lead);
10945
- if (goals.length === 0 || goals.some(([id]) => isWorkable(next, id))) return null;
10946
- return {
10951
+ const review = {
10947
10952
  key: `review:${workItemId}:${lead}#${event.sequence}`,
10948
10953
  projectId,
10949
10954
  workItemId,
10950
10955
  threadId: lead,
10951
10956
  by
10952
10957
  };
10958
+ if (goals.some(([id]) => isWorkable(next, id)) || goals.length === 0 && !hasOpenTeamGoal(next, review))
10959
+ return null;
10960
+ return review;
10953
10961
  }
10954
- var isLiveReview = (project2, review) => isLeadThread(project2, review.threadId) && readFact(project2.items, review.workItemId)?.stateGroup === "completed" && openLeadItemsBlockedBy(project2, review.workItemId, review.threadId).length > 0;
10962
+ var isLiveReview = (project2, review) => isLeadThread(project2, review.threadId) && readFact(project2.items, review.workItemId)?.stateGroup === "completed" && (openLeadItemsBlockedBy(project2, review.workItemId, review.threadId).length > 0 || hasOpenTeamGoal(project2, review));
10955
10963
  var isReviewDue = (project2, key) => project2.pendingReviews?.some((review) => review.key === key && isLiveReview(project2, review)) === true;
10956
10964
  var dueReviews = (project2) => (project2.pendingReviews ?? []).filter((review) => isLiveReview(project2, review)).map((review) => {
10957
10965
  const item = readFact(project2.items, review.workItemId);
@@ -12114,7 +12122,7 @@ function withPause(project2, change, legacyEventId) {
12114
12122
 
12115
12123
  // src/runtime/wakeState.ts
12116
12124
  var WAKE_STATE_KEY = "wakes";
12117
- var WAKE_STATE_VERSION = 9;
12125
+ var WAKE_STATE_VERSION = 10;
12118
12126
  var WAKE_EVENTS = [
12119
12127
  "work.item-created",
12120
12128
  "work.item-updated",
@@ -12126,6 +12134,8 @@ var WAKE_EVENTS = [
12126
12134
  "work.item-dispatched",
12127
12135
  "plugin.event-appended",
12128
12136
  "thread.session-set",
12137
+ "thread.turn-start-requested",
12138
+ "thread.unarchived",
12129
12139
  // 线与线上成员的暂停:引擎的看板事实,派发闸读它(见 `linePauses` / `pausedMembers`)。
12130
12140
  "work.line-paused",
12131
12141
  "work.line-resumed",
@@ -12541,6 +12551,7 @@ function foldWakes(state, event) {
12541
12551
  }
12542
12552
 
12543
12553
  // src/runtime/wake.ts
12554
+ var decodeThread = decodeUnknownOption2(Struct({ threadId: String4 }));
12544
12555
  function startWakeRuntime(ctx, goals, options = {}) {
12545
12556
  const wakes = ctx.derivedState({
12546
12557
  key: WAKE_STATE_KEY,
@@ -12552,6 +12563,7 @@ function startWakeRuntime(ctx, goals, options = {}) {
12552
12563
  const worktrees = createMemberWorktreeLane(wakes, ctx.events);
12553
12564
  const hash2 = options.hash ?? stableHash;
12554
12565
  let pending = Promise.resolve();
12566
+ let queued;
12555
12567
  const readItem = async (projectId, workItemId) => {
12556
12568
  const result2 = await ctx.work.items.get({ projectId, workItemIds: [workItemId] });
12557
12569
  return result2.items.find((item) => item.workItemId === workItemId);
@@ -12586,7 +12598,7 @@ function startWakeRuntime(ctx, goals, options = {}) {
12586
12598
  {
12587
12599
  idle: facts.idle.map((threadId) => name({ threadId })),
12588
12600
  queued: facts.queued.map(
12589
- (queued) => `${workLabel(queued.workItemId, queued.sequenceId)}, assigned to ${name({ threadId: queued.threadId })}`
12601
+ (queued2) => `${workLabel(queued2.workItemId, queued2.sequenceId)}, assigned to ${name({ threadId: queued2.threadId })}`
12590
12602
  )
12591
12603
  }
12592
12604
  );
@@ -12690,7 +12702,12 @@ function startWakeRuntime(ctx, goals, options = {}) {
12690
12702
  }
12691
12703
  };
12692
12704
  const flush = () => {
12693
- const result2 = pending.then(execute);
12705
+ if (queued !== void 0) return queued;
12706
+ const result2 = pending.then(() => {
12707
+ queued = void 0;
12708
+ return execute();
12709
+ });
12710
+ queued = result2;
12694
12711
  pending = result2.then(
12695
12712
  () => void 0,
12696
12713
  () => void 0
@@ -12700,7 +12717,17 @@ function startWakeRuntime(ctx, goals, options = {}) {
12700
12717
  ctx.reactor({
12701
12718
  name: "team-wake",
12702
12719
  events: WAKE_EVENTS,
12703
- handle: (event) => event.type === "thread.session-set" || isRecoveryFact(event) ? Promise.resolve() : flush()
12720
+ handle: async (event) => {
12721
+ if (event.type === "thread.session-set" || isRecoveryFact(event)) return;
12722
+ if (event.type === "thread.turn-start-requested" || event.type === "thread.unarchived") {
12723
+ const thread = decodeThread(event.payload);
12724
+ if (isNone2(thread) || !dueWakes(await wakes.get()).some(
12725
+ (wake) => "threadId" in wake && wake.threadId === thread.value.threadId
12726
+ ))
12727
+ return;
12728
+ }
12729
+ await flush();
12730
+ }
12704
12731
  });
12705
12732
  const ready = flush();
12706
12733
  void ready.catch((error) => ctx.log?.warn("team wake catch-up failed", { error }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/plugin-team",
3
- "version": "0.2.4160",
3
+ "version": "0.2.4162",
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.4160",
37
+ "@ycodium-ai/plugin-api": "0.2.4162",
38
38
  "ycodium-system-text": "0.0.0"
39
39
  },
40
40
  "ycodium": {