@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/README.md +5 -0
- package/assets/ui.js +26 -25
- package/dist/index.js +118 -22
- package/locales/en.json +18 -1
- package/locales/zh-CN.json +18 -1
- package/package.json +2 -2
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([
|
|
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.
|
|
7316
|
-
|
|
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
|
|
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
|
|
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({
|
|
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
|
|
8650
|
-
(
|
|
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:
|
|
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",
|
package/locales/zh-CN.json
CHANGED
|
@@ -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.
|
|
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.
|
|
37
|
+
"@ycodium-ai/plugin-api": "0.2.3168"
|
|
38
38
|
},
|
|
39
39
|
"ycodium": {
|
|
40
40
|
"plugin": "./dist/index.js",
|