@ycodium-ai/plugin-team 0.2.3614 → 0.2.3671
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 +2 -2
- package/assets/ui.js +6 -6
- package/dist/index.js +383 -114
- package/locales/en.json +10 -1
- package/locales/zh-CN.json +10 -1
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -9301,12 +9301,31 @@ var remotePrincipalOf = (identity2) => typeof identity2 === "object" && identity
|
|
|
9301
9301
|
|
|
9302
9302
|
// src/domain/defaultModel.ts
|
|
9303
9303
|
var isSelectionUnavailable = isTagged("ProviderSelectionError");
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9304
|
+
var MODEL_UNAVAILABLE_REASONS = /* @__PURE__ */ new Set([
|
|
9305
|
+
"instance-not-found",
|
|
9306
|
+
"instance-unavailable",
|
|
9307
|
+
"model-not-in-catalog"
|
|
9308
|
+
]);
|
|
9309
|
+
var UNAVAILABLE_MESSAGE_KEYS = {
|
|
9310
|
+
"instance-not-found": "instanceNotFound",
|
|
9311
|
+
"instance-unavailable": "instanceUnavailable",
|
|
9312
|
+
"model-not-in-catalog": "modelNotInCatalog"
|
|
9313
|
+
};
|
|
9314
|
+
var unavailableFrom = (error) => {
|
|
9315
|
+
const reason = Reflect.get(error, "reason");
|
|
9316
|
+
return typeof reason === "string" && MODEL_UNAVAILABLE_REASONS.has(reason) ? { code: "model-unavailable", reason } : { code: "model-unavailable" };
|
|
9317
|
+
};
|
|
9318
|
+
async function resolveModel(ctx, base, named = false) {
|
|
9319
|
+
try {
|
|
9320
|
+
return {
|
|
9321
|
+
selection: await ctx.providers.selection.resolve(
|
|
9322
|
+
named && base !== null ? { base, instanceId: base.instanceId, model: base.model } : { base }
|
|
9323
|
+
)
|
|
9324
|
+
};
|
|
9325
|
+
} catch (error) {
|
|
9326
|
+
if (isSelectionUnavailable(error)) return unavailableFrom(error);
|
|
9307
9327
|
throw error;
|
|
9308
|
-
}
|
|
9309
|
-
return selection === null ? { code: "model-unavailable" } : { selection };
|
|
9328
|
+
}
|
|
9310
9329
|
}
|
|
9311
9330
|
async function resolveDefaultSelection(ctx, projectId) {
|
|
9312
9331
|
const project2 = await ctx.projects.get({ projectId });
|
|
@@ -9365,6 +9384,9 @@ var en_default = {
|
|
|
9365
9384
|
memberNotFound: "There is no member {{memberId}} in this project. List the members with team_roster_overview.",
|
|
9366
9385
|
memberRemoved: "Member {{memberId}} was removed from the project. Restore them first with team_restore_member.",
|
|
9367
9386
|
modelUnavailable: "The model chosen for member {{memberId}} is not available on this machine. Check list_providers and list_models, then change it with team_update_member.",
|
|
9387
|
+
instanceNotFound: "The provider instance chosen for member {{memberId}} does not exist on this machine. Check list_providers, then change it with team_update_member.",
|
|
9388
|
+
instanceUnavailable: "The provider instance chosen for member {{memberId}} is turned off or cannot run on this machine. Check list_providers, then change it with team_update_member.",
|
|
9389
|
+
modelNotInCatalog: "The model chosen for member {{memberId}} is not in that provider instance's model list. Check list_models, then change it with team_update_member.",
|
|
9368
9390
|
noDefaultModel: "Member {{memberId}} has no model of its own and the project has no default model. Give them one with team_update_member.",
|
|
9369
9391
|
duplicateTeamName: "A team named {{name}} already exists in this project. Choose another name and use a new requestId.",
|
|
9370
9392
|
leadOnly: "Only the lead conversation of a team can change its members.",
|
|
@@ -9384,6 +9406,9 @@ var en_default = {
|
|
|
9384
9406
|
requestVoided: "This requestId was abandoned before the change reached the engine. Use a new requestId.",
|
|
9385
9407
|
invalidAgent: "Give both instanceId and model, or neither.",
|
|
9386
9408
|
modelUnavailable: "That provider instance or model is not available on this machine. Check list_providers and list_models, then try again.",
|
|
9409
|
+
instanceNotFound: "That provider instance does not exist on this machine. Check list_providers, then try again.",
|
|
9410
|
+
instanceUnavailable: "That provider instance is turned off or cannot run on this machine. Check list_providers, then try again.",
|
|
9411
|
+
modelNotInCatalog: "That model is not in the provider instance's model list. Check list_models, then try again.",
|
|
9387
9412
|
noDefaultModel: "The project has no default model. Give instanceId and model.",
|
|
9388
9413
|
notAgentMember: "Only agent members can be changed with this tool.",
|
|
9389
9414
|
memberInOtherTeam: "Another team is using this member. You can only change or remove members who are on no team, or only on yours. See which teams each member is on with team_roster_overview.",
|
|
@@ -9615,6 +9640,9 @@ var en_default = {
|
|
|
9615
9640
|
invalidPayload: "Check the member fields and try again.",
|
|
9616
9641
|
noDefaultModel: "This project has no default model. Choose one in the project settings under New threads \u2192 Model, then try again.",
|
|
9617
9642
|
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.",
|
|
9643
|
+
instanceNotFound: "The project's default model belongs to a provider instance that does not exist on this machine. Choose another model in the project settings under New threads \u2192 Model.",
|
|
9644
|
+
instanceUnavailable: "The provider instance of the project's default model is turned off or cannot run on this machine. Check the provider, or choose another model in the project settings under New threads \u2192 Model.",
|
|
9645
|
+
modelNotInCatalog: "The project's default model is not in its provider instance's model list. Choose another model in the project settings under New threads \u2192 Model.",
|
|
9618
9646
|
duplicateMember: "Another member already has this name or remote agent. Rename or remove that member first.",
|
|
9619
9647
|
alreadyYou: "You are already {{name}} on this roster. Clear \u201CThis is me\u201D on {{name}} first.",
|
|
9620
9648
|
staleVersion: "This member was changed elsewhere and has been reloaded. Review it and save again.",
|
|
@@ -9635,7 +9663,7 @@ var en_default = {
|
|
|
9635
9663
|
legacy: {
|
|
9636
9664
|
title: "This project still uses an older roster",
|
|
9637
9665
|
description: "Its members are not project members yet. Import them to edit, remove and restore them here, and to give them titles and work instructions. Goals keep starting from the older roster until you do.",
|
|
9638
|
-
members: "
|
|
9666
|
+
members: "{{names}}",
|
|
9639
9667
|
import: "Import roster",
|
|
9640
9668
|
importing: "Importing\u2026",
|
|
9641
9669
|
imported: "Roster imported."
|
|
@@ -10481,10 +10509,12 @@ var GUARD_MESSAGES = {
|
|
|
10481
10509
|
"model-unavailable": "modelUnavailable",
|
|
10482
10510
|
"no-default-model": "noDefaultModel"
|
|
10483
10511
|
};
|
|
10484
|
-
var refuse = (code) => ({
|
|
10512
|
+
var refuse = (code, reason) => ({
|
|
10485
10513
|
status: "rejected",
|
|
10486
10514
|
code,
|
|
10487
|
-
detail: coordinatorMessage(
|
|
10515
|
+
detail: coordinatorMessage(
|
|
10516
|
+
code === "model-unavailable" && reason !== void 0 ? UNAVAILABLE_MESSAGE_KEYS[reason] : GUARD_MESSAGES[code]
|
|
10517
|
+
)
|
|
10488
10518
|
});
|
|
10489
10519
|
function terminalRefusal(error) {
|
|
10490
10520
|
const refusal = memberRefusal(error);
|
|
@@ -10605,14 +10635,14 @@ function startCoordinatorRuntime(ctx, deps) {
|
|
|
10605
10635
|
if (instanceId === void 0 && model === void 0) {
|
|
10606
10636
|
if (change.op === "update") return {};
|
|
10607
10637
|
const fallback = await defaultAgent(ctx, projectId);
|
|
10608
|
-
return "code" in fallback ? refuse(fallback.code) : { agent: fallback.agent };
|
|
10638
|
+
return "code" in fallback ? refuse(fallback.code, "reason" in fallback ? fallback.reason : void 0) : { agent: fallback.agent };
|
|
10609
10639
|
}
|
|
10610
10640
|
if (instanceId === void 0 || model === void 0) return refuse("invalid-agent");
|
|
10611
10641
|
const environmentId = target?.agent?.environmentId ?? ctx.environment.id;
|
|
10612
10642
|
if (environmentId !== ctx.environment.id)
|
|
10613
10643
|
return { agent: { environmentId, modelSelection: { instanceId, model } } };
|
|
10614
|
-
const resolved = await resolveModel(ctx, { instanceId, model });
|
|
10615
|
-
return "code" in resolved ? refuse(resolved.code) : { agent: { environmentId, modelSelection: resolved.selection.modelSelection } };
|
|
10644
|
+
const resolved = await resolveModel(ctx, { instanceId, model }, true);
|
|
10645
|
+
return "code" in resolved ? refuse(resolved.code, "reason" in resolved ? resolved.reason : void 0) : { agent: { environmentId, modelSelection: resolved.selection.modelSelection } };
|
|
10616
10646
|
};
|
|
10617
10647
|
const plan = async (change, requestId, projectId, target) => {
|
|
10618
10648
|
if (change.op === "create") {
|
|
@@ -11179,6 +11209,11 @@ var toEngineAgent = (agent) => ({
|
|
|
11179
11209
|
environmentId: agent.environmentId,
|
|
11180
11210
|
modelSelection: agent.modelSelection
|
|
11181
11211
|
});
|
|
11212
|
+
var rejectDefault = (commandType, refusal) => rejectMember(
|
|
11213
|
+
commandType,
|
|
11214
|
+
refusal.code,
|
|
11215
|
+
"reason" in refusal && refusal.reason !== void 0 ? { reason: refusal.reason } : void 0
|
|
11216
|
+
);
|
|
11182
11217
|
async function refused(commandType, run2) {
|
|
11183
11218
|
try {
|
|
11184
11219
|
return await run2();
|
|
@@ -11219,7 +11254,7 @@ function createMemberWriter(ctx, rosters, queue = createSerial()) {
|
|
|
11219
11254
|
agent = toEngineAgent(input.agent);
|
|
11220
11255
|
} else {
|
|
11221
11256
|
const fallback = await defaultAgent(ctx, input.projectId);
|
|
11222
|
-
if ("code" in fallback) return
|
|
11257
|
+
if ("code" in fallback) return rejectDefault("createMember", fallback);
|
|
11223
11258
|
agent = fallback.agent;
|
|
11224
11259
|
}
|
|
11225
11260
|
}
|
|
@@ -11317,7 +11352,7 @@ function createMemberWriter(ctx, rosters, queue = createSerial()) {
|
|
|
11317
11352
|
let local;
|
|
11318
11353
|
if (missing2.some(({ member }) => member.principal === void 0)) {
|
|
11319
11354
|
const fallback = await defaultAgent(ctx, projectId);
|
|
11320
|
-
if ("code" in fallback) return
|
|
11355
|
+
if ("code" in fallback) return rejectDefault("importRoster", fallback);
|
|
11321
11356
|
local = fallback;
|
|
11322
11357
|
}
|
|
11323
11358
|
for (const { member, memberId } of missing2) {
|
|
@@ -11642,6 +11677,33 @@ function startCommentMentionRuntime(ctx, goals) {
|
|
|
11642
11677
|
ctx.reactor({ name: "team-comment-mentions", events: ["work.comment-posted"], handle });
|
|
11643
11678
|
}
|
|
11644
11679
|
|
|
11680
|
+
// src/runtime/dispatchClaim.ts
|
|
11681
|
+
var allow = { allowed: true };
|
|
11682
|
+
var claim = (detail) => ({ allowed: false, detail });
|
|
11683
|
+
function registerDispatchClaim(ctx, wakes) {
|
|
11684
|
+
const check = async (input) => {
|
|
11685
|
+
const project2 = readFact(
|
|
11686
|
+
await wakes.get({ throughSequence: input.throughSequence }),
|
|
11687
|
+
input.projectId
|
|
11688
|
+
);
|
|
11689
|
+
if (project2 === null) return allow;
|
|
11690
|
+
if (input.workLineId !== null && project2.lineScopes?.[input.workLineId] !== void 0)
|
|
11691
|
+
return claim("the team on this work line dispatches its members");
|
|
11692
|
+
if (project2.goalId === void 0) return allow;
|
|
11693
|
+
if (readFact(project2.bindings ?? {}, input.memberId) !== null)
|
|
11694
|
+
return claim("the project's team goal dispatches this member");
|
|
11695
|
+
if (isClosed(readFact(project2.items, teamGoalItemId(input.projectId, project2.goalId))))
|
|
11696
|
+
return allow;
|
|
11697
|
+
const lines = await ctx.work.lines.list({
|
|
11698
|
+
projectId: input.projectId,
|
|
11699
|
+
includeArchived: true,
|
|
11700
|
+
limit: 1
|
|
11701
|
+
});
|
|
11702
|
+
return lines.items.length === 0 ? claim("the project's team goal takes this member in and dispatches it") : allow;
|
|
11703
|
+
};
|
|
11704
|
+
return ctx.operations.guard({ operations: ["work.dispatch"], check });
|
|
11705
|
+
}
|
|
11706
|
+
|
|
11645
11707
|
// src/runtime/deliveryPacing.ts
|
|
11646
11708
|
function foldProgress(state, event) {
|
|
11647
11709
|
const decoded = decodeWorkEvent(event);
|
|
@@ -11823,6 +11885,8 @@ function startGroupDeliveryRuntime(ctx, wakes, now3 = () => runPromise2(map5(now
|
|
|
11823
11885
|
events: [
|
|
11824
11886
|
"communication.group-message-sent",
|
|
11825
11887
|
"work.line-restored",
|
|
11888
|
+
// 线或成员恢复:暂停期间没绑的目标补扫出去。
|
|
11889
|
+
"work.line-resumed",
|
|
11826
11890
|
"plugin.event-appended",
|
|
11827
11891
|
"member.created",
|
|
11828
11892
|
"member.updated",
|
|
@@ -12846,9 +12910,63 @@ function memberStarter(previous, settled, moved) {
|
|
|
12846
12910
|
return threadId !== void 0 && Object.values(settled.memberThreads ?? {}).includes(threadId) ? threadId : void 0;
|
|
12847
12911
|
}
|
|
12848
12912
|
|
|
12913
|
+
// src/runtime/linePauseFold.ts
|
|
12914
|
+
var EnginePause = Struct({
|
|
12915
|
+
projectId: String4,
|
|
12916
|
+
workLineId: String4,
|
|
12917
|
+
memberId: optionalKey2(String4)
|
|
12918
|
+
});
|
|
12919
|
+
var decodeEnginePause = decodeUnknownOption2(EnginePause);
|
|
12920
|
+
var pauseOfEngineEvent = (event) => {
|
|
12921
|
+
if (event.type !== "work.line-paused" && event.type !== "work.line-resumed") return null;
|
|
12922
|
+
const decoded = decodeEnginePause(event.payload);
|
|
12923
|
+
if (isNone2(decoded)) return null;
|
|
12924
|
+
return { ...decoded.value, paused: event.type === "work.line-paused" };
|
|
12925
|
+
};
|
|
12926
|
+
function applyPause(project2, change) {
|
|
12927
|
+
const { workLineId, memberId, paused } = change;
|
|
12928
|
+
if (memberId === void 0) {
|
|
12929
|
+
const known = project2.linePauses ?? {};
|
|
12930
|
+
if (paused === (known[workLineId] === true)) return project2;
|
|
12931
|
+
return {
|
|
12932
|
+
...project2,
|
|
12933
|
+
linePauses: paused ? { ...known, [workLineId]: true } : without(known, workLineId)
|
|
12934
|
+
};
|
|
12935
|
+
}
|
|
12936
|
+
const list = project2.pausedMembers?.[workLineId] ?? [];
|
|
12937
|
+
if (paused === list.includes(memberId)) return project2;
|
|
12938
|
+
const remaining = paused ? [...list, memberId] : list.filter((id) => id !== memberId);
|
|
12939
|
+
const pausedMembers = { ...project2.pausedMembers };
|
|
12940
|
+
if (remaining.length === 0) delete pausedMembers[workLineId];
|
|
12941
|
+
else pausedMembers[workLineId] = remaining;
|
|
12942
|
+
return { ...project2, pausedMembers };
|
|
12943
|
+
}
|
|
12944
|
+
var legacyPauseId = (project2, workLineId, memberId) => memberId === void 0 ? project2.legacyLinePauses?.[workLineId] : project2.legacyMemberPauses?.[workLineId]?.[memberId];
|
|
12945
|
+
function withPause(project2, change, legacyEventId) {
|
|
12946
|
+
const { workLineId, memberId, paused } = change;
|
|
12947
|
+
const previous = legacyPauseId(project2, workLineId, memberId);
|
|
12948
|
+
if (!paused && legacyEventId !== void 0 && previous === void 0) return project2;
|
|
12949
|
+
const next = applyPause(project2, change);
|
|
12950
|
+
const legacy = paused ? legacyEventId : void 0;
|
|
12951
|
+
if (legacy === previous) return next;
|
|
12952
|
+
if (memberId === void 0) {
|
|
12953
|
+
const known2 = project2.legacyLinePauses ?? {};
|
|
12954
|
+
return {
|
|
12955
|
+
...next,
|
|
12956
|
+
legacyLinePauses: legacy === void 0 ? without(known2, workLineId) : { ...known2, [workLineId]: legacy }
|
|
12957
|
+
};
|
|
12958
|
+
}
|
|
12959
|
+
const known = project2.legacyMemberPauses?.[workLineId] ?? {};
|
|
12960
|
+
const members = legacy === void 0 ? without(known, memberId) : { ...known, [memberId]: legacy };
|
|
12961
|
+
const legacyMemberPauses = { ...project2.legacyMemberPauses };
|
|
12962
|
+
if (Object.keys(members).length === 0) delete legacyMemberPauses[workLineId];
|
|
12963
|
+
else legacyMemberPauses[workLineId] = members;
|
|
12964
|
+
return { ...next, legacyMemberPauses };
|
|
12965
|
+
}
|
|
12966
|
+
|
|
12849
12967
|
// src/runtime/wakeState.ts
|
|
12850
12968
|
var WAKE_STATE_KEY = "wakes";
|
|
12851
|
-
var WAKE_STATE_VERSION =
|
|
12969
|
+
var WAKE_STATE_VERSION = 9;
|
|
12852
12970
|
var WAKE_EVENTS = [
|
|
12853
12971
|
"work.item-created",
|
|
12854
12972
|
"work.item-updated",
|
|
@@ -12858,6 +12976,9 @@ var WAKE_EVENTS = [
|
|
|
12858
12976
|
"work.comment-posted",
|
|
12859
12977
|
"plugin.event-appended",
|
|
12860
12978
|
"thread.session-set",
|
|
12979
|
+
// 线与线上成员的暂停:引擎的看板事实,派发闸读它(见 `linePauses` / `pausedMembers`)。
|
|
12980
|
+
"work.line-paused",
|
|
12981
|
+
"work.line-resumed",
|
|
12861
12982
|
// 团队的线归档、恢复,负责人会话被删:这个团队停工(见 `lineStops`)。
|
|
12862
12983
|
"work.line-archived",
|
|
12863
12984
|
"work.line-restored",
|
|
@@ -12994,28 +13115,17 @@ function foldWorkWakes(state, event) {
|
|
|
12994
13115
|
if (fact.name === "team/line-paused" || fact.name === "team/line-member-paused") {
|
|
12995
13116
|
const { projectId: projectId3, workLineId, status } = fact.data;
|
|
12996
13117
|
const project4 = readFact(state, projectId3) ?? emptyProject();
|
|
12997
|
-
const
|
|
12998
|
-
|
|
12999
|
-
|
|
13000
|
-
|
|
13001
|
-
|
|
13002
|
-
...
|
|
13003
|
-
|
|
13004
|
-
|
|
13005
|
-
|
|
13006
|
-
|
|
13007
|
-
|
|
13008
|
-
}
|
|
13009
|
-
const list = project4.pausedMembers?.[workLineId] ?? [];
|
|
13010
|
-
if (paused === list.includes(fact.data.memberId)) return state;
|
|
13011
|
-
const remaining = paused ? [...list, fact.data.memberId] : list.filter((memberId) => memberId !== fact.data.memberId);
|
|
13012
|
-
const pausedMembers = { ...project4.pausedMembers };
|
|
13013
|
-
if (remaining.length === 0) delete pausedMembers[workLineId];
|
|
13014
|
-
else pausedMembers[workLineId] = remaining;
|
|
13015
|
-
return {
|
|
13016
|
-
...state,
|
|
13017
|
-
[projectId3]: { ...project4, pausedMembers }
|
|
13018
|
-
};
|
|
13118
|
+
const next2 = withPause(
|
|
13119
|
+
project4,
|
|
13120
|
+
{
|
|
13121
|
+
projectId: projectId3,
|
|
13122
|
+
workLineId,
|
|
13123
|
+
...fact.name === "team/line-member-paused" ? { memberId: fact.data.memberId } : {},
|
|
13124
|
+
paused: status === "paused"
|
|
13125
|
+
},
|
|
13126
|
+
event.eventId
|
|
13127
|
+
);
|
|
13128
|
+
return next2 === project4 ? state : { ...state, [projectId3]: next2 };
|
|
13019
13129
|
}
|
|
13020
13130
|
if (fact.name === COMMENT_MENTIONS_EVENT) {
|
|
13021
13131
|
const { projectId: projectId3, workItemId: workItemId2, commentId, recipients } = fact.data;
|
|
@@ -13283,7 +13393,16 @@ function foldLineStops(state, event) {
|
|
|
13283
13393
|
}
|
|
13284
13394
|
return next;
|
|
13285
13395
|
}
|
|
13396
|
+
function foldEnginePause(state, event) {
|
|
13397
|
+
const change = pauseOfEngineEvent(event);
|
|
13398
|
+
if (change === null) return state;
|
|
13399
|
+
const project2 = readFact(state, change.projectId) ?? emptyProject();
|
|
13400
|
+
const next = withPause(project2, change);
|
|
13401
|
+
return next === project2 ? state : { ...state, [change.projectId]: next };
|
|
13402
|
+
}
|
|
13286
13403
|
function foldWakes(state, event) {
|
|
13404
|
+
if (event.type === "work.line-paused" || event.type === "work.line-resumed")
|
|
13405
|
+
return foldEnginePause(state, event);
|
|
13287
13406
|
return foldRecovery(
|
|
13288
13407
|
pruneReviews(state, foldLineStops(foldWorkWakes(state, event), event)),
|
|
13289
13408
|
event,
|
|
@@ -13692,7 +13811,9 @@ function startRecoveryRuntime(ctx, goals, state, worktrees) {
|
|
|
13692
13811
|
"thread.turn-intent-transitioned",
|
|
13693
13812
|
"thread.turn-queue-updated",
|
|
13694
13813
|
"thread.request-resolved",
|
|
13695
|
-
"thread.user-input-pending"
|
|
13814
|
+
"thread.user-input-pending",
|
|
13815
|
+
// 线或成员恢复:暂停期间扣下的恢复计划补发。
|
|
13816
|
+
"work.line-resumed"
|
|
13696
13817
|
],
|
|
13697
13818
|
handle: (event) => flush(recoveryEventScopeOf(event))
|
|
13698
13819
|
});
|
|
@@ -14492,7 +14613,7 @@ function startHandbookRuntime(ctx, worktrees) {
|
|
|
14492
14613
|
const flush = () => serial(execute);
|
|
14493
14614
|
ctx.reactor({
|
|
14494
14615
|
name: "team-handbook",
|
|
14495
|
-
events: [...HANDBOOK_EVENTS2, "work.item-updated"],
|
|
14616
|
+
events: [...HANDBOOK_EVENTS2, "work.item-updated", "work.line-resumed"],
|
|
14496
14617
|
handle: () => flush()
|
|
14497
14618
|
});
|
|
14498
14619
|
ctx.onDispose(queue.close);
|
|
@@ -15447,7 +15568,7 @@ function createTeamOpener(ctx, deps, runner = createLineChangeRunner(ctx, deps),
|
|
|
15447
15568
|
throw new TeamRuleError(
|
|
15448
15569
|
resolved.code,
|
|
15449
15570
|
teamMessage(
|
|
15450
|
-
resolved.code === "no-default-model" ? "noDefaultModel" : "modelUnavailable",
|
|
15571
|
+
resolved.code === "no-default-model" ? "noDefaultModel" : resolved.reason === void 0 ? "modelUnavailable" : UNAVAILABLE_MESSAGE_KEYS[resolved.reason],
|
|
15451
15572
|
{ memberId: row.memberId }
|
|
15452
15573
|
)
|
|
15453
15574
|
);
|
|
@@ -15649,13 +15770,11 @@ var MEMBER_LIMIT = 500;
|
|
|
15649
15770
|
var TEAM_LIMIT = 200;
|
|
15650
15771
|
function createTeamOverview(ctx, deps) {
|
|
15651
15772
|
return async (projectId) => {
|
|
15652
|
-
const [members, lines, trials2
|
|
15773
|
+
const [members, lines, trials2] = await Promise.all([
|
|
15653
15774
|
readPages(MEMBER_LIMIT, (page) => ctx.members.list({ projectId, ...page })),
|
|
15654
15775
|
readPages(TEAM_LIMIT, (page) => ctx.work.lines.list({ projectId, ...page })),
|
|
15655
|
-
deps.trials.get()
|
|
15656
|
-
deps.wakes.get()
|
|
15776
|
+
deps.trials.get()
|
|
15657
15777
|
]);
|
|
15658
|
-
const paused = wakes[projectId] ?? {};
|
|
15659
15778
|
const teamsOf = (memberId) => lines.items.flatMap(
|
|
15660
15779
|
(line) => line.memberIds.includes(memberId) ? [
|
|
15661
15780
|
{
|
|
@@ -15682,9 +15801,9 @@ function createTeamOverview(ctx, deps) {
|
|
|
15682
15801
|
trial: member.kind === "human" ? "none" : trial === null ? principalId === null ? "none" : "unverified" : trial.evidence === "invoked" ? "invoked" : trial.status === "failed" ? "failed" : trial.status === "passed" || trial.status === "overridden" ? "ready" : "pending",
|
|
15683
15802
|
trialFailure: trial?.failure?.category ?? null,
|
|
15684
15803
|
teams: teamsOf(member.memberId),
|
|
15685
|
-
// 这名成员被暂停的团队:整线暂停,或它在这条线上被单独暂停(ADR-0027:371
|
|
15804
|
+
// 这名成员被暂停的团队:整线暂停,或它在这条线上被单独暂停(ADR-0027:371);读线上的引擎事实。
|
|
15686
15805
|
pausedOnLines: lines.items.filter(
|
|
15687
|
-
(line) => line.memberIds.includes(member.memberId) && (
|
|
15806
|
+
(line) => line.memberIds.includes(member.memberId) && (line.pause !== void 0 || (line.memberPauses ?? []).some((pause) => pause.memberId === member.memberId))
|
|
15688
15807
|
).map((line) => line.workLineId)
|
|
15689
15808
|
};
|
|
15690
15809
|
}),
|
|
@@ -15694,7 +15813,7 @@ function createTeamOverview(ctx, deps) {
|
|
|
15694
15813
|
leadMemberId: line.leadMemberId,
|
|
15695
15814
|
memberCount: line.memberIds.length,
|
|
15696
15815
|
conversation: line.threadId,
|
|
15697
|
-
paused:
|
|
15816
|
+
paused: line.pause !== void 0
|
|
15698
15817
|
})),
|
|
15699
15818
|
truncated: members.truncated || lines.truncated
|
|
15700
15819
|
};
|
|
@@ -15890,96 +16009,134 @@ var LineMemberPauseInput = Struct({
|
|
|
15890
16009
|
memberId: String4
|
|
15891
16010
|
});
|
|
15892
16011
|
var decodeLine = decodeUnknownSync(LinePauseInput);
|
|
16012
|
+
var decodeRestored = decodeUnknownOption2(
|
|
16013
|
+
Struct({ projectId: String4, workLineId: String4 })
|
|
16014
|
+
);
|
|
15893
16015
|
var decodeMember = decodeUnknownSync(LineMemberPauseInput);
|
|
15894
|
-
var
|
|
15895
|
-
|
|
15896
|
-
|
|
15897
|
-
|
|
15898
|
-
|
|
15899
|
-
|
|
16016
|
+
var engineRequestId = (status, target, requestId) => `team-pause:${stableHash(JSON.stringify([status, target.projectId, target.workLineId, target.memberId ?? null, requestId]))}`;
|
|
16017
|
+
function registerPauseCommands(ctx, deps) {
|
|
16018
|
+
const write = async (invocation, status, target, requestId) => {
|
|
16019
|
+
const lines = invocation.asPerson.work.lines;
|
|
16020
|
+
const input = { ...target, requestId: engineRequestId(status, target, requestId) };
|
|
16021
|
+
try {
|
|
16022
|
+
await (status === "paused" ? lines.pause(input) : lines.resume(input));
|
|
16023
|
+
} catch (error) {
|
|
16024
|
+
const code = hostRefusalCode(error);
|
|
16025
|
+
if (code === "not-permitted")
|
|
16026
|
+
throw new Error("This team is archived; restore it instead of pausing", { cause: error });
|
|
16027
|
+
if (code === "invalid-input")
|
|
16028
|
+
throw new Error("This member is not on that team's work line", { cause: error });
|
|
16029
|
+
throw error;
|
|
16030
|
+
}
|
|
16031
|
+
};
|
|
16032
|
+
const handler = (status, withMember) => async (payload, invocation) => {
|
|
15900
16033
|
if (invocation.asPerson === void 0)
|
|
15901
16034
|
throw Object.assign(new Error("Only a person can pause or resume a team"), {
|
|
15902
16035
|
code: "needs-person"
|
|
15903
16036
|
});
|
|
15904
|
-
|
|
15905
|
-
|
|
15906
|
-
|
|
15907
|
-
|
|
15908
|
-
|
|
15909
|
-
workLineId: input.workLineId
|
|
15910
|
-
});
|
|
15911
|
-
if (line.archivedAt !== null)
|
|
15912
|
-
throw new Error("This team is archived; restore it instead of pausing");
|
|
15913
|
-
await ctx.events.append({
|
|
15914
|
-
...appendOf("line-paused", [input.projectId, input.workLineId, input.requestId]),
|
|
15915
|
-
aggregate: { kind: "project", id: input.projectId },
|
|
15916
|
-
data: {
|
|
15917
|
-
version: 1,
|
|
15918
|
-
status: paused ? "paused" : "resumed",
|
|
15919
|
-
projectId: input.projectId,
|
|
15920
|
-
workLineId: input.workLineId
|
|
15921
|
-
}
|
|
15922
|
-
});
|
|
15923
|
-
return {
|
|
15924
|
-
projectId: input.projectId,
|
|
15925
|
-
workLineId: input.workLineId,
|
|
15926
|
-
status: paused ? "paused" : "resumed"
|
|
15927
|
-
};
|
|
15928
|
-
};
|
|
15929
|
-
const setLineMemberPaused = async (input, paused) => {
|
|
15930
|
-
const { line } = await ctx.work.lines.get({
|
|
15931
|
-
projectId: input.projectId,
|
|
15932
|
-
workLineId: input.workLineId
|
|
16037
|
+
const { requestId, ...target } = withMember ? decodeMember(payload) : decodeLine(payload);
|
|
16038
|
+
await deps.queue.run(async () => {
|
|
16039
|
+
await backfillLine(ctx, deps.wakes, target.projectId, target.workLineId);
|
|
16040
|
+
await write(invocation, status, target, requestId);
|
|
16041
|
+
if (status === "resumed") await releaseLegacyLeftover(ctx, deps.wakes, target, requestId);
|
|
15933
16042
|
});
|
|
15934
|
-
|
|
15935
|
-
throw new Error("This member is not on that team's work line");
|
|
15936
|
-
await ctx.events.append({
|
|
15937
|
-
...appendOf("line-member-paused", [
|
|
15938
|
-
input.projectId,
|
|
15939
|
-
input.workLineId,
|
|
15940
|
-
input.memberId,
|
|
15941
|
-
input.requestId
|
|
15942
|
-
]),
|
|
15943
|
-
aggregate: { kind: "project", id: input.projectId },
|
|
15944
|
-
data: {
|
|
15945
|
-
version: 1,
|
|
15946
|
-
status: paused ? "paused" : "resumed",
|
|
15947
|
-
projectId: input.projectId,
|
|
15948
|
-
workLineId: input.workLineId,
|
|
15949
|
-
memberId: input.memberId
|
|
15950
|
-
}
|
|
15951
|
-
});
|
|
15952
|
-
return {
|
|
15953
|
-
projectId: input.projectId,
|
|
15954
|
-
workLineId: input.workLineId,
|
|
15955
|
-
memberId: input.memberId,
|
|
15956
|
-
status: paused ? "paused" : "resumed"
|
|
15957
|
-
};
|
|
16043
|
+
return { ...target, status };
|
|
15958
16044
|
};
|
|
15959
16045
|
ctx.command({
|
|
15960
16046
|
name: "pauseLine",
|
|
15961
16047
|
scope: "operate",
|
|
15962
16048
|
payloadSchema: payloadSchemaOf(LinePauseInput),
|
|
15963
|
-
handle:
|
|
16049
|
+
handle: handler("paused", false)
|
|
15964
16050
|
});
|
|
15965
16051
|
ctx.command({
|
|
15966
16052
|
name: "resumeLine",
|
|
15967
16053
|
scope: "operate",
|
|
15968
16054
|
payloadSchema: payloadSchemaOf(LinePauseInput),
|
|
15969
|
-
handle:
|
|
16055
|
+
handle: handler("resumed", false)
|
|
15970
16056
|
});
|
|
15971
16057
|
ctx.command({
|
|
15972
16058
|
name: "pauseLineMember",
|
|
15973
16059
|
scope: "operate",
|
|
15974
16060
|
payloadSchema: payloadSchemaOf(LineMemberPauseInput),
|
|
15975
|
-
handle:
|
|
16061
|
+
handle: handler("paused", true)
|
|
15976
16062
|
});
|
|
15977
16063
|
ctx.command({
|
|
15978
16064
|
name: "resumeLineMember",
|
|
15979
16065
|
scope: "operate",
|
|
15980
16066
|
payloadSchema: payloadSchemaOf(LineMemberPauseInput),
|
|
15981
|
-
handle:
|
|
16067
|
+
handle: handler("resumed", true)
|
|
16068
|
+
});
|
|
16069
|
+
ctx.reactor({
|
|
16070
|
+
name: "team-pause-backfill",
|
|
16071
|
+
events: ["work.line-restored"],
|
|
16072
|
+
handle: (event) => match(decodeRestored(event.payload), {
|
|
16073
|
+
onNone: () => Promise.resolve(),
|
|
16074
|
+
onSome: ({ projectId, workLineId }) => deps.queue.run(() => backfillLine(ctx, deps.wakes, projectId, workLineId))
|
|
16075
|
+
})
|
|
15982
16076
|
});
|
|
16077
|
+
const ready = deps.queue.run(() => backfillLegacyPauses(ctx, deps.wakes));
|
|
16078
|
+
void ready.catch((error) => ctx.log.warn("team pause backfill failed", { error }));
|
|
16079
|
+
return { ready };
|
|
16080
|
+
}
|
|
16081
|
+
async function backfillLine(ctx, wakes, projectId, workLineId) {
|
|
16082
|
+
try {
|
|
16083
|
+
const { line, snapshotSequence } = await ctx.work.lines.get({ projectId, workLineId });
|
|
16084
|
+
if (line.archivedAt !== null) return;
|
|
16085
|
+
const caught = readFact(await wakes.get({ throughSequence: snapshotSequence }), projectId);
|
|
16086
|
+
if (caught === null) return;
|
|
16087
|
+
const targets = [
|
|
16088
|
+
...isLinePaused(caught, workLineId) && line.pause === void 0 ? [{ projectId, workLineId }] : [],
|
|
16089
|
+
...(caught.pausedMembers?.[workLineId] ?? []).filter(
|
|
16090
|
+
(memberId) => isMemberPausedOnLine(caught, workLineId, memberId) && line.memberIds.includes(memberId) && !(line.memberPauses ?? []).some((pause) => pause.memberId === memberId)
|
|
16091
|
+
).map((memberId) => ({ projectId, workLineId, memberId }))
|
|
16092
|
+
];
|
|
16093
|
+
for (const target of targets)
|
|
16094
|
+
await ctx.work.lines.pause({
|
|
16095
|
+
...target,
|
|
16096
|
+
requestId: `team-pause-backfill:${stableHash(JSON.stringify([target.workLineId, target.memberId ?? null, line.version]))}`
|
|
16097
|
+
});
|
|
16098
|
+
} catch (error) {
|
|
16099
|
+
ctx.log.warn("team pause could not be recorded on the work line", {
|
|
16100
|
+
projectId,
|
|
16101
|
+
workLineId,
|
|
16102
|
+
error
|
|
16103
|
+
});
|
|
16104
|
+
}
|
|
16105
|
+
}
|
|
16106
|
+
async function backfillLegacyPauses(ctx, wakes) {
|
|
16107
|
+
const state = await wakes.get();
|
|
16108
|
+
for (const [projectId, project2] of Object.entries(state)) {
|
|
16109
|
+
const lineIds = /* @__PURE__ */ new Set([
|
|
16110
|
+
...Object.keys(project2.linePauses ?? {}),
|
|
16111
|
+
...Object.keys(project2.pausedMembers ?? {})
|
|
16112
|
+
]);
|
|
16113
|
+
for (const workLineId of lineIds) await backfillLine(ctx, wakes, projectId, workLineId);
|
|
16114
|
+
}
|
|
16115
|
+
}
|
|
16116
|
+
async function releaseLegacyLeftover(ctx, wakes, target, requestId) {
|
|
16117
|
+
const { line, snapshotSequence } = await ctx.work.lines.get({
|
|
16118
|
+
projectId: target.projectId,
|
|
16119
|
+
workLineId: target.workLineId
|
|
16120
|
+
});
|
|
16121
|
+
const engineHolds = target.memberId === void 0 ? line.pause !== void 0 : (line.memberPauses ?? []).some((pause) => pause.memberId === target.memberId);
|
|
16122
|
+
if (engineHolds) return;
|
|
16123
|
+
const caught = readFact(await wakes.get({ throughSequence: snapshotSequence }), target.projectId);
|
|
16124
|
+
if (caught === null) return;
|
|
16125
|
+
if (legacyPauseId(caught, target.workLineId, target.memberId) === void 0) return;
|
|
16126
|
+
const name = target.memberId === void 0 ? "line-paused" : "line-member-paused";
|
|
16127
|
+
const receipt = await ctx.events.append({
|
|
16128
|
+
commandId: `team-${name}:${stableHash(JSON.stringify([target, requestId]))}`,
|
|
16129
|
+
name,
|
|
16130
|
+
aggregate: { kind: "project", id: target.projectId },
|
|
16131
|
+
data: {
|
|
16132
|
+
version: 1,
|
|
16133
|
+
status: "resumed",
|
|
16134
|
+
projectId: target.projectId,
|
|
16135
|
+
workLineId: target.workLineId,
|
|
16136
|
+
...target.memberId === void 0 ? {} : { memberId: target.memberId }
|
|
16137
|
+
}
|
|
16138
|
+
});
|
|
16139
|
+
await wakes.get({ throughSequence: receipt.sequence });
|
|
15983
16140
|
}
|
|
15984
16141
|
|
|
15985
16142
|
// src/team/waiting.ts
|
|
@@ -16262,6 +16419,9 @@ var zh_CN_default = {
|
|
|
16262
16419
|
memberNotFound: "\u8FD9\u4E2A\u9879\u76EE\u91CC\u6CA1\u6709\u6210\u5458 {{memberId}}\u3002\u7528 team_roster_overview \u5217\u51FA\u6210\u5458\u3002",
|
|
16263
16420
|
memberRemoved: "\u6210\u5458 {{memberId}} \u5DF2\u4ECE\u9879\u76EE\u91CC\u79FB\u9664\u3002\u5148\u7528 team_restore_member \u628A\u5B83\u8BF7\u56DE\u6765\u3002",
|
|
16264
16421
|
modelUnavailable: "\u7ED9\u6210\u5458 {{memberId}} \u9009\u7684\u6A21\u578B\u5728\u8FD9\u53F0\u673A\u5668\u4E0A\u7528\u4E0D\u4E86\u3002\u67E5 list_providers \u548C list_models\uFF0C\u518D\u7528 team_update_member \u6539\u3002",
|
|
16422
|
+
instanceNotFound: "\u7ED9\u6210\u5458 {{memberId}} \u9009\u7684 provider \u5B9E\u4F8B\u5728\u8FD9\u53F0\u673A\u5668\u4E0A\u4E0D\u5B58\u5728\u3002\u67E5 list_providers\uFF0C\u518D\u7528 team_update_member \u6539\u3002",
|
|
16423
|
+
instanceUnavailable: "\u7ED9\u6210\u5458 {{memberId}} \u9009\u7684 provider \u5B9E\u4F8B\u5DF2\u505C\u7528\u6216\u5728\u8FD9\u53F0\u673A\u5668\u4E0A\u8DD1\u4E0D\u4E86\u3002\u67E5 list_providers\uFF0C\u518D\u7528 team_update_member \u6539\u3002",
|
|
16424
|
+
modelNotInCatalog: "\u7ED9\u6210\u5458 {{memberId}} \u9009\u7684\u6A21\u578B\u4E0D\u5728\u8BE5 provider \u5B9E\u4F8B\u7684\u6A21\u578B\u6E05\u5355\u91CC\u3002\u67E5 list_models\uFF0C\u518D\u7528 team_update_member \u6539\u3002",
|
|
16265
16425
|
noDefaultModel: "\u6210\u5458 {{memberId}} \u6CA1\u6709\u81EA\u5DF1\u7684\u6A21\u578B\uFF0C\u9879\u76EE\u4E5F\u6CA1\u6709\u9ED8\u8BA4\u6A21\u578B\u3002\u7528 team_update_member \u7ED9\u5B83\u4E00\u4E2A\u3002",
|
|
16266
16426
|
duplicateTeamName: "\u8FD9\u4E2A\u9879\u76EE\u91CC\u5DF2\u7ECF\u6709\u540D\u4E3A {{name}} \u7684\u56E2\u961F\u3002\u6362\u4E2A\u540D\u5B57\uFF0C\u5E76\u7528\u65B0\u7684 requestId\u3002",
|
|
16267
16427
|
leadOnly: "\u53EA\u6709\u56E2\u961F\u7684\u8D1F\u8D23\u4EBA\u4F1A\u8BDD\u80FD\u6539\u5B83\u7684\u6210\u5458\u3002",
|
|
@@ -16281,6 +16441,9 @@ var zh_CN_default = {
|
|
|
16281
16441
|
requestVoided: "\u8FD9\u4E2A requestId \u5728\u6539\u52A8\u5230\u8FBE\u5F15\u64CE\u4E4B\u524D\u5C31\u4F5C\u5E9F\u4E86\u3002\u8BF7\u6362\u4E00\u4E2A\u65B0\u7684 requestId\u3002",
|
|
16282
16442
|
invalidAgent: "instanceId \u548C model \u8981\u4E48\u90FD\u7ED9\uFF0C\u8981\u4E48\u90FD\u4E0D\u7ED9\u3002",
|
|
16283
16443
|
modelUnavailable: "\u8FD9\u53F0\u673A\u5668\u4E0A\u6CA1\u6709\u8FD9\u4E2A provider \u5B9E\u4F8B\u6216\u6A21\u578B\u3002\u5148\u770B list_providers \u548C list_models\uFF0C\u518D\u91CD\u8BD5\u3002",
|
|
16444
|
+
instanceNotFound: "\u8FD9\u53F0\u673A\u5668\u4E0A\u6CA1\u6709\u8FD9\u4E2A provider \u5B9E\u4F8B\u3002\u5148\u770B list_providers\uFF0C\u518D\u91CD\u8BD5\u3002",
|
|
16445
|
+
instanceUnavailable: "\u8FD9\u4E2A provider \u5B9E\u4F8B\u5DF2\u505C\u7528\u6216\u5728\u8FD9\u53F0\u673A\u5668\u4E0A\u8DD1\u4E0D\u4E86\u3002\u5148\u770B list_providers\uFF0C\u518D\u91CD\u8BD5\u3002",
|
|
16446
|
+
modelNotInCatalog: "\u8FD9\u4E2A\u6A21\u578B\u4E0D\u5728\u8BE5 provider \u5B9E\u4F8B\u7684\u6A21\u578B\u6E05\u5355\u91CC\u3002\u5148\u770B list_models\uFF0C\u518D\u91CD\u8BD5\u3002",
|
|
16284
16447
|
noDefaultModel: "\u9879\u76EE\u6CA1\u6709\u8BBE\u9ED8\u8BA4\u6A21\u578B\uFF0C\u8BF7\u7ED9\u51FA instanceId \u548C model\u3002",
|
|
16285
16448
|
memberInOtherTeam: "\u8FD9\u4E2A\u6210\u5458\u5DF2\u5728\u522B\u7684\u56E2\u961F\u91CC\u3002\u4F60\u53EA\u80FD\u4FEE\u6539\u6216\u79FB\u9664\u4E0D\u5728\u4EFB\u4F55\u56E2\u961F\u3001\u6216\u53EA\u5728\u4F60\u8FD9\u4E2A\u56E2\u961F\u91CC\u7684\u6210\u5458\u3002\u7528 team_roster_overview \u770B\u6BCF\u4E2A\u6210\u5458\u5728\u54EA\u4E2A\u56E2\u961F\u3002",
|
|
16286
16449
|
notAgentMember: "\u8FD9\u4E2A\u5DE5\u5177\u53EA\u80FD\u6539 agent \u6210\u5458\u3002",
|
|
@@ -16512,6 +16675,9 @@ var zh_CN_default = {
|
|
|
16512
16675
|
invalidPayload: "\u8BF7\u68C0\u67E5\u6210\u5458\u5B57\u6BB5\u540E\u91CD\u8BD5\u3002",
|
|
16513
16676
|
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",
|
|
16514
16677
|
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",
|
|
16678
|
+
instanceNotFound: "\u8FD9\u4E2A\u9879\u76EE\u7684\u9ED8\u8BA4\u6A21\u578B\u6240\u5C5E\u7684 provider \u5B9E\u4F8B\u5728\u8FD9\u53F0\u673A\u5668\u4E0A\u4E0D\u5B58\u5728\u3002\u5230\u9879\u76EE\u8BBE\u7F6E\u7684\u300C\u65B0\u4F1A\u8BDD \u2192 \u6A21\u578B\u300D\u6362\u4E00\u4E2A\u3002",
|
|
16679
|
+
instanceUnavailable: "\u8FD9\u4E2A\u9879\u76EE\u9ED8\u8BA4\u6A21\u578B\u6240\u5C5E\u7684 provider \u5B9E\u4F8B\u5DF2\u505C\u7528\u6216\u5728\u8FD9\u53F0\u673A\u5668\u4E0A\u8DD1\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",
|
|
16680
|
+
modelNotInCatalog: "\u8FD9\u4E2A\u9879\u76EE\u7684\u9ED8\u8BA4\u6A21\u578B\u4E0D\u5728\u5176 provider \u5B9E\u4F8B\u7684\u6A21\u578B\u6E05\u5355\u91CC\u3002\u5230\u9879\u76EE\u8BBE\u7F6E\u7684\u300C\u65B0\u4F1A\u8BDD \u2192 \u6A21\u578B\u300D\u6362\u4E00\u4E2A\u3002",
|
|
16515
16681
|
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",
|
|
16516
16682
|
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",
|
|
16517
16683
|
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",
|
|
@@ -16532,7 +16698,7 @@ var zh_CN_default = {
|
|
|
16532
16698
|
legacy: {
|
|
16533
16699
|
title: "\u8FD9\u4E2A\u9879\u76EE\u8FD8\u5728\u7528\u65E7\u540D\u5355",
|
|
16534
16700
|
description: "\u65E7\u540D\u5355\u91CC\u7684\u6210\u5458\u8FD8\u4E0D\u662F\u9879\u76EE\u6210\u5458\u3002\u5BFC\u5165\u540E\u53EF\u4EE5\u5728\u8FD9\u91CC\u7F16\u8F91\u3001\u79FB\u9664\u548C\u6062\u590D\u4ED6\u4EEC\uFF0C\u5E76\u4E3A\u4ED6\u4EEC\u5199\u5934\u8854\u548C\u5DE5\u4F5C\u8BF4\u660E\u3002\u5BFC\u5165\u4E4B\u524D\uFF0C\u76EE\u6807\u4ECD\u6309\u65E7\u540D\u5355\u5F00\u59CB\u3002",
|
|
16535
|
-
members: "
|
|
16701
|
+
members: "{{names}}",
|
|
16536
16702
|
import: "\u5BFC\u5165\u540D\u5355",
|
|
16537
16703
|
importing: "\u6B63\u5728\u5BFC\u5165\u2026",
|
|
16538
16704
|
imported: "\u540D\u5355\u5DF2\u5BFC\u5165\u3002"
|
|
@@ -16783,6 +16949,107 @@ function registerTrial(ctx, runtime) {
|
|
|
16783
16949
|
});
|
|
16784
16950
|
}
|
|
16785
16951
|
|
|
16952
|
+
// src/trial/mirror.ts
|
|
16953
|
+
var SUMMARY_MAX = 500;
|
|
16954
|
+
var MEMBER_LIMIT2 = 500;
|
|
16955
|
+
var RECONCILE_MS2 = 12e4;
|
|
16956
|
+
var cut = (text) => text.length > SUMMARY_MAX ? `${text.slice(0, SUMMARY_MAX - 1)}\u2026` : text;
|
|
16957
|
+
var desiredTrialOf = (view) => {
|
|
16958
|
+
if (view === null) return null;
|
|
16959
|
+
switch (view.status) {
|
|
16960
|
+
case "passed":
|
|
16961
|
+
return {
|
|
16962
|
+
outcome: "passed",
|
|
16963
|
+
summary: view.evidence === "remote" ? "Remote connection verified" : view.evidence === "invoked" ? "Proved by the conversation that opened the team" : "Passed in a local session"
|
|
16964
|
+
};
|
|
16965
|
+
case "overridden":
|
|
16966
|
+
return { outcome: "skipped", summary: "Skipped by a person" };
|
|
16967
|
+
case "failed":
|
|
16968
|
+
return {
|
|
16969
|
+
outcome: "failed",
|
|
16970
|
+
summary: cut(
|
|
16971
|
+
view.failure === null ? "Failed" : `${view.failure.category}: ${view.failure.reason.replace(/\s+/g, " ").trim()}`
|
|
16972
|
+
)
|
|
16973
|
+
};
|
|
16974
|
+
case "pending":
|
|
16975
|
+
return { outcome: "not-run", summary: "Waiting to run" };
|
|
16976
|
+
case "waiting":
|
|
16977
|
+
return { outcome: "not-run", summary: "Sent to the remote agent" };
|
|
16978
|
+
case "running":
|
|
16979
|
+
return { outcome: "not-run", summary: "Running" };
|
|
16980
|
+
}
|
|
16981
|
+
};
|
|
16982
|
+
var TRIAL_FACT = /^team\/member-trial-/u;
|
|
16983
|
+
var isTrialTrigger = (event) => event.type !== "plugin.event-appended" || TRIAL_FACT.test(String(event.payload?.name ?? ""));
|
|
16984
|
+
function startTrialMirror(ctx, deps) {
|
|
16985
|
+
const queue = createSerial("team-trial-mirror-closed");
|
|
16986
|
+
ctx.onDispose(queue.close);
|
|
16987
|
+
const reconcile = async (onlyProjectId, throughSequence) => {
|
|
16988
|
+
const state = await deps.state.get(
|
|
16989
|
+
throughSequence === void 0 ? void 0 : { throughSequence }
|
|
16990
|
+
);
|
|
16991
|
+
const projects = /* @__PURE__ */ new Map();
|
|
16992
|
+
for (const record2 of Object.values(state.members)) {
|
|
16993
|
+
if (onlyProjectId !== void 0 && record2.projectId !== onlyProjectId) continue;
|
|
16994
|
+
const desired = desiredTrialOf(trialViewOf(record2));
|
|
16995
|
+
if (desired === null) continue;
|
|
16996
|
+
const rows = projects.get(record2.projectId) ?? [];
|
|
16997
|
+
rows.push({
|
|
16998
|
+
memberId: record2.memberId,
|
|
16999
|
+
desired,
|
|
17000
|
+
key: JSON.stringify([record2.specKey, record2.attempt])
|
|
17001
|
+
});
|
|
17002
|
+
projects.set(record2.projectId, rows);
|
|
17003
|
+
}
|
|
17004
|
+
for (const [projectId, rows] of projects) {
|
|
17005
|
+
try {
|
|
17006
|
+
const members = await readPages(
|
|
17007
|
+
MEMBER_LIMIT2,
|
|
17008
|
+
(page) => ctx.members.list({ projectId, ...page })
|
|
17009
|
+
);
|
|
17010
|
+
const recorded = new Map(members.items.map((member) => [member.memberId, member]));
|
|
17011
|
+
for (const row of rows) {
|
|
17012
|
+
const member = recorded.get(row.memberId);
|
|
17013
|
+
if (member === void 0 || member.removedAt !== null || member.kind !== "agent")
|
|
17014
|
+
continue;
|
|
17015
|
+
if (member.trial?.outcome === row.desired.outcome && (member.trial.summary ?? "") === row.desired.summary)
|
|
17016
|
+
continue;
|
|
17017
|
+
await ctx.members.trial.record({
|
|
17018
|
+
projectId,
|
|
17019
|
+
memberId: row.memberId,
|
|
17020
|
+
outcome: row.desired.outcome,
|
|
17021
|
+
summary: row.desired.summary,
|
|
17022
|
+
requestId: `team-trial-record:${stableHash(
|
|
17023
|
+
JSON.stringify([projectId, row.memberId, row.key, row.desired])
|
|
17024
|
+
)}`
|
|
17025
|
+
}).catch(
|
|
17026
|
+
(error) => ctx.log.warn("team trial result could not be recorded on the member", {
|
|
17027
|
+
projectId,
|
|
17028
|
+
memberId: row.memberId,
|
|
17029
|
+
error
|
|
17030
|
+
})
|
|
17031
|
+
);
|
|
17032
|
+
}
|
|
17033
|
+
} catch (error) {
|
|
17034
|
+
ctx.log.warn("team trial results could not be compared with the members", {
|
|
17035
|
+
projectId,
|
|
17036
|
+
error
|
|
17037
|
+
});
|
|
17038
|
+
}
|
|
17039
|
+
}
|
|
17040
|
+
};
|
|
17041
|
+
const flush = (onlyProjectId, throughSequence) => queue.run(() => reconcile(onlyProjectId, throughSequence));
|
|
17042
|
+
ctx.reactor({
|
|
17043
|
+
name: "team-trial-mirror",
|
|
17044
|
+
events: ["plugin.event-appended", "member.created", "member.updated", "member.restored"],
|
|
17045
|
+
handle: (event) => isTrialTrigger(event) ? flush(event.aggregateKind === "project" ? event.aggregateId : void 0, event.sequence) : Promise.resolve()
|
|
17046
|
+
});
|
|
17047
|
+
ctx.interval({ name: "team-trial-mirror", everyMs: RECONCILE_MS2, handle: () => flush() });
|
|
17048
|
+
const ready = flush();
|
|
17049
|
+
void ready.catch((error) => ctx.log.warn("team trial mirror catch-up failed", { error }));
|
|
17050
|
+
return { ready, flush };
|
|
17051
|
+
}
|
|
17052
|
+
|
|
16786
17053
|
// src/trial/env.ts
|
|
16787
17054
|
var factKey = (record2) => ({
|
|
16788
17055
|
version: 1,
|
|
@@ -17134,7 +17401,7 @@ var decodeHuman2 = decodeUnknownOption2(HumanPrincipal);
|
|
|
17134
17401
|
var decodeFactName = decodeUnknownOption2(
|
|
17135
17402
|
Struct({ pluginId: Literal2("team"), name: String4 })
|
|
17136
17403
|
);
|
|
17137
|
-
var
|
|
17404
|
+
var isTrialTrigger2 = (event) => {
|
|
17138
17405
|
if (event.type.startsWith("member.")) return true;
|
|
17139
17406
|
if (event.type !== "plugin.event-appended") return false;
|
|
17140
17407
|
const fact = decodeFactName(event.payload);
|
|
@@ -17321,7 +17588,7 @@ function startTrialRuntime(ctx, deps, options = {}) {
|
|
|
17321
17588
|
const threadId = event.payload?.threadId;
|
|
17322
17589
|
return typeof threadId === "string" && threadId.startsWith("team-trial:") ? failOnSessionError(event).then(() => flush()) : Promise.resolve();
|
|
17323
17590
|
}
|
|
17324
|
-
return
|
|
17591
|
+
return isTrialTrigger2(event) ? flush() : Promise.resolve();
|
|
17325
17592
|
}
|
|
17326
17593
|
});
|
|
17327
17594
|
ctx.interval({ name: "team-trial", everyMs: options.tickMs ?? TICK_MS2, handle: () => flush() });
|
|
@@ -17452,7 +17719,7 @@ function startTrialRuntime(ctx, deps, options = {}) {
|
|
|
17452
17719
|
// src/index.ts
|
|
17453
17720
|
var index_default = definePlugin({
|
|
17454
17721
|
id: "team",
|
|
17455
|
-
apiVersion:
|
|
17722
|
+
apiVersion: 51,
|
|
17456
17723
|
activate(ctx) {
|
|
17457
17724
|
const trialState = ctx.derivedState(trialStateDefinition);
|
|
17458
17725
|
const rosters = createRosterService(ctx);
|
|
@@ -17484,7 +17751,8 @@ var index_default = definePlugin({
|
|
|
17484
17751
|
},
|
|
17485
17752
|
memberQueue
|
|
17486
17753
|
);
|
|
17487
|
-
|
|
17754
|
+
registerDispatchClaim(ctx, wakes.state);
|
|
17755
|
+
registerPauseCommands(ctx, { wakes: wakes.state, queue: memberQueue });
|
|
17488
17756
|
startArchiveMirror(
|
|
17489
17757
|
ctx,
|
|
17490
17758
|
{ state: ctx.derivedState(archiveStateDefinition), wakes: wakes.state },
|
|
@@ -17512,6 +17780,7 @@ var index_default = definePlugin({
|
|
|
17512
17780
|
handbookRelease: async (projectId) => (await handbook.read(projectId)).currentRelease
|
|
17513
17781
|
});
|
|
17514
17782
|
registerTrial(ctx, trials2);
|
|
17783
|
+
startTrialMirror(ctx, { state: trialState });
|
|
17515
17784
|
}
|
|
17516
17785
|
});
|
|
17517
17786
|
export {
|