@ycodium-ai/plugin-team 0.2.3130 → 0.2.3168

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/dist/index.js CHANGED
@@ -151,6 +151,7 @@ function isObjectKeyword(input) {
151
151
  return typeof input === "object" && input !== null || isFunction(input);
152
152
  }
153
153
  var hasProperty = /* @__PURE__ */ dual(2, (self, property) => isObjectKeyword(self) && property in self);
154
+ var isTagged = /* @__PURE__ */ dual(2, (self, tag2) => hasProperty(self, "_tag") && self["_tag"] === tag2);
154
155
 
155
156
  // ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Hash.js
156
157
  var symbol = "~effect/interfaces/Hash";
@@ -6866,6 +6867,19 @@ function goalExecution(goal) {
6866
6867
  members: goal === null ? [] : [...goal.threads, ...goal.remoteMembers ?? []]
6867
6868
  };
6868
6869
  }
6870
+ function findGoalMember(members, identity2) {
6871
+ return members.find(
6872
+ (member) => "threadId" in identity2 ? "threadId" in member && member.threadId === identity2.threadId : "principalId" in member && member.principalId === identity2.principalId
6873
+ );
6874
+ }
6875
+
6876
+ // src/domain/goalItem.ts
6877
+ var teamGoalItemId = (projectId, goalId) => `team-goal:${projectId}:${goalId}`;
6878
+ var GOAL_ITEM_TITLE_MAX = 120;
6879
+ var goalItemTitle = (goal) => {
6880
+ const line = (goal.titleSeed ?? goal.goal).split(/\r?\n/u, 1)[0].trim();
6881
+ return line.length <= GOAL_ITEM_TITLE_MAX ? line : `${line.slice(0, GOAL_ITEM_TITLE_MAX - 1)}\u2026`;
6882
+ };
6869
6883
 
6870
6884
  // locales/en.json
6871
6885
  var en_default = {
@@ -6896,6 +6910,7 @@ var en_default = {
6896
6910
  retryCreate: "Retry creation",
6897
6911
  saving: "Saving\u2026",
6898
6912
  moveTo: "Move to\u2026",
6913
+ goalItem: "Goal",
6899
6914
  moveItem: "Move work item #{{number}}",
6900
6915
  moveItemTo: "Move work item #{{number}} to {{state}}",
6901
6916
  assignTo: "Assign to\u2026",
@@ -6938,6 +6953,18 @@ var en_default = {
6938
6953
  reply: "Reply",
6939
6954
  replyTo: "Reply to comment {{number}}",
6940
6955
  newComment: "Post a comment",
6956
+ commentHint: "To wake a member, choose it under Mention\u2026 (or type @), or choose Reply under its comment. Commenting on an open work item assigned to a remote member also wakes it.",
6957
+ mention: "Mention\u2026",
6958
+ mentionLabel: "Mention a member \u2014 {{comment}}",
6959
+ mentionMember: "Mention {{name}} \u2014 {{comment}}",
6960
+ mentionMemberSelected: "{{name}} (mentioned) \u2014 {{comment}}",
6961
+ mentionSelected: "{{name}} (mentioned)",
6962
+ mentionRemove: "Remove mention of {{name}} \u2014 {{comment}}",
6963
+ mentionNone: "Start a goal to mention members.",
6964
+ mentionNoneLabel: "Start a goal to mention members \u2014 {{comment}}",
6965
+ mentioned: "Mentioned: {{names}}",
6966
+ mentionSeparator: ", ",
6967
+ notAMember: "One of the mentioned members is not in the current goal. Remove it and try again.",
6941
6968
  send: "Send",
6942
6969
  sendComment: "Send comment",
6943
6970
  sendReply: "Send reply to comment {{number}}",
@@ -6997,12 +7024,16 @@ var en_default = {
6997
7024
  confirmStart: "Start new goal",
6998
7025
  cancel: "Cancel",
6999
7026
  noRoster: "No saved roster was found. Save the roster and choose a lead first.",
7027
+ noDefaultModel: "The lead's thread didn't start: this project has no default model. Choose one in the project settings under New threads \u2192 Model, then retry.",
7028
+ modelUnavailable: "The lead's thread didn't start: this project's default model isn't available on this machine. Check the provider, or choose another model in the project settings under New threads \u2192 Model, then retry.",
7000
7029
  invalidPayload: "Check the goal fields and try again.",
7001
7030
  invalidGoal: "The goal must be 1\u20134000 characters after trimming spaces.",
7002
7031
  invalidRequestId: "The request ID must be 1\u201364 letters, numbers, underscores, or hyphens.",
7003
7032
  loadFailed: "The current goal could not be loaded. Try reloading it.",
7004
7033
  startFailed: "The goal could not be fully started. Retry to finish creating the threads and sending the lead's brief.",
7005
- remoteMembers: "Remote members:"
7034
+ remoteMembers: "Remote members:",
7035
+ item: "Goal work item #{{number}}: {{state}}",
7036
+ openItem: "Open details for goal work item #{{number}}"
7006
7037
  },
7007
7038
  roster: {
7008
7039
  title: "Roster",
@@ -7130,7 +7161,7 @@ var PERSON_MESSAGE_RULE = "Send a message to the person only when you need their
7130
7161
  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.";
7131
7162
  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. When they are all done you will be told; then check the results and mark that item done with work_update_item.";
7132
7163
  var LEAD_SEND_BACK_RULE = "If a finished item is not acceptable, send it back: use work_update_item to set its state back to an open one (see work_list_states), and change its assignees too if someone else should redo it. Then say what is wrong in a comment with work_post_comment, mentioning the member.";
7133
- var LEAD_NO_MEMBER_TASKS = "Do not do members' tasks yourself.";
7164
+ var LEAD_NO_MEMBER_TASKS = "Do not do members' tasks yourself, and never assign an item you create to yourself: merging, pushing and integrating the work are member tasks too.";
7134
7165
  var tableCell = (value) => value.replace(/\|/g, "\\|").replace(/[\r\n]/g, " ");
7135
7166
  function leadBrief(goal, roster) {
7136
7167
  const localMembers = goal.threads.filter((thread) => thread.memberId !== goal.leadMemberId).map((thread) => {
@@ -7152,6 +7183,7 @@ function leadBrief(goal, roster) {
7152
7183
  ...localMembers,
7153
7184
  ...remoteMembers
7154
7185
  ].join("\n"),
7186
+ `This goal is on the board as work item "${teamGoalItemId(goal.projectId, goal.goalId)}", assigned to you so the person can see when it is finished. Do not claim it or work on it yourself.`,
7155
7187
  LEAD_SPLIT_RULE,
7156
7188
  'Then use work_add_relation with type "blocked_by" to record dependencies: the dependent workItemId is blocked by the prerequisite relatedWorkItemId.',
7157
7189
  LEAD_OWN_ITEM_RULE,
@@ -7211,7 +7243,15 @@ var StartGoalInput = Struct({
7211
7243
  var GoalRejection = Struct({
7212
7244
  _tag: Literal2("TeamGoalRejection"),
7213
7245
  commandType: Literal2("startGoal"),
7214
- code: Literals(["invalid-payload", "invalid-goal", "invalid-request-id", "no-roster"])
7246
+ code: Literals([
7247
+ "invalid-payload",
7248
+ "invalid-goal",
7249
+ "invalid-request-id",
7250
+ "no-roster",
7251
+ // 负责人会话起不来:项目没设默认型号,或设了但解析不出来(provider 不在)。目标不落事实。
7252
+ "no-default-model",
7253
+ "model-unavailable"
7254
+ ])
7215
7255
  });
7216
7256
  var StartGoalResult = Union2([
7217
7257
  Struct({
@@ -7227,6 +7267,7 @@ var rejectGoal = (code) => ({
7227
7267
  commandType: "startGoal",
7228
7268
  code
7229
7269
  });
7270
+ var isSelectionUnavailable = isTagged("ProviderSelectionError");
7230
7271
  var decodeInput = decodeUnknownOption2(StartGoalInput);
7231
7272
  var decodeEnvelope = decodeUnknownOption2(
7232
7273
  Struct({
@@ -7278,6 +7319,13 @@ function createGoalService(ctx, rosterService, options = {}) {
7278
7319
  if (!REQUEST_ID_PATTERN.test(input.requestId)) return rejectGoal("invalid-request-id");
7279
7320
  const roster = await rosterService.read(input.projectId);
7280
7321
  if (roster === null) return rejectGoal("no-roster");
7322
+ const project2 = await ctx.projects.get({ projectId: input.projectId });
7323
+ if (project2.defaultModelSelection == null) return rejectGoal("no-default-model");
7324
+ const selection = await ctx.providers.selection.resolve({ base: project2.defaultModelSelection }).catch((error) => {
7325
+ if (isSelectionUnavailable(error)) return null;
7326
+ throw error;
7327
+ });
7328
+ if (selection === null) return rejectGoal("model-unavailable");
7281
7329
  const key = requestKey(input.projectId, input.requestId);
7282
7330
  const leadThreadId = teamThreadId(input.projectId, input.requestId, null);
7283
7331
  const remoteMembers = roster.members.flatMap(
@@ -7304,17 +7352,14 @@ function createGoalService(ctx, rosterService, options = {}) {
7304
7352
  });
7305
7353
  await goals.get({ throughSequence: receipt.sequence });
7306
7354
  goal = readFact(await requests.get({ throughSequence: receipt.sequence }), key) ?? goal;
7307
- const project2 = await ctx.projects.get({ projectId: goal.projectId });
7308
- const selection = await ctx.providers.resolveSelection({ base: project2.defaultModelSelection });
7309
7355
  const orderedThreads = [
7310
7356
  ...goal.threads.filter((thread) => thread.memberId === goal.leadMemberId),
7311
7357
  ...goal.threads.filter((thread) => thread.memberId !== goal.leadMemberId)
7312
7358
  ];
7313
7359
  for (const thread of orderedThreads) {
7314
7360
  const name = roster.members.find((member) => member.memberId === thread.memberId)?.name ?? thread.memberId;
7315
- await ctx.commands.dispatch({
7316
- type: "thread.create",
7317
- commandId: `thread:${thread.threadId}`,
7361
+ await ctx.threads.create({
7362
+ requestId: `thread:${thread.threadId}`,
7318
7363
  threadId: thread.threadId,
7319
7364
  projectId: goal.projectId,
7320
7365
  title: `${name} \xB7 ${(goal.titleSeed ?? goal.goal).slice(0, 48)}`,
@@ -7331,10 +7376,17 @@ function createGoalService(ctx, rosterService, options = {}) {
7331
7376
  requestedBy: "agent",
7332
7377
  notificationPolicy: "activity-only"
7333
7378
  }
7334
- },
7335
- createdAt: goal.startedAt
7379
+ }
7336
7380
  });
7337
7381
  }
7382
+ await ctx.work.items.create({
7383
+ projectId: goal.projectId,
7384
+ workItemId: teamGoalItemId(goal.projectId, goal.goalId),
7385
+ requestId: `goal-item:${goal.projectId}:${goal.goalId}`,
7386
+ title: goalItemTitle(goal),
7387
+ description: goal.goal,
7388
+ assignees: [{ kind: "agent", threadId: leadThreadId }]
7389
+ });
7338
7390
  await ctx.threads.turns.start({
7339
7391
  requestId: `lead-turn:${goal.projectId}:${goal.goalId}`,
7340
7392
  threadId: leadThreadId,
@@ -7474,11 +7526,17 @@ var BoardItem = Struct({
7474
7526
  blockedByTotal: Number5,
7475
7527
  version: Number5
7476
7528
  });
7529
+ var BoardGoalItem = Struct({
7530
+ workItemId: String4,
7531
+ sequenceId: Number5,
7532
+ state: Struct({ stateId: String4, name: String4, group: String4 })
7533
+ });
7477
7534
  var BoardSnapshot = Struct({
7478
7535
  states: ArraySchema(BoardState),
7479
7536
  items: ArraySchema(BoardItem),
7480
7537
  // 当前目标与 goal 命令同一份形状;目标栏与看板都从这里读,同一个门铃刷新。
7481
7538
  goal: ReadGoalResult,
7539
+ goalItem: optionalKey2(BoardGoalItem),
7482
7540
  people: ArraySchema(BoardPerson),
7483
7541
  // 已保存名单里的成员;名字显示(含远端成员)读这里,名单编辑器的草稿另存。
7484
7542
  rosterMembers: ArraySchema(TeamMember),
@@ -7689,9 +7747,7 @@ var decodeRead2 = decodeUnknownSync(ReadBoardInput);
7689
7747
  var decodeCreate = decodeUnknownOption2(CreateItemInput);
7690
7748
  var decodeUpdate = decodeUnknownOption2(UpdateItemInput);
7691
7749
  function registerBoardCommands(ctx, goals, rosters, options = {}) {
7692
- const isMember2 = async (projectId, threadId) => goalExecution(await goals.read(projectId)).members.some(
7693
- (member) => "threadId" in member && member.threadId === threadId
7694
- );
7750
+ const isMember2 = async (projectId, threadId) => findGoalMember(goalExecution(await goals.read(projectId)).members, { threadId }) !== void 0;
7695
7751
  ctx.command({
7696
7752
  name: "board",
7697
7753
  scope: "read",
@@ -7714,7 +7770,8 @@ function registerBoardCommands(ctx, goals, rosters, options = {}) {
7714
7770
  // 认出当前读者只为把作者显示成「你」:读不出来就当没有,不连累整张看板。
7715
7771
  invocation.viewer?.communication.people.current({}).catch(() => null)
7716
7772
  ]);
7717
- const [remoteWork, { items: rows, truncated }] = await Promise.all([
7773
+ const goalItemId = goal === null ? null : teamGoalItemId(projectId, goal.goalId);
7774
+ const [remoteWork, { items: rows, truncated }, goalItem] = await Promise.all([
7718
7775
  Promise.all(
7719
7776
  (roster?.members ?? []).flatMap(
7720
7777
  (member) => member.principal === void 0 ? [] : [
@@ -7725,7 +7782,9 @@ function registerBoardCommands(ctx, goals, rosters, options = {}) {
7725
7782
  ]
7726
7783
  )
7727
7784
  ),
7728
- readPages(ITEM_LIMIT, (page) => ctx.work.items.list({ projectId, ...page }))
7785
+ readPages(ITEM_LIMIT, (page) => ctx.work.items.list({ projectId, ...page })),
7786
+ // 目标那件按号单读:看板只列最新的 500 件,目标那件可能不在里面。
7787
+ goalItemId === null ? void 0 : ctx.work.items.get({ projectId, workItemIds: [goalItemId] }).then(({ items: items2 }) => items2.find((item) => item.workItemId === goalItemId))
7729
7788
  ]);
7730
7789
  const enabled = (toolkit) => toolkitStates.toolkits.some((row) => row.toolkit === toolkit && row.enabled);
7731
7790
  const items = rows.map((item) => ({
@@ -7746,6 +7805,17 @@ function registerBoardCommands(ctx, goals, rosters, options = {}) {
7746
7805
  })).sort((a, b) => a.sequence - b.sequence),
7747
7806
  items,
7748
7807
  goal,
7808
+ ...goalItem === void 0 ? {} : {
7809
+ goalItem: {
7810
+ workItemId: goalItem.workItemId,
7811
+ sequenceId: goalItem.sequenceId,
7812
+ state: {
7813
+ stateId: goalItem.state.stateId,
7814
+ name: goalItem.state.name,
7815
+ group: goalItem.state.group
7816
+ }
7817
+ }
7818
+ },
7749
7819
  people: people.items.map((row) => ({
7750
7820
  key: personKey(row.person),
7751
7821
  displayName: row.displayName
@@ -7839,8 +7909,17 @@ var PostCommentInput = Struct({
7839
7909
  workItemId: String4,
7840
7910
  body: String4,
7841
7911
  parentId: optionalKey2(String4),
7912
+ mentions: optionalKey2(
7913
+ ArraySchema(
7914
+ Struct({
7915
+ threadId: optionalKey2(String4),
7916
+ principalId: optionalKey2(String4)
7917
+ })
7918
+ )
7919
+ ),
7842
7920
  requestId: String4
7843
7921
  });
7922
+ var mentionPrincipal = (mention) => mention.threadId !== void 0 ? mention.principalId === void 0 ? { kind: "agent", threadId: mention.threadId } : null : mention.principalId !== void 0 ? { kind: "remote-agent", principalId: mention.principalId } : null;
7844
7923
  var PostCommentResult = Union2([
7845
7924
  Struct({ commentId: String4 }),
7846
7925
  BoardRejection
@@ -7848,6 +7927,7 @@ var PostCommentResult = Union2([
7848
7927
  var DetailComment = Struct({
7849
7928
  commentId: String4,
7850
7929
  author: WorkIdentity,
7930
+ mentions: optionalKey2(ArraySchema(WorkIdentity)),
7851
7931
  body: NullOr(String4),
7852
7932
  parentId: NullOr(String4),
7853
7933
  createdAt: String4
@@ -7897,7 +7977,7 @@ var HISTORY_LIMIT = 200;
7897
7977
  var GET_BATCH_SIZE = 50;
7898
7978
  var decodeRead3 = decodeUnknownSync(ReadItemDetailInput);
7899
7979
  var decodePost = decodeUnknownOption2(PostCommentInput);
7900
- function registerDetailCommands(ctx) {
7980
+ function registerDetailCommands(ctx, goals) {
7901
7981
  ctx.command({
7902
7982
  name: "itemDetail",
7903
7983
  scope: "read",
@@ -7957,6 +8037,7 @@ function registerDetailCommands(ctx) {
7957
8037
  comments: comments.items.map((comment) => ({
7958
8038
  commentId: comment.commentId,
7959
8039
  author: workIdentity(comment.author),
8040
+ mentions: comment.mentions.map(workIdentity),
7960
8041
  body: comment.bodyState === "present" ? comment.body : null,
7961
8042
  parentId: comment.parentId,
7962
8043
  createdAt: comment.createdAt
@@ -8000,13 +8081,25 @@ function registerDetailCommands(ctx) {
8000
8081
  handle: async (payload, invocation) => {
8001
8082
  const decoded = decodePost(payload);
8002
8083
  if (isNone2(decoded)) return rejectWork("postComment", "invalid-payload");
8003
- const input = decoded.value;
8084
+ const { mentions, ...input } = decoded.value;
8004
8085
  const body = commentText(input.body);
8005
8086
  if (body === null) return rejectWork("postComment", "invalid-body");
8087
+ const principals = mentions?.flatMap((mention) => mentionPrincipal(mention) ?? []);
8088
+ if (principals?.length !== mentions?.length)
8089
+ return rejectWork("postComment", "invalid-payload");
8090
+ if (principals !== void 0 && principals.length > 0) {
8091
+ const members = goalExecution(await goals.read(input.projectId)).members;
8092
+ if (principals.some((principal) => findGoalMember(members, principal) === void 0))
8093
+ return rejectWork("postComment", "not-a-member");
8094
+ }
8006
8095
  const result2 = await writeWork(
8007
8096
  invocation,
8008
8097
  "postComment",
8009
- (work) => work.comments.post({ ...input, body })
8098
+ (work) => work.comments.post({
8099
+ ...input,
8100
+ body,
8101
+ ...principals === void 0 ? {} : { mentions: principals }
8102
+ })
8010
8103
  );
8011
8104
  return "code" in result2 ? result2 : { commentId: result2.result.commentId };
8012
8105
  }
@@ -8646,8 +8739,9 @@ var decodeRelease = decodeUnknownSync(
8646
8739
  );
8647
8740
  function callerMember(project2, caller) {
8648
8741
  if (caller === void 0) return void 0;
8649
- return goalExecution(project2.goal).members.find(
8650
- (member) => caller.kind === "thread" ? "threadId" in member && member.threadId === caller.threadId : "principalId" in member && member.principalId === caller.principalId
8742
+ return findGoalMember(
8743
+ goalExecution(project2.goal).members,
8744
+ caller.kind === "thread" ? { threadId: caller.threadId } : { principalId: caller.principalId }
8651
8745
  );
8652
8746
  }
8653
8747
  var hasAcknowledged = (project2, memberId, release) => readFact(readFact(project2.acknowledgements, memberId)?.releases ?? {}, String(release)) === true;
@@ -9017,6 +9111,8 @@ function startHandbookRuntime(ctx) {
9017
9111
  input.projectId
9018
9112
  );
9019
9113
  if (project2 === null || project2.requiredRelease === null) return { allowed: true };
9114
+ if (project2.goal !== null && input.workItemId === teamGoalItemId(input.projectId, project2.goal.goalId))
9115
+ return { allowed: true };
9020
9116
  for (const actor of input.added) {
9021
9117
  const caller = actor.kind === "human" ? void 0 : actor.kind === "agent" ? { kind: "thread", threadId: actor.threadId } : actor;
9022
9118
  const member = callerMember(project2, caller);
@@ -9200,14 +9296,14 @@ function registerHandbookPanel(ctx, runtime) {
9200
9296
  // src/index.ts
9201
9297
  var index_default = definePlugin({
9202
9298
  id: "team",
9203
- apiVersion: 14,
9299
+ apiVersion: 16,
9204
9300
  activate(ctx) {
9205
9301
  const rosters = createRosterService(ctx);
9206
9302
  registerRosterCommands(ctx, rosters);
9207
9303
  const goals = createGoalService(ctx, rosters);
9208
9304
  registerGoalCommands(ctx, goals);
9209
9305
  registerBoardCommands(ctx, goals, rosters);
9210
- registerDetailCommands(ctx);
9306
+ registerDetailCommands(ctx, goals);
9211
9307
  startWakeRuntime(ctx);
9212
9308
  const handbook = startHandbookRuntime(ctx);
9213
9309
  registerHandbook(ctx, handbook);
package/locales/en.json CHANGED
@@ -26,6 +26,7 @@
26
26
  "retryCreate": "Retry creation",
27
27
  "saving": "Saving…",
28
28
  "moveTo": "Move to…",
29
+ "goalItem": "Goal",
29
30
  "moveItem": "Move work item #{{number}}",
30
31
  "moveItemTo": "Move work item #{{number}} to {{state}}",
31
32
  "assignTo": "Assign to…",
@@ -68,6 +69,18 @@
68
69
  "reply": "Reply",
69
70
  "replyTo": "Reply to comment {{number}}",
70
71
  "newComment": "Post a comment",
72
+ "commentHint": "To wake a member, choose it under Mention… (or type @), or choose Reply under its comment. Commenting on an open work item assigned to a remote member also wakes it.",
73
+ "mention": "Mention…",
74
+ "mentionLabel": "Mention a member — {{comment}}",
75
+ "mentionMember": "Mention {{name}} — {{comment}}",
76
+ "mentionMemberSelected": "{{name}} (mentioned) — {{comment}}",
77
+ "mentionSelected": "{{name}} (mentioned)",
78
+ "mentionRemove": "Remove mention of {{name}} — {{comment}}",
79
+ "mentionNone": "Start a goal to mention members.",
80
+ "mentionNoneLabel": "Start a goal to mention members — {{comment}}",
81
+ "mentioned": "Mentioned: {{names}}",
82
+ "mentionSeparator": ", ",
83
+ "notAMember": "One of the mentioned members is not in the current goal. Remove it and try again.",
71
84
  "send": "Send",
72
85
  "sendComment": "Send comment",
73
86
  "sendReply": "Send reply to comment {{number}}",
@@ -127,12 +140,16 @@
127
140
  "confirmStart": "Start new goal",
128
141
  "cancel": "Cancel",
129
142
  "noRoster": "No saved roster was found. Save the roster and choose a lead first.",
143
+ "noDefaultModel": "The lead's thread didn't start: this project has no default model. Choose one in the project settings under New threads → Model, then retry.",
144
+ "modelUnavailable": "The lead's thread didn't start: this project's default model isn't available on this machine. Check the provider, or choose another model in the project settings under New threads → Model, then retry.",
130
145
  "invalidPayload": "Check the goal fields and try again.",
131
146
  "invalidGoal": "The goal must be 1–4000 characters after trimming spaces.",
132
147
  "invalidRequestId": "The request ID must be 1–64 letters, numbers, underscores, or hyphens.",
133
148
  "loadFailed": "The current goal could not be loaded. Try reloading it.",
134
149
  "startFailed": "The goal could not be fully started. Retry to finish creating the threads and sending the lead's brief.",
135
- "remoteMembers": "Remote members:"
150
+ "remoteMembers": "Remote members:",
151
+ "item": "Goal work item #{{number}}: {{state}}",
152
+ "openItem": "Open details for goal work item #{{number}}"
136
153
  },
137
154
  "roster": {
138
155
  "title": "Roster",
@@ -26,6 +26,7 @@
26
26
  "retryCreate": "重试创建",
27
27
  "saving": "保存中…",
28
28
  "moveTo": "移到…",
29
+ "goalItem": "目标",
29
30
  "moveItem": "移动工作项 #{{number}}",
30
31
  "moveItemTo": "将工作项 #{{number}} 移到 {{state}}",
31
32
  "assignTo": "指派给…",
@@ -68,6 +69,18 @@
68
69
  "reply": "回复",
69
70
  "replyTo": "回复第 {{number}} 条评论",
70
71
  "newComment": "发表评论",
72
+ "commentHint": "要叫醒成员,用「提及…」选择它(或输入 @),或在它的评论下点「回复」;在指派给远端成员、还没结束的工作项上评论也会叫醒它。",
73
+ "mention": "提及…",
74
+ "mentionLabel": "提及成员({{comment}})",
75
+ "mentionMember": "提及 {{name}}({{comment}})",
76
+ "mentionMemberSelected": "{{name}}(已提及)({{comment}})",
77
+ "mentionSelected": "{{name}}(已提及)",
78
+ "mentionRemove": "移除对 {{name}} 的提及({{comment}})",
79
+ "mentionNone": "先开始一个目标,才能提及成员。",
80
+ "mentionNoneLabel": "先开始一个目标,才能提及成员({{comment}})",
81
+ "mentioned": "提及:{{names}}",
82
+ "mentionSeparator": "、",
83
+ "notAMember": "被提及的成员里有人不在当前目标中,请移除后重试。",
71
84
  "send": "发送",
72
85
  "sendComment": "发送评论",
73
86
  "sendReply": "发送第 {{number}} 条评论的回复",
@@ -127,12 +140,16 @@
127
140
  "confirmStart": "开始新目标",
128
141
  "cancel": "取消",
129
142
  "noRoster": "没有已保存的名单,请先保存名单并选一名负责人。",
143
+ "noDefaultModel": "负责人会话没起来:这个项目没设默认模型。到项目设置的「新会话 → 模型」选一个,再点重试。",
144
+ "modelUnavailable": "负责人会话没起来:这个项目的默认模型在这台机器上用不了。检查一下 provider,或到项目设置的「新会话 → 模型」换一个,再点重试。",
130
145
  "invalidPayload": "请检查目标字段后重试。",
131
146
  "invalidGoal": "目标去掉首尾空白后需为 1 到 4000 个字符。",
132
147
  "invalidRequestId": "请求 ID 需为 1 到 64 个字母、数字、下划线或连字符。",
133
148
  "loadFailed": "未能载入当前目标,请重新载入。",
134
149
  "startFailed": "目标未能全部开始,请重试以补齐会话并给负责人发话。",
135
- "remoteMembers": "远端成员:"
150
+ "remoteMembers": "远端成员:",
151
+ "item": "目标工作项 #{{number}}:{{state}}",
152
+ "openItem": "打开目标工作项 #{{number}} 的详情"
136
153
  },
137
154
  "roster": {
138
155
  "title": "名单",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/plugin-team",
3
- "version": "0.2.3130",
3
+ "version": "0.2.3168",
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.3130"
37
+ "@ycodium-ai/plugin-api": "0.2.3168"
38
38
  },
39
39
  "ycodium": {
40
40
  "plugin": "./dist/index.js",