@ycodium-ai/plugin-team 0.2.3576 → 0.2.3598

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
@@ -7268,6 +7268,7 @@ async function createGoalThread(ctx, goal, thread) {
7268
7268
  requestId: `thread:${thread.threadId}`,
7269
7269
  threadId: thread.threadId,
7270
7270
  projectId: goal.projectId,
7271
+ memberId: thread.memberId,
7271
7272
  title: goalThreadTitle(goal, thread.name),
7272
7273
  ...thread.selection,
7273
7274
  // 有意写死、不读默认档:带团队的 AI 要无人值守地干活,成员子会话按 YCO-337 只能与负责人同档或更严。
@@ -7290,6 +7291,7 @@ async function createTeamThread(ctx, thread) {
7290
7291
  requestId: `thread:${thread.threadId}`,
7291
7292
  threadId: thread.threadId,
7292
7293
  projectId: thread.projectId,
7294
+ memberId: thread.memberId,
7293
7295
  title: thread.title,
7294
7296
  ...thread.selection,
7295
7297
  runtimeMode: "full-access",
@@ -7411,6 +7413,16 @@ function registerGoalCommands(ctx, service2) {
7411
7413
  // src/watch.ts
7412
7414
  import * as NodeTimers from "node:timers";
7413
7415
 
7416
+ // src/domain/person.ts
7417
+ var personKey = (person) => person.kind === "account" ? `account:${person.userId}` : `local-owner:${person.environmentId}`;
7418
+ var samePerson = (a, b) => personKey(a) === personKey(b);
7419
+ var personOfMember = (member) => member.identity?.kind === "human" && member.identity.principal !== void 0 ? member.identity.principal : null;
7420
+ var currentPerson = async (invocation) => invocation.viewer === void 0 ? null : (await invocation.viewer.communication.people.current({})).person;
7421
+ async function personDisplayName(ctx, projectId, person, fallback) {
7422
+ const { items } = await ctx.communication.people.list({ projectId, limit: 100 });
7423
+ return items.find((item) => samePerson(item.person, person))?.displayName ?? fallback;
7424
+ }
7425
+
7414
7426
  // src/domain/roster.ts
7415
7427
  var MEMBER_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
7416
7428
  var MAX_NAME_LENGTH = 40;
@@ -7535,7 +7547,6 @@ var WorkIdentity = Struct({
7535
7547
  /** 人的稳定键(见 personKey),界面拿它到快照的人名表里找名字。 */
7536
7548
  personKey: optionalKey2(String4)
7537
7549
  });
7538
- var personKey = (principal) => principal.kind === "account" ? `account:${principal.userId}` : `local-owner:${principal.environmentId}`;
7539
7550
  var workIdentity = (value) => ({
7540
7551
  kind: value.kind,
7541
7552
  ...value.principalId === void 0 ? {} : { principalId: value.principalId },
@@ -9487,6 +9498,10 @@ var en_default = {
9487
9498
  kindAgentHint: "Runs with the provider and model you pick when the machine is this one. A member set to another machine fails its trial run: set it back to this machine, or skip the trial run, and it runs on this machine with the project's default model.",
9488
9499
  kindRemoteHint: "An agent that connects from another machine with its own credentials.",
9489
9500
  kindPersonHint: "A teammate. People are listed as members but do not run sessions.",
9501
+ thisIsMe: "This is me",
9502
+ thisIsMeHint: "When someone @-mentions this member in a team group, the message goes to your Sent to me.",
9503
+ boundToOther: "This member is another person. Only they can change this.",
9504
+ you: "You",
9490
9505
  name: "Name",
9491
9506
  memberTitle: "Title",
9492
9507
  responsibility: "Responsibility",
@@ -9533,6 +9548,7 @@ var en_default = {
9533
9548
  noDefaultModel: "This project has no default model. Choose one in the project settings under New threads \u2192 Model, then try again.",
9534
9549
  modelUnavailable: "The 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.",
9535
9550
  duplicateMember: "Another member already has this name or remote agent. Rename or remove that member first.",
9551
+ alreadyYou: "You are already {{name}} on this roster. Clear \u201CThis is me\u201D on {{name}} first.",
9536
9552
  staleVersion: "This member was changed elsewhere and has been reloaded. Review it and save again.",
9537
9553
  notFound: "This member no longer exists.",
9538
9554
  invalidState: "The member's state was changed elsewhere and has been reloaded.",
@@ -10090,6 +10106,7 @@ import {
10090
10106
  MEMBER_RESPONSIBILITY_MAX,
10091
10107
  MEMBER_TITLE_MAX
10092
10108
  } from "@ycodium-ai/plugin-api";
10109
+ var MAX_MEMBER_NAME_LENGTH = MEMBER_NAME_MAX;
10093
10110
  var MemberAvatar = Struct({ pattern: String4, color: String4 });
10094
10111
  var AgentChoice = Struct({
10095
10112
  environmentId: String4,
@@ -10104,6 +10121,8 @@ var MemberRow = Struct({
10104
10121
  avatar: NullOr(MemberAvatar),
10105
10122
  /** 远端 agent 成员绑的主体;本机 agent 与人是 null。 */
10106
10123
  remotePrincipalId: NullOr(String4),
10124
+ /** 人成员绑着的人是不是正在看这一页的人;没绑就没有这一项。 */
10125
+ person: optionalKey2(Literals(["me", "other"])),
10107
10126
  agent: NullOr(
10108
10127
  Struct({
10109
10128
  environmentId: String4,
@@ -10158,7 +10177,9 @@ var CreateMemberInput = Struct({
10158
10177
  avatar: optionalKey2(MemberAvatar),
10159
10178
  /** 给了就是远端 agent:绑这个主体。 */
10160
10179
  remotePrincipalId: optionalKey2(String4),
10161
- agent: optionalKey2(AgentChoice)
10180
+ agent: optionalKey2(AgentChoice),
10181
+ /** 人成员「这是我」:绑到发起这次调用的人。 */
10182
+ bindToMe: optionalKey2(Boolean3)
10162
10183
  });
10163
10184
  var UpdateMemberInput = Struct({
10164
10185
  ...projectAndRequest,
@@ -10168,7 +10189,9 @@ var UpdateMemberInput = Struct({
10168
10189
  ...memberTextFields,
10169
10190
  avatar: optionalKey2(MemberAvatar),
10170
10191
  clearAvatar: optionalKey2(Boolean3),
10171
- agent: optionalKey2(AgentChoice)
10192
+ agent: optionalKey2(AgentChoice),
10193
+ /** 人成员「这是我」:`true` 绑到发起这次调用的人,`false` 解绑。 */
10194
+ bindToMe: optionalKey2(Boolean3)
10172
10195
  });
10173
10196
  var MemberRefInput = Struct({ ...projectAndRequest, memberId: String4 });
10174
10197
  var ImportRosterInput = Struct({ projectId: String4 });
@@ -10646,24 +10669,30 @@ function startCoordinatorRuntime(ctx, deps) {
10646
10669
  }
10647
10670
 
10648
10671
  // src/members/snapshot.ts
10649
- var toMemberRow = (member, trial) => ({
10650
- memberId: member.memberId,
10651
- kind: member.kind,
10652
- name: member.name,
10653
- title: member.title,
10654
- responsibility: member.responsibility,
10655
- avatar: member.avatar === null ? null : { pattern: member.avatar.pattern, color: member.avatar.color },
10656
- remotePrincipalId: member.identity?.kind === "remote-agent" ? member.identity.principalId : null,
10657
- agent: member.agent === null ? null : {
10658
- environmentId: member.agent.environmentId,
10659
- instanceId: member.agent.modelSelection.instanceId,
10660
- model: member.agent.modelSelection.model
10661
- },
10662
- hasInstructions: member.workInstructionsRevision !== null,
10663
- version: member.version,
10664
- removed: member.removedAt !== null,
10665
- ...trial === null ? {} : { trial }
10666
- });
10672
+ var toMemberRow = (member, trial, viewer) => {
10673
+ const person = personOfMember(member);
10674
+ return {
10675
+ memberId: member.memberId,
10676
+ kind: member.kind,
10677
+ name: member.name,
10678
+ title: member.title,
10679
+ responsibility: member.responsibility,
10680
+ avatar: member.avatar === null ? null : { pattern: member.avatar.pattern, color: member.avatar.color },
10681
+ remotePrincipalId: member.identity?.kind === "remote-agent" ? member.identity.principalId : null,
10682
+ ...person === null ? {} : {
10683
+ person: viewer !== null && samePerson(person, viewer) ? "me" : "other"
10684
+ },
10685
+ agent: member.agent === null ? null : {
10686
+ environmentId: member.agent.environmentId,
10687
+ instanceId: member.agent.modelSelection.instanceId,
10688
+ model: member.agent.modelSelection.model
10689
+ },
10690
+ hasInstructions: member.workInstructionsRevision !== null,
10691
+ version: member.version,
10692
+ removed: member.removedAt !== null,
10693
+ ...trial === null ? {} : { trial }
10694
+ };
10695
+ };
10667
10696
  var legacyOffer = (stored) => ({
10668
10697
  revision: stored.roster.revision,
10669
10698
  leadMemberId: stored.roster.leadMemberId,
@@ -10673,10 +10702,10 @@ var legacyOffer = (stored) => ({
10673
10702
  principalId: member.principal?.principalId ?? null
10674
10703
  }))
10675
10704
  });
10676
- function membersSnapshot(view, trialOf = () => null) {
10705
+ function membersSnapshot(view, trialOf = () => null, viewer = null) {
10677
10706
  const { stored } = view;
10678
10707
  return {
10679
- members: view.members.map((member) => toMemberRow(member, trialOf(member.memberId))),
10708
+ members: view.members.map((member) => toMemberRow(member, trialOf(member.memberId), viewer)),
10680
10709
  lead: {
10681
10710
  memberId: stored?.version === 2 ? stored.roster.leadMemberId : null,
10682
10711
  revision: stored?.roster.revision ?? 0
@@ -10999,10 +11028,18 @@ function registerMemberCommands(ctx, rosters, writer, trials2) {
10999
11028
  name: "members",
11000
11029
  scope: "read",
11001
11030
  payloadSchema: payloadSchemaOf(ReadMembersInput),
11002
- handle: async (payload) => {
11031
+ handle: async (payload, invocation) => {
11003
11032
  const { projectId } = decodeReadMembers(payload);
11004
- const [view, trial] = await Promise.all([rosters.inspect(projectId), trials2.get()]);
11005
- return membersSnapshot(view, (memberId) => trialViewOf(recordOf(trial, projectId, memberId)));
11033
+ const [view, trial, viewer] = await Promise.all([
11034
+ rosters.inspect(projectId),
11035
+ trials2.get(),
11036
+ currentPerson(invocation)
11037
+ ]);
11038
+ return membersSnapshot(
11039
+ view,
11040
+ (memberId) => trialViewOf(recordOf(trial, projectId, memberId)),
11041
+ viewer
11042
+ );
11006
11043
  }
11007
11044
  });
11008
11045
  ctx.command({
@@ -11091,14 +11128,21 @@ function createMemberWriter(ctx, rosters, queue = createSerial()) {
11091
11128
  const serial = queue.run;
11092
11129
  const asPerson = (commandType, handler) => (payload, invocation) => serial(async () => {
11093
11130
  const person = invocation.asPerson;
11094
- return person === void 0 ? rejectMember(commandType, "needs-person") : handler(payload, person.members);
11131
+ return person === void 0 ? rejectMember(commandType, "needs-person") : handler(payload, person.members, invocation);
11095
11132
  });
11096
- const create = asPerson("createMember", async (payload, members) => {
11133
+ const meOf = async (commandType, invocation) => await currentPerson(invocation) ?? rejectMember(commandType, "needs-person");
11134
+ const create = asPerson("createMember", async (payload, members, invocation) => {
11097
11135
  const decoded = decodeCreate3(payload);
11098
11136
  if (isNone2(decoded)) return rejectMember("createMember", "invalid-payload");
11099
11137
  const input = decoded.value;
11100
- if (input.kind === "human" && (input.agent !== void 0 || input.remotePrincipalId !== void 0))
11138
+ if (input.kind === "human" ? input.agent !== void 0 || input.remotePrincipalId !== void 0 : input.bindToMe !== void 0)
11101
11139
  return rejectMember("createMember", "invalid-payload");
11140
+ let me;
11141
+ if (input.bindToMe === true) {
11142
+ const found = await meOf("createMember", invocation);
11143
+ if ("code" in found) return found;
11144
+ me = found;
11145
+ }
11102
11146
  const memberId = createdMemberId(input.projectId, input.requestId);
11103
11147
  let agent;
11104
11148
  if (input.kind === "agent") {
@@ -11125,17 +11169,29 @@ function createMemberWriter(ctx, rosters, queue = createSerial()) {
11125
11169
  ...input.avatar === void 0 ? {} : { avatar: input.avatar },
11126
11170
  ...input.workInstructions === void 0 ? {} : { workInstructions: input.workInstructions },
11127
11171
  ...input.remotePrincipalId === void 0 ? {} : { identity: { kind: "remote-agent", principalId: input.remotePrincipalId } },
11172
+ ...me === void 0 ? {} : { identity: { kind: "human", principal: me } },
11128
11173
  ...agent === void 0 ? {} : { agent }
11129
11174
  })
11130
11175
  );
11131
11176
  return "code" in result2 ? result2 : written(result2);
11132
11177
  });
11133
- const update = asPerson("updateMember", async (payload, members) => {
11178
+ const update = asPerson("updateMember", async (payload, members, invocation) => {
11134
11179
  const decoded = decodeUpdate3(payload);
11135
11180
  if (isNone2(decoded)) return rejectMember("updateMember", "invalid-payload");
11136
11181
  const input = decoded.value;
11137
11182
  if (input.avatar !== void 0 && input.clearAvatar === true)
11138
11183
  return rejectMember("updateMember", "invalid-payload");
11184
+ let identity2;
11185
+ if (input.bindToMe !== void 0) {
11186
+ const me = await meOf("updateMember", invocation);
11187
+ if ("code" in me) return me;
11188
+ const member = await findMember(ctx, input.projectId, input.memberId);
11189
+ if (member === null) return rejectMember("updateMember", "not-found");
11190
+ const held = personOfMember(member);
11191
+ if (held !== null && !samePerson(held, me))
11192
+ return rejectMember("updateMember", "bound-to-other");
11193
+ identity2 = input.bindToMe ? { kind: "human", principal: me } : null;
11194
+ }
11139
11195
  const result2 = await refused(
11140
11196
  "updateMember",
11141
11197
  () => members.update({
@@ -11148,7 +11204,8 @@ function createMemberWriter(ctx, rosters, queue = createSerial()) {
11148
11204
  ...input.responsibility === void 0 ? {} : { responsibility: input.responsibility },
11149
11205
  ...input.clearAvatar === true ? { avatar: null } : input.avatar === void 0 ? {} : { avatar: input.avatar },
11150
11206
  ...input.workInstructions === void 0 ? {} : { workInstructions: input.workInstructions },
11151
- ...input.agent === void 0 ? {} : { agent: toEngineAgent(input.agent) }
11207
+ ...input.agent === void 0 ? {} : { agent: toEngineAgent(input.agent) },
11208
+ ...identity2 === void 0 ? {} : { identity: identity2 }
11152
11209
  })
11153
11210
  );
11154
11211
  return "code" in result2 ? result2 : written(result2);
@@ -11694,7 +11751,15 @@ function startGroupDeliveryRuntime(ctx, wakes, now3 = () => runPromise2(map5(now
11694
11751
  };
11695
11752
  ctx.reactor({
11696
11753
  name: "team-group-delivery",
11697
- events: ["communication.group-message-sent", "work.line-restored", "plugin.event-appended"],
11754
+ // 成员建出或改了(人点「这是我」绑上)也补扫:停在待绑定的人目标立刻投到人。
11755
+ events: [
11756
+ "communication.group-message-sent",
11757
+ "work.line-restored",
11758
+ "plugin.event-appended",
11759
+ "member.created",
11760
+ "member.updated",
11761
+ "member.restored"
11762
+ ],
11698
11763
  handle: (event) => {
11699
11764
  const projectId = decodeProjectEvent(event.payload);
11700
11765
  if (isSome2(projectId)) return sweep(projectId.value.projectId);
@@ -11792,6 +11857,7 @@ function startMemberBindingRuntime(ctx, goals, rosters, wakes, trials2) {
11792
11857
  if (goal.workLineId !== void 0 && lead !== void 0)
11793
11858
  await createTeamThread(ctx, {
11794
11859
  projectId,
11860
+ memberId: member.memberId,
11795
11861
  threadId,
11796
11862
  parentThreadId: lead.threadId,
11797
11863
  title: goalThreadTitle(goal, member.name),
@@ -15184,14 +15250,78 @@ function startLineNameMirror(ctx, queue) {
15184
15250
  });
15185
15251
  }
15186
15252
 
15253
+ // src/team/freeName.ts
15254
+ var NAME_RETRIES = 3;
15255
+ var nameTag = (seed, attempt) => attempt === 0 ? "" : ` #${stableHash(`${seed}${attempt}`).slice(0, 4)}`;
15256
+ var withNameTag = (name, tag2) => {
15257
+ const base = name.trim().slice(0, MAX_MEMBER_NAME_LENGTH);
15258
+ return tag2 === "" ? base : `${base.slice(0, MAX_MEMBER_NAME_LENGTH - tag2.length)}${tag2}`;
15259
+ };
15260
+
15261
+ // src/team/ownerMember.ts
15262
+ async function ownerOf(ctx, threadId) {
15263
+ const createdBy = (await ctx.threads.get({ threadId })).createdBy ?? null;
15264
+ const person = createdBy === null ? { kind: "local-owner", environmentId: ctx.environment.id } : { kind: "account", userId: createdBy.userId };
15265
+ return { person, createdName: createdBy?.displayName ?? null };
15266
+ }
15267
+ async function boundOwnerMember(ctx, projectId, threadId) {
15268
+ const { person } = await ownerOf(ctx, threadId);
15269
+ const { items } = await readPages(
15270
+ Number.POSITIVE_INFINITY,
15271
+ (page) => ctx.members.list({ projectId, ...page })
15272
+ );
15273
+ return items.find((row) => {
15274
+ const held = row.kind === "human" && row.removedAt === null ? personOfMember(row) : null;
15275
+ return held !== null && samePerson(held, person);
15276
+ })?.memberId ?? null;
15277
+ }
15278
+ async function ensureOwnerMember(ctx, projectId, threadId, chosen) {
15279
+ if (chosen !== null) return chosen;
15280
+ const memberId = `person:${stableHash(JSON.stringify([projectId, threadId])).slice(0, 24)}`;
15281
+ const mine = await findMember(ctx, projectId, memberId);
15282
+ if (mine !== null) return mine.removedAt === null ? memberId : null;
15283
+ const { person, createdName } = await ownerOf(ctx, threadId);
15284
+ const name = await personDisplayName(ctx, projectId, person, createdName);
15285
+ if (name === null) return null;
15286
+ for (let attempt = 0; ; attempt++) {
15287
+ const candidate = withNameTag(name, nameTag(threadId, attempt));
15288
+ try {
15289
+ await ctx.members.create({
15290
+ projectId,
15291
+ requestId: `team-owner-member:${mark(projectId, threadId, "owner")}:${attempt}`,
15292
+ memberId,
15293
+ kind: "human",
15294
+ name: candidate,
15295
+ identity: { kind: "human", principal: person }
15296
+ });
15297
+ return memberId;
15298
+ } catch (error) {
15299
+ const refusal = memberRefusal(error);
15300
+ if (refusal?.code !== "duplicate-member") throw error;
15301
+ const details = refusal.details;
15302
+ if (typeof details === "object" && details !== null && Reflect.get(details, "field") === "identity")
15303
+ return boundOwnerMember(ctx, projectId, threadId);
15304
+ if (attempt >= NAME_RETRIES) throw error;
15305
+ }
15306
+ }
15307
+ }
15308
+
15187
15309
  // src/team/open.ts
15188
15310
  var decodeOpen = decodeUnknownOption2(TeamOpenInput);
15311
+ var decodeOwner = decodeUnknownOption2(
15312
+ Struct({ ownerMemberId: NullOr(String4) })
15313
+ );
15189
15314
  function statusOf2(trials2, projectId, member) {
15190
15315
  if (member.kind === "human") return "human";
15191
15316
  const view = trialViewOf(recordOf(trials2, projectId, member.memberId));
15192
15317
  if (view === null) return "ready";
15193
15318
  return view.status === "passed" || view.status === "overridden" ? "ready" : view.status === "failed" ? "trial-failed" : "trial-pending";
15194
15319
  }
15320
+ function leadMemberName(leadName, title, tag2) {
15321
+ if (leadName !== void 0) return withNameTag(leadName, tag2);
15322
+ const tail = ` lead${tag2}`;
15323
+ return `${title.trim().slice(0, MAX_MEMBER_NAME_LENGTH - tail.length).trimEnd()}${tail}`.trim();
15324
+ }
15195
15325
  var remotePrincipalOf2 = (member) => member.identity?.kind === "remote-agent" ? member.identity.principalId : null;
15196
15326
  function createTeamOpener(ctx, deps, runner = createLineChangeRunner(ctx, deps), now3 = factTime) {
15197
15327
  const lineIdOf = (projectId, threadId, requestId) => `wl-${mark(projectId, threadId, requestId).slice(0, 24)}`;
@@ -15211,9 +15341,8 @@ function createTeamOpener(ctx, deps, runner = createLineChangeRunner(ctx, deps),
15211
15341
  ctx.projections.getThreadExecution(threadId)
15212
15342
  ]);
15213
15343
  if (execution === null) throw new TeamRuleError("not-local", teamMessage("notLocal"));
15214
- const base = (leadName ?? `${shell.title} lead`).trim().slice(0, 40);
15215
15344
  for (let attempt = 0; ; attempt++) {
15216
- const name = attempt === 0 ? base : `${base.slice(0, 33)} #${stableHash(`${threadId}${attempt}`).slice(0, 4)}`;
15345
+ const name = leadMemberName(leadName, shell.title, nameTag(threadId, attempt));
15217
15346
  try {
15218
15347
  await ctx.members.create({
15219
15348
  projectId,
@@ -15228,7 +15357,7 @@ function createTeamOpener(ctx, deps, runner = createLineChangeRunner(ctx, deps),
15228
15357
  });
15229
15358
  return memberId;
15230
15359
  } catch (error) {
15231
- if (hostRefusalCode(error) !== "duplicate-member" || attempt >= 3) throw error;
15360
+ if (hostRefusalCode(error) !== "duplicate-member" || attempt >= NAME_RETRIES) throw error;
15232
15361
  }
15233
15362
  }
15234
15363
  };
@@ -15265,6 +15394,17 @@ function createTeamOpener(ctx, deps, runner = createLineChangeRunner(ctx, deps),
15265
15394
  const local = rows.filter((row) => row.kind === "agent" && remotePrincipalOf2(row) === null);
15266
15395
  const selections = await resolveLocalSelections(projectId, local);
15267
15396
  const leadMemberId = await ensureLeadMember(projectId, callerThreadId, input.leadName);
15397
+ const ownerMemberId = await ensureOwnerMember(
15398
+ ctx,
15399
+ projectId,
15400
+ callerThreadId,
15401
+ match(decodeOwner(intent.input), {
15402
+ onNone: () => null,
15403
+ onSome: (recorded) => recorded.ownerMemberId
15404
+ })
15405
+ );
15406
+ const owner = ownerMemberId === null || rows.some((row) => row.memberId === ownerMemberId) ? null : await findMember(ctx, projectId, ownerMemberId);
15407
+ const team = owner === null ? rows : [owner, ...rows];
15268
15408
  try {
15269
15409
  const created = await ctx.work.lines.create({
15270
15410
  projectId,
@@ -15272,7 +15412,7 @@ function createTeamOpener(ctx, deps, runner = createLineChangeRunner(ctx, deps),
15272
15412
  workLineId,
15273
15413
  name,
15274
15414
  leadMemberId,
15275
- members: [leadMemberId, ...rows.map((row) => row.memberId)],
15415
+ members: [leadMemberId, ...team.map((row) => row.memberId)],
15276
15416
  threadId: callerThreadId
15277
15417
  });
15278
15418
  await ctx.events.append(baselineMirrored(projectId, workLineId, created.result.version));
@@ -15317,6 +15457,7 @@ function createTeamOpener(ctx, deps, runner = createLineChangeRunner(ctx, deps),
15317
15457
  for (const row of local) {
15318
15458
  await createTeamThread(ctx, {
15319
15459
  projectId,
15460
+ memberId: row.memberId,
15320
15461
  threadId: teamThreadId(projectId, goalId, row.memberId),
15321
15462
  parentThreadId: callerThreadId,
15322
15463
  title: goalThreadTitle(goal, row.name),
@@ -15335,7 +15476,7 @@ function createTeamOpener(ctx, deps, runner = createLineChangeRunner(ctx, deps),
15335
15476
  });
15336
15477
  await syncLineTitle(ctx, projectId, workLineId);
15337
15478
  const trials2 = await deps.trials.get();
15338
- const roster = rows.map((row) => {
15479
+ const roster = team.map((row) => {
15339
15480
  const principalId = remotePrincipalOf2(row);
15340
15481
  return {
15341
15482
  name: row.name,
@@ -15416,7 +15557,10 @@ function createTeamOpener(ctx, deps, runner = createLineChangeRunner(ctx, deps),
15416
15557
  projectId,
15417
15558
  rows.filter((row) => row.kind === "agent" && remotePrincipalOf2(row) === null)
15418
15559
  );
15419
- return input;
15560
+ return {
15561
+ ...input,
15562
+ ownerMemberId: await boundOwnerMember(ctx, projectId, callerThreadId)
15563
+ };
15420
15564
  }
15421
15565
  });
15422
15566
  };
@@ -16278,6 +16422,10 @@ var zh_CN_default = {
16278
16422
  kindAgentHint: "\u673A\u5668\u9009\u8FD9\u4E00\u53F0\u65F6\uFF0C\u7528\u4F60\u9009\u7684 provider \u548C\u6A21\u578B\u8FD0\u884C\u3002\u9009\u4E86\u522B\u7684\u673A\u5668\u7684\u6210\u5458\u8BD5\u8DD1\u4F1A\u51FA\u9519\uFF1A\u6539\u56DE\u8FD9\u4E00\u53F0\uFF0C\u6216\u8005\u8DF3\u8FC7\u8BD5\u8DD1\uFF0C\u5B83\u5C31\u5728\u8FD9\u53F0\u673A\u5668\u4E0A\u7528\u9879\u76EE\u7684\u9ED8\u8BA4\u6A21\u578B\u8FD0\u884C\u3002",
16279
16423
  kindRemoteHint: "\u4ECE\u53E6\u4E00\u53F0\u673A\u5668\u7528\u81EA\u5DF1\u7684\u51ED\u636E\u8FDE\u8FDB\u6765\u7684 agent\u3002",
16280
16424
  kindPersonHint: "\u56E2\u961F\u91CC\u7684\u4EBA\u3002\u4EBA\u4F1A\u5217\u5728\u6210\u5458\u91CC\uFF0C\u4F46\u4E0D\u4F1A\u8FD0\u884C\u4F1A\u8BDD\u3002",
16425
+ thisIsMe: "\u8FD9\u662F\u6211",
16426
+ thisIsMeHint: "\u6709\u4EBA\u5728\u56E2\u961F\u7FA4\u91CC @ \u8FD9\u4E2A\u6210\u5458\u65F6\uFF0C\u6D88\u606F\u4F1A\u8FDB\u4F60\u7684\u300C\u53D1\u7ED9\u6211\u7684\u300D\u3002",
16427
+ boundToOther: "\u8FD9\u4E2A\u6210\u5458\u662F\u53E6\u4E00\u4E2A\u4EBA\uFF0C\u53EA\u6709\u5BF9\u65B9\u672C\u4EBA\u80FD\u6539\u8FD9\u4E00\u9879\u3002",
16428
+ you: "\u6211",
16281
16429
  name: "\u540D\u5B57",
16282
16430
  memberTitle: "\u5934\u8854",
16283
16431
  responsibility: "\u804C\u8D23",
@@ -16324,6 +16472,7 @@ var zh_CN_default = {
16324
16472
  noDefaultModel: "\u8FD9\u4E2A\u9879\u76EE\u6CA1\u8BBE\u9ED8\u8BA4\u6A21\u578B\u3002\u5230\u9879\u76EE\u8BBE\u7F6E\u7684\u300C\u65B0\u4F1A\u8BDD \u2192 \u6A21\u578B\u300D\u9009\u4E00\u4E2A\uFF0C\u518D\u91CD\u8BD5\u3002",
16325
16473
  modelUnavailable: "\u8FD9\u4E2A\u9879\u76EE\u7684\u9ED8\u8BA4\u6A21\u578B\u5728\u8FD9\u53F0\u673A\u5668\u4E0A\u7528\u4E0D\u4E86\u3002\u68C0\u67E5\u4E00\u4E0B provider\uFF0C\u6216\u5230\u9879\u76EE\u8BBE\u7F6E\u7684\u300C\u65B0\u4F1A\u8BDD \u2192 \u6A21\u578B\u300D\u6362\u4E00\u4E2A\u3002",
16326
16474
  duplicateMember: "\u5DF2\u6709\u6210\u5458\u7528\u4E86\u8FD9\u4E2A\u540D\u5B57\u6216\u8FD9\u4E2A\u8FDC\u7AEF agent\uFF0C\u8BF7\u5148\u6539\u540D\u6216\u79FB\u9664\u5B83\u3002",
16475
+ alreadyYou: "\u4F60\u5728\u540D\u518C\u4E0A\u5DF2\u7ECF\u662F\u300C{{name}}\u300D\u4E86\uFF0C\u8BF7\u5148\u5728\u300C{{name}}\u300D\u90A3\u91CC\u53D6\u6D88\u300C\u8FD9\u662F\u6211\u300D\u3002",
16327
16476
  staleVersion: "\u8FD9\u540D\u6210\u5458\u5DF2\u88AB\u522B\u5904\u6539\u8FC7\uFF0C\u5DF2\u91CD\u65B0\u8F7D\u5165\u3002\u8BF7\u786E\u8BA4\u540E\u518D\u4FDD\u5B58\u3002",
16328
16477
  notFound: "\u8FD9\u540D\u6210\u5458\u5DF2\u4E0D\u5B58\u5728\u3002",
16329
16478
  invalidState: "\u8FD9\u540D\u6210\u5458\u7684\u72B6\u6001\u5DF2\u88AB\u522B\u5904\u6539\u8FC7\uFF0C\u5DF2\u91CD\u65B0\u8F7D\u5165\u3002",
@@ -16742,6 +16891,7 @@ async function ensureSession(env, record2, ensured, prepared) {
16742
16891
  if (parentThreadId !== void 0)
16743
16892
  await createTeamThread(ctx, {
16744
16893
  projectId: record2.projectId,
16894
+ memberId: record2.memberId,
16745
16895
  threadId: trialId,
16746
16896
  parentThreadId,
16747
16897
  title: member.name,
@@ -16752,6 +16902,7 @@ async function ensureSession(env, record2, ensured, prepared) {
16752
16902
  requestId: `thread:${trialId}`,
16753
16903
  threadId: trialId,
16754
16904
  projectId: record2.projectId,
16905
+ memberId: record2.memberId,
16755
16906
  title: member.name,
16756
16907
  ...selection,
16757
16908
  // 与旧目标的成员一致:不然试跑里的工具调用会卡在审批上。
@@ -17262,7 +17413,7 @@ function startTrialRuntime(ctx, deps, options = {}) {
17262
17413
  // src/index.ts
17263
17414
  var index_default = definePlugin({
17264
17415
  id: "team",
17265
- apiVersion: 47,
17416
+ apiVersion: 48,
17266
17417
  activate(ctx) {
17267
17418
  const trialState = ctx.derivedState(trialStateDefinition);
17268
17419
  const rosters = createRosterService(ctx);
package/locales/en.json CHANGED
@@ -236,6 +236,10 @@
236
236
  "kindAgentHint": "Runs with the provider and model you pick when the machine is this one. A member set to another machine fails its trial run: set it back to this machine, or skip the trial run, and it runs on this machine with the project's default model.",
237
237
  "kindRemoteHint": "An agent that connects from another machine with its own credentials.",
238
238
  "kindPersonHint": "A teammate. People are listed as members but do not run sessions.",
239
+ "thisIsMe": "This is me",
240
+ "thisIsMeHint": "When someone @-mentions this member in a team group, the message goes to your Sent to me.",
241
+ "boundToOther": "This member is another person. Only they can change this.",
242
+ "you": "You",
239
243
  "name": "Name",
240
244
  "memberTitle": "Title",
241
245
  "responsibility": "Responsibility",
@@ -282,6 +286,7 @@
282
286
  "noDefaultModel": "This project has no default model. Choose one in the project settings under New threads → Model, then try again.",
283
287
  "modelUnavailable": "The 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.",
284
288
  "duplicateMember": "Another member already has this name or remote agent. Rename or remove that member first.",
289
+ "alreadyYou": "You are already {{name}} on this roster. Clear “This is me” on {{name}} first.",
285
290
  "staleVersion": "This member was changed elsewhere and has been reloaded. Review it and save again.",
286
291
  "notFound": "This member no longer exists.",
287
292
  "invalidState": "The member's state was changed elsewhere and has been reloaded.",
@@ -236,6 +236,10 @@
236
236
  "kindAgentHint": "机器选这一台时,用你选的 provider 和模型运行。选了别的机器的成员试跑会出错:改回这一台,或者跳过试跑,它就在这台机器上用项目的默认模型运行。",
237
237
  "kindRemoteHint": "从另一台机器用自己的凭据连进来的 agent。",
238
238
  "kindPersonHint": "团队里的人。人会列在成员里,但不会运行会话。",
239
+ "thisIsMe": "这是我",
240
+ "thisIsMeHint": "有人在团队群里 @ 这个成员时,消息会进你的「发给我的」。",
241
+ "boundToOther": "这个成员是另一个人,只有对方本人能改这一项。",
242
+ "you": "我",
239
243
  "name": "名字",
240
244
  "memberTitle": "头衔",
241
245
  "responsibility": "职责",
@@ -282,6 +286,7 @@
282
286
  "noDefaultModel": "这个项目没设默认模型。到项目设置的「新会话 → 模型」选一个,再重试。",
283
287
  "modelUnavailable": "这个项目的默认模型在这台机器上用不了。检查一下 provider,或到项目设置的「新会话 → 模型」换一个。",
284
288
  "duplicateMember": "已有成员用了这个名字或这个远端 agent,请先改名或移除它。",
289
+ "alreadyYou": "你在名册上已经是「{{name}}」了,请先在「{{name}}」那里取消「这是我」。",
285
290
  "staleVersion": "这名成员已被别处改过,已重新载入。请确认后再保存。",
286
291
  "notFound": "这名成员已不存在。",
287
292
  "invalidState": "这名成员的状态已被别处改过,已重新载入。",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/plugin-team",
3
- "version": "0.2.3576",
3
+ "version": "0.2.3598",
4
4
  "description": "A project team roster with members, a lead, and goals.",
5
5
  "keywords": [
6
6
  "teams",
@@ -35,7 +35,7 @@
35
35
  "typescript": "~6.0.3",
36
36
  "vite-plus": "0.2.2",
37
37
  "ycodium-system-text": "0.0.0",
38
- "@ycodium-ai/plugin-api": "0.2.3576"
38
+ "@ycodium-ai/plugin-api": "0.2.3598"
39
39
  },
40
40
  "ycodium": {
41
41
  "plugin": "./dist/index.js",