@ycodium-ai/plugin-team 0.2.3598 → 0.2.3608
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 +92 -41
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -9056,6 +9056,67 @@ function createRosterService(ctx, options = {}) {
|
|
|
9056
9056
|
|
|
9057
9057
|
// src/runtime/deliver.ts
|
|
9058
9058
|
import * as NodeCrypto from "node:crypto";
|
|
9059
|
+
|
|
9060
|
+
// ../../packages/ycodium-system-text/src/systemText.ts
|
|
9061
|
+
var SYSTEM_NOTIFICATION_OPEN_TAG = "<ycodium-system>";
|
|
9062
|
+
var SYSTEM_NOTIFICATION_CLOSE_TAG = "</ycodium-system>";
|
|
9063
|
+
var isSystemNotificationText = (text) => text.startsWith(SYSTEM_NOTIFICATION_OPEN_TAG);
|
|
9064
|
+
var rendersAsSystemMessage = (text) => isSystemNotificationText(text) && !(isPresetPrefixMessage(text) && text.includes(PRESET_PREFIX_CLOSE) && parsePresetPrefixText(text) === null);
|
|
9065
|
+
var FIRST_BLOCK_START = `^(?:${SYSTEM_NOTIFICATION_OPEN_TAG}\\n)?`;
|
|
9066
|
+
var PRESET_PREFIX_MESSAGE_START = `${SYSTEM_NOTIFICATION_OPEN_TAG}
|
|
9067
|
+
<preset-prefix `;
|
|
9068
|
+
var isPresetPrefixMessage = (text) => text.startsWith(PRESET_PREFIX_MESSAGE_START);
|
|
9069
|
+
var SYSTEM_TEXT_ESCAPED_ATTRIBUTE = 'esc="1"';
|
|
9070
|
+
var escapeSystemText = (text) => text.replace(/&/g, "&").replace(/</g, "<");
|
|
9071
|
+
var SYSTEM_TEXT_MAX_ESCAPE_GROWTH = "&".length;
|
|
9072
|
+
var escapeSystemAttribute = (text) => escapeSystemText(text).replace(/>/g, ">").replace(/"/g, """).replace(/\r/g, " ").replace(/\n/g, " ");
|
|
9073
|
+
var ESCAPED_BLOCK_NAMES = [
|
|
9074
|
+
"thread-response",
|
|
9075
|
+
"thread-handover",
|
|
9076
|
+
"scheduled-wake",
|
|
9077
|
+
"plugin-wake"
|
|
9078
|
+
];
|
|
9079
|
+
var escapedBlockOpenTag = (name, attributes) => `<${name} ${[
|
|
9080
|
+
...attributes.map(([key, value]) => `${key}="${escapeSystemAttribute(value)}"`),
|
|
9081
|
+
SYSTEM_TEXT_ESCAPED_ATTRIBUTE
|
|
9082
|
+
].join(" ")}>`;
|
|
9083
|
+
var ESCAPED_OPEN_LINE_PATTERN = new RegExp(
|
|
9084
|
+
`^<(?:${ESCAPED_BLOCK_NAMES.join("|")})(?:\\s[^>]*)? ${SYSTEM_TEXT_ESCAPED_ATTRIBUTE}>$`
|
|
9085
|
+
);
|
|
9086
|
+
var PRESET_PREFIX_CLOSE = `
|
|
9087
|
+
</preset-prefix>
|
|
9088
|
+
${SYSTEM_NOTIFICATION_CLOSE_TAG}`;
|
|
9089
|
+
var PRESET_PREFIX_PATTERN = new RegExp(
|
|
9090
|
+
`^${SYSTEM_NOTIFICATION_OPEN_TAG}\\n<preset-prefix id="([^"]*)">\\n([\\s\\S]*?)\\n</preset-prefix>\\n${SYSTEM_NOTIFICATION_CLOSE_TAG}(?:\\n\\n([\\s\\S]*))?$`
|
|
9091
|
+
);
|
|
9092
|
+
var parsePresetPrefixText = (text) => {
|
|
9093
|
+
if (text.split(PRESET_PREFIX_CLOSE).length !== 2) return null;
|
|
9094
|
+
const match7 = PRESET_PREFIX_PATTERN.exec(text);
|
|
9095
|
+
if (match7 === null) return null;
|
|
9096
|
+
const [, presetId, prefix, body] = match7;
|
|
9097
|
+
if (!presetId) return null;
|
|
9098
|
+
return { presetId, prefix: prefix ?? "", body: body ?? "" };
|
|
9099
|
+
};
|
|
9100
|
+
var userSpokenText = (text) => {
|
|
9101
|
+
if (!rendersAsSystemMessage(text)) return text;
|
|
9102
|
+
return parsePresetPrefixText(text)?.body || null;
|
|
9103
|
+
};
|
|
9104
|
+
var formatPluginWakeText = (input) => [
|
|
9105
|
+
SYSTEM_NOTIFICATION_OPEN_TAG,
|
|
9106
|
+
escapedBlockOpenTag("plugin-wake", [
|
|
9107
|
+
["plugin", input.pluginId],
|
|
9108
|
+
["reason", input.reason],
|
|
9109
|
+
...input.item ? [["item", input.item]] : []
|
|
9110
|
+
]),
|
|
9111
|
+
escapeSystemText(input.text),
|
|
9112
|
+
"</plugin-wake>",
|
|
9113
|
+
SYSTEM_NOTIFICATION_CLOSE_TAG
|
|
9114
|
+
].join("\n");
|
|
9115
|
+
var PLUGIN_WAKE_PATTERN = new RegExp(
|
|
9116
|
+
`${FIRST_BLOCK_START}<plugin-wake plugin="([^"]+)" reason="([^"]+)"(?: item="([^"]+)")? ${SYSTEM_TEXT_ESCAPED_ATTRIBUTE}>\\n[\\s\\S]*?\\n</plugin-wake>`
|
|
9117
|
+
);
|
|
9118
|
+
|
|
9119
|
+
// src/runtime/deliver.ts
|
|
9059
9120
|
var worktreeSetupSentence = async (ctx, projectId, branch) => {
|
|
9060
9121
|
const intro = `You are in your own newly created worktree on branch ${branch}.`;
|
|
9061
9122
|
const project2 = await ctx.projects.get({ projectId }).catch(() => null);
|
|
@@ -9064,6 +9125,12 @@ var worktreeSetupSentence = async (ctx, projectId, branch) => {
|
|
|
9064
9125
|
return `${intro} Install dependencies according to the project's instructions before starting work.`;
|
|
9065
9126
|
return `${intro} If dependencies are missing, install them before starting work. This project defines a setup command for that: ${setup.command}; run it from the worktree root with the environment variables YCODIUM_PROJECT_ROOT set to "${project2.workspaceRoot}" and YCODIUM_WORKTREE_PATH set to this worktree's path. If it fails with "could not lock config file", wait a moment and run it again.`;
|
|
9066
9127
|
};
|
|
9128
|
+
var teamWakeText = (display, text) => formatPluginWakeText({
|
|
9129
|
+
pluginId: "team",
|
|
9130
|
+
reason: display.reason,
|
|
9131
|
+
item: display.sequenceId === void 0 ? void 0 : `W${display.sequenceId}`,
|
|
9132
|
+
text
|
|
9133
|
+
});
|
|
9067
9134
|
var stableHash = (key) => NodeCrypto.createHash("sha256").update(key).digest("hex").slice(0, 32);
|
|
9068
9135
|
var memberWorktreeBranch = (name, threadId) => {
|
|
9069
9136
|
const slug = Array.from(
|
|
@@ -9115,7 +9182,7 @@ async function deliverWake(ctx, input) {
|
|
|
9115
9182
|
message: {
|
|
9116
9183
|
messageId: input.messageId,
|
|
9117
9184
|
role: "user",
|
|
9118
|
-
text,
|
|
9185
|
+
text: teamWakeText(input.wake, text),
|
|
9119
9186
|
attachments: []
|
|
9120
9187
|
},
|
|
9121
9188
|
modelSelection: execution.modelSelection,
|
|
@@ -9152,9 +9219,12 @@ async function deliverWake(ctx, input) {
|
|
|
9152
9219
|
requestId: input.requestId,
|
|
9153
9220
|
message: {
|
|
9154
9221
|
...turn.message,
|
|
9155
|
-
text:
|
|
9222
|
+
text: teamWakeText(
|
|
9223
|
+
input.wake,
|
|
9224
|
+
`${text}
|
|
9156
9225
|
|
|
9157
9226
|
${await worktreeSetupSentence(ctx, input.projectId, branch)}`
|
|
9227
|
+
)
|
|
9158
9228
|
},
|
|
9159
9229
|
bootstrap: {
|
|
9160
9230
|
prepareWorktree: {
|
|
@@ -9190,7 +9260,8 @@ ${await worktreeSetupSentence(ctx, input.projectId, branch)}`
|
|
|
9190
9260
|
recipient: { threadId: worktree.leadThreadId },
|
|
9191
9261
|
requestId: `team-worktree-report:${threadId}`,
|
|
9192
9262
|
messageId: `team-worktree-report-msg:${threadId}`,
|
|
9193
|
-
text: `Could not create a worktree for member ${await worktree.name()} (threadId ${threadId}): ${failure.reason}. They will work in the project folder for now
|
|
9263
|
+
text: `Could not create a worktree for member ${await worktree.name()} (threadId ${threadId}): ${failure.reason}. They will work in the project folder for now.`,
|
|
9264
|
+
wake: { reason: "notice" }
|
|
9194
9265
|
});
|
|
9195
9266
|
if (!reported) throw new Error("Member worktree failure could not be reported to the lead");
|
|
9196
9267
|
const receipt = await worktree.lane.events.append({
|
|
@@ -10051,7 +10122,10 @@ function createGoalService(ctx, rosterService, options = {}) {
|
|
|
10051
10122
|
message: {
|
|
10052
10123
|
messageId: `team-lead-message:${goal.projectId}:${goal.goalId}`,
|
|
10053
10124
|
role: "user",
|
|
10054
|
-
text:
|
|
10125
|
+
text: teamWakeText(
|
|
10126
|
+
{ reason: "instructions" },
|
|
10127
|
+
leadBrief(goal, roster, { engineMembers: view.stored?.version === 2 })
|
|
10128
|
+
),
|
|
10055
10129
|
attachments: []
|
|
10056
10130
|
},
|
|
10057
10131
|
modelSelection: selections.get(goal.leadMemberId).modelSelection,
|
|
@@ -11902,6 +11976,7 @@ function startMemberBindingRuntime(ctx, goals, rosters, wakes, trials2) {
|
|
|
11902
11976
|
recipient: { threadId: leadThreadId },
|
|
11903
11977
|
requestId: `team-member-unbound-notice:${key}`,
|
|
11904
11978
|
messageId: `team-member-unbound-notice-message:${key}`,
|
|
11979
|
+
wake: { reason: "notice" },
|
|
11905
11980
|
text: rebinding ? `Member ${member.name} (memberId ${member.memberId}) passed its trial run with the new setup but could not be moved onto it: ${failure.detail}. Work not yet handed to them waits until it is. Fix the cause, for example change their model with team_update_member; they are set up again within a couple of minutes.` : `Member ${member.name} (memberId ${member.memberId}) could not join this goal: ${failure.detail}. Work assigned to them waits until they join. Fix the cause, for example change their model with team_update_member; they are set up again within a couple of minutes.`
|
|
11906
11981
|
});
|
|
11907
11982
|
if (delivered) told.add(key);
|
|
@@ -12080,6 +12155,7 @@ function startMemberRemovalRuntime(ctx, goals, wakes) {
|
|
|
12080
12155
|
recipient: { threadId: lead },
|
|
12081
12156
|
requestId: `team-member-removed-notice:${key}`,
|
|
12082
12157
|
messageId: `team-member-removed-notice-message:${key}`,
|
|
12158
|
+
wake: { reason: "notice" },
|
|
12083
12159
|
text: [
|
|
12084
12160
|
`Member ${member.name} (memberId ${memberId}) was removed from this project's team.`,
|
|
12085
12161
|
`Work that had not reached them yet was taken off them and now has no assignee: ${list(mine(taken))}. Assign it to another member with work_update_item.`,
|
|
@@ -13371,6 +13447,7 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13371
13447
|
recipient: wake,
|
|
13372
13448
|
requestId: wakeRequestId(id),
|
|
13373
13449
|
messageId: `team-wake-msg:${id}`,
|
|
13450
|
+
wake: { reason: "work", sequenceId: wake.sequenceId },
|
|
13374
13451
|
memberWorktree: worktree === void 0 ? void 0 : { ...worktree, lane: worktrees },
|
|
13375
13452
|
// 评论在收件人正在跑时插进当前这一轮,不排到这一轮结束(试跑 3:一轮 97 分钟,检查点落空)。
|
|
13376
13453
|
...wake.kind === "comment" ? { steer: true } : {},
|
|
@@ -13574,6 +13651,10 @@ function startRecoveryRuntime(ctx, goals, state, worktrees) {
|
|
|
13574
13651
|
requestId: `team-recovery:${id}:${plan.action}`,
|
|
13575
13652
|
messageId: `team-recovery-msg:${id}:${plan.action}`,
|
|
13576
13653
|
text: plan.text,
|
|
13654
|
+
// 续做与提醒是叫成员接着干活;告诉负责人谁停了是通知。
|
|
13655
|
+
wake: {
|
|
13656
|
+
reason: plan.action === "resume" || plan.action === "remind" ? "work" : "notice"
|
|
13657
|
+
},
|
|
13577
13658
|
memberWorktree: worktree === void 0 ? void 0 : { ...worktree, lane: worktrees }
|
|
13578
13659
|
});
|
|
13579
13660
|
if (!delivered) continue;
|
|
@@ -13665,7 +13746,8 @@ fired:${fired.wakes.length}`);
|
|
|
13665
13746
|
recipient: { threadId },
|
|
13666
13747
|
requestId: `team-lead-checkin:${threadId}:${key}`,
|
|
13667
13748
|
messageId: `team-lead-checkin-message:${threadId}:${key}`,
|
|
13668
|
-
text: LEAD_CHECKIN_REMINDER
|
|
13749
|
+
text: LEAD_CHECKIN_REMINDER,
|
|
13750
|
+
wake: { reason: "check-in" }
|
|
13669
13751
|
});
|
|
13670
13752
|
}
|
|
13671
13753
|
};
|
|
@@ -14372,6 +14454,7 @@ function startHandbookRuntime(ctx, worktrees) {
|
|
|
14372
14454
|
messageId: `team-handbook-msg:${id}`,
|
|
14373
14455
|
// 成员闲着时被换版提醒叫醒,不能借机自己挑活:成员的提醒写死只确认、确认完就结束这一轮。
|
|
14374
14456
|
text: handbookReminder(release, seat.goal.leadMemberId === member.memberId),
|
|
14457
|
+
wake: { reason: "instructions" },
|
|
14375
14458
|
memberWorktree: worktree === void 0 ? void 0 : { ...worktree, lane: worktrees.lane }
|
|
14376
14459
|
});
|
|
14377
14460
|
if (!delivered) continue;
|
|
@@ -15931,39 +16014,6 @@ async function teamWaitingList(ctx, memberThreads, nameOf2) {
|
|
|
15931
16014
|
return waiting.length === 0 ? null : `${count(waiting.length, "member is", "members are")} waiting on the person: ${waiting.join("; ")}. These appear in this conversation for the person to answer; you cannot answer them and should not wait for them. Hand out work to members who are not blocked.`;
|
|
15932
16015
|
}
|
|
15933
16016
|
|
|
15934
|
-
// ../../packages/ycodium-system-text/src/systemText.ts
|
|
15935
|
-
var SYSTEM_NOTIFICATION_OPEN_TAG = "<ycodium-system>";
|
|
15936
|
-
var SYSTEM_NOTIFICATION_CLOSE_TAG = "</ycodium-system>";
|
|
15937
|
-
var isSystemNotificationText = (text) => text.startsWith(SYSTEM_NOTIFICATION_OPEN_TAG);
|
|
15938
|
-
var rendersAsSystemMessage = (text) => isSystemNotificationText(text) && !(isPresetPrefixMessage(text) && text.includes(PRESET_PREFIX_CLOSE) && parsePresetPrefixText(text) === null);
|
|
15939
|
-
var FIRST_BLOCK_START = `^(?:${SYSTEM_NOTIFICATION_OPEN_TAG}\\n)?`;
|
|
15940
|
-
var PRESET_PREFIX_MESSAGE_START = `${SYSTEM_NOTIFICATION_OPEN_TAG}
|
|
15941
|
-
<preset-prefix `;
|
|
15942
|
-
var isPresetPrefixMessage = (text) => text.startsWith(PRESET_PREFIX_MESSAGE_START);
|
|
15943
|
-
var SYSTEM_TEXT_ESCAPED_ATTRIBUTE = 'esc="1"';
|
|
15944
|
-
var ESCAPED_BLOCK_NAMES = ["thread-response", "thread-handover", "scheduled-wake"];
|
|
15945
|
-
var ESCAPED_OPEN_LINE_PATTERN = new RegExp(
|
|
15946
|
-
`^<(?:${ESCAPED_BLOCK_NAMES.join("|")})(?:\\s[^>]*)? ${SYSTEM_TEXT_ESCAPED_ATTRIBUTE}>$`
|
|
15947
|
-
);
|
|
15948
|
-
var PRESET_PREFIX_CLOSE = `
|
|
15949
|
-
</preset-prefix>
|
|
15950
|
-
${SYSTEM_NOTIFICATION_CLOSE_TAG}`;
|
|
15951
|
-
var PRESET_PREFIX_PATTERN = new RegExp(
|
|
15952
|
-
`^${SYSTEM_NOTIFICATION_OPEN_TAG}\\n<preset-prefix id="([^"]*)">\\n([\\s\\S]*?)\\n</preset-prefix>\\n${SYSTEM_NOTIFICATION_CLOSE_TAG}(?:\\n\\n([\\s\\S]*))?$`
|
|
15953
|
-
);
|
|
15954
|
-
var parsePresetPrefixText = (text) => {
|
|
15955
|
-
if (text.split(PRESET_PREFIX_CLOSE).length !== 2) return null;
|
|
15956
|
-
const match7 = PRESET_PREFIX_PATTERN.exec(text);
|
|
15957
|
-
if (match7 === null) return null;
|
|
15958
|
-
const [, presetId, prefix, body] = match7;
|
|
15959
|
-
if (!presetId) return null;
|
|
15960
|
-
return { presetId, prefix: prefix ?? "", body: body ?? "" };
|
|
15961
|
-
};
|
|
15962
|
-
var userSpokenText = (text) => {
|
|
15963
|
-
if (!rendersAsSystemMessage(text)) return text;
|
|
15964
|
-
return parsePresetPrefixText(text)?.body || null;
|
|
15965
|
-
};
|
|
15966
|
-
|
|
15967
16017
|
// src/team/groupDigest.ts
|
|
15968
16018
|
var DIGEST_LIMIT = 30;
|
|
15969
16019
|
var SCAN_PAGES = 5;
|
|
@@ -16917,7 +16967,7 @@ async function ensureSession(env, record2, ensured, prepared) {
|
|
|
16917
16967
|
message: {
|
|
16918
16968
|
messageId: `team-trial-message:${key}`,
|
|
16919
16969
|
role: "user",
|
|
16920
|
-
text: trialMessage("localPrompt", { trialId }),
|
|
16970
|
+
text: teamWakeText({ reason: "instructions" }, trialMessage("localPrompt", { trialId })),
|
|
16921
16971
|
attachments: []
|
|
16922
16972
|
},
|
|
16923
16973
|
modelSelection: selection.modelSelection,
|
|
@@ -16987,7 +17037,8 @@ async function tellLeads(env, leadThreads, projectId, key, text) {
|
|
|
16987
17037
|
recipient: { threadId: leadThreadId },
|
|
16988
17038
|
requestId,
|
|
16989
17039
|
messageId: `${requestId}:message`,
|
|
16990
|
-
text
|
|
17040
|
+
text,
|
|
17041
|
+
wake: { reason: "notice" }
|
|
16991
17042
|
});
|
|
16992
17043
|
delivered ||= sent;
|
|
16993
17044
|
}
|
|
@@ -17413,7 +17464,7 @@ function startTrialRuntime(ctx, deps, options = {}) {
|
|
|
17413
17464
|
// src/index.ts
|
|
17414
17465
|
var index_default = definePlugin({
|
|
17415
17466
|
id: "team",
|
|
17416
|
-
apiVersion:
|
|
17467
|
+
apiVersion: 49,
|
|
17417
17468
|
activate(ctx) {
|
|
17418
17469
|
const trialState = ctx.derivedState(trialStateDefinition);
|
|
17419
17470
|
const rosters = createRosterService(ctx);
|
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.3608",
|
|
4
4
|
"description": "A project team roster with members, a lead, and goals.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"teams",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"tailwindcss": "^4.0.0",
|
|
35
35
|
"typescript": "~6.0.3",
|
|
36
36
|
"vite-plus": "0.2.2",
|
|
37
|
-
"ycodium-
|
|
38
|
-
"
|
|
37
|
+
"@ycodium-ai/plugin-api": "0.2.3608",
|
|
38
|
+
"ycodium-system-text": "0.0.0"
|
|
39
39
|
},
|
|
40
40
|
"ycodium": {
|
|
41
41
|
"plugin": "./dist/index.js",
|