@ycodium-ai/plugin-team 0.2.3681 → 0.2.3766
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/assets/ui.js +10 -10
- package/dist/index.js +1537 -1981
- package/locales/en.json +14 -4
- package/locales/zh-CN.json +14 -4
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -475,134 +475,6 @@ var compareSets = /* @__PURE__ */ makeCompareSet(compareBoth);
|
|
|
475
475
|
var isEqual = (u) => hasProperty(u, symbol2);
|
|
476
476
|
var asEquivalence = () => equals;
|
|
477
477
|
|
|
478
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Reducer.js
|
|
479
|
-
function make(combine2, initialValue, combineAll) {
|
|
480
|
-
return {
|
|
481
|
-
combine: combine2,
|
|
482
|
-
initialValue,
|
|
483
|
-
combineAll: combineAll ?? ((collection) => {
|
|
484
|
-
let out = initialValue;
|
|
485
|
-
for (const value of collection) {
|
|
486
|
-
out = combine2(out, value);
|
|
487
|
-
}
|
|
488
|
-
return out;
|
|
489
|
-
})
|
|
490
|
-
};
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Equivalence.js
|
|
494
|
-
var make2 = (isEquivalent) => (self, that) => self === that || isEquivalent(self, that);
|
|
495
|
-
|
|
496
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/array.js
|
|
497
|
-
var isArrayNonEmpty = (self) => self.length > 0;
|
|
498
|
-
|
|
499
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/doNotation.js
|
|
500
|
-
var let_ = (map7) => dual(3, (self, name, f) => map7(self, (a) => ({
|
|
501
|
-
...a,
|
|
502
|
-
[name]: f(a)
|
|
503
|
-
})));
|
|
504
|
-
var bindTo = (map7) => dual(2, (self, name) => map7(self, (a) => ({
|
|
505
|
-
[name]: a
|
|
506
|
-
})));
|
|
507
|
-
var bind = (map7, flatMap4) => dual(3, (self, name, f) => flatMap4(self, (a) => map7(f(a), (b) => ({
|
|
508
|
-
...a,
|
|
509
|
-
[name]: b
|
|
510
|
-
}))));
|
|
511
|
-
|
|
512
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/record.js
|
|
513
|
-
function assignProperty(self, key, value) {
|
|
514
|
-
if (key === "__proto__") {
|
|
515
|
-
Object.defineProperty(self, key, {
|
|
516
|
-
value,
|
|
517
|
-
writable: true,
|
|
518
|
-
enumerable: true,
|
|
519
|
-
configurable: true
|
|
520
|
-
});
|
|
521
|
-
} else {
|
|
522
|
-
;
|
|
523
|
-
self[key] = value;
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
function assignProperties(self, source) {
|
|
527
|
-
for (const key of Reflect.ownKeys(source)) {
|
|
528
|
-
if (Object.prototype.propertyIsEnumerable.call(source, key)) {
|
|
529
|
-
assignProperty(self, key, source[key]);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Option.js
|
|
535
|
-
var Option_exports = {};
|
|
536
|
-
__export(Option_exports, {
|
|
537
|
-
Do: () => Do,
|
|
538
|
-
all: () => all,
|
|
539
|
-
andThen: () => andThen,
|
|
540
|
-
as: () => as,
|
|
541
|
-
asVoid: () => asVoid,
|
|
542
|
-
bind: () => bind2,
|
|
543
|
-
bindTo: () => bindTo2,
|
|
544
|
-
composeK: () => composeK,
|
|
545
|
-
contains: () => contains,
|
|
546
|
-
containsWith: () => containsWith,
|
|
547
|
-
exists: () => exists,
|
|
548
|
-
filter: () => filter,
|
|
549
|
-
filterMap: () => filterMap,
|
|
550
|
-
firstSomeOf: () => firstSomeOf,
|
|
551
|
-
flatMap: () => flatMap,
|
|
552
|
-
flatMapNullishOr: () => flatMapNullishOr,
|
|
553
|
-
flatten: () => flatten,
|
|
554
|
-
fromIterable: () => fromIterable,
|
|
555
|
-
fromNullOr: () => fromNullOr,
|
|
556
|
-
fromNullishOr: () => fromNullishOr,
|
|
557
|
-
fromUndefinedOr: () => fromUndefinedOr,
|
|
558
|
-
gen: () => gen,
|
|
559
|
-
getFailure: () => getFailure2,
|
|
560
|
-
getOrElse: () => getOrElse,
|
|
561
|
-
getOrNull: () => getOrNull,
|
|
562
|
-
getOrThrow: () => getOrThrow,
|
|
563
|
-
getOrThrowWith: () => getOrThrowWith,
|
|
564
|
-
getOrUndefined: () => getOrUndefined,
|
|
565
|
-
getSuccess: () => getSuccess2,
|
|
566
|
-
isNone: () => isNone2,
|
|
567
|
-
isOption: () => isOption2,
|
|
568
|
-
isSome: () => isSome2,
|
|
569
|
-
let: () => let_2,
|
|
570
|
-
lift2: () => lift2,
|
|
571
|
-
liftNullishOr: () => liftNullishOr,
|
|
572
|
-
liftPredicate: () => liftPredicate,
|
|
573
|
-
liftThrowable: () => liftThrowable,
|
|
574
|
-
makeCombinerFailFast: () => makeCombinerFailFast,
|
|
575
|
-
makeEquivalence: () => makeEquivalence,
|
|
576
|
-
makeOrder: () => makeOrder,
|
|
577
|
-
makeReducer: () => makeReducer,
|
|
578
|
-
makeReducerFailFast: () => makeReducerFailFast,
|
|
579
|
-
map: () => map,
|
|
580
|
-
match: () => match,
|
|
581
|
-
none: () => none2,
|
|
582
|
-
orElse: () => orElse,
|
|
583
|
-
orElseResult: () => orElseResult,
|
|
584
|
-
orElseSome: () => orElseSome,
|
|
585
|
-
partitionMap: () => partitionMap,
|
|
586
|
-
product: () => product,
|
|
587
|
-
productMany: () => productMany,
|
|
588
|
-
reduceCompact: () => reduceCompact,
|
|
589
|
-
some: () => some2,
|
|
590
|
-
tap: () => tap,
|
|
591
|
-
toArray: () => toArray,
|
|
592
|
-
toRefinement: () => toRefinement,
|
|
593
|
-
void: () => void_,
|
|
594
|
-
zipLeft: () => zipLeft,
|
|
595
|
-
zipRight: () => zipRight,
|
|
596
|
-
zipWith: () => zipWith
|
|
597
|
-
});
|
|
598
|
-
|
|
599
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Combiner.js
|
|
600
|
-
function make3(combine2) {
|
|
601
|
-
return {
|
|
602
|
-
combine: combine2
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
|
|
606
478
|
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Redactable.js
|
|
607
479
|
var symbolRedactable = /* @__PURE__ */ Symbol.for("~effect/Redactable");
|
|
608
480
|
var isRedactable = (u) => hasProperty(u, symbolRedactable);
|
|
@@ -825,6 +697,28 @@ var pickInternalCall = () => {
|
|
|
825
697
|
};
|
|
826
698
|
var internalCall = /* @__PURE__ */ pickInternalCall();
|
|
827
699
|
|
|
700
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/record.js
|
|
701
|
+
function assignProperty(self, key, value) {
|
|
702
|
+
if (key === "__proto__") {
|
|
703
|
+
Object.defineProperty(self, key, {
|
|
704
|
+
value,
|
|
705
|
+
writable: true,
|
|
706
|
+
enumerable: true,
|
|
707
|
+
configurable: true
|
|
708
|
+
});
|
|
709
|
+
} else {
|
|
710
|
+
;
|
|
711
|
+
self[key] = value;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
function assignProperties(self, source) {
|
|
715
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
716
|
+
if (Object.prototype.propertyIsEnumerable.call(source, key)) {
|
|
717
|
+
assignProperty(self, key, source[key]);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
828
722
|
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/core.js
|
|
829
723
|
var EffectTypeId = `~effect/Effect`;
|
|
830
724
|
var ExitTypeId = `~effect/Exit`;
|
|
@@ -1168,103 +1062,229 @@ var DoneVoid = {
|
|
|
1168
1062
|
value: void 0
|
|
1169
1063
|
};
|
|
1170
1064
|
|
|
1171
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/
|
|
1172
|
-
var
|
|
1173
|
-
|
|
1174
|
-
[
|
|
1175
|
-
_A: (_) => _
|
|
1176
|
-
},
|
|
1177
|
-
...PipeInspectableProto,
|
|
1178
|
-
[Symbol.iterator]() {
|
|
1179
|
-
return new SingleShotGen(this);
|
|
1180
|
-
}
|
|
1181
|
-
};
|
|
1182
|
-
var SomeProto = /* @__PURE__ */ Object.defineProperty(/* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(CommonProto), {
|
|
1183
|
-
_tag: "Some",
|
|
1184
|
-
_op: "Some",
|
|
1185
|
-
[symbol2](that) {
|
|
1186
|
-
return isOption(that) && isSome(that) && equals(this.value, that.value);
|
|
1187
|
-
},
|
|
1188
|
-
[symbol]() {
|
|
1189
|
-
return combine(hash(this._tag))(hash(this.value));
|
|
1190
|
-
},
|
|
1191
|
-
toString() {
|
|
1192
|
-
return `some(${format(this.value)})`;
|
|
1193
|
-
},
|
|
1194
|
-
toJSON() {
|
|
1195
|
-
return {
|
|
1196
|
-
_id: "Option",
|
|
1197
|
-
_tag: this._tag,
|
|
1198
|
-
value: toJson(this.value)
|
|
1199
|
-
};
|
|
1200
|
-
}
|
|
1201
|
-
}), "valueOrUndefined", {
|
|
1202
|
-
get() {
|
|
1203
|
-
return this.value;
|
|
1204
|
-
}
|
|
1205
|
-
});
|
|
1206
|
-
var NoneHash = /* @__PURE__ */ hash("None");
|
|
1207
|
-
var NoneProto = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(CommonProto), {
|
|
1208
|
-
_tag: "None",
|
|
1209
|
-
_op: "None",
|
|
1210
|
-
valueOrUndefined: void 0,
|
|
1211
|
-
[symbol2](that) {
|
|
1212
|
-
return isOption(that) && isNone(that);
|
|
1213
|
-
},
|
|
1214
|
-
[symbol]() {
|
|
1215
|
-
return NoneHash;
|
|
1216
|
-
},
|
|
1217
|
-
toString() {
|
|
1218
|
-
return `none()`;
|
|
1219
|
-
},
|
|
1220
|
-
toJSON() {
|
|
1221
|
-
return {
|
|
1222
|
-
_id: "Option",
|
|
1223
|
-
_tag: this._tag
|
|
1224
|
-
};
|
|
1225
|
-
}
|
|
1065
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Effectable.js
|
|
1066
|
+
var Prototype2 = (options) => makePrimitiveProto({
|
|
1067
|
+
op: options.label,
|
|
1068
|
+
[evaluate]: options.evaluate
|
|
1226
1069
|
});
|
|
1227
|
-
var isOption = (input) => hasProperty(input, TypeId);
|
|
1228
|
-
var isNone = (fa) => fa._tag === "None";
|
|
1229
|
-
var isSome = (fa) => fa._tag === "Some";
|
|
1230
|
-
var none = /* @__PURE__ */ Object.create(NoneProto);
|
|
1231
|
-
var some = (value) => {
|
|
1232
|
-
const a = Object.create(SomeProto);
|
|
1233
|
-
a.value = value;
|
|
1234
|
-
return a;
|
|
1235
|
-
};
|
|
1236
1070
|
|
|
1237
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/
|
|
1238
|
-
var
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
_A: (_) => _,
|
|
1243
|
-
_E: (_) => _
|
|
1244
|
-
},
|
|
1245
|
-
...PipeInspectableProto,
|
|
1246
|
-
[Symbol.iterator]() {
|
|
1247
|
-
return new SingleShotGen(this);
|
|
1071
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/stackTraceLimit.js
|
|
1072
|
+
var isStackTraceLimitWritable = () => {
|
|
1073
|
+
const desc = Object.getOwnPropertyDescriptor(Error, "stackTraceLimit");
|
|
1074
|
+
if (desc === void 0) {
|
|
1075
|
+
return Object.isExtensible(Error);
|
|
1248
1076
|
}
|
|
1077
|
+
return Object.hasOwn(desc, "writable") ? desc.writable === true : desc.set !== void 0;
|
|
1249
1078
|
};
|
|
1250
|
-
var
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1079
|
+
var canWriteStackTraceLimit = /* @__PURE__ */ isStackTraceLimitWritable();
|
|
1080
|
+
var getStackTraceLimit = () => Error.stackTraceLimit;
|
|
1081
|
+
var setStackTraceLimit = (value) => {
|
|
1082
|
+
if (canWriteStackTraceLimit) {
|
|
1083
|
+
;
|
|
1084
|
+
Error.stackTraceLimit = value;
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
|
|
1088
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Option.js
|
|
1089
|
+
var Option_exports = {};
|
|
1090
|
+
__export(Option_exports, {
|
|
1091
|
+
Do: () => Do,
|
|
1092
|
+
all: () => all,
|
|
1093
|
+
andThen: () => andThen,
|
|
1094
|
+
as: () => as,
|
|
1095
|
+
asVoid: () => asVoid,
|
|
1096
|
+
bind: () => bind2,
|
|
1097
|
+
bindTo: () => bindTo2,
|
|
1098
|
+
composeK: () => composeK,
|
|
1099
|
+
contains: () => contains,
|
|
1100
|
+
containsWith: () => containsWith,
|
|
1101
|
+
exists: () => exists,
|
|
1102
|
+
filter: () => filter,
|
|
1103
|
+
filterMap: () => filterMap,
|
|
1104
|
+
firstSomeOf: () => firstSomeOf,
|
|
1105
|
+
flatMap: () => flatMap,
|
|
1106
|
+
flatMapNullishOr: () => flatMapNullishOr,
|
|
1107
|
+
flatten: () => flatten,
|
|
1108
|
+
fromIterable: () => fromIterable,
|
|
1109
|
+
fromNullOr: () => fromNullOr,
|
|
1110
|
+
fromNullishOr: () => fromNullishOr,
|
|
1111
|
+
fromUndefinedOr: () => fromUndefinedOr,
|
|
1112
|
+
gen: () => gen,
|
|
1113
|
+
getFailure: () => getFailure2,
|
|
1114
|
+
getOrElse: () => getOrElse,
|
|
1115
|
+
getOrNull: () => getOrNull,
|
|
1116
|
+
getOrThrow: () => getOrThrow,
|
|
1117
|
+
getOrThrowWith: () => getOrThrowWith,
|
|
1118
|
+
getOrUndefined: () => getOrUndefined,
|
|
1119
|
+
getSuccess: () => getSuccess2,
|
|
1120
|
+
isNone: () => isNone2,
|
|
1121
|
+
isOption: () => isOption2,
|
|
1122
|
+
isSome: () => isSome2,
|
|
1123
|
+
let: () => let_2,
|
|
1124
|
+
lift2: () => lift2,
|
|
1125
|
+
liftNullishOr: () => liftNullishOr,
|
|
1126
|
+
liftPredicate: () => liftPredicate,
|
|
1127
|
+
liftThrowable: () => liftThrowable,
|
|
1128
|
+
makeCombinerFailFast: () => makeCombinerFailFast,
|
|
1129
|
+
makeEquivalence: () => makeEquivalence,
|
|
1130
|
+
makeOrder: () => makeOrder,
|
|
1131
|
+
makeReducer: () => makeReducer,
|
|
1132
|
+
makeReducerFailFast: () => makeReducerFailFast,
|
|
1133
|
+
map: () => map,
|
|
1134
|
+
match: () => match,
|
|
1135
|
+
none: () => none2,
|
|
1136
|
+
orElse: () => orElse,
|
|
1137
|
+
orElseResult: () => orElseResult,
|
|
1138
|
+
orElseSome: () => orElseSome,
|
|
1139
|
+
partitionMap: () => partitionMap,
|
|
1140
|
+
product: () => product,
|
|
1141
|
+
productMany: () => productMany,
|
|
1142
|
+
reduceCompact: () => reduceCompact,
|
|
1143
|
+
some: () => some2,
|
|
1144
|
+
tap: () => tap,
|
|
1145
|
+
toArray: () => toArray,
|
|
1146
|
+
toRefinement: () => toRefinement,
|
|
1147
|
+
void: () => void_,
|
|
1148
|
+
zipLeft: () => zipLeft,
|
|
1149
|
+
zipRight: () => zipRight,
|
|
1150
|
+
zipWith: () => zipWith
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Combiner.js
|
|
1154
|
+
function make(combine2) {
|
|
1155
|
+
return {
|
|
1156
|
+
combine: combine2
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Reducer.js
|
|
1161
|
+
function make2(combine2, initialValue, combineAll) {
|
|
1162
|
+
return {
|
|
1163
|
+
combine: combine2,
|
|
1164
|
+
initialValue,
|
|
1165
|
+
combineAll: combineAll ?? ((collection) => {
|
|
1166
|
+
let out = initialValue;
|
|
1167
|
+
for (const value of collection) {
|
|
1168
|
+
out = combine2(out, value);
|
|
1169
|
+
}
|
|
1170
|
+
return out;
|
|
1171
|
+
})
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Equivalence.js
|
|
1176
|
+
var make3 = (isEquivalent) => (self, that) => self === that || isEquivalent(self, that);
|
|
1177
|
+
|
|
1178
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/doNotation.js
|
|
1179
|
+
var let_ = (map7) => dual(3, (self, name, f) => map7(self, (a) => ({
|
|
1180
|
+
...a,
|
|
1181
|
+
[name]: f(a)
|
|
1182
|
+
})));
|
|
1183
|
+
var bindTo = (map7) => dual(2, (self, name) => map7(self, (a) => ({
|
|
1184
|
+
[name]: a
|
|
1185
|
+
})));
|
|
1186
|
+
var bind = (map7, flatMap4) => dual(3, (self, name, f) => flatMap4(self, (a) => map7(f(a), (b) => ({
|
|
1187
|
+
...a,
|
|
1188
|
+
[name]: b
|
|
1189
|
+
}))));
|
|
1190
|
+
|
|
1191
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/option.js
|
|
1192
|
+
var TypeId = "~effect/data/Option";
|
|
1193
|
+
var CommonProto = {
|
|
1194
|
+
[TypeId]: {
|
|
1195
|
+
_A: (_) => _
|
|
1196
|
+
},
|
|
1197
|
+
...PipeInspectableProto,
|
|
1198
|
+
[Symbol.iterator]() {
|
|
1199
|
+
return new SingleShotGen(this);
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
1202
|
+
var SomeProto = /* @__PURE__ */ Object.defineProperty(/* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(CommonProto), {
|
|
1203
|
+
_tag: "Some",
|
|
1204
|
+
_op: "Some",
|
|
1205
|
+
[symbol2](that) {
|
|
1206
|
+
return isOption(that) && isSome(that) && equals(this.value, that.value);
|
|
1207
|
+
},
|
|
1208
|
+
[symbol]() {
|
|
1209
|
+
return combine(hash(this._tag))(hash(this.value));
|
|
1210
|
+
},
|
|
1211
|
+
toString() {
|
|
1212
|
+
return `some(${format(this.value)})`;
|
|
1213
|
+
},
|
|
1214
|
+
toJSON() {
|
|
1215
|
+
return {
|
|
1216
|
+
_id: "Option",
|
|
1217
|
+
_tag: this._tag,
|
|
1218
|
+
value: toJson(this.value)
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
}), "valueOrUndefined", {
|
|
1222
|
+
get() {
|
|
1223
|
+
return this.value;
|
|
1224
|
+
}
|
|
1225
|
+
});
|
|
1226
|
+
var NoneHash = /* @__PURE__ */ hash("None");
|
|
1227
|
+
var NoneProto = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(CommonProto), {
|
|
1228
|
+
_tag: "None",
|
|
1229
|
+
_op: "None",
|
|
1230
|
+
valueOrUndefined: void 0,
|
|
1231
|
+
[symbol2](that) {
|
|
1232
|
+
return isOption(that) && isNone(that);
|
|
1233
|
+
},
|
|
1234
|
+
[symbol]() {
|
|
1235
|
+
return NoneHash;
|
|
1236
|
+
},
|
|
1237
|
+
toString() {
|
|
1238
|
+
return `none()`;
|
|
1239
|
+
},
|
|
1240
|
+
toJSON() {
|
|
1241
|
+
return {
|
|
1242
|
+
_id: "Option",
|
|
1243
|
+
_tag: this._tag
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1247
|
+
var isOption = (input) => hasProperty(input, TypeId);
|
|
1248
|
+
var isNone = (fa) => fa._tag === "None";
|
|
1249
|
+
var isSome = (fa) => fa._tag === "Some";
|
|
1250
|
+
var none = /* @__PURE__ */ Object.create(NoneProto);
|
|
1251
|
+
var some = (value) => {
|
|
1252
|
+
const a = Object.create(SomeProto);
|
|
1253
|
+
a.value = value;
|
|
1254
|
+
return a;
|
|
1255
|
+
};
|
|
1256
|
+
|
|
1257
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/result.js
|
|
1258
|
+
var TypeId2 = "~effect/data/Result";
|
|
1259
|
+
var CommonProto2 = {
|
|
1260
|
+
[TypeId2]: {
|
|
1261
|
+
/* v8 ignore next 2 */
|
|
1262
|
+
_A: (_) => _,
|
|
1263
|
+
_E: (_) => _
|
|
1264
|
+
},
|
|
1265
|
+
...PipeInspectableProto,
|
|
1266
|
+
[Symbol.iterator]() {
|
|
1267
|
+
return new SingleShotGen(this);
|
|
1268
|
+
}
|
|
1269
|
+
};
|
|
1270
|
+
var SuccessProto = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(CommonProto2), {
|
|
1271
|
+
_tag: "Success",
|
|
1272
|
+
_op: "Success",
|
|
1273
|
+
[symbol2](that) {
|
|
1274
|
+
return isResult(that) && isSuccess(that) && equals(this.success, that.success);
|
|
1275
|
+
},
|
|
1276
|
+
[symbol]() {
|
|
1277
|
+
return combine(hash(this._tag))(hash(this.success));
|
|
1278
|
+
},
|
|
1279
|
+
toString() {
|
|
1280
|
+
return `success(${format(this.success)})`;
|
|
1281
|
+
},
|
|
1282
|
+
toJSON() {
|
|
1283
|
+
return {
|
|
1284
|
+
_id: "Result",
|
|
1285
|
+
_tag: this._tag,
|
|
1286
|
+
value: toJson(this.success)
|
|
1287
|
+
};
|
|
1268
1288
|
}
|
|
1269
1289
|
});
|
|
1270
1290
|
var FailureProto = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(CommonProto2), {
|
|
@@ -1443,7 +1463,7 @@ var filterMap = /* @__PURE__ */ dual(2, (self, f) => {
|
|
|
1443
1463
|
return isSuccess(next) ? some2(next.success) : none2();
|
|
1444
1464
|
});
|
|
1445
1465
|
var filter = /* @__PURE__ */ dual(2, (self, predicate) => isNone2(self) ? none2() : predicate(self.value) ? some2(self.value) : none2());
|
|
1446
|
-
var makeEquivalence = (isEquivalent) =>
|
|
1466
|
+
var makeEquivalence = (isEquivalent) => make3((x, y) => isNone2(x) ? isNone2(y) : isNone2(y) ? false : isEquivalent(x.value, y.value));
|
|
1447
1467
|
var makeOrder = (O) => make4((self, that) => isSome2(self) ? isSome2(that) ? O(self.value, that.value) : 1 : -1);
|
|
1448
1468
|
var lift2 = (f) => dual(2, (self, that) => zipWith(self, that, f));
|
|
1449
1469
|
var liftPredicate = /* @__PURE__ */ dual(2, (b, predicate) => predicate(b) ? some2(b) : none2());
|
|
@@ -1468,14 +1488,14 @@ var gen = (...args2) => {
|
|
|
1468
1488
|
return some2(state.value);
|
|
1469
1489
|
};
|
|
1470
1490
|
function makeReducer(combiner) {
|
|
1471
|
-
return
|
|
1491
|
+
return make2((self, that) => {
|
|
1472
1492
|
if (isNone2(self)) return that;
|
|
1473
1493
|
if (isNone2(that)) return self;
|
|
1474
1494
|
return some2(combiner.combine(self.value, that.value));
|
|
1475
1495
|
}, none2());
|
|
1476
1496
|
}
|
|
1477
1497
|
function makeCombinerFailFast(combiner) {
|
|
1478
|
-
return
|
|
1498
|
+
return make((self, that) => {
|
|
1479
1499
|
if (isNone2(self) || isNone2(that)) return none2();
|
|
1480
1500
|
return some2(combiner.combine(self.value, that.value));
|
|
1481
1501
|
});
|
|
@@ -1483,7 +1503,7 @@ function makeCombinerFailFast(combiner) {
|
|
|
1483
1503
|
function makeReducerFailFast(reducer) {
|
|
1484
1504
|
const combine2 = makeCombinerFailFast(reducer).combine;
|
|
1485
1505
|
const initialValue = some2(reducer.initialValue);
|
|
1486
|
-
return
|
|
1506
|
+
return make2(combine2, initialValue, (collection) => {
|
|
1487
1507
|
let out = initialValue;
|
|
1488
1508
|
for (const value of collection) {
|
|
1489
1509
|
out = combine2(out, value);
|
|
@@ -1493,100 +1513,20 @@ function makeReducerFailFast(reducer) {
|
|
|
1493
1513
|
});
|
|
1494
1514
|
}
|
|
1495
1515
|
|
|
1496
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/
|
|
1497
|
-
var
|
|
1498
|
-
var
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Array.js
|
|
1506
|
-
var Array2 = globalThis.Array;
|
|
1507
|
-
var fromIterable2 = (collection) => Array2.isArray(collection) ? collection : Array2.from(collection);
|
|
1508
|
-
var append = /* @__PURE__ */ dual(2, (self, last) => [...self, last]);
|
|
1509
|
-
var appendAll = /* @__PURE__ */ dual(2, (self, that) => fromIterable2(self).concat(fromIterable2(that)));
|
|
1510
|
-
var isArray = Array2.isArray;
|
|
1511
|
-
var isArrayNonEmpty2 = isArrayNonEmpty;
|
|
1512
|
-
var isReadonlyArrayNonEmpty = isArrayNonEmpty;
|
|
1513
|
-
var hashBucketsAdd = (buckets, value) => {
|
|
1514
|
-
const hash2 = hash(value);
|
|
1515
|
-
const bucket = buckets.get(hash2);
|
|
1516
|
-
if (bucket === void 0) {
|
|
1517
|
-
buckets.set(hash2, [value]);
|
|
1518
|
-
return true;
|
|
1516
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Context.js
|
|
1517
|
+
var ServiceTypeId = "~effect/Context/Service";
|
|
1518
|
+
var Service = function() {
|
|
1519
|
+
const prevLimit = getStackTraceLimit();
|
|
1520
|
+
setStackTraceLimit(2);
|
|
1521
|
+
const err = new Error();
|
|
1522
|
+
setStackTraceLimit(prevLimit);
|
|
1523
|
+
function KeyClass() {
|
|
1519
1524
|
}
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
bucket.push(value);
|
|
1526
|
-
return true;
|
|
1527
|
-
};
|
|
1528
|
-
var union = /* @__PURE__ */ dual(2, (self, that) => {
|
|
1529
|
-
const a = fromIterable2(self);
|
|
1530
|
-
const b = fromIterable2(that);
|
|
1531
|
-
if (isReadonlyArrayNonEmpty(a)) {
|
|
1532
|
-
return isReadonlyArrayNonEmpty(b) ? dedupe(appendAll(a, b)) : a;
|
|
1533
|
-
}
|
|
1534
|
-
return b;
|
|
1535
|
-
});
|
|
1536
|
-
var empty = () => [];
|
|
1537
|
-
var map2 = /* @__PURE__ */ dual(2, (self, f) => self.map(f));
|
|
1538
|
-
var dedupe = (self) => {
|
|
1539
|
-
const input = fromIterable2(self);
|
|
1540
|
-
if (input.length < 2) {
|
|
1541
|
-
return [...input];
|
|
1542
|
-
}
|
|
1543
|
-
const buckets = /* @__PURE__ */ new Map();
|
|
1544
|
-
const out = [];
|
|
1545
|
-
for (const value of input) {
|
|
1546
|
-
if (hashBucketsAdd(buckets, value)) {
|
|
1547
|
-
out.push(value);
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
return out;
|
|
1551
|
-
};
|
|
1552
|
-
|
|
1553
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Effectable.js
|
|
1554
|
-
var Prototype2 = (options) => makePrimitiveProto({
|
|
1555
|
-
op: options.label,
|
|
1556
|
-
[evaluate]: options.evaluate
|
|
1557
|
-
});
|
|
1558
|
-
|
|
1559
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/stackTraceLimit.js
|
|
1560
|
-
var isStackTraceLimitWritable = () => {
|
|
1561
|
-
const desc = Object.getOwnPropertyDescriptor(Error, "stackTraceLimit");
|
|
1562
|
-
if (desc === void 0) {
|
|
1563
|
-
return Object.isExtensible(Error);
|
|
1564
|
-
}
|
|
1565
|
-
return Object.hasOwn(desc, "writable") ? desc.writable === true : desc.set !== void 0;
|
|
1566
|
-
};
|
|
1567
|
-
var canWriteStackTraceLimit = /* @__PURE__ */ isStackTraceLimitWritable();
|
|
1568
|
-
var getStackTraceLimit = () => Error.stackTraceLimit;
|
|
1569
|
-
var setStackTraceLimit = (value) => {
|
|
1570
|
-
if (canWriteStackTraceLimit) {
|
|
1571
|
-
;
|
|
1572
|
-
Error.stackTraceLimit = value;
|
|
1573
|
-
}
|
|
1574
|
-
};
|
|
1575
|
-
|
|
1576
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Context.js
|
|
1577
|
-
var ServiceTypeId = "~effect/Context/Service";
|
|
1578
|
-
var Service = function() {
|
|
1579
|
-
const prevLimit = getStackTraceLimit();
|
|
1580
|
-
setStackTraceLimit(2);
|
|
1581
|
-
const err = new Error();
|
|
1582
|
-
setStackTraceLimit(prevLimit);
|
|
1583
|
-
function KeyClass() {
|
|
1584
|
-
}
|
|
1585
|
-
const self = KeyClass;
|
|
1586
|
-
Object.setPrototypeOf(self, ServiceProto);
|
|
1587
|
-
Object.defineProperty(self, "stack", {
|
|
1588
|
-
get() {
|
|
1589
|
-
return err.stack;
|
|
1525
|
+
const self = KeyClass;
|
|
1526
|
+
Object.setPrototypeOf(self, ServiceProto);
|
|
1527
|
+
Object.defineProperty(self, "stack", {
|
|
1528
|
+
get() {
|
|
1529
|
+
return err.stack;
|
|
1590
1530
|
}
|
|
1591
1531
|
});
|
|
1592
1532
|
const init = (key, options) => {
|
|
@@ -1711,7 +1651,7 @@ var Proto = {
|
|
|
1711
1651
|
var hasSameCache = (self, that) => self.cacheRoot === that.cacheRoot;
|
|
1712
1652
|
var isContext = (u) => hasProperty(u, TypeId3);
|
|
1713
1653
|
var isReference = (u) => !!u[ReferenceTypeId];
|
|
1714
|
-
var
|
|
1654
|
+
var empty = () => emptyContext2;
|
|
1715
1655
|
var emptyContext2 = /* @__PURE__ */ makeUnsafe(/* @__PURE__ */ new Map());
|
|
1716
1656
|
var make5 = (key, service2) => makeUnsafe(/* @__PURE__ */ new Map([[key.key, service2]]));
|
|
1717
1657
|
var add = /* @__PURE__ */ dual(3, (self, key, service2) => {
|
|
@@ -1959,7 +1899,7 @@ var minutes = (minutes2) => make6(minutes2 * 6e4);
|
|
|
1959
1899
|
var hours = (hours2) => make6(hours2 * 36e5);
|
|
1960
1900
|
var days = (days2) => make6(days2 * 864e5);
|
|
1961
1901
|
var weeks = (weeks2) => make6(weeks2 * 6048e5);
|
|
1962
|
-
var toMillis = (self) =>
|
|
1902
|
+
var toMillis = (self) => match2(fromInputUnsafe(self), {
|
|
1963
1903
|
onMillis: identity,
|
|
1964
1904
|
onNanos: (nanos2) => Number(nanos2) / 1e6,
|
|
1965
1905
|
onInfinity: () => Infinity,
|
|
@@ -1977,7 +1917,7 @@ var toNanosUnsafe = (input) => {
|
|
|
1977
1917
|
return roundMillisToNanos(self.value.millis);
|
|
1978
1918
|
}
|
|
1979
1919
|
};
|
|
1980
|
-
var
|
|
1920
|
+
var match2 = /* @__PURE__ */ dual(2, (self, options) => {
|
|
1981
1921
|
switch (self.value._tag) {
|
|
1982
1922
|
case "Millis":
|
|
1983
1923
|
return options.onMillis(self.value.millis);
|
|
@@ -2004,6 +1944,66 @@ var Equivalence = (self, that) => matchPair(self, that, {
|
|
|
2004
1944
|
});
|
|
2005
1945
|
var equals2 = /* @__PURE__ */ dual(2, (self, that) => Equivalence(self, that));
|
|
2006
1946
|
|
|
1947
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/internal/array.js
|
|
1948
|
+
var isArrayNonEmpty = (self) => self.length > 0;
|
|
1949
|
+
|
|
1950
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Result.js
|
|
1951
|
+
var succeed2 = succeed;
|
|
1952
|
+
var fail2 = fail;
|
|
1953
|
+
var isFailure2 = isFailure;
|
|
1954
|
+
var match3 = /* @__PURE__ */ dual(2, (self, {
|
|
1955
|
+
onFailure,
|
|
1956
|
+
onSuccess
|
|
1957
|
+
}) => isFailure2(self) ? onFailure(self.failure) : onSuccess(self.success));
|
|
1958
|
+
|
|
1959
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Array.js
|
|
1960
|
+
var Array2 = globalThis.Array;
|
|
1961
|
+
var fromIterable2 = (collection) => Array2.isArray(collection) ? collection : Array2.from(collection);
|
|
1962
|
+
var append = /* @__PURE__ */ dual(2, (self, last) => [...self, last]);
|
|
1963
|
+
var appendAll = /* @__PURE__ */ dual(2, (self, that) => fromIterable2(self).concat(fromIterable2(that)));
|
|
1964
|
+
var isArray = Array2.isArray;
|
|
1965
|
+
var isArrayNonEmpty2 = isArrayNonEmpty;
|
|
1966
|
+
var isReadonlyArrayNonEmpty = isArrayNonEmpty;
|
|
1967
|
+
var hashBucketsAdd = (buckets, value) => {
|
|
1968
|
+
const hash2 = hash(value);
|
|
1969
|
+
const bucket = buckets.get(hash2);
|
|
1970
|
+
if (bucket === void 0) {
|
|
1971
|
+
buckets.set(hash2, [value]);
|
|
1972
|
+
return true;
|
|
1973
|
+
}
|
|
1974
|
+
for (const previous of bucket) {
|
|
1975
|
+
if (equals(previous, value)) {
|
|
1976
|
+
return false;
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
bucket.push(value);
|
|
1980
|
+
return true;
|
|
1981
|
+
};
|
|
1982
|
+
var union = /* @__PURE__ */ dual(2, (self, that) => {
|
|
1983
|
+
const a = fromIterable2(self);
|
|
1984
|
+
const b = fromIterable2(that);
|
|
1985
|
+
if (isReadonlyArrayNonEmpty(a)) {
|
|
1986
|
+
return isReadonlyArrayNonEmpty(b) ? dedupe(appendAll(a, b)) : a;
|
|
1987
|
+
}
|
|
1988
|
+
return b;
|
|
1989
|
+
});
|
|
1990
|
+
var empty2 = () => [];
|
|
1991
|
+
var map2 = /* @__PURE__ */ dual(2, (self, f) => self.map(f));
|
|
1992
|
+
var dedupe = (self) => {
|
|
1993
|
+
const input = fromIterable2(self);
|
|
1994
|
+
if (input.length < 2) {
|
|
1995
|
+
return [...input];
|
|
1996
|
+
}
|
|
1997
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1998
|
+
const out = [];
|
|
1999
|
+
for (const value of input) {
|
|
2000
|
+
if (hashBucketsAdd(buckets, value)) {
|
|
2001
|
+
out.push(value);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
return out;
|
|
2005
|
+
};
|
|
2006
|
+
|
|
2007
2007
|
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Scheduler.js
|
|
2008
2008
|
var Scheduler = /* @__PURE__ */ Reference("effect/Scheduler", {
|
|
2009
2009
|
fiberCached: true,
|
|
@@ -2354,7 +2354,7 @@ var FiberImpl = class {
|
|
|
2354
2354
|
}
|
|
2355
2355
|
this._stack.length = 0;
|
|
2356
2356
|
this._children = void 0;
|
|
2357
|
-
this.context =
|
|
2357
|
+
this.context = empty();
|
|
2358
2358
|
}
|
|
2359
2359
|
runLoop(effect) {
|
|
2360
2360
|
const prevFiber = globalThis[currentFiberTypeId];
|
|
@@ -2493,7 +2493,7 @@ var fiberAwaitAll = (self) => callback((resume) => {
|
|
|
2493
2493
|
});
|
|
2494
2494
|
var fiberInterruptAll = (fibers) => withFiber((parent) => {
|
|
2495
2495
|
const annotations = fiberStackAnnotations(parent);
|
|
2496
|
-
let fiberArr =
|
|
2496
|
+
let fiberArr = empty2();
|
|
2497
2497
|
for (const fiber2 of fibers) {
|
|
2498
2498
|
fiber2.interruptUnsafe(parent.id, annotations);
|
|
2499
2499
|
fiberArr.push(fiber2);
|
|
@@ -2517,7 +2517,7 @@ var suspend = /* @__PURE__ */ makePrimitive({
|
|
|
2517
2517
|
return this[args]();
|
|
2518
2518
|
}
|
|
2519
2519
|
});
|
|
2520
|
-
var fromResult = /* @__PURE__ */
|
|
2520
|
+
var fromResult = /* @__PURE__ */ match3({
|
|
2521
2521
|
onFailure: fail3,
|
|
2522
2522
|
onSuccess: succeed3
|
|
2523
2523
|
});
|
|
@@ -3013,7 +3013,7 @@ var runPromiseWith = (context2) => {
|
|
|
3013
3013
|
return exit3.value;
|
|
3014
3014
|
});
|
|
3015
3015
|
};
|
|
3016
|
-
var runPromise = /* @__PURE__ */ runPromiseWith(/* @__PURE__ */
|
|
3016
|
+
var runPromise = /* @__PURE__ */ runPromiseWith(/* @__PURE__ */ empty());
|
|
3017
3017
|
var runSyncExitWith = (context2) => {
|
|
3018
3018
|
const runFork3 = runForkWith(context2);
|
|
3019
3019
|
return (effect) => {
|
|
@@ -3026,7 +3026,7 @@ var runSyncExitWith = (context2) => {
|
|
|
3026
3026
|
return fiber2._exit ?? exitDie(new AsyncFiberError(fiber2));
|
|
3027
3027
|
};
|
|
3028
3028
|
};
|
|
3029
|
-
var runSyncExit = /* @__PURE__ */ runSyncExitWith(/* @__PURE__ */
|
|
3029
|
+
var runSyncExit = /* @__PURE__ */ runSyncExitWith(/* @__PURE__ */ empty());
|
|
3030
3030
|
var ClockRef = /* @__PURE__ */ Reference("effect/Clock", {
|
|
3031
3031
|
defaultValue: () => new ClockImpl()
|
|
3032
3032
|
});
|
|
@@ -3175,13 +3175,6 @@ var logLevelColors = {
|
|
|
3175
3175
|
Fatal: [colors.bgBrightRed, colors.black]
|
|
3176
3176
|
};
|
|
3177
3177
|
|
|
3178
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Cause.js
|
|
3179
|
-
var isFailReason2 = isFailReason;
|
|
3180
|
-
var map4 = causeMap;
|
|
3181
|
-
|
|
3182
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Data.js
|
|
3183
|
-
var TaggedError2 = TaggedError;
|
|
3184
|
-
|
|
3185
3178
|
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Exit.js
|
|
3186
3179
|
var succeed4 = exitSucceed;
|
|
3187
3180
|
var failCause2 = exitFailCause;
|
|
@@ -3189,6 +3182,13 @@ var fail4 = exitFail;
|
|
|
3189
3182
|
var void_3 = exitVoid;
|
|
3190
3183
|
var isSuccess3 = exitIsSuccess;
|
|
3191
3184
|
|
|
3185
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Cause.js
|
|
3186
|
+
var isFailReason2 = isFailReason;
|
|
3187
|
+
var map4 = causeMap;
|
|
3188
|
+
|
|
3189
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Data.js
|
|
3190
|
+
var TaggedError2 = TaggedError;
|
|
3191
|
+
|
|
3192
3192
|
// ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Clock.js
|
|
3193
3193
|
var currentTimeMillis2 = currentTimeMillis;
|
|
3194
3194
|
|
|
@@ -4501,7 +4501,7 @@ var Objects = class _Objects extends Base2 {
|
|
|
4501
4501
|
}
|
|
4502
4502
|
}
|
|
4503
4503
|
} else if (parseIndexes) {
|
|
4504
|
-
const keyPairs =
|
|
4504
|
+
const keyPairs = empty2();
|
|
4505
4505
|
for (let i = 0; i < indexCount; i++) {
|
|
4506
4506
|
const index = indexes[i];
|
|
4507
4507
|
const keys = getIndexSignatureKeys(record2, index.is.parameter, options);
|
|
@@ -6908,7 +6908,7 @@ var File = /* @__PURE__ */ instanceOf(globalThis.File, {
|
|
|
6908
6908
|
name: String4,
|
|
6909
6909
|
lastModified: Int
|
|
6910
6910
|
}), transformOrFail2({
|
|
6911
|
-
decode: (e) =>
|
|
6911
|
+
decode: (e) => match3(decodeBase64(e.data), {
|
|
6912
6912
|
onFailure: () => fail5(new InvalidValue({
|
|
6913
6913
|
message: "Expected a valid Base64 string"
|
|
6914
6914
|
})),
|
|
@@ -7538,19 +7538,11 @@ var WorkIdentity = Struct({
|
|
|
7538
7538
|
principalId: optionalKey2(String4),
|
|
7539
7539
|
threadId: optionalKey2(String4),
|
|
7540
7540
|
pluginId: optionalKey2(String4),
|
|
7541
|
-
/**
|
|
7541
|
+
/** 指派给项目成员时的成员号(引擎成员号)。 */
|
|
7542
7542
|
memberId: optionalKey2(String4),
|
|
7543
7543
|
/** 人的稳定键(见 personKey),界面拿它到快照的人名表里找名字。 */
|
|
7544
7544
|
personKey: optionalKey2(String4)
|
|
7545
7545
|
});
|
|
7546
|
-
var workIdentity = (value) => ({
|
|
7547
|
-
kind: value.kind,
|
|
7548
|
-
...value.principalId === void 0 ? {} : { principalId: value.principalId },
|
|
7549
|
-
...value.threadId === void 0 ? {} : { threadId: value.threadId },
|
|
7550
|
-
...value.memberId === void 0 ? {} : { memberId: value.memberId },
|
|
7551
|
-
...value.pluginId === void 0 ? {} : { pluginId: value.pluginId },
|
|
7552
|
-
...value.principal === void 0 ? {} : { personKey: personKey(value.principal) }
|
|
7553
|
-
});
|
|
7554
7546
|
var BoardPerson = Struct({ key: String4, displayName: String4 });
|
|
7555
7547
|
var BoardMachine = Struct({
|
|
7556
7548
|
principalId: String4,
|
|
@@ -7568,53 +7560,20 @@ var BoardRemoteWork = Struct({
|
|
|
7568
7560
|
})
|
|
7569
7561
|
)
|
|
7570
7562
|
});
|
|
7571
|
-
var MemberName = Struct({
|
|
7572
|
-
memberId: String4,
|
|
7573
|
-
name: String4
|
|
7574
|
-
});
|
|
7575
|
-
var AssignableMember = Struct({
|
|
7576
|
-
memberId: String4,
|
|
7577
|
-
name: String4,
|
|
7578
|
-
kind: Literals(["human", "agent"])
|
|
7579
|
-
});
|
|
7580
7563
|
var BoardItem = Struct({
|
|
7581
7564
|
workItemId: String4,
|
|
7582
7565
|
sequenceId: Number5,
|
|
7583
|
-
title: NullOr(String4)
|
|
7584
|
-
state: Struct({ stateId: String4, name: String4 }),
|
|
7585
|
-
assignees: ArraySchema(WorkIdentity),
|
|
7586
|
-
blockedByTotal: Number5,
|
|
7587
|
-
version: Number5,
|
|
7588
|
-
/** 件所在的线;没分线(旧项目级目标的件、手动建的件)是 null。 */
|
|
7589
|
-
workLineId: NullOr(String4),
|
|
7590
|
-
assigneeSession: optionalKey2(
|
|
7591
|
-
Struct({
|
|
7592
|
-
threadId: String4,
|
|
7593
|
-
status: Literals(["running", "failed", "waiting", "stopped"]),
|
|
7594
|
-
stoppedAt: optionalKey2(String4)
|
|
7595
|
-
})
|
|
7596
|
-
),
|
|
7597
|
-
queued: optionalKey2(Boolean3)
|
|
7566
|
+
title: NullOr(String4)
|
|
7598
7567
|
});
|
|
7599
7568
|
var BoardGoalItem = Struct({
|
|
7600
7569
|
workItemId: String4,
|
|
7601
7570
|
sequenceId: Number5,
|
|
7602
7571
|
state: Struct({ stateId: String4, name: String4, group: String4 })
|
|
7603
7572
|
});
|
|
7604
|
-
var BoardLane = Struct({
|
|
7605
|
-
workLineId: NullOr(String4),
|
|
7606
|
-
name: NullOr(String4),
|
|
7607
|
-
archived: Boolean3,
|
|
7608
|
-
/** 这条线的目标一句话;没分线的一道取旧项目级目标。 */
|
|
7609
|
-
goal: optionalKey2(String4),
|
|
7610
|
-
/** 线的群会话;界面据此给「打开团队」。 */
|
|
7611
|
-
threadId: optionalKey2(String4)
|
|
7612
|
-
});
|
|
7613
7573
|
var BoardSnapshot = Struct({
|
|
7614
7574
|
states: ArraySchema(BoardState),
|
|
7575
|
+
// 远端成员待处理摘要里的件(按号读到的那些)。
|
|
7615
7576
|
items: ArraySchema(BoardItem),
|
|
7616
|
-
// 只在项目层(读取没给 workLineId)出现;团队层的件都在同一条线上。
|
|
7617
|
-
lanes: optionalKey2(ArraySchema(BoardLane)),
|
|
7618
7577
|
// 当前目标与 goal 命令同一份形状;目标栏与看板都从这里读,同一个门铃刷新。
|
|
7619
7578
|
goal: ReadGoalResult,
|
|
7620
7579
|
goalItem: optionalKey2(BoardGoalItem),
|
|
@@ -7623,18 +7582,12 @@ var BoardSnapshot = Struct({
|
|
|
7623
7582
|
rosterMembers: ArraySchema(TeamMember),
|
|
7624
7583
|
// 导入旧名单时记下的「旧成员号 → 引擎成员号」;目标和手册里记的还是旧号,名字靠它认回来。
|
|
7625
7584
|
rosterAliases: optionalKey2(Record(String4, String4)),
|
|
7626
|
-
// 看板上被指派的项目成员(含人和已移除的)的名字;没有成员指派时省略,读不出来也省略,界面退回通用名。
|
|
7627
|
-
memberNames: optionalKey2(ArraySchema(MemberName)),
|
|
7628
|
-
// 指派菜单的选项:项目里还在队的成员(人和 agent)。引擎里的成员读不出来时省略并标 membersUnavailable。
|
|
7629
|
-
assignableMembers: optionalKey2(ArraySchema(AssignableMember)),
|
|
7630
|
-
membersUnavailable: optionalKey2(Literal2(true)),
|
|
7631
7585
|
machines: ArraySchema(BoardMachine),
|
|
7632
7586
|
machinesUnavailable: optionalKey2(Literal2(true)),
|
|
7633
7587
|
remoteWork: ArraySchema(BoardRemoteWork),
|
|
7634
7588
|
viewerKey: optionalKey2(String4),
|
|
7635
7589
|
// 负责人要用看板与项目记忆两组工具;开关由宿主控件拨,这里只读来提示。
|
|
7636
|
-
toolkits: Struct({ board: Boolean3, memory: Boolean3 })
|
|
7637
|
-
truncated: Boolean3
|
|
7590
|
+
toolkits: Struct({ board: Boolean3, memory: Boolean3 })
|
|
7638
7591
|
});
|
|
7639
7592
|
var ReadBoardInput = Struct({
|
|
7640
7593
|
projectId: String4,
|
|
@@ -7660,7 +7613,7 @@ var WORK_EVENTS = /* @__PURE__ */ new Set([
|
|
|
7660
7613
|
"work.relation-removed",
|
|
7661
7614
|
"work.comment-posted",
|
|
7662
7615
|
"work.states-seeded",
|
|
7663
|
-
//
|
|
7616
|
+
// 线建、改名、归档、恢复:团队层快照要核线还在。
|
|
7664
7617
|
"work.line-created",
|
|
7665
7618
|
"work.line-updated",
|
|
7666
7619
|
"work.line-archived",
|
|
@@ -7684,7 +7637,7 @@ var kindsOf = (type) => [
|
|
|
7684
7637
|
...HANDBOOK_EVENTS.has(type) ? ["handbook"] : [],
|
|
7685
7638
|
...MEMBER_EVENTS.has(type) ? ["members"] : []
|
|
7686
7639
|
];
|
|
7687
|
-
function registerTeamWatch(ctx,
|
|
7640
|
+
function registerTeamWatch(ctx, options) {
|
|
7688
7641
|
const after = options.after ?? ((delay2, notify) => {
|
|
7689
7642
|
const timer = NodeTimers.setTimeout(notify, delay2);
|
|
7690
7643
|
return () => NodeTimers.clearTimeout(timer);
|
|
@@ -7693,7 +7646,6 @@ function registerTeamWatch(ctx, hasMember, options) {
|
|
|
7693
7646
|
const cursors = /* @__PURE__ */ new Map();
|
|
7694
7647
|
const timers = /* @__PURE__ */ new Map();
|
|
7695
7648
|
const pending = /* @__PURE__ */ new Map();
|
|
7696
|
-
const subscriptions = /* @__PURE__ */ new Map();
|
|
7697
7649
|
let disposed = false;
|
|
7698
7650
|
const invalidate = (projectId, kinds, sequence = 0) => {
|
|
7699
7651
|
if (projectId === null || disposed || !listeners.has(projectId)) return;
|
|
@@ -7724,59 +7676,13 @@ function registerTeamWatch(ctx, hasMember, options) {
|
|
|
7724
7676
|
const stops = [.../* @__PURE__ */ new Set([...WORK_EVENTS, ...HANDBOOK_EVENTS, ...MEMBER_EVENTS])].map(
|
|
7725
7677
|
(type) => ctx.events.onRaw(type, (event) => changed(event, kindsOf(type)))
|
|
7726
7678
|
);
|
|
7727
|
-
const subscribe = (projectId) => {
|
|
7728
|
-
if (subscriptions.has(projectId)) return;
|
|
7729
|
-
const controller = new AbortController();
|
|
7730
|
-
const { signal } = controller;
|
|
7731
|
-
const known = /* @__PURE__ */ new Set();
|
|
7732
|
-
const active = () => !disposed && !signal.aborted && listeners.has(projectId);
|
|
7733
|
-
const done2 = (async () => {
|
|
7734
|
-
while (active()) {
|
|
7735
|
-
try {
|
|
7736
|
-
await ctx.threads.subscribeList(
|
|
7737
|
-
{ projectId },
|
|
7738
|
-
async (frame) => {
|
|
7739
|
-
if (!active() || frame._tag === "synchronized") return;
|
|
7740
|
-
const ids = frame._tag === "snapshot" ? [.../* @__PURE__ */ new Set([...known, ...frame.value.items.map((row) => row.threadId)])] : frame._tag === "refresh" ? frame.threads.map((row) => row.threadId) : [
|
|
7741
|
-
frame.change._tag === "removed" ? frame.change.threadId : frame.change.thread.threadId
|
|
7742
|
-
];
|
|
7743
|
-
if (frame._tag === "snapshot") {
|
|
7744
|
-
known.clear();
|
|
7745
|
-
for (const row of frame.value.items) known.add(row.threadId);
|
|
7746
|
-
} else if (frame._tag === "delta") {
|
|
7747
|
-
if (frame.change._tag === "removed") known.delete(frame.change.threadId);
|
|
7748
|
-
else known.add(frame.change.thread.threadId);
|
|
7749
|
-
}
|
|
7750
|
-
if (ids.length === 0) return;
|
|
7751
|
-
const matches = await hasMember(projectId, ids).catch(() => false);
|
|
7752
|
-
if (matches && active()) invalidate(projectId, ["board"]);
|
|
7753
|
-
},
|
|
7754
|
-
signal
|
|
7755
|
-
);
|
|
7756
|
-
} catch {
|
|
7757
|
-
}
|
|
7758
|
-
if (!active()) return;
|
|
7759
|
-
await new Promise((resolve2) => {
|
|
7760
|
-
const finish = () => {
|
|
7761
|
-
cancel();
|
|
7762
|
-
signal.removeEventListener("abort", finish);
|
|
7763
|
-
resolve2();
|
|
7764
|
-
};
|
|
7765
|
-
const cancel = after(1e3, finish);
|
|
7766
|
-
signal.addEventListener("abort", finish, { once: true });
|
|
7767
|
-
if (signal.aborted) finish();
|
|
7768
|
-
});
|
|
7769
|
-
}
|
|
7770
|
-
})();
|
|
7771
|
-
subscriptions.set(projectId, { controller, done: done2 });
|
|
7772
|
-
};
|
|
7773
7679
|
stops.push(
|
|
7774
7680
|
ctx.events.onRaw("plugin.event-appended", (event) => {
|
|
7775
7681
|
const fact = decodeFact(event.payload);
|
|
7776
7682
|
if (isNone2(fact)) return;
|
|
7777
7683
|
const name = fact.value.name;
|
|
7778
7684
|
const kinds = [];
|
|
7779
|
-
if (name === "team/goal-started" || name === "team/roster-set" || name === "team/member-
|
|
7685
|
+
if (name === "team/goal-started" || name === "team/roster-set" || name === "team/member-bound")
|
|
7780
7686
|
kinds.push("board");
|
|
7781
7687
|
if (name === "team/goal-started" || name === "team/member-bound" || name === "team/handbook-acknowledged" || name === "team/handbook-publication-completed")
|
|
7782
7688
|
kinds.push("handbook");
|
|
@@ -7799,7 +7705,6 @@ function registerTeamWatch(ctx, hasMember, options) {
|
|
|
7799
7705
|
};
|
|
7800
7706
|
listeners.set(projectId, subscribers);
|
|
7801
7707
|
subscribers.add(ring);
|
|
7802
|
-
subscribe(projectId);
|
|
7803
7708
|
try {
|
|
7804
7709
|
ring(cursors.get(projectId) ?? emptyChanges());
|
|
7805
7710
|
await new Promise((resolve2) => {
|
|
@@ -7810,30 +7715,22 @@ function registerTeamWatch(ctx, hasMember, options) {
|
|
|
7810
7715
|
subscribers.delete(ring);
|
|
7811
7716
|
if (subscribers.size === 0) {
|
|
7812
7717
|
listeners.delete(projectId);
|
|
7813
|
-
const subscription = subscriptions.get(projectId);
|
|
7814
|
-
subscriptions.delete(projectId);
|
|
7815
|
-
subscription?.controller.abort();
|
|
7816
7718
|
timers.get(projectId)?.();
|
|
7817
7719
|
timers.delete(projectId);
|
|
7818
7720
|
pending.delete(projectId);
|
|
7819
7721
|
cursors.delete(projectId);
|
|
7820
|
-
await subscription?.done;
|
|
7821
7722
|
}
|
|
7822
7723
|
}
|
|
7823
7724
|
}
|
|
7824
7725
|
});
|
|
7825
|
-
ctx.onDispose(
|
|
7726
|
+
ctx.onDispose(() => {
|
|
7826
7727
|
disposed = true;
|
|
7827
|
-
const owned = [...subscriptions.values()];
|
|
7828
|
-
for (const subscription of owned) subscription.controller.abort();
|
|
7829
7728
|
for (const stop of stops) stop();
|
|
7830
7729
|
for (const cancel of timers.values()) cancel();
|
|
7831
7730
|
timers.clear();
|
|
7832
7731
|
listeners.clear();
|
|
7833
7732
|
cursors.clear();
|
|
7834
7733
|
pending.clear();
|
|
7835
|
-
subscriptions.clear();
|
|
7836
|
-
await Promise.all(owned.map((subscription) => subscription.done));
|
|
7837
7734
|
});
|
|
7838
7735
|
}
|
|
7839
7736
|
|
|
@@ -7848,6 +7745,9 @@ async function readMachines(ctx, projectId) {
|
|
|
7848
7745
|
}
|
|
7849
7746
|
var memberEnvironment = (member) => member.agent?.environmentId ?? null;
|
|
7850
7747
|
var isRemoteMember = (member, localEnvironmentId) => member.kind === "agent" && memberEnvironment(member) !== localEnvironmentId;
|
|
7748
|
+
var readyProviders = (machine) => machine.providers.filter(
|
|
7749
|
+
(provider) => provider.readiness === void 0 || provider.readiness === "ready"
|
|
7750
|
+
);
|
|
7851
7751
|
|
|
7852
7752
|
// src/workReads.ts
|
|
7853
7753
|
var PAGE_SIZE = 200;
|
|
@@ -7873,45 +7773,160 @@ async function readPages(maximum, read, keep = "oldest") {
|
|
|
7873
7773
|
return { items, truncated };
|
|
7874
7774
|
}
|
|
7875
7775
|
|
|
7876
|
-
// src/
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7776
|
+
// src/domain/goalItem.ts
|
|
7777
|
+
var teamGoalItemId = (projectId, goalId) => `team-goal:${projectId}:${goalId}`;
|
|
7778
|
+
var GOAL_ITEM_TITLE_MAX = 120;
|
|
7779
|
+
var goalItemTitle = (goal) => {
|
|
7780
|
+
const line = (goal.titleSeed ?? goal.goal).split(/\r?\n/u, 1)[0].trim();
|
|
7781
|
+
return line.length <= GOAL_ITEM_TITLE_MAX ? line : `${line.slice(0, GOAL_ITEM_TITLE_MAX - 1)}\u2026`;
|
|
7782
|
+
};
|
|
7783
|
+
|
|
7784
|
+
// src/board.ts
|
|
7785
|
+
var PEOPLE_LIMIT = 200;
|
|
7786
|
+
var ITEMS_GET_MAX = 50;
|
|
7787
|
+
var decodeRead2 = decodeUnknownSync(ReadBoardInput);
|
|
7788
|
+
function registerBoardCommands(ctx, goals, rosters, options = {}) {
|
|
7789
|
+
const readTeam = async (projectId, workLineId) => {
|
|
7790
|
+
const view = await rosters.activeView(projectId).catch(() => null);
|
|
7791
|
+
const roster = view?.team ?? null;
|
|
7792
|
+
const members = view?.active ?? null;
|
|
7793
|
+
const read = await goals.read(projectId, {
|
|
7794
|
+
roster,
|
|
7795
|
+
...members === null ? {} : { known: members },
|
|
7796
|
+
...workLineId === void 0 ? {} : { forLine: workLineId }
|
|
7797
|
+
});
|
|
7880
7798
|
return {
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
...goal === void 0 ? {} : { goal },
|
|
7885
|
-
...line.threadId === null ? {} : { threadId: line.threadId }
|
|
7799
|
+
roster,
|
|
7800
|
+
// 线上没有目标时 read 会退回项目级目标;团队层只认这条线自己的。
|
|
7801
|
+
goal: read !== null && workLineId !== void 0 && read.workLineId !== workLineId ? null : read
|
|
7886
7802
|
};
|
|
7887
7803
|
};
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
7895
|
-
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7804
|
+
ctx.command({
|
|
7805
|
+
name: "board",
|
|
7806
|
+
scope: "read",
|
|
7807
|
+
payloadSchema: payloadSchemaOf(ReadBoardInput),
|
|
7808
|
+
handle: async (payload, invocation) => {
|
|
7809
|
+
const { projectId, workLineId } = decodeRead2(payload);
|
|
7810
|
+
const [stateList, { goal, roster }, toolkitStates, people, machines, viewer] = await Promise.all([
|
|
7811
|
+
ctx.work.states.list({ projectId }),
|
|
7812
|
+
readTeam(projectId, workLineId),
|
|
7813
|
+
ctx.projects.toolkits.get({ projectId }),
|
|
7814
|
+
// 人名只用来显示作者;本机所有者排第一,后面是这个项目认识的账号。
|
|
7815
|
+
readPages(PEOPLE_LIMIT, (page) => ctx.communication.people.list({ projectId, ...page })),
|
|
7816
|
+
// 项目里的别的机器:远端作者的名字与在线状态;读不出来退回空,不连累快照。
|
|
7817
|
+
readMachines(ctx, projectId),
|
|
7818
|
+
// 认出当前读者只为把作者显示成「你」:读不出来就当没有。
|
|
7819
|
+
invocation.viewer?.communication.people.current({}).catch(() => null),
|
|
7820
|
+
// 团队层核这条线还在(读不到照抛,界面显示读取失败)。
|
|
7821
|
+
workLineId === void 0 ? void 0 : ctx.work.lines.get({ projectId, workLineId })
|
|
7822
|
+
]);
|
|
7823
|
+
const goalItemId = goal === null ? null : teamGoalItemId(projectId, goal.goalId);
|
|
7824
|
+
const [remoteWork, goalItem] = await Promise.all([
|
|
7825
|
+
Promise.all(
|
|
7826
|
+
(roster?.members ?? []).flatMap(
|
|
7827
|
+
(member) => member.principal === void 0 ? [] : [
|
|
7828
|
+
ctx.work.remoteAgentPending.get({ projectId, principalId: member.principal.principalId }).then(
|
|
7829
|
+
// 一台机器上可能有好几个成员:只算派给这个成员的(与直接派给那台机器的)。
|
|
7830
|
+
({ work }) => {
|
|
7831
|
+
const items2 = work.items.filter(
|
|
7832
|
+
(item) => item.memberId === void 0 || item.memberId === member.memberId
|
|
7833
|
+
).map(({ workItemId, blocked }) => ({ workItemId, blocked }));
|
|
7834
|
+
return { count: items2.length, items: items2 };
|
|
7835
|
+
},
|
|
7836
|
+
() => null
|
|
7837
|
+
).then((pending) => ({ memberId: member.memberId, pending }))
|
|
7838
|
+
]
|
|
7839
|
+
)
|
|
7840
|
+
),
|
|
7841
|
+
// 目标那件按号单读。
|
|
7842
|
+
goalItemId === null ? void 0 : ctx.work.items.get({ projectId, workItemIds: [goalItemId] }).then(({ items: items2 }) => items2.find((item) => item.workItemId === goalItemId))
|
|
7843
|
+
]);
|
|
7844
|
+
const pendingIds = [
|
|
7845
|
+
...new Set(
|
|
7846
|
+
remoteWork.flatMap(({ pending }) => pending?.items.map((row) => row.workItemId) ?? [])
|
|
7847
|
+
)
|
|
7848
|
+
];
|
|
7849
|
+
const items = (await Promise.all(
|
|
7850
|
+
Array.from(
|
|
7851
|
+
{ length: Math.ceil(pendingIds.length / ITEMS_GET_MAX) },
|
|
7852
|
+
(_, index) => ctx.work.items.get({
|
|
7853
|
+
projectId,
|
|
7854
|
+
workItemIds: pendingIds.slice(index * ITEMS_GET_MAX, (index + 1) * ITEMS_GET_MAX)
|
|
7855
|
+
}).then(
|
|
7856
|
+
({ items: items2 }) => items2,
|
|
7857
|
+
() => []
|
|
7858
|
+
)
|
|
7859
|
+
)
|
|
7860
|
+
)).flat().map(({ workItemId, sequenceId, title }) => ({ workItemId, sequenceId, title }));
|
|
7861
|
+
const enabled = (toolkit) => toolkitStates.toolkits.some((row) => row.toolkit === toolkit && row.enabled);
|
|
7862
|
+
return {
|
|
7863
|
+
states: stateList.states.map(({ stateId, name, sequence, defaultKey }) => ({
|
|
7864
|
+
stateId,
|
|
7865
|
+
name,
|
|
7866
|
+
sequence,
|
|
7867
|
+
...defaultKey === void 0 ? {} : { defaultKey }
|
|
7868
|
+
})).sort((a, b) => a.sequence - b.sequence),
|
|
7869
|
+
items,
|
|
7870
|
+
goal,
|
|
7871
|
+
...goalItem === void 0 ? {} : {
|
|
7872
|
+
goalItem: {
|
|
7873
|
+
workItemId: goalItem.workItemId,
|
|
7874
|
+
sequenceId: goalItem.sequenceId,
|
|
7875
|
+
state: {
|
|
7876
|
+
stateId: goalItem.state.stateId,
|
|
7877
|
+
name: goalItem.state.name,
|
|
7878
|
+
group: goalItem.state.group
|
|
7879
|
+
}
|
|
7880
|
+
}
|
|
7881
|
+
},
|
|
7882
|
+
people: people.items.map((row) => ({
|
|
7883
|
+
key: personKey(row.person),
|
|
7884
|
+
displayName: row.displayName
|
|
7885
|
+
})),
|
|
7886
|
+
rosterMembers: roster?.members ?? [],
|
|
7887
|
+
...roster?.aliases === void 0 ? {} : { rosterAliases: roster.aliases },
|
|
7888
|
+
...machines === null ? { machinesUnavailable: true } : {},
|
|
7889
|
+
machines: [...machines?.values() ?? []].map(
|
|
7890
|
+
({ principalId, environmentId, name, online, lastSeenAt }) => ({
|
|
7891
|
+
principalId,
|
|
7892
|
+
environmentId,
|
|
7893
|
+
name,
|
|
7894
|
+
online,
|
|
7895
|
+
...lastSeenAt === void 0 ? {} : { lastSeenAt }
|
|
7896
|
+
})
|
|
7897
|
+
),
|
|
7898
|
+
remoteWork,
|
|
7899
|
+
...viewer?.person == null ? {} : { viewerKey: personKey(viewer.person) },
|
|
7900
|
+
toolkits: { board: enabled("board"), memory: enabled("memory") }
|
|
7901
|
+
};
|
|
7902
|
+
}
|
|
7903
|
+
});
|
|
7904
|
+
registerTeamWatch(ctx, options);
|
|
7901
7905
|
}
|
|
7902
7906
|
|
|
7903
|
-
// src/
|
|
7904
|
-
function
|
|
7907
|
+
// src/runtime/serial.ts
|
|
7908
|
+
function createSerial(closedMessage = "team-serial-closed") {
|
|
7909
|
+
let pending = Promise.resolve();
|
|
7910
|
+
let closed = false;
|
|
7905
7911
|
return {
|
|
7906
|
-
|
|
7907
|
-
|
|
7912
|
+
run(execute) {
|
|
7913
|
+
const result2 = pending.then(() => {
|
|
7914
|
+
if (closed) throw new Error(closedMessage);
|
|
7915
|
+
return execute();
|
|
7916
|
+
});
|
|
7917
|
+
pending = result2.then(
|
|
7918
|
+
() => void 0,
|
|
7919
|
+
() => void 0
|
|
7920
|
+
);
|
|
7921
|
+
return result2;
|
|
7922
|
+
},
|
|
7923
|
+
/** 不再开始新任务,并等已经在跑和排在前面的任务落定。 */
|
|
7924
|
+
async close() {
|
|
7925
|
+
closed = true;
|
|
7926
|
+
await pending;
|
|
7927
|
+
}
|
|
7908
7928
|
};
|
|
7909
7929
|
}
|
|
7910
|
-
function findGoalMember(members, identity2) {
|
|
7911
|
-
return members.find(
|
|
7912
|
-
(member) => "threadId" in identity2 ? "threadId" in member && member.threadId === identity2.threadId : "principalId" in member && member.principalId === identity2.principalId
|
|
7913
|
-
);
|
|
7914
|
-
}
|
|
7915
7930
|
|
|
7916
7931
|
// src/domain/facts.ts
|
|
7917
7932
|
function foldFact(state, event, decode4, keyOf) {
|
|
@@ -7933,786 +7948,171 @@ var factEnvelope = (name, data) => Struct({ pluginId: Literal2("team"), name: Li
|
|
|
7933
7948
|
var nowIso = map5(now2, formatIso2);
|
|
7934
7949
|
var factTime = () => runPromise2(nowIso);
|
|
7935
7950
|
|
|
7936
|
-
// src/domain/
|
|
7937
|
-
var
|
|
7938
|
-
var
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
makeFilter2((fact) => fact.threadId === void 0 !== (fact.principalId === void 0))
|
|
7952
|
-
);
|
|
7953
|
-
var MemberBoundEnvelope = factEnvelope("member-bound", MemberBoundFact);
|
|
7954
|
-
var bindingOfFact = (fact) => fact.threadId !== void 0 ? { threadId: fact.threadId } : { principalId: fact.principalId };
|
|
7955
|
-
function bindingsOf(goal) {
|
|
7956
|
-
const bindings = {};
|
|
7957
|
-
for (const member of goalExecution(goal).members)
|
|
7958
|
-
bindings[member.memberId] = "threadId" in member ? { threadId: member.threadId } : { principalId: member.principalId };
|
|
7959
|
-
return bindings;
|
|
7960
|
-
}
|
|
7961
|
-
function withBoundBinding(bindings, fact) {
|
|
7962
|
-
const next = { ...bindings };
|
|
7963
|
-
if (fact.replaces !== void 0) delete next[fact.replaces];
|
|
7964
|
-
next[fact.memberId] = bindingOfFact(fact);
|
|
7965
|
-
return next;
|
|
7966
|
-
}
|
|
7967
|
-
var leadAfterBinding = (leadMemberId, fact) => fact.replaces !== void 0 && leadMemberId === fact.replaces ? fact.memberId : leadMemberId;
|
|
7968
|
-
function withBoundMember(goal, fact) {
|
|
7969
|
-
if (fact.projectId !== goal.projectId || fact.goalId !== goal.goalId) return goal;
|
|
7970
|
-
const { remoteMembers: _before, ...rest } = goal;
|
|
7971
|
-
const superseded = (memberId) => memberId === fact.memberId || memberId === fact.replaces;
|
|
7972
|
-
const threads = goal.threads.filter((row) => !superseded(row.memberId));
|
|
7973
|
-
const remoteMembers = (goal.remoteMembers ?? []).filter((row) => !superseded(row.memberId));
|
|
7974
|
-
const binding = bindingOfFact(fact);
|
|
7975
|
-
const next = "threadId" in binding ? {
|
|
7976
|
-
threads: [...threads, { memberId: fact.memberId, threadId: binding.threadId }],
|
|
7977
|
-
remoteMembers
|
|
7978
|
-
} : {
|
|
7979
|
-
threads,
|
|
7980
|
-
remoteMembers: [
|
|
7981
|
-
...remoteMembers,
|
|
7982
|
-
{ memberId: fact.memberId, principalId: binding.principalId }
|
|
7983
|
-
]
|
|
7984
|
-
};
|
|
7985
|
-
return {
|
|
7986
|
-
...rest,
|
|
7987
|
-
leadMemberId: leadAfterBinding(goal.leadMemberId, fact),
|
|
7988
|
-
threads: next.threads,
|
|
7989
|
-
...next.remoteMembers.length === 0 ? {} : { remoteMembers: next.remoteMembers }
|
|
7990
|
-
};
|
|
7951
|
+
// src/domain/service.ts
|
|
7952
|
+
var HISTORY_LIMIT = 500;
|
|
7953
|
+
var ACTIVE_LIMIT = 2e3;
|
|
7954
|
+
var MEMBER_NAMES_LIMIT = 50;
|
|
7955
|
+
var FactEnvelope = Struct({
|
|
7956
|
+
pluginId: Literal2("team"),
|
|
7957
|
+
name: Literal2("team/roster-set"),
|
|
7958
|
+
data: RosterSetFact
|
|
7959
|
+
});
|
|
7960
|
+
var decodeFact2 = decodeUnknownOption2(FactEnvelope);
|
|
7961
|
+
var decodeSetLead = decodeUnknownOption2(SetLeadInput);
|
|
7962
|
+
var decodeRosterFact = (payload) => map(decodeFact2(payload), (fact) => fact.data);
|
|
7963
|
+
var factProject = (fact) => fact.roster.projectId;
|
|
7964
|
+
function foldRoster(state, event) {
|
|
7965
|
+
return foldFact(state, event, decodeRosterFact, factProject);
|
|
7991
7966
|
}
|
|
7992
|
-
function
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
if (
|
|
7998
|
-
return
|
|
7967
|
+
async function listMembers(ctx, projectId) {
|
|
7968
|
+
const { items, truncated } = await readPages(
|
|
7969
|
+
ACTIVE_LIMIT,
|
|
7970
|
+
(page) => ctx.members.list({ projectId, ...page })
|
|
7971
|
+
);
|
|
7972
|
+
if (truncated) throw new Error("team-members-truncated");
|
|
7973
|
+
return items;
|
|
7999
7974
|
}
|
|
8000
|
-
function
|
|
8001
|
-
const
|
|
8002
|
-
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
});
|
|
7975
|
+
async function listMemberHistory(ctx, projectId) {
|
|
7976
|
+
const { items } = await readPages(
|
|
7977
|
+
HISTORY_LIMIT,
|
|
7978
|
+
(page) => ctx.members.list({ projectId, includeRemoved: true, ...page }),
|
|
7979
|
+
"newest"
|
|
7980
|
+
);
|
|
7981
|
+
return items;
|
|
8008
7982
|
}
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
...Object.entries(project2.lineScopes ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([, scope2]) => scope2)
|
|
8018
|
-
];
|
|
8019
|
-
var scopeForLine = (project2, workLineId) => (workLineId === void 0 ? void 0 : project2.lineScopes?.[workLineId]) ?? project2;
|
|
8020
|
-
var scopeOfThread = (project2, threadId) => scopesOf(project2).find((scope2) => scope2.threads.includes(threadId));
|
|
8021
|
-
var teamSessions = (scope2) => [
|
|
8022
|
-
.../* @__PURE__ */ new Set([...scope2.threads, ...Object.keys(scope2.memberIds ?? {})])
|
|
8023
|
-
];
|
|
8024
|
-
var lineScopeOfThread = (project2, threadId) => {
|
|
8025
|
-
for (const [workLineId, scope2] of Object.entries(project2.lineScopes ?? {}))
|
|
8026
|
-
if (teamSessions(scope2).includes(threadId)) return { workLineId, scope: scope2 };
|
|
8027
|
-
return void 0;
|
|
8028
|
-
};
|
|
8029
|
-
var scopeOfPrincipal = (project2, principalId) => scopesOf(project2).find((scope2) => scope2.remoteMembers.includes(principalId));
|
|
8030
|
-
var isGoalThread = (project2, threadId) => scopeOfThread(project2, threadId) !== void 0;
|
|
8031
|
-
var isLeadThread = (project2, threadId) => scopesOf(project2).some((scope2) => scope2.leadThreads?.includes(threadId) === true);
|
|
8032
|
-
var isRemoteMember2 = (project2, principalId) => scopeOfPrincipal(project2, principalId) !== void 0;
|
|
8033
|
-
var leadOfThread = (project2, threadId) => scopeOfThread(project2, threadId)?.leadThreads?.[0];
|
|
8034
|
-
var placeOfRecipient = (project2, who, workLineId) => {
|
|
8035
|
-
if ("threadId" in who) {
|
|
8036
|
-
const line = lineScopeOfThread(project2, who.threadId);
|
|
8037
|
-
if (line !== void 0) return line;
|
|
8038
|
-
return project2.threads.includes(who.threadId) ? { scope: project2 } : void 0;
|
|
7983
|
+
async function findMember(ctx, projectId, memberId, window) {
|
|
7984
|
+
try {
|
|
7985
|
+
const { member } = await ctx.members.get({ projectId, memberId, ...window });
|
|
7986
|
+
return member;
|
|
7987
|
+
} catch (error) {
|
|
7988
|
+
const reason = typeof error === "object" && error !== null && "reason" in error ? error.reason : null;
|
|
7989
|
+
if (reason === "member-not-found") return null;
|
|
7990
|
+
throw error;
|
|
8039
7991
|
}
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
if (
|
|
8044
|
-
const
|
|
8045
|
-
return found === void 0 ? void 0 : { workLineId: found[0], scope: found[1] };
|
|
8046
|
-
};
|
|
8047
|
-
var scopeOfRecipient = (project2, who, workLineId) => placeOfRecipient(project2, who, workLineId)?.scope;
|
|
8048
|
-
var memberOfRecipientIn = (scope2, who) => {
|
|
8049
|
-
if ("threadId" in who) return scope2.memberIds?.[who.threadId];
|
|
8050
|
-
for (const [memberId, recipient] of Object.entries(scope2.bindings ?? {}))
|
|
8051
|
-
if ("principalId" in recipient && recipient.principalId === who.principalId) return memberId;
|
|
8052
|
-
return void 0;
|
|
8053
|
-
};
|
|
8054
|
-
var isRecipientGated = (project2, who, workLineId) => {
|
|
8055
|
-
const place = placeOfRecipient(project2, who, workLineId);
|
|
8056
|
-
if (place === void 0 || place.workLineId === void 0) return false;
|
|
8057
|
-
if (isLineGated(project2, place.workLineId)) return true;
|
|
8058
|
-
const member = memberOfRecipientIn(place.scope, who);
|
|
8059
|
-
return member !== void 0 && isMemberPausedOnLine(project2, place.workLineId, member);
|
|
8060
|
-
};
|
|
8061
|
-
var isThreadGated = (project2, threadId) => isRecipientGated(project2, { threadId });
|
|
8062
|
-
var teamLeadCandidates = (project2, memberId) => Object.entries(project2.lineScopes ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).flatMap(([workLineId, scope2]) => {
|
|
8063
|
-
const leadThreadId = scope2.leadThreads?.[0];
|
|
8064
|
-
return scope2.bindings?.[memberId] !== void 0 && leadThreadId !== void 0 && !isLineStopped(project2, workLineId) ? [{ workLineId, leadThreadId }] : [];
|
|
8065
|
-
});
|
|
8066
|
-
|
|
8067
|
-
// src/runtime/wakeQueries.ts
|
|
8068
|
-
function memberWorktreeFor(goals, project2, projectId, recipient) {
|
|
8069
|
-
if (!("threadId" in recipient) || project2 === void 0) return;
|
|
8070
|
-
const { threadId } = recipient;
|
|
8071
|
-
const scope2 = scopeOfThread(project2, threadId);
|
|
8072
|
-
if (scope2 === void 0 || scope2.leadThreads?.includes(threadId)) return;
|
|
8073
|
-
const leadThreadId = scope2.leadThreads?.[0];
|
|
8074
|
-
if (leadThreadId === void 0) return;
|
|
7992
|
+
}
|
|
7993
|
+
var isActiveAgent = (member) => member.kind === "agent" && member.removedAt === null;
|
|
7994
|
+
var toTeamMember = (member, where) => {
|
|
7995
|
+
if (!isRemoteMember(member, where.local)) return { memberId: member.memberId, name: member.name };
|
|
7996
|
+
const machine = member.agent === null ? void 0 : where.machines?.get(member.agent.environmentId);
|
|
8075
7997
|
return {
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
(member) => member.threadId === threadId
|
|
8081
|
-
)?.name ?? scope2.memberIds?.[threadId] ?? threadId
|
|
7998
|
+
memberId: member.memberId,
|
|
7999
|
+
name: member.name,
|
|
8000
|
+
remote: true,
|
|
8001
|
+
...machine === void 0 ? {} : { principal: { kind: "remote-agent", principalId: machine.principalId } }
|
|
8082
8002
|
};
|
|
8083
|
-
}
|
|
8084
|
-
var compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
8085
|
-
var compareWakeItems = (a, b) => a.sequenceId - b.sequenceId || compare(a.workItemId, b.workItemId);
|
|
8086
|
-
var OPEN_ITEM_GROUPS = ["backlog", "unstarted", "started"];
|
|
8087
|
-
var isClosed = (item) => item?.stateGroup === "completed" || item?.stateGroup === "cancelled";
|
|
8088
|
-
var hasOpenBlocker = (project2, workItemId) => (readFact(project2.blockers, workItemId) ?? []).some(
|
|
8089
|
-
(blocker) => !isClosed(readFact(project2.items, blocker))
|
|
8090
|
-
);
|
|
8091
|
-
var isAssignedOpen = (project2, workItemId, threadId) => {
|
|
8092
|
-
const item = readFact(project2.items, workItemId);
|
|
8093
|
-
return item !== null && item !== void 0 && !isClosed(item) && item.assigneeThreads.includes(threadId);
|
|
8094
|
-
};
|
|
8095
|
-
var isWorkable = (project2, workItemId) => !isClosed(readFact(project2.items, workItemId)) && !hasOpenBlocker(project2, workItemId);
|
|
8096
|
-
var isOpenWorkFor = (project2, workItemId, threadId) => isAssignedOpen(project2, workItemId, threadId) && !hasOpenBlocker(project2, workItemId);
|
|
8097
|
-
var isHandedOver = (item, threadId) => {
|
|
8098
|
-
if (item.stateGroup === "started") return true;
|
|
8099
|
-
const status = threadId === void 0 ? void 0 : item.wakeStatus?.[threadId];
|
|
8100
|
-
return status === "active" || status === "released";
|
|
8101
|
-
};
|
|
8102
|
-
var memberOfThread = (item, threadId) => {
|
|
8103
|
-
for (const [memberId, thread] of Object.entries(item.memberThreads ?? {}))
|
|
8104
|
-
if (thread === threadId) return memberId;
|
|
8105
|
-
return void 0;
|
|
8106
|
-
};
|
|
8107
|
-
var isPinnedTo = (item, threadId) => !isClosed(item) && memberOfThread(item, threadId) !== void 0 && isHandedOver(item, threadId);
|
|
8108
|
-
var hasPinnedOpenItem = (project2, threadId) => Object.values(project2.items).some((item) => isPinnedTo(item, threadId));
|
|
8109
|
-
var pinnedThreadsOf = (item) => Object.values(item.memberThreads ?? {}).filter((threadId) => isPinnedTo(item, threadId));
|
|
8110
|
-
var pinnedOpenThreads = (project2) => {
|
|
8111
|
-
const threads = /* @__PURE__ */ new Set();
|
|
8112
|
-
for (const item of Object.values(project2.items))
|
|
8113
|
-
for (const threadId of pinnedThreadsOf(item)) threads.add(threadId);
|
|
8114
|
-
return threads;
|
|
8115
|
-
};
|
|
8116
|
-
var memberLookup = (project2) => {
|
|
8117
|
-
let pinned;
|
|
8118
|
-
return (threadId) => isGoalThread(project2, threadId) || (pinned ??= pinnedOpenThreads(project2)).has(threadId);
|
|
8119
8003
|
};
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
}
|
|
8131
|
-
function deferredWakes(project2, threadId) {
|
|
8132
|
-
return Object.entries(project2.items).filter(([, item]) => isDeferredWake(project2, item, threadId)).map(([workItemId, item]) => ({ workItemId, sequenceId: item.sequenceId })).sort(
|
|
8133
|
-
(a, b) => Number(hasOpenBlocker(project2, a.workItemId)) - Number(hasOpenBlocker(project2, b.workItemId)) || compareWakeItems(a, b)
|
|
8134
|
-
);
|
|
8135
|
-
}
|
|
8136
|
-
var exemptFromTrial = (project2, recipient, workItemId) => {
|
|
8137
|
-
if (project2 === void 0 || !("threadId" in recipient)) return false;
|
|
8138
|
-
if (isLeadThread(project2, recipient.threadId)) return true;
|
|
8139
|
-
if (workItemId === void 0) return false;
|
|
8140
|
-
const item = readFact(project2.items, workItemId);
|
|
8141
|
-
return item !== null && item !== void 0 && pinnedThreadsOf(item).includes(recipient.threadId);
|
|
8142
|
-
};
|
|
8143
|
-
function memberOfRecipient(project2, recipient) {
|
|
8144
|
-
if (project2 === void 0) return void 0;
|
|
8145
|
-
const key = recipientKey(recipient);
|
|
8146
|
-
for (const scope2 of scopesOf(project2))
|
|
8147
|
-
for (const [memberId, bound] of Object.entries(scope2.bindings ?? {}))
|
|
8148
|
-
if (recipientKey(bound) === key) return memberId;
|
|
8149
|
-
return void 0;
|
|
8150
|
-
}
|
|
8151
|
-
function executorOf(project2, workItemId, memberId) {
|
|
8152
|
-
if (project2 === void 0) return void 0;
|
|
8153
|
-
const item = readFact(project2.items, workItemId);
|
|
8154
|
-
const target = targetOf(
|
|
8155
|
-
scopeForLine(project2, item?.workLineId).bindings,
|
|
8156
|
-
{ kind: "member", memberId },
|
|
8157
|
-
item?.memberThreads
|
|
8158
|
-
);
|
|
8159
|
-
if (target === void 0) return void 0;
|
|
8160
|
-
if ("threadId" in target && isLeadThread(project2, target.threadId)) return void 0;
|
|
8161
|
-
return isMember(project2, target) ? target : void 0;
|
|
8162
|
-
}
|
|
8163
|
-
|
|
8164
|
-
// src/boardProgress.ts
|
|
8165
|
-
var sessionStatus = (thread) => {
|
|
8166
|
-
const { status, threadId } = thread;
|
|
8167
|
-
switch (status) {
|
|
8168
|
-
case "running":
|
|
8169
|
-
case "failed":
|
|
8170
|
-
return { threadId, status };
|
|
8171
|
-
case "needs-input":
|
|
8172
|
-
case "needs-approval":
|
|
8173
|
-
return { threadId, status: "waiting" };
|
|
8174
|
-
case "idle":
|
|
8175
|
-
case "stopped": {
|
|
8176
|
-
const stoppedAt = thread.summary?.latestTurn?.completedAt;
|
|
8177
|
-
return { threadId, status: "stopped", ...stoppedAt == null ? {} : { stoppedAt } };
|
|
8178
|
-
}
|
|
8179
|
-
default:
|
|
8180
|
-
return void 0;
|
|
8181
|
-
}
|
|
8182
|
-
};
|
|
8183
|
-
var cardSessions = (members, wakes, pinned = wakes === void 0 ? void 0 : memberLookup(wakes)) => {
|
|
8184
|
-
return (threadId) => findGoalMember(members, { threadId }) !== void 0 || pinned?.(threadId) === true;
|
|
8185
|
-
};
|
|
8186
|
-
function boardProgress(rows, goalOf, threads, wakes) {
|
|
8187
|
-
const sessions = new Map(threads.map((thread) => [thread.threadId, thread]));
|
|
8188
|
-
const pinned = wakes === void 0 ? void 0 : memberLookup(wakes);
|
|
8189
|
-
const scopes = /* @__PURE__ */ new Map();
|
|
8190
|
-
const scopeOf = (goal) => {
|
|
8191
|
-
let scope2 = scopes.get(goal);
|
|
8192
|
-
if (scope2 === void 0) {
|
|
8193
|
-
scope2 = {
|
|
8194
|
-
isMember: cardSessions(goalExecution(goal).members, wakes, pinned),
|
|
8195
|
-
bindings: bindingsOf(goal)
|
|
8196
|
-
};
|
|
8197
|
-
scopes.set(goal, scope2);
|
|
8198
|
-
}
|
|
8199
|
-
return scope2;
|
|
8004
|
+
function resolveTeam(stored, members, where) {
|
|
8005
|
+
if (stored === null) return { team: null, problem: null };
|
|
8006
|
+
if (stored.version === 1) return { team: stored.roster, problem: null };
|
|
8007
|
+
const { roster: lead } = stored;
|
|
8008
|
+
const team = {
|
|
8009
|
+
projectId: lead.projectId,
|
|
8010
|
+
members: members.filter(isActiveAgent).map((member) => toTeamMember(member, where)),
|
|
8011
|
+
leadMemberId: lead.leadMemberId,
|
|
8012
|
+
revision: lead.revision,
|
|
8013
|
+
updatedAt: lead.updatedAt,
|
|
8014
|
+
...lead.aliases === void 0 ? {} : { aliases: lead.aliases }
|
|
8200
8015
|
};
|
|
8201
|
-
const
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8016
|
+
const problem = teamRuleError(team);
|
|
8017
|
+
return problem === null ? { team, problem: null } : { team: null, problem };
|
|
8018
|
+
}
|
|
8019
|
+
function createRosterService(ctx, options = {}) {
|
|
8020
|
+
const rosters = ctx.derivedState({
|
|
8021
|
+
key: "rosters",
|
|
8022
|
+
version: 2,
|
|
8023
|
+
events: ["plugin.event-appended"],
|
|
8024
|
+
init: () => ({}),
|
|
8025
|
+
apply: foldRoster
|
|
8208
8026
|
});
|
|
8209
|
-
const
|
|
8210
|
-
const
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
};
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
}
|
|
8223
|
-
}
|
|
8224
|
-
const queuedByMember = /* @__PURE__ */ new Map();
|
|
8225
|
-
const queuedFor = (threadId) => {
|
|
8226
|
-
let items = queuedByMember.get(threadId);
|
|
8227
|
-
if (items === void 0) {
|
|
8228
|
-
items = new Set(
|
|
8229
|
-
wakes === void 0 ? [] : deferredWakes(wakes, threadId).map((item) => item.workItemId)
|
|
8230
|
-
);
|
|
8231
|
-
queuedByMember.set(threadId, items);
|
|
8232
|
-
}
|
|
8233
|
-
return items;
|
|
8027
|
+
const now3 = options.now ?? factTime;
|
|
8028
|
+
const storedOf = async (projectId) => readFact(await rosters.get(), projectId);
|
|
8029
|
+
const machinesOf = async (projectId) => ({
|
|
8030
|
+
local: ctx.environment.id,
|
|
8031
|
+
machines: await readMachines(ctx, projectId)
|
|
8032
|
+
});
|
|
8033
|
+
const activeView = async (projectId) => {
|
|
8034
|
+
const [stored, active, where] = await Promise.all([
|
|
8035
|
+
storedOf(projectId),
|
|
8036
|
+
listMembers(ctx, projectId),
|
|
8037
|
+
machinesOf(projectId)
|
|
8038
|
+
]);
|
|
8039
|
+
return { stored, active, machines: where.machines, ...resolveTeam(stored, active, where) };
|
|
8234
8040
|
};
|
|
8235
|
-
|
|
8236
|
-
const
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
)
|
|
8241
|
-
const thread = assignee === void 0 ? void 0 : sessions.get(assignee);
|
|
8242
|
-
const session = thread === void 0 ? void 0 : sessionStatus(thread);
|
|
8041
|
+
const inspect = async (projectId) => {
|
|
8042
|
+
const [view, history] = await Promise.all([
|
|
8043
|
+
activeView(projectId),
|
|
8044
|
+
listMemberHistory(ctx, projectId)
|
|
8045
|
+
]);
|
|
8046
|
+
const shown = new Set(history.map((member) => member.memberId));
|
|
8243
8047
|
return {
|
|
8244
|
-
...
|
|
8245
|
-
|
|
8048
|
+
...view,
|
|
8049
|
+
members: [...view.active.filter((member) => !shown.has(member.memberId)), ...history]
|
|
8246
8050
|
};
|
|
8247
8051
|
};
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
)
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
|
|
8266
|
-
|
|
8267
|
-
|
|
8268
|
-
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
summary: { latestTurn: leadThread.latestTurn }
|
|
8280
|
-
}
|
|
8281
|
-
]
|
|
8282
|
-
];
|
|
8283
|
-
}
|
|
8284
|
-
async function readPinnedSessions(ctx, rows, wakeProject, listed) {
|
|
8285
|
-
const threadIds = [
|
|
8286
|
-
...new Set(
|
|
8287
|
-
rows.flatMap((row) => {
|
|
8288
|
-
const wakeItem = wakeProject?.items[row.workItemId];
|
|
8289
|
-
return wakeItem === void 0 ? [] : pinnedThreadsOf(wakeItem);
|
|
8290
|
-
})
|
|
8291
|
-
)
|
|
8292
|
-
].filter((threadId) => !listed.has(threadId)).slice(0, PINNED_SESSION_LIMIT);
|
|
8293
|
-
const pinned = await Promise.all(
|
|
8294
|
-
threadIds.map((threadId) => ctx.threads.get({ threadId }).catch(() => null))
|
|
8295
|
-
);
|
|
8296
|
-
return pinned.flatMap(
|
|
8297
|
-
(thread) => thread === null ? [] : [
|
|
8298
|
-
{
|
|
8299
|
-
threadId: thread.id,
|
|
8300
|
-
status: thread.status,
|
|
8301
|
-
summary: { latestTurn: thread.latestTurn }
|
|
8052
|
+
const aliases = async (projectId) => {
|
|
8053
|
+
const stored = await storedOf(projectId);
|
|
8054
|
+
return stored?.version === 2 ? stored.roster.aliases ?? {} : {};
|
|
8055
|
+
};
|
|
8056
|
+
const storedLeadMemberId = async (projectId) => {
|
|
8057
|
+
const stored = await storedOf(projectId);
|
|
8058
|
+
return stored?.version === 2 ? stored.roster.leadMemberId : null;
|
|
8059
|
+
};
|
|
8060
|
+
const readTeam = async (projectId) => {
|
|
8061
|
+
const stored = await storedOf(projectId);
|
|
8062
|
+
if (stored === null) return { team: null };
|
|
8063
|
+
if (stored.version === 1) return { team: stored.roster };
|
|
8064
|
+
const [active, where] = await Promise.all([listMembers(ctx, projectId), machinesOf(projectId)]);
|
|
8065
|
+
return { team: resolveTeam(stored, active, where).team, active };
|
|
8066
|
+
};
|
|
8067
|
+
const read = async (projectId) => (await readTeam(projectId)).team;
|
|
8068
|
+
const append2 = async (projectId, expectedRevision, lead) => {
|
|
8069
|
+
const revision = expectedRevision + 1;
|
|
8070
|
+
const receipt = await ctx.events.append({
|
|
8071
|
+
commandId: `roster:${projectId}:${revision}`,
|
|
8072
|
+
name: "roster-set",
|
|
8073
|
+
aggregate: { kind: "project", id: projectId },
|
|
8074
|
+
data: {
|
|
8075
|
+
version: 2,
|
|
8076
|
+
roster: {
|
|
8077
|
+
projectId,
|
|
8078
|
+
leadMemberId: lead.leadMemberId,
|
|
8079
|
+
revision,
|
|
8080
|
+
updatedAt: await now3(),
|
|
8081
|
+
...lead.aliases === void 0 ? {} : { aliases: lead.aliases }
|
|
8082
|
+
}
|
|
8302
8083
|
}
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
}
|
|
8306
|
-
|
|
8307
|
-
// src/domain/goalItem.ts
|
|
8308
|
-
var teamGoalItemId = (projectId, goalId) => `team-goal:${projectId}:${goalId}`;
|
|
8309
|
-
var GOAL_ITEM_TITLE_MAX = 120;
|
|
8310
|
-
var goalItemTitle = (goal) => {
|
|
8311
|
-
const line = (goal.titleSeed ?? goal.goal).split(/\r?\n/u, 1)[0].trim();
|
|
8312
|
-
return line.length <= GOAL_ITEM_TITLE_MAX ? line : `${line.slice(0, GOAL_ITEM_TITLE_MAX - 1)}\u2026`;
|
|
8313
|
-
};
|
|
8314
|
-
|
|
8315
|
-
// src/board.ts
|
|
8316
|
-
var ITEM_LIMIT = 500;
|
|
8317
|
-
var PEOPLE_LIMIT = 200;
|
|
8318
|
-
var decodeRead2 = decodeUnknownSync(ReadBoardInput);
|
|
8319
|
-
function registerBoardCommands(ctx, goals, rosters, wakes, options = {}) {
|
|
8320
|
-
const hasMember = async (projectId, threadIds) => {
|
|
8321
|
-
const members = (await goals.allOf(projectId)).flatMap((goal) => goalExecution(goal).members);
|
|
8322
|
-
if (threadIds.some(cardSessions(members, void 0))) return true;
|
|
8323
|
-
const wake = (await wakes.get())[projectId];
|
|
8324
|
-
return wake !== void 0 && threadIds.some(cardSessions(members, wake));
|
|
8084
|
+
});
|
|
8085
|
+
await rosters.get({ throughSequence: receipt.sequence });
|
|
8086
|
+
return { revision };
|
|
8325
8087
|
};
|
|
8326
|
-
const
|
|
8327
|
-
|
|
8328
|
-
const
|
|
8329
|
-
|
|
8330
|
-
const
|
|
8331
|
-
const
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8088
|
+
const { run: serial } = createSerial();
|
|
8089
|
+
const setLead = async (payload) => {
|
|
8090
|
+
const decoded = decodeSetLead(payload);
|
|
8091
|
+
if (isNone2(decoded)) return rejectRoster("invalid-payload");
|
|
8092
|
+
const { projectId, leadMemberId, expectedRevision } = decoded.value;
|
|
8093
|
+
const { stored, active } = await activeView(projectId);
|
|
8094
|
+
if (stored?.version === 1) return rejectRoster("legacy-roster");
|
|
8095
|
+
if (expectedRevision !== (stored?.roster.revision ?? 0)) return rejectRoster("stale-revision");
|
|
8096
|
+
const lead = active.find((member) => member.memberId === leadMemberId);
|
|
8097
|
+
if (lead === void 0 || !isActiveAgent(lead)) return rejectRoster("lead-not-member");
|
|
8098
|
+
if (isRemoteMember(lead, ctx.environment.id)) return rejectRoster("lead-remote");
|
|
8099
|
+
return append2(projectId, expectedRevision, {
|
|
8100
|
+
leadMemberId,
|
|
8101
|
+
...stored?.roster.aliases === void 0 ? {} : { aliases: stored.roster.aliases }
|
|
8335
8102
|
});
|
|
8336
|
-
return {
|
|
8337
|
-
roster,
|
|
8338
|
-
members,
|
|
8339
|
-
aliases,
|
|
8340
|
-
// 线上没有目标时 read 会退回项目级目标;团队层只认这条线自己的。
|
|
8341
|
-
goal: read !== null && workLineId !== void 0 && read.workLineId !== workLineId ? null : read
|
|
8342
|
-
};
|
|
8343
8103
|
};
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
|
|
8349
|
-
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
|
|
8355
|
-
|
|
8356
|
-
viewer,
|
|
8357
|
-
lines,
|
|
8358
|
-
everyGoal
|
|
8359
|
-
] = await Promise.all([
|
|
8360
|
-
ctx.work.states.list({ projectId }),
|
|
8361
|
-
// 团队只读一次:目标上的姓名和下面的 rosterMembers 用同一份。它随成员事件与 team/roster-set 门铃一起刷新。
|
|
8362
|
-
readTeam(projectId, workLineId),
|
|
8363
|
-
ctx.projects.toolkits.get({ projectId }),
|
|
8364
|
-
// 人名只用来显示作者;本机所有者排第一,后面是这个项目认识的账号。
|
|
8365
|
-
readPages(PEOPLE_LIMIT, (page) => ctx.communication.people.list({ projectId, ...page })),
|
|
8366
|
-
// 项目里的别的机器:远端作者(那台机器上的 agent)的名字与在线状态;读不出来退回空,不连累看板。
|
|
8367
|
-
readMachines(ctx, projectId),
|
|
8368
|
-
// 认出当前读者只为把作者显示成「你」:读不出来就当没有,不连累整张看板。
|
|
8369
|
-
invocation.viewer?.communication.people.current({}).catch(() => null),
|
|
8370
|
-
// 团队层只核这条线还在(读不到照抛,界面显示读取失败);项目层要全部线(含已归档)来分道,线不设上限。
|
|
8371
|
-
workLineId === void 0 ? readPages(
|
|
8372
|
-
Number.POSITIVE_INFINITY,
|
|
8373
|
-
(page) => ctx.work.lines.list({ projectId, includeArchived: true, ...page })
|
|
8374
|
-
).then(({ items: items2 }) => items2) : ctx.work.lines.get({ projectId, workLineId }).then(({ line }) => [line]),
|
|
8375
|
-
// 项目层各线的目标只用来在道内解析成员绑定、写道头一句话,不补姓名;团队层只要这一条线,上面已读好。
|
|
8376
|
-
workLineId === void 0 ? goals.allOf(projectId) : []
|
|
8377
|
-
]);
|
|
8378
|
-
const lineGoals = new Map(
|
|
8379
|
-
everyGoal.flatMap((row) => row.workLineId === void 0 ? [] : [[row.workLineId, row]])
|
|
8380
|
-
);
|
|
8381
|
-
if (workLineId !== void 0 && goal !== null) lineGoals.set(workLineId, goal);
|
|
8382
|
-
const goalOfLane = (laneId) => (laneId === null ? void 0 : lineGoals.get(laneId)) ?? (workLineId === void 0 ? goal : null);
|
|
8383
|
-
const archivedLines = new Set(
|
|
8384
|
-
lines.flatMap((line) => line.archivedAt === null ? [] : [line.workLineId])
|
|
8385
|
-
);
|
|
8386
|
-
const sessionGoals = workLineId === void 0 ? [
|
|
8387
|
-
goal,
|
|
8388
|
-
...[...lineGoals].filter(([laneId]) => !archivedLines.has(laneId)).map(([, row]) => row)
|
|
8389
|
-
] : [goal];
|
|
8390
|
-
const goalItemId = goal === null ? null : teamGoalItemId(projectId, goal.goalId);
|
|
8391
|
-
const [remoteWork, { items: rows, truncated }, goalItem, sessionGroups, wakeState] = await Promise.all([
|
|
8392
|
-
Promise.all(
|
|
8393
|
-
(roster?.members ?? []).flatMap(
|
|
8394
|
-
(member) => member.principal === void 0 ? [] : [
|
|
8395
|
-
ctx.work.remoteAgentPending.get({ projectId, principalId: member.principal.principalId }).then(
|
|
8396
|
-
// 一台机器上可能有好几个成员:只算派给这个成员的(与直接派给那台机器的)。
|
|
8397
|
-
({ work }) => {
|
|
8398
|
-
const items2 = work.items.filter(
|
|
8399
|
-
(item) => item.memberId === void 0 || item.memberId === member.memberId
|
|
8400
|
-
).map(({ workItemId, blocked }) => ({ workItemId, blocked }));
|
|
8401
|
-
return { count: items2.length, items: items2 };
|
|
8402
|
-
},
|
|
8403
|
-
() => null
|
|
8404
|
-
).then((pending) => ({ memberId: member.memberId, pending }))
|
|
8405
|
-
]
|
|
8406
|
-
)
|
|
8407
|
-
),
|
|
8408
|
-
readPages(
|
|
8409
|
-
ITEM_LIMIT,
|
|
8410
|
-
(page) => ctx.work.items.list({
|
|
8411
|
-
projectId,
|
|
8412
|
-
...workLineId === void 0 ? {} : { workLineIds: [workLineId] },
|
|
8413
|
-
...page
|
|
8414
|
-
})
|
|
8415
|
-
),
|
|
8416
|
-
// 目标那件按号单读:看板只列最新的 500 件,目标那件可能不在里面。
|
|
8417
|
-
goalItemId === null ? void 0 : ctx.work.items.get({ projectId, workItemIds: [goalItemId] }).then(({ items: items2 }) => items2.find((item) => item.workItemId === goalItemId)),
|
|
8418
|
-
Promise.all(sessionGoals.map((row) => readGoalSessions(ctx, projectId, row))),
|
|
8419
|
-
wakes.get().catch(() => null)
|
|
8420
|
-
]);
|
|
8421
|
-
const sessions = sessionGroups.flat();
|
|
8422
|
-
const wakeProject = wakeState?.[projectId];
|
|
8423
|
-
sessions.push(
|
|
8424
|
-
...await readPinnedSessions(
|
|
8425
|
-
ctx,
|
|
8426
|
-
rows,
|
|
8427
|
-
wakeProject,
|
|
8428
|
-
new Set(sessions.map((session) => session.threadId))
|
|
8429
|
-
)
|
|
8430
|
-
);
|
|
8431
|
-
const progress = boardProgress(
|
|
8432
|
-
rows,
|
|
8433
|
-
(item) => goalOfLane(item.workLineId ?? null),
|
|
8434
|
-
sessions,
|
|
8435
|
-
wakeProject
|
|
8436
|
-
);
|
|
8437
|
-
const assignedMemberIds = [
|
|
8438
|
-
...new Set(
|
|
8439
|
-
rows.flatMap(
|
|
8440
|
-
(item) => item.assignees.flatMap(
|
|
8441
|
-
(assignee) => assignee.kind === "member" ? [assignee.memberId] : []
|
|
8442
|
-
)
|
|
8443
|
-
)
|
|
8444
|
-
)
|
|
8445
|
-
];
|
|
8446
|
-
const known = [
|
|
8447
|
-
...members ?? roster?.members ?? [],
|
|
8448
|
-
...(goal?.members ?? []).flatMap(
|
|
8449
|
-
({ memberId, name }) => name === null ? [] : [{ memberId: aliasedMemberId(aliases, memberId) ?? memberId, name }]
|
|
8450
|
-
)
|
|
8451
|
-
];
|
|
8452
|
-
const memberNames = assignedMemberIds.length === 0 ? [] : await rosters.memberNames(projectId, assignedMemberIds, known).catch(() => []);
|
|
8453
|
-
const enabled = (toolkit) => toolkitStates.toolkits.some((row) => row.toolkit === toolkit && row.enabled);
|
|
8454
|
-
const items = rows.map((item) => ({
|
|
8455
|
-
workItemId: item.workItemId,
|
|
8456
|
-
sequenceId: item.sequenceId,
|
|
8457
|
-
title: item.title,
|
|
8458
|
-
state: { stateId: item.state.stateId, name: item.state.name },
|
|
8459
|
-
assignees: item.assignees.map(workIdentity),
|
|
8460
|
-
blockedByTotal: item.blockedByTotal,
|
|
8461
|
-
version: item.version,
|
|
8462
|
-
workLineId: item.workLineId ?? null,
|
|
8463
|
-
...progress(item)
|
|
8464
|
-
}));
|
|
8465
|
-
return {
|
|
8466
|
-
states: stateList.states.map(({ stateId, name, sequence, defaultKey }) => ({
|
|
8467
|
-
stateId,
|
|
8468
|
-
name,
|
|
8469
|
-
sequence,
|
|
8470
|
-
...defaultKey === void 0 ? {} : { defaultKey }
|
|
8471
|
-
})).sort((a, b) => a.sequence - b.sequence),
|
|
8472
|
-
items,
|
|
8473
|
-
// 项目里没有线(还没开过团队)保持原来的一张平板看板,不出泳道。
|
|
8474
|
-
...workLineId === void 0 && lines.length > 0 ? {
|
|
8475
|
-
lanes: boardLanes(
|
|
8476
|
-
lines,
|
|
8477
|
-
(laneId) => laneId === null ? goal?.goal : lineGoals.get(laneId)?.goal,
|
|
8478
|
-
rows.some((row) => row.workLineId == null)
|
|
8479
|
-
)
|
|
8480
|
-
} : {},
|
|
8481
|
-
goal,
|
|
8482
|
-
...goalItem === void 0 ? {} : {
|
|
8483
|
-
goalItem: {
|
|
8484
|
-
workItemId: goalItem.workItemId,
|
|
8485
|
-
sequenceId: goalItem.sequenceId,
|
|
8486
|
-
state: {
|
|
8487
|
-
stateId: goalItem.state.stateId,
|
|
8488
|
-
name: goalItem.state.name,
|
|
8489
|
-
group: goalItem.state.group
|
|
8490
|
-
}
|
|
8491
|
-
}
|
|
8492
|
-
},
|
|
8493
|
-
people: people.items.map((row) => ({
|
|
8494
|
-
key: personKey(row.person),
|
|
8495
|
-
displayName: row.displayName
|
|
8496
|
-
})),
|
|
8497
|
-
rosterMembers: roster?.members ?? [],
|
|
8498
|
-
...memberNames.length === 0 ? {} : { memberNames },
|
|
8499
|
-
...members === null ? { membersUnavailable: true } : {
|
|
8500
|
-
assignableMembers: members.map(({ memberId, name, kind }) => ({
|
|
8501
|
-
memberId,
|
|
8502
|
-
name,
|
|
8503
|
-
kind
|
|
8504
|
-
}))
|
|
8505
|
-
},
|
|
8506
|
-
...roster?.aliases === void 0 ? {} : { rosterAliases: roster.aliases },
|
|
8507
|
-
...machines === null ? { machinesUnavailable: true } : {},
|
|
8508
|
-
machines: [...machines?.values() ?? []].map(
|
|
8509
|
-
({ principalId, environmentId, name, online, lastSeenAt }) => ({
|
|
8510
|
-
principalId,
|
|
8511
|
-
environmentId,
|
|
8512
|
-
name,
|
|
8513
|
-
online,
|
|
8514
|
-
...lastSeenAt === void 0 ? {} : { lastSeenAt }
|
|
8515
|
-
})
|
|
8516
|
-
),
|
|
8517
|
-
remoteWork,
|
|
8518
|
-
...viewer?.person == null ? {} : { viewerKey: personKey(viewer.person) },
|
|
8519
|
-
toolkits: { board: enabled("board"), memory: enabled("memory") },
|
|
8520
|
-
truncated
|
|
8521
|
-
};
|
|
8522
|
-
}
|
|
8523
|
-
});
|
|
8524
|
-
registerTeamWatch(ctx, hasMember, options);
|
|
8525
|
-
}
|
|
8526
|
-
|
|
8527
|
-
// src/runtime/serial.ts
|
|
8528
|
-
function createSerial(closedMessage = "team-serial-closed") {
|
|
8529
|
-
let pending = Promise.resolve();
|
|
8530
|
-
let closed = false;
|
|
8531
|
-
return {
|
|
8532
|
-
run(execute) {
|
|
8533
|
-
const result2 = pending.then(() => {
|
|
8534
|
-
if (closed) throw new Error(closedMessage);
|
|
8535
|
-
return execute();
|
|
8536
|
-
});
|
|
8537
|
-
pending = result2.then(
|
|
8538
|
-
() => void 0,
|
|
8539
|
-
() => void 0
|
|
8540
|
-
);
|
|
8541
|
-
return result2;
|
|
8542
|
-
},
|
|
8543
|
-
/** 不再开始新任务,并等已经在跑和排在前面的任务落定。 */
|
|
8544
|
-
async close() {
|
|
8545
|
-
closed = true;
|
|
8546
|
-
await pending;
|
|
8547
|
-
}
|
|
8548
|
-
};
|
|
8549
|
-
}
|
|
8550
|
-
|
|
8551
|
-
// src/domain/service.ts
|
|
8552
|
-
var HISTORY_LIMIT = 500;
|
|
8553
|
-
var ACTIVE_LIMIT = 2e3;
|
|
8554
|
-
var MEMBER_NAMES_LIMIT = 50;
|
|
8555
|
-
var FactEnvelope = Struct({
|
|
8556
|
-
pluginId: Literal2("team"),
|
|
8557
|
-
name: Literal2("team/roster-set"),
|
|
8558
|
-
data: RosterSetFact
|
|
8559
|
-
});
|
|
8560
|
-
var decodeFact2 = decodeUnknownOption2(FactEnvelope);
|
|
8561
|
-
var decodeSetLead = decodeUnknownOption2(SetLeadInput);
|
|
8562
|
-
var decodeRosterFact = (payload) => map(decodeFact2(payload), (fact) => fact.data);
|
|
8563
|
-
var factProject = (fact) => fact.roster.projectId;
|
|
8564
|
-
function foldRoster(state, event) {
|
|
8565
|
-
return foldFact(state, event, decodeRosterFact, factProject);
|
|
8566
|
-
}
|
|
8567
|
-
async function listMembers(ctx, projectId) {
|
|
8568
|
-
const { items, truncated } = await readPages(
|
|
8569
|
-
ACTIVE_LIMIT,
|
|
8570
|
-
(page) => ctx.members.list({ projectId, ...page })
|
|
8571
|
-
);
|
|
8572
|
-
if (truncated) throw new Error("team-members-truncated");
|
|
8573
|
-
return items;
|
|
8574
|
-
}
|
|
8575
|
-
async function listMemberHistory(ctx, projectId) {
|
|
8576
|
-
const { items } = await readPages(
|
|
8577
|
-
HISTORY_LIMIT,
|
|
8578
|
-
(page) => ctx.members.list({ projectId, includeRemoved: true, ...page }),
|
|
8579
|
-
"newest"
|
|
8580
|
-
);
|
|
8581
|
-
return items;
|
|
8582
|
-
}
|
|
8583
|
-
async function findMember(ctx, projectId, memberId, window) {
|
|
8584
|
-
try {
|
|
8585
|
-
const { member } = await ctx.members.get({ projectId, memberId, ...window });
|
|
8586
|
-
return member;
|
|
8587
|
-
} catch (error) {
|
|
8588
|
-
const reason = typeof error === "object" && error !== null && "reason" in error ? error.reason : null;
|
|
8589
|
-
if (reason === "member-not-found") return null;
|
|
8590
|
-
throw error;
|
|
8591
|
-
}
|
|
8592
|
-
}
|
|
8593
|
-
var isActiveAgent = (member) => member.kind === "agent" && member.removedAt === null;
|
|
8594
|
-
var toTeamMember = (member, where) => {
|
|
8595
|
-
if (!isRemoteMember(member, where.local)) return { memberId: member.memberId, name: member.name };
|
|
8596
|
-
const machine = member.agent === null ? void 0 : where.machines?.get(member.agent.environmentId);
|
|
8597
|
-
return {
|
|
8598
|
-
memberId: member.memberId,
|
|
8599
|
-
name: member.name,
|
|
8600
|
-
remote: true,
|
|
8601
|
-
...machine === void 0 ? {} : { principal: { kind: "remote-agent", principalId: machine.principalId } }
|
|
8602
|
-
};
|
|
8603
|
-
};
|
|
8604
|
-
function resolveTeam(stored, members, where) {
|
|
8605
|
-
if (stored === null) return { team: null, problem: null };
|
|
8606
|
-
if (stored.version === 1) return { team: stored.roster, problem: null };
|
|
8607
|
-
const { roster: lead } = stored;
|
|
8608
|
-
const team = {
|
|
8609
|
-
projectId: lead.projectId,
|
|
8610
|
-
members: members.filter(isActiveAgent).map((member) => toTeamMember(member, where)),
|
|
8611
|
-
leadMemberId: lead.leadMemberId,
|
|
8612
|
-
revision: lead.revision,
|
|
8613
|
-
updatedAt: lead.updatedAt,
|
|
8614
|
-
...lead.aliases === void 0 ? {} : { aliases: lead.aliases }
|
|
8615
|
-
};
|
|
8616
|
-
const problem = teamRuleError(team);
|
|
8617
|
-
return problem === null ? { team, problem: null } : { team: null, problem };
|
|
8618
|
-
}
|
|
8619
|
-
function createRosterService(ctx, options = {}) {
|
|
8620
|
-
const rosters = ctx.derivedState({
|
|
8621
|
-
key: "rosters",
|
|
8622
|
-
version: 2,
|
|
8623
|
-
events: ["plugin.event-appended"],
|
|
8624
|
-
init: () => ({}),
|
|
8625
|
-
apply: foldRoster
|
|
8626
|
-
});
|
|
8627
|
-
const now3 = options.now ?? factTime;
|
|
8628
|
-
const storedOf = async (projectId) => readFact(await rosters.get(), projectId);
|
|
8629
|
-
const machinesOf = async (projectId) => ({
|
|
8630
|
-
local: ctx.environment.id,
|
|
8631
|
-
machines: await readMachines(ctx, projectId)
|
|
8632
|
-
});
|
|
8633
|
-
const activeView = async (projectId) => {
|
|
8634
|
-
const [stored, active, where] = await Promise.all([
|
|
8635
|
-
storedOf(projectId),
|
|
8636
|
-
listMembers(ctx, projectId),
|
|
8637
|
-
machinesOf(projectId)
|
|
8638
|
-
]);
|
|
8639
|
-
return { stored, active, machines: where.machines, ...resolveTeam(stored, active, where) };
|
|
8640
|
-
};
|
|
8641
|
-
const inspect = async (projectId) => {
|
|
8642
|
-
const [view, history] = await Promise.all([
|
|
8643
|
-
activeView(projectId),
|
|
8644
|
-
listMemberHistory(ctx, projectId)
|
|
8645
|
-
]);
|
|
8646
|
-
const shown = new Set(history.map((member) => member.memberId));
|
|
8647
|
-
return {
|
|
8648
|
-
...view,
|
|
8649
|
-
members: [...view.active.filter((member) => !shown.has(member.memberId)), ...history]
|
|
8650
|
-
};
|
|
8651
|
-
};
|
|
8652
|
-
const aliases = async (projectId) => {
|
|
8653
|
-
const stored = await storedOf(projectId);
|
|
8654
|
-
return stored?.version === 2 ? stored.roster.aliases ?? {} : {};
|
|
8655
|
-
};
|
|
8656
|
-
const storedLeadMemberId = async (projectId) => {
|
|
8657
|
-
const stored = await storedOf(projectId);
|
|
8658
|
-
return stored?.version === 2 ? stored.roster.leadMemberId : null;
|
|
8659
|
-
};
|
|
8660
|
-
const readTeam = async (projectId) => {
|
|
8661
|
-
const stored = await storedOf(projectId);
|
|
8662
|
-
if (stored === null) return { team: null };
|
|
8663
|
-
if (stored.version === 1) return { team: stored.roster };
|
|
8664
|
-
const [active, where] = await Promise.all([listMembers(ctx, projectId), machinesOf(projectId)]);
|
|
8665
|
-
return { team: resolveTeam(stored, active, where).team, active };
|
|
8666
|
-
};
|
|
8667
|
-
const read = async (projectId) => (await readTeam(projectId)).team;
|
|
8668
|
-
const append2 = async (projectId, expectedRevision, lead) => {
|
|
8669
|
-
const revision = expectedRevision + 1;
|
|
8670
|
-
const receipt = await ctx.events.append({
|
|
8671
|
-
commandId: `roster:${projectId}:${revision}`,
|
|
8672
|
-
name: "roster-set",
|
|
8673
|
-
aggregate: { kind: "project", id: projectId },
|
|
8674
|
-
data: {
|
|
8675
|
-
version: 2,
|
|
8676
|
-
roster: {
|
|
8677
|
-
projectId,
|
|
8678
|
-
leadMemberId: lead.leadMemberId,
|
|
8679
|
-
revision,
|
|
8680
|
-
updatedAt: await now3(),
|
|
8681
|
-
...lead.aliases === void 0 ? {} : { aliases: lead.aliases }
|
|
8682
|
-
}
|
|
8683
|
-
}
|
|
8684
|
-
});
|
|
8685
|
-
await rosters.get({ throughSequence: receipt.sequence });
|
|
8686
|
-
return { revision };
|
|
8687
|
-
};
|
|
8688
|
-
const { run: serial } = createSerial();
|
|
8689
|
-
const setLead = async (payload) => {
|
|
8690
|
-
const decoded = decodeSetLead(payload);
|
|
8691
|
-
if (isNone2(decoded)) return rejectRoster("invalid-payload");
|
|
8692
|
-
const { projectId, leadMemberId, expectedRevision } = decoded.value;
|
|
8693
|
-
const { stored, active } = await activeView(projectId);
|
|
8694
|
-
if (stored?.version === 1) return rejectRoster("legacy-roster");
|
|
8695
|
-
if (expectedRevision !== (stored?.roster.revision ?? 0)) return rejectRoster("stale-revision");
|
|
8696
|
-
const lead = active.find((member) => member.memberId === leadMemberId);
|
|
8697
|
-
if (lead === void 0 || !isActiveAgent(lead)) return rejectRoster("lead-not-member");
|
|
8698
|
-
if (isRemoteMember(lead, ctx.environment.id)) return rejectRoster("lead-remote");
|
|
8699
|
-
return append2(projectId, expectedRevision, {
|
|
8700
|
-
leadMemberId,
|
|
8701
|
-
...stored?.roster.aliases === void 0 ? {} : { aliases: stored.roster.aliases }
|
|
8702
|
-
});
|
|
8703
|
-
};
|
|
8704
|
-
const adoptImported = async (input) => {
|
|
8705
|
-
const stored = await storedOf(input.projectId);
|
|
8706
|
-
if (stored?.version !== 1 || stored.roster.revision !== input.expectedRevision)
|
|
8707
|
-
return rejectRoster("stale-revision");
|
|
8708
|
-
return append2(input.projectId, input.expectedRevision, input);
|
|
8709
|
-
};
|
|
8710
|
-
const memberNames = async (projectId, memberIds, known = []) => (await Promise.all(
|
|
8711
|
-
memberIds.slice(0, MEMBER_NAMES_LIMIT).map(async (memberId) => {
|
|
8712
|
-
const named = known.find((row) => row.memberId === memberId);
|
|
8713
|
-
if (named !== void 0) return [{ memberId, name: named.name }];
|
|
8714
|
-
const member = await findMember(ctx, projectId, memberId, { textLimit: 2 }).catch(
|
|
8715
|
-
() => null
|
|
8104
|
+
const adoptImported = async (input) => {
|
|
8105
|
+
const stored = await storedOf(input.projectId);
|
|
8106
|
+
if (stored?.version !== 1 || stored.roster.revision !== input.expectedRevision)
|
|
8107
|
+
return rejectRoster("stale-revision");
|
|
8108
|
+
return append2(input.projectId, input.expectedRevision, input);
|
|
8109
|
+
};
|
|
8110
|
+
const memberNames = async (projectId, memberIds, known = []) => (await Promise.all(
|
|
8111
|
+
memberIds.slice(0, MEMBER_NAMES_LIMIT).map(async (memberId) => {
|
|
8112
|
+
const named = known.find((row) => row.memberId === memberId);
|
|
8113
|
+
if (named !== void 0) return [{ memberId, name: named.name }];
|
|
8114
|
+
const member = await findMember(ctx, projectId, memberId, { textLimit: 2 }).catch(
|
|
8115
|
+
() => null
|
|
8716
8116
|
);
|
|
8717
8117
|
return member === null ? [] : [{ memberId, name: member.name }];
|
|
8718
8118
|
})
|
|
@@ -8975,33 +8375,120 @@ var specOfMember = (member) => ({
|
|
|
8975
8375
|
});
|
|
8976
8376
|
var trialIdOf = (projectId, memberId, specKey, attempt) => `team-trial:${stableHash(JSON.stringify([projectId, memberId, specKey, attempt]))}`;
|
|
8977
8377
|
|
|
8978
|
-
// src/domain/
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
}
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
}
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
|
|
9000
|
-
|
|
9001
|
-
|
|
9002
|
-
|
|
9003
|
-
|
|
9004
|
-
|
|
8378
|
+
// src/domain/execution.ts
|
|
8379
|
+
function goalExecution(goal) {
|
|
8380
|
+
return {
|
|
8381
|
+
leadMemberId: goal?.leadMemberId ?? null,
|
|
8382
|
+
members: goal === null ? [] : [...goal.threads, ...goal.remoteMembers ?? []]
|
|
8383
|
+
};
|
|
8384
|
+
}
|
|
8385
|
+
function findGoalMember(members, identity2) {
|
|
8386
|
+
return members.find(
|
|
8387
|
+
(member) => "threadId" in identity2 ? "threadId" in member && member.threadId === identity2.threadId : "principalId" in member && member.principalId === identity2.principalId
|
|
8388
|
+
);
|
|
8389
|
+
}
|
|
8390
|
+
|
|
8391
|
+
// src/domain/recipient.ts
|
|
8392
|
+
var recipientOf = (principal) => principal.kind === "agent" && principal.threadId !== void 0 ? { threadId: principal.threadId } : principal.kind === "remote-agent" && principal.principalId !== void 0 ? { principalId: principal.principalId } : void 0;
|
|
8393
|
+
var recipientKey = (who) => "threadId" in who ? `thread:${who.threadId}` : `principal:${who.principalId}`;
|
|
8394
|
+
|
|
8395
|
+
// src/domain/binding.ts
|
|
8396
|
+
var MemberBoundFact = Struct({
|
|
8397
|
+
version: Literal2(1),
|
|
8398
|
+
projectId: String4,
|
|
8399
|
+
memberId: String4,
|
|
8400
|
+
specKey: String4,
|
|
8401
|
+
goalId: String4,
|
|
8402
|
+
threadId: optionalKey2(String4),
|
|
8403
|
+
principalId: optionalKey2(String4),
|
|
8404
|
+
replaces: optionalKey2(String4)
|
|
8405
|
+
}).check(
|
|
8406
|
+
makeFilter2((fact) => fact.threadId === void 0 !== (fact.principalId === void 0))
|
|
8407
|
+
);
|
|
8408
|
+
var MemberBoundEnvelope = factEnvelope("member-bound", MemberBoundFact);
|
|
8409
|
+
var bindingOfFact = (fact) => fact.threadId !== void 0 ? { threadId: fact.threadId } : { principalId: fact.principalId };
|
|
8410
|
+
function bindingsOf(goal) {
|
|
8411
|
+
const bindings = {};
|
|
8412
|
+
for (const member of goalExecution(goal).members)
|
|
8413
|
+
bindings[member.memberId] = "threadId" in member ? { threadId: member.threadId } : { principalId: member.principalId };
|
|
8414
|
+
return bindings;
|
|
8415
|
+
}
|
|
8416
|
+
function withBoundBinding(bindings, fact) {
|
|
8417
|
+
const next = { ...bindings };
|
|
8418
|
+
if (fact.replaces !== void 0) delete next[fact.replaces];
|
|
8419
|
+
next[fact.memberId] = bindingOfFact(fact);
|
|
8420
|
+
return next;
|
|
8421
|
+
}
|
|
8422
|
+
var leadAfterBinding = (leadMemberId, fact) => fact.replaces !== void 0 && leadMemberId === fact.replaces ? fact.memberId : leadMemberId;
|
|
8423
|
+
function withBoundMember(goal, fact) {
|
|
8424
|
+
if (fact.projectId !== goal.projectId || fact.goalId !== goal.goalId) return goal;
|
|
8425
|
+
const { remoteMembers: _before, ...rest } = goal;
|
|
8426
|
+
const superseded = (memberId) => memberId === fact.memberId || memberId === fact.replaces;
|
|
8427
|
+
const threads = goal.threads.filter((row) => !superseded(row.memberId));
|
|
8428
|
+
const remoteMembers = (goal.remoteMembers ?? []).filter((row) => !superseded(row.memberId));
|
|
8429
|
+
const binding = bindingOfFact(fact);
|
|
8430
|
+
const next = "threadId" in binding ? {
|
|
8431
|
+
threads: [...threads, { memberId: fact.memberId, threadId: binding.threadId }],
|
|
8432
|
+
remoteMembers
|
|
8433
|
+
} : {
|
|
8434
|
+
threads,
|
|
8435
|
+
remoteMembers: [
|
|
8436
|
+
...remoteMembers,
|
|
8437
|
+
{ memberId: fact.memberId, principalId: binding.principalId }
|
|
8438
|
+
]
|
|
8439
|
+
};
|
|
8440
|
+
return {
|
|
8441
|
+
...rest,
|
|
8442
|
+
leadMemberId: leadAfterBinding(goal.leadMemberId, fact),
|
|
8443
|
+
threads: next.threads,
|
|
8444
|
+
...next.remoteMembers.length === 0 ? {} : { remoteMembers: next.remoteMembers }
|
|
8445
|
+
};
|
|
8446
|
+
}
|
|
8447
|
+
function targetOf(bindings, assignee, pinned) {
|
|
8448
|
+
if (assignee.kind !== "member") return recipientOf(assignee);
|
|
8449
|
+
const { memberId } = assignee;
|
|
8450
|
+
if (memberId === void 0) return void 0;
|
|
8451
|
+
const fixed = pinned !== void 0 && Object.hasOwn(pinned, memberId) ? pinned[memberId] : void 0;
|
|
8452
|
+
if (fixed !== void 0) return { threadId: fixed };
|
|
8453
|
+
return bindings !== void 0 && Object.hasOwn(bindings, memberId) ? bindings[memberId] : void 0;
|
|
8454
|
+
}
|
|
8455
|
+
function assignedToGoalMember(goal, assignees) {
|
|
8456
|
+
const execution = goalExecution(goal);
|
|
8457
|
+
const members = execution.members.filter((member) => member.memberId !== execution.leadMemberId);
|
|
8458
|
+
const bindings = bindingsOf(goal);
|
|
8459
|
+
return assignees.some((assignee) => {
|
|
8460
|
+
const who = targetOf(bindings, assignee);
|
|
8461
|
+
return who !== void 0 && findGoalMember(members, who) !== void 0;
|
|
8462
|
+
});
|
|
8463
|
+
}
|
|
8464
|
+
|
|
8465
|
+
// src/domain/defaultModel.ts
|
|
8466
|
+
var isSelectionUnavailable = isTagged("ProviderSelectionError");
|
|
8467
|
+
var MODEL_UNAVAILABLE_REASONS = /* @__PURE__ */ new Set([
|
|
8468
|
+
"instance-not-found",
|
|
8469
|
+
"instance-unavailable",
|
|
8470
|
+
"model-not-in-catalog"
|
|
8471
|
+
]);
|
|
8472
|
+
var UNAVAILABLE_MESSAGE_KEYS = {
|
|
8473
|
+
"instance-not-found": "instanceNotFound",
|
|
8474
|
+
"instance-unavailable": "instanceUnavailable",
|
|
8475
|
+
"model-not-in-catalog": "modelNotInCatalog"
|
|
8476
|
+
};
|
|
8477
|
+
var unavailableFrom = (error) => {
|
|
8478
|
+
const reason = Reflect.get(error, "reason");
|
|
8479
|
+
return typeof reason === "string" && MODEL_UNAVAILABLE_REASONS.has(reason) ? { code: "model-unavailable", reason } : { code: "model-unavailable" };
|
|
8480
|
+
};
|
|
8481
|
+
async function resolveModel(ctx, base, named = false) {
|
|
8482
|
+
try {
|
|
8483
|
+
return {
|
|
8484
|
+
selection: await ctx.providers.selection.resolve(
|
|
8485
|
+
named && base !== null ? { base, instanceId: base.instanceId, model: base.model } : { base }
|
|
8486
|
+
)
|
|
8487
|
+
};
|
|
8488
|
+
} catch (error) {
|
|
8489
|
+
if (isSelectionUnavailable(error)) return unavailableFrom(error);
|
|
8490
|
+
throw error;
|
|
8491
|
+
}
|
|
9005
8492
|
}
|
|
9006
8493
|
async function resolveDefaultSelection(ctx, projectId) {
|
|
9007
8494
|
const project2 = await ctx.projects.get({ projectId });
|
|
@@ -9027,6 +8514,10 @@ async function defaultAgent(ctx, projectId) {
|
|
|
9027
8514
|
|
|
9028
8515
|
// locales/en.json
|
|
9029
8516
|
var en_default = {
|
|
8517
|
+
presentation: {
|
|
8518
|
+
name: "Teams",
|
|
8519
|
+
description: "Give a project team a goal: the lead plans it on the board and hands work to the members."
|
|
8520
|
+
},
|
|
9030
8521
|
handbook: {
|
|
9031
8522
|
requestConflict: "This requestId was already used for a different handbook request. Use a new requestId.",
|
|
9032
8523
|
requestVoided: "This requestId was abandoned before the handbook received it. Use a new requestId.",
|
|
@@ -9071,8 +8562,8 @@ var en_default = {
|
|
|
9071
8562
|
versionConflict: "The team was changed at the same moment. Read it again and retry with a new requestId."
|
|
9072
8563
|
},
|
|
9073
8564
|
coordinator: {
|
|
9074
|
-
createTool: `Add an AI teammate to this project's team as the lead of the current goal. Pass a new requestId, and reuse it only to retry the same request. The member runs on this machine with the provider instanceId and model
|
|
9075
|
-
updateTool: "Change a teammate as the lead of the current goal: name, title, responsibility, work instructions (an empty string clears them) or provider instanceId and model (both or neither);
|
|
8565
|
+
createTool: `Add an AI teammate to this project's team as the lead of the current goal. Pass a new requestId, and reuse it only to retry the same request. The member runs on this machine unless you give environmentId: another machine that joined this project (work_list_machines lists them with the providers each one offers). Give the provider instanceId and model together (both or neither); on this machine they default to the project's default model, while on another machine they are required and must be a ready provider instance that machine reported. The new member joins the current goal and gets its own conversation under yours, normally within moments (if that fails you are told why, and it is retried every couple of minutes); in a team opened with team_open, that starts once you add the member with team_set_members; once it is ready you can assign work to it with work_update_item and assignees [{ "kind": "member", "memberId": <the memberId this tool returns> }]. Check who is on the team first with work_list_members.`,
|
|
8566
|
+
updateTool: "Change a teammate as the lead of the current goal: name, title, responsibility, work instructions (an empty string clears them), the machine it runs on (environmentId: this machine's id or another machine from work_list_machines), or provider instanceId and model (both or neither). Without environmentId the member stays on its machine. Moving it to another machine keeps its provider instance only if that machine reported the same ready instance; otherwise give instanceId and model from that machine too. A new machine or model applies to conversations opened afterwards, and a conversation already running keeps its setup. Pass the member's version from work_read_member as expectedVersion; if it has changed you get stale-version, so read the member again. You cannot change your own machine, provider or model. Reuse requestId only to retry the same request.",
|
|
9076
8567
|
removeTool: "Remove a teammate from the team as the lead of the current goal. The record is kept and the member can be restored. Work assigned to the member that has not reached it yet is taken back and you are told; work already in its hands stays with it until you decide. You cannot remove yourself. Reuse requestId only to retry the same request.",
|
|
9077
8568
|
restoreTool: "Bring a removed teammate back as the lead of the current goal. Reuse requestId only to retry the same request.",
|
|
9078
8569
|
noProject: "This call is not tied to a project, so there is no team to change.",
|
|
@@ -9090,7 +8581,12 @@ var en_default = {
|
|
|
9090
8581
|
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.",
|
|
9091
8582
|
memberNotFound: "No such member in this project. List the members with work_list_members.",
|
|
9092
8583
|
cannotRemoveLead: "You cannot remove yourself, the lead of the current goal.",
|
|
9093
|
-
cannotReplaceLead: "You cannot change your own provider or model."
|
|
8584
|
+
cannotReplaceLead: "You cannot change your own machine, provider or model.",
|
|
8585
|
+
machineNotInProject: "Machine {{environmentId}} is not in this project. Call work_list_machines to see the machines that joined it, or leave out environmentId to use this machine.",
|
|
8586
|
+
machineNeedsModel: "A member on machine {{environmentId}} needs a provider from that machine. Give instanceId and model from what work_list_machines reports for it.",
|
|
8587
|
+
machineInstanceNotFound: "Machine {{environmentId}} did not report a provider instance {{instanceId}}. Call work_list_machines (with includeModels) and give an instanceId and model that machine reported. The list is what that machine reported when it last connected: if the provider was set up there since, ask a person to reconnect that machine (or restart its Ycodium) to refresh the list, then call work_list_machines again.",
|
|
8588
|
+
machineInstanceNotReady: "Provider instance {{instanceId}} on machine {{environmentId}} is not ready to take work. Call work_list_machines and pick a ready instance, or ask a person to fix that provider on that machine. The readiness is what that machine reported when it last connected: if it was fixed since, ask a person to reconnect that machine (or restart its Ycodium) to refresh the list, then call work_list_machines again.",
|
|
8589
|
+
machinesUnavailable: "Could not read this project's machines right now. Try again in a moment."
|
|
9094
8590
|
},
|
|
9095
8591
|
board: {
|
|
9096
8592
|
openTeam: "Open this team on the board",
|
|
@@ -9276,7 +8772,8 @@ var en_default = {
|
|
|
9276
8772
|
thisMachine: "This machine",
|
|
9277
8773
|
machineOffline: "{{name}} (offline)",
|
|
9278
8774
|
machineRemoved: "A machine that left this project",
|
|
9279
|
-
noMachine: "No machine chosen"
|
|
8775
|
+
noMachine: "No machine chosen",
|
|
8776
|
+
machineJoining: "Adding {{name}} to this project\u2026"
|
|
9280
8777
|
},
|
|
9281
8778
|
handbookPanel: {
|
|
9282
8779
|
title: "Handbook",
|
|
@@ -9601,7 +9098,7 @@ function createGoalService(ctx, rosterService, options = {}) {
|
|
|
9601
9098
|
rosterMemberName(roster, member.memberId)
|
|
9602
9099
|
])
|
|
9603
9100
|
);
|
|
9604
|
-
const others =
|
|
9101
|
+
const others = await engineNames(
|
|
9605
9102
|
projectId,
|
|
9606
9103
|
execution.members.flatMap(
|
|
9607
9104
|
({ memberId }) => teamNames.get(memberId) === null ? [memberId] : []
|
|
@@ -9900,6 +9397,7 @@ var ImportResult = Union2([
|
|
|
9900
9397
|
|
|
9901
9398
|
// src/coordinator/contracts.ts
|
|
9902
9399
|
var agentFields = {
|
|
9400
|
+
environmentId: optionalKey2(String4),
|
|
9903
9401
|
instanceId: optionalKey2(String4),
|
|
9904
9402
|
model: optionalKey2(String4)
|
|
9905
9403
|
};
|
|
@@ -9955,8 +9453,15 @@ var MemberChangeCompleted = Struct({
|
|
|
9955
9453
|
])
|
|
9956
9454
|
});
|
|
9957
9455
|
|
|
9456
|
+
// src/messages.ts
|
|
9457
|
+
var interpolateMessage = (template, values) => template.replace(
|
|
9458
|
+
/{{(\w+)}}/g,
|
|
9459
|
+
(whole, name) => Object.hasOwn(values, name) ? String(values[name]) : whole
|
|
9460
|
+
);
|
|
9461
|
+
|
|
9958
9462
|
// src/coordinator/messages.ts
|
|
9959
9463
|
var coordinatorMessage = (key) => en_default.coordinator[key];
|
|
9464
|
+
var machineMessage = (key, values) => interpolateMessage(en_default.coordinator[key], values);
|
|
9960
9465
|
|
|
9961
9466
|
// src/coordinator/entry.ts
|
|
9962
9467
|
var decodeCreate = decodeUnknownSync(CreateMemberToolInput);
|
|
@@ -10094,8 +9599,17 @@ var GUARD_MESSAGES = {
|
|
|
10094
9599
|
"cannot-replace-lead": "cannotReplaceLead",
|
|
10095
9600
|
"invalid-agent": "invalidAgent",
|
|
10096
9601
|
"model-unavailable": "modelUnavailable",
|
|
10097
|
-
"no-default-model": "noDefaultModel"
|
|
9602
|
+
"no-default-model": "noDefaultModel",
|
|
9603
|
+
"machine-not-in-project": "machineNotInProject",
|
|
9604
|
+
"machine-needs-model": "machineNeedsModel",
|
|
9605
|
+
"machine-instance-not-found": "machineInstanceNotFound",
|
|
9606
|
+
"machine-instance-not-ready": "machineInstanceNotReady"
|
|
10098
9607
|
};
|
|
9608
|
+
var refuseMachine = (code, values) => ({
|
|
9609
|
+
status: "rejected",
|
|
9610
|
+
code,
|
|
9611
|
+
detail: machineMessage(GUARD_MESSAGES[code], values)
|
|
9612
|
+
});
|
|
10099
9613
|
var refuse = (code, reason) => ({
|
|
10100
9614
|
status: "rejected",
|
|
10101
9615
|
code,
|
|
@@ -10213,22 +9727,39 @@ function startCoordinatorRuntime(ctx, deps) {
|
|
|
10213
9727
|
return refuse("cannot-remove-lead");
|
|
10214
9728
|
if ((change.op === "remove" || change.op === "update") && await usedByOtherTeam(lead, target.memberId))
|
|
10215
9729
|
return refuse("member-in-other-team");
|
|
10216
|
-
if (change.op === "update" && (change.input.instanceId !== void 0 || change.input.model !== void 0) && await isLead(lead, target.memberId))
|
|
9730
|
+
if (change.op === "update" && (change.input.instanceId !== void 0 || change.input.model !== void 0 || change.input.environmentId !== void 0 && change.input.environmentId !== (target.agent?.environmentId ?? null)) && await isLead(lead, target.memberId))
|
|
10217
9731
|
return refuse("cannot-replace-lead");
|
|
10218
9732
|
return null;
|
|
10219
9733
|
};
|
|
10220
9734
|
const agentFor = async (change, projectId, target) => {
|
|
10221
9735
|
const { instanceId, model } = change.input;
|
|
10222
|
-
if (instanceId === void 0
|
|
10223
|
-
|
|
9736
|
+
if (instanceId === void 0 !== (model === void 0)) return refuse("invalid-agent");
|
|
9737
|
+
const current = target?.agent ?? null;
|
|
9738
|
+
const environmentId = change.input.environmentId ?? current?.environmentId ?? ctx.environment.id;
|
|
9739
|
+
const named = instanceId !== void 0 && model !== void 0;
|
|
9740
|
+
if (!named && change.op === "update" && (change.input.environmentId === void 0 || environmentId === current?.environmentId))
|
|
9741
|
+
return {};
|
|
9742
|
+
const selection = named ? { instanceId, model } : current?.modelSelection ?? null;
|
|
9743
|
+
if (environmentId !== ctx.environment.id) {
|
|
9744
|
+
if (selection === null) return refuseMachine("machine-needs-model", { environmentId });
|
|
9745
|
+
const machines = await readMachines(ctx, projectId);
|
|
9746
|
+
if (machines === null) throw new Error(coordinatorMessage("machinesUnavailable"));
|
|
9747
|
+
const machine = machines.get(environmentId);
|
|
9748
|
+
if (machine === void 0) return refuseMachine("machine-not-in-project", { environmentId });
|
|
9749
|
+
if (machine.providers.length > 0) {
|
|
9750
|
+
const values = { environmentId, instanceId: selection.instanceId };
|
|
9751
|
+
if (!machine.providers.some((row) => row.instanceId === selection.instanceId))
|
|
9752
|
+
return refuseMachine("machine-instance-not-found", values);
|
|
9753
|
+
if (!readyProviders(machine).some((row) => row.instanceId === selection.instanceId))
|
|
9754
|
+
return refuseMachine("machine-instance-not-ready", values);
|
|
9755
|
+
}
|
|
9756
|
+
return { agent: { environmentId, modelSelection: selection } };
|
|
9757
|
+
}
|
|
9758
|
+
if (selection === null) {
|
|
10224
9759
|
const fallback = await defaultAgent(ctx, projectId);
|
|
10225
9760
|
return "code" in fallback ? refuse(fallback.code, "reason" in fallback ? fallback.reason : void 0) : { agent: fallback.agent };
|
|
10226
9761
|
}
|
|
10227
|
-
|
|
10228
|
-
const environmentId = target?.agent?.environmentId ?? ctx.environment.id;
|
|
10229
|
-
if (environmentId !== ctx.environment.id)
|
|
10230
|
-
return { agent: { environmentId, modelSelection: { instanceId, model } } };
|
|
10231
|
-
const resolved = await resolveModel(ctx, { instanceId, model }, true);
|
|
9762
|
+
const resolved = await resolveModel(ctx, selection, named);
|
|
10232
9763
|
return "code" in resolved ? refuse(resolved.code, "reason" in resolved ? resolved.reason : void 0) : { agent: { environmentId, modelSelection: resolved.selection.modelSelection } };
|
|
10233
9764
|
};
|
|
10234
9765
|
const plan = async (change, requestId, projectId, target) => {
|
|
@@ -10395,7 +9926,7 @@ function membersSnapshot(view, trialOf = () => null, viewer = null) {
|
|
|
10395
9926
|
name: machine.name,
|
|
10396
9927
|
online: machine.online,
|
|
10397
9928
|
...machine.lastSeenAt === void 0 ? {} : { lastSeenAt: machine.lastSeenAt },
|
|
10398
|
-
providers: machine.
|
|
9929
|
+
providers: readyProviders(machine).map((provider) => ({
|
|
10399
9930
|
instanceId: provider.instanceId,
|
|
10400
9931
|
displayName: provider.displayName,
|
|
10401
9932
|
models: provider.models.map(({ slug, name }) => ({ slug, name })),
|
|
@@ -10952,7 +10483,7 @@ function createMemberWriter(ctx, rosters, queue = createSerial()) {
|
|
|
10952
10483
|
const machines = missing2.some(({ member }) => member.principal !== void 0) ? [...(await readMachines(ctx, projectId))?.values() ?? []] : [];
|
|
10953
10484
|
const remoteAgentOf = (principalId) => {
|
|
10954
10485
|
const machine = machines.find((entry) => entry.principalId === principalId);
|
|
10955
|
-
const provider = machine
|
|
10486
|
+
const provider = machine === void 0 ? void 0 : readyProviders(machine)[0];
|
|
10956
10487
|
const model = provider?.defaultModel ?? provider?.models[0]?.slug;
|
|
10957
10488
|
return machine === void 0 || provider === void 0 || model === void 0 ? void 0 : {
|
|
10958
10489
|
environmentId: machine.environmentId,
|
|
@@ -10988,90 +10519,6 @@ function createMemberWriter(ctx, rosters, queue = createSerial()) {
|
|
|
10988
10519
|
return { create, update, remove, restore, importLegacy };
|
|
10989
10520
|
}
|
|
10990
10521
|
|
|
10991
|
-
// src/runtime/commentWakes.ts
|
|
10992
|
-
var COMMENT_MENTIONS_FACT = "comment-mentions";
|
|
10993
|
-
var COMMENT_MENTIONS_EVENT = `team/${COMMENT_MENTIONS_FACT}`;
|
|
10994
|
-
var CommentMentionsFact = Struct({
|
|
10995
|
-
version: Literal2(1),
|
|
10996
|
-
projectId: String4,
|
|
10997
|
-
workItemId: String4,
|
|
10998
|
-
commentId: String4,
|
|
10999
|
-
recipients: ArraySchema(
|
|
11000
|
-
Union2([
|
|
11001
|
-
Struct({ threadId: String4 }),
|
|
11002
|
-
Struct({ principalId: String4 })
|
|
11003
|
-
])
|
|
11004
|
-
)
|
|
11005
|
-
});
|
|
11006
|
-
var commentPeople = (comment) => [
|
|
11007
|
-
...comment.parentAuthor === void 0 ? [] : [comment.parentAuthor],
|
|
11008
|
-
...comment.mentions
|
|
11009
|
-
];
|
|
11010
|
-
var recipientsOf = (people) => {
|
|
11011
|
-
const recipients = /* @__PURE__ */ new Map();
|
|
11012
|
-
for (const person of people) {
|
|
11013
|
-
const recipient = recipientOf(person);
|
|
11014
|
-
if (recipient !== void 0) recipients.set(recipientKey(recipient), recipient);
|
|
11015
|
-
}
|
|
11016
|
-
return recipients;
|
|
11017
|
-
};
|
|
11018
|
-
var reachedKeys = (actor, people) => new Set(recipientsOf([actor, ...people]).keys());
|
|
11019
|
-
var commentRecipients = (project2, actor, people) => {
|
|
11020
|
-
const author = recipientOf(actor);
|
|
11021
|
-
const authorKey = author === void 0 ? void 0 : recipientKey(author);
|
|
11022
|
-
return [...recipientsOf(people)].filter(([key]) => key !== authorKey).map(([, recipient]) => recipient).filter((recipient) => isMember(project2, recipient));
|
|
11023
|
-
};
|
|
11024
|
-
var commentWakeKey = (commentId, recipient) => "threadId" in recipient ? `comment:${commentId}:${recipient.threadId}` : `comment:${commentId}:principal:${recipient.principalId}`;
|
|
11025
|
-
var queueCommentWakes = (project2, comment, recipients) => [
|
|
11026
|
-
...project2.pendingComments,
|
|
11027
|
-
...recipients.map((recipient) => ({
|
|
11028
|
-
...recipient,
|
|
11029
|
-
key: commentWakeKey(comment.commentId, recipient),
|
|
11030
|
-
projectId: comment.projectId,
|
|
11031
|
-
workItemId: comment.workItemId,
|
|
11032
|
-
commentId: comment.commentId
|
|
11033
|
-
})).filter((queued) => !project2.pendingComments.some((pending) => pending.key === queued.key))
|
|
11034
|
-
];
|
|
11035
|
-
|
|
11036
|
-
// src/domain/mentionText.ts
|
|
11037
|
-
var isAtSign = (character) => character === "@" || character === "\uFF20";
|
|
11038
|
-
var MENTION_BOUNDARY = /[\s\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\u3000-\u303f\uff01-\uff0f\uff1a-\uff20\uff3b-\uff40\uff5b-\uff65]/u;
|
|
11039
|
-
var isMentionStart = (text, index) => {
|
|
11040
|
-
if (!isAtSign(text[index])) return false;
|
|
11041
|
-
const before = Array.from(text.slice(Math.max(0, index - 2), index)).at(-1);
|
|
11042
|
-
return before === void 0 || MENTION_BOUNDARY.test(before);
|
|
11043
|
-
};
|
|
11044
|
-
|
|
11045
|
-
// src/runtime/mentionedMembers.ts
|
|
11046
|
-
var mentionPrincipal = (member) => member.threadId !== void 0 ? member.principalId === void 0 ? { kind: "agent", threadId: member.threadId } : null : member.principalId !== void 0 ? { kind: "remote-agent", principalId: member.principalId } : null;
|
|
11047
|
-
var ASCII_WORD = /[A-Za-z0-9_-]/;
|
|
11048
|
-
function mentionedMembers(body, members) {
|
|
11049
|
-
const aliases = members.flatMap((member) => {
|
|
11050
|
-
const principal = mentionPrincipal(member);
|
|
11051
|
-
const recipient = principal === null ? void 0 : recipientOf(principal);
|
|
11052
|
-
if (recipient === void 0) return [];
|
|
11053
|
-
const id = "threadId" in recipient ? recipient.threadId : recipient.principalId;
|
|
11054
|
-
return [id, member.memberId, member.name].flatMap(
|
|
11055
|
-
(text) => text === void 0 || text === null || text === "" ? [] : [{ text: text.toLowerCase(), key: recipientKey(recipient), recipient }]
|
|
11056
|
-
);
|
|
11057
|
-
}).sort((a, b) => b.text.length - a.text.length);
|
|
11058
|
-
const found = /* @__PURE__ */ new Map();
|
|
11059
|
-
for (let at = 0; at < body.length; at++) {
|
|
11060
|
-
if (!isMentionStart(body, at)) continue;
|
|
11061
|
-
const rest = body.slice(at + 1);
|
|
11062
|
-
const hits = aliases.filter((alias) => {
|
|
11063
|
-
if (rest.slice(0, alias.text.length).toLowerCase() !== alias.text) return false;
|
|
11064
|
-
const next = rest[alias.text.length];
|
|
11065
|
-
return next === void 0 || !(ASCII_WORD.test(alias.text.slice(-1)) && ASCII_WORD.test(next));
|
|
11066
|
-
});
|
|
11067
|
-
const longest = hits.filter((hit) => hit.text.length === hits[0]?.text.length);
|
|
11068
|
-
const keys = new Set(longest.map((hit) => hit.key));
|
|
11069
|
-
const [only] = longest;
|
|
11070
|
-
if (only !== void 0 && keys.size === 1) found.set(only.key, only.recipient);
|
|
11071
|
-
}
|
|
11072
|
-
return [...found.values()];
|
|
11073
|
-
}
|
|
11074
|
-
|
|
11075
10522
|
// src/domain/pause.ts
|
|
11076
10523
|
var LinePausedEnvelope = factEnvelope(
|
|
11077
10524
|
"line-paused",
|
|
@@ -11119,11 +10566,6 @@ var decodeEnvelope2 = decodeUnknownOption2(
|
|
|
11119
10566
|
name: Literal2("team/member-woken"),
|
|
11120
10567
|
data: MemberWokenFact
|
|
11121
10568
|
}),
|
|
11122
|
-
Struct({
|
|
11123
|
-
pluginId: Literal2("team"),
|
|
11124
|
-
name: Literal2(COMMENT_MENTIONS_EVENT),
|
|
11125
|
-
data: CommentMentionsFact
|
|
11126
|
-
}),
|
|
11127
10569
|
MemberBoundEnvelope,
|
|
11128
10570
|
LinePausedEnvelope,
|
|
11129
10571
|
LineMemberPausedEnvelope,
|
|
@@ -11226,87 +10668,6 @@ var assigneeMembers = (principals) => [
|
|
|
11226
10668
|
...new Set(principals.flatMap((p) => p.kind === "member" ? [p.memberId] : []))
|
|
11227
10669
|
];
|
|
11228
10670
|
|
|
11229
|
-
// src/runtime/commentMentions.ts
|
|
11230
|
-
var COMMENT_MENTION_RETRIES = 2;
|
|
11231
|
-
function startCommentMentionRuntime(ctx, goals) {
|
|
11232
|
-
const handle = async (event) => {
|
|
11233
|
-
const decoded = decodeWorkEvent(event);
|
|
11234
|
-
if (isNone2(decoded) || decoded.value.type !== "work.comment-posted") return;
|
|
11235
|
-
const comment = decoded.value.payload;
|
|
11236
|
-
const { projectId, workItemId, commentId } = comment;
|
|
11237
|
-
const resolve2 = async () => {
|
|
11238
|
-
const { items } = await ctx.work.items.get({ projectId, workItemIds: [workItemId] });
|
|
11239
|
-
const forLine = items.find((row) => row.workItemId === workItemId)?.workLineId ?? null;
|
|
11240
|
-
const goal = await goals.read(projectId, { teamOnly: true, forLine });
|
|
11241
|
-
if (goal === null) return;
|
|
11242
|
-
const { comment: posted } = await ctx.work.comments.get({ projectId, commentId });
|
|
11243
|
-
if (posted.body === null) return;
|
|
11244
|
-
const reached = reachedKeys(comment.actor, commentPeople(comment));
|
|
11245
|
-
const { workLineId } = goal;
|
|
11246
|
-
const onTeam = workLineId === void 0 ? goal.members : (await Promise.all(
|
|
11247
|
-
goal.members.map(
|
|
11248
|
-
async (member) => await memberOnLine(ctx, projectId, workLineId, member.memberId) ? [member] : []
|
|
11249
|
-
)
|
|
11250
|
-
)).flat();
|
|
11251
|
-
const recipients = mentionedMembers(posted.body, onTeam).filter(
|
|
11252
|
-
(recipient) => !reached.has(recipientKey(recipient))
|
|
11253
|
-
);
|
|
11254
|
-
if (recipients.length === 0) return;
|
|
11255
|
-
await ctx.events.append({
|
|
11256
|
-
commandId: `team-comment-mentions:${commentId}`,
|
|
11257
|
-
name: COMMENT_MENTIONS_FACT,
|
|
11258
|
-
aggregate: { kind: "project", id: projectId },
|
|
11259
|
-
data: { version: 1, projectId, workItemId, commentId, recipients }
|
|
11260
|
-
});
|
|
11261
|
-
};
|
|
11262
|
-
for (let attempt = 1; ; attempt++) {
|
|
11263
|
-
try {
|
|
11264
|
-
return await resolve2();
|
|
11265
|
-
} catch (error) {
|
|
11266
|
-
if (attempt > COMMENT_MENTION_RETRIES) {
|
|
11267
|
-
ctx.log.warn("team comment mentions failed", {
|
|
11268
|
-
projectId,
|
|
11269
|
-
workItemId,
|
|
11270
|
-
commentId,
|
|
11271
|
-
eventId: event.eventId,
|
|
11272
|
-
attempts: attempt,
|
|
11273
|
-
error
|
|
11274
|
-
});
|
|
11275
|
-
return;
|
|
11276
|
-
}
|
|
11277
|
-
}
|
|
11278
|
-
}
|
|
11279
|
-
};
|
|
11280
|
-
ctx.reactor({ name: "team-comment-mentions", events: ["work.comment-posted"], handle });
|
|
11281
|
-
}
|
|
11282
|
-
|
|
11283
|
-
// src/runtime/dispatchClaim.ts
|
|
11284
|
-
var allow = { allowed: true };
|
|
11285
|
-
var claim = (detail) => ({ allowed: false, detail });
|
|
11286
|
-
function registerDispatchClaim(ctx, wakes) {
|
|
11287
|
-
const check = async (input) => {
|
|
11288
|
-
const project2 = readFact(
|
|
11289
|
-
await wakes.get({ throughSequence: input.throughSequence }),
|
|
11290
|
-
input.projectId
|
|
11291
|
-
);
|
|
11292
|
-
if (project2 === null) return allow;
|
|
11293
|
-
if (input.workLineId !== null && project2.lineScopes?.[input.workLineId] !== void 0)
|
|
11294
|
-
return claim("the team on this work line dispatches its members");
|
|
11295
|
-
if (project2.goalId === void 0) return allow;
|
|
11296
|
-
if (readFact(project2.bindings ?? {}, input.memberId) !== null)
|
|
11297
|
-
return claim("the project's team goal dispatches this member");
|
|
11298
|
-
if (isClosed(readFact(project2.items, teamGoalItemId(input.projectId, project2.goalId))))
|
|
11299
|
-
return allow;
|
|
11300
|
-
const lines = await ctx.work.lines.list({
|
|
11301
|
-
projectId: input.projectId,
|
|
11302
|
-
includeArchived: true,
|
|
11303
|
-
limit: 1
|
|
11304
|
-
});
|
|
11305
|
-
return lines.items.length === 0 ? claim("the project's team goal takes this member in and dispatches it") : allow;
|
|
11306
|
-
};
|
|
11307
|
-
return ctx.operations.guard({ operations: ["work.dispatch"], check });
|
|
11308
|
-
}
|
|
11309
|
-
|
|
11310
10671
|
// src/runtime/deliveryPacing.ts
|
|
11311
10672
|
function foldProgress(state, event) {
|
|
11312
10673
|
const decoded = decodeWorkEvent(event);
|
|
@@ -11375,148 +10736,478 @@ function createDeliveryPacing(progress, waitingOnSomeone2) {
|
|
|
11375
10736
|
return { observe, allows };
|
|
11376
10737
|
}
|
|
11377
10738
|
|
|
11378
|
-
// src/runtime/
|
|
11379
|
-
var
|
|
11380
|
-
|
|
11381
|
-
|
|
11382
|
-
|
|
11383
|
-
|
|
11384
|
-
|
|
11385
|
-
|
|
11386
|
-
|
|
11387
|
-
var
|
|
11388
|
-
|
|
11389
|
-
)
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
10739
|
+
// src/runtime/goalScopes.ts
|
|
10740
|
+
var isLinePaused = (project2, workLineId) => project2.linePauses?.[workLineId] === true;
|
|
10741
|
+
var isMemberPausedOnLine = (project2, workLineId, memberId) => (project2.pausedMembers?.[workLineId] ?? []).includes(memberId);
|
|
10742
|
+
var isLineStopped = (project2, workLineId) => workLineId !== void 0 && project2.lineStops?.[workLineId] !== void 0;
|
|
10743
|
+
var isLineGated = (project2, workLineId) => isLineStopped(project2, workLineId) || workLineId !== void 0 && isLinePaused(project2, workLineId);
|
|
10744
|
+
var scopesOf = (project2) => [
|
|
10745
|
+
project2,
|
|
10746
|
+
...Object.entries(project2.lineScopes ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([, scope2]) => scope2)
|
|
10747
|
+
];
|
|
10748
|
+
var scopeForLine = (project2, workLineId) => (workLineId === void 0 ? void 0 : project2.lineScopes?.[workLineId]) ?? project2;
|
|
10749
|
+
var scopeOfThread = (project2, threadId) => scopesOf(project2).find((scope2) => scope2.threads.includes(threadId));
|
|
10750
|
+
var teamSessions = (scope2) => [
|
|
10751
|
+
.../* @__PURE__ */ new Set([...scope2.threads, ...Object.keys(scope2.memberIds ?? {})])
|
|
10752
|
+
];
|
|
10753
|
+
var lineScopeOfThread = (project2, threadId) => {
|
|
10754
|
+
for (const [workLineId, scope2] of Object.entries(project2.lineScopes ?? {}))
|
|
10755
|
+
if (teamSessions(scope2).includes(threadId)) return { workLineId, scope: scope2 };
|
|
10756
|
+
return void 0;
|
|
10757
|
+
};
|
|
10758
|
+
var scopeOfPrincipal = (project2, principalId) => scopesOf(project2).find((scope2) => scope2.remoteMembers.includes(principalId));
|
|
10759
|
+
var isGoalThread = (project2, threadId) => scopeOfThread(project2, threadId) !== void 0;
|
|
10760
|
+
var isLeadThread = (project2, threadId) => scopesOf(project2).some((scope2) => scope2.leadThreads?.includes(threadId) === true);
|
|
10761
|
+
var isRemoteMember2 = (project2, principalId) => scopeOfPrincipal(project2, principalId) !== void 0;
|
|
10762
|
+
var leadOfThread = (project2, threadId) => scopeOfThread(project2, threadId)?.leadThreads?.[0];
|
|
10763
|
+
var placeOfRecipient = (project2, who, workLineId) => {
|
|
10764
|
+
if ("threadId" in who) {
|
|
10765
|
+
const line = lineScopeOfThread(project2, who.threadId);
|
|
10766
|
+
if (line !== void 0) return line;
|
|
10767
|
+
return project2.threads.includes(who.threadId) ? { scope: project2 } : void 0;
|
|
10768
|
+
}
|
|
10769
|
+
const own = workLineId === void 0 ? void 0 : project2.lineScopes?.[workLineId];
|
|
10770
|
+
if (workLineId !== void 0 && own?.remoteMembers.includes(who.principalId) === true)
|
|
10771
|
+
return { workLineId, scope: own };
|
|
10772
|
+
if (project2.remoteMembers.includes(who.principalId)) return { scope: project2 };
|
|
10773
|
+
const found = Object.entries(project2.lineScopes ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).find(([, scope2]) => scope2.remoteMembers.includes(who.principalId));
|
|
10774
|
+
return found === void 0 ? void 0 : { workLineId: found[0], scope: found[1] };
|
|
10775
|
+
};
|
|
10776
|
+
var scopeOfRecipient = (project2, who, workLineId) => placeOfRecipient(project2, who, workLineId)?.scope;
|
|
10777
|
+
var memberOfRecipientIn = (scope2, who) => {
|
|
10778
|
+
if ("threadId" in who) return scope2.memberIds?.[who.threadId];
|
|
10779
|
+
for (const [memberId, recipient] of Object.entries(scope2.bindings ?? {}))
|
|
10780
|
+
if ("principalId" in recipient && recipient.principalId === who.principalId) return memberId;
|
|
10781
|
+
return void 0;
|
|
10782
|
+
};
|
|
10783
|
+
var isRecipientGated = (project2, who, workLineId) => {
|
|
10784
|
+
const place = placeOfRecipient(project2, who, workLineId);
|
|
10785
|
+
if (place === void 0 || place.workLineId === void 0) return false;
|
|
10786
|
+
if (isLineGated(project2, place.workLineId)) return true;
|
|
10787
|
+
const member = memberOfRecipientIn(place.scope, who);
|
|
10788
|
+
return member !== void 0 && isMemberPausedOnLine(project2, place.workLineId, member);
|
|
10789
|
+
};
|
|
10790
|
+
var isThreadGated = (project2, threadId) => isRecipientGated(project2, { threadId });
|
|
10791
|
+
var teamLeadCandidates = (project2, memberId) => Object.entries(project2.lineScopes ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).flatMap(([workLineId, scope2]) => {
|
|
10792
|
+
const leadThreadId = scope2.leadThreads?.[0];
|
|
10793
|
+
return scope2.bindings?.[memberId] !== void 0 && leadThreadId !== void 0 && !isLineStopped(project2, workLineId) ? [{ workLineId, leadThreadId }] : [];
|
|
10794
|
+
});
|
|
10795
|
+
|
|
10796
|
+
// src/runtime/memberWaiting.ts
|
|
10797
|
+
var readMemberExecution = async (ctx, threadId, known) => {
|
|
10798
|
+
const shell = await ctx.threads.get({ threadId });
|
|
10799
|
+
const summary = known ?? await ctx.threads.execution.summary({ threadId, limit: 1 });
|
|
10800
|
+
return { ...shell, queuePaused: summary.queuePaused, summary };
|
|
10801
|
+
};
|
|
10802
|
+
var waitingOnSomeone = (execution) => execution.summary.queuePaused || execution.summary.pendingApprovalCount > 0 || execution.summary.pendingUserInputCount > 0 || (execution.pendingAsyncQuestionCount ?? 0) > 0 || (execution.awaitingPersonReplyCount ?? 0) > 0;
|
|
10803
|
+
|
|
10804
|
+
// src/runtime/wakeQueries.ts
|
|
10805
|
+
function memberWorktreeFor(goals, project2, projectId, recipient) {
|
|
10806
|
+
if (!("threadId" in recipient) || project2 === void 0) return;
|
|
10807
|
+
const { threadId } = recipient;
|
|
10808
|
+
const scope2 = scopeOfThread(project2, threadId);
|
|
10809
|
+
if (scope2 === void 0 || scope2.leadThreads?.includes(threadId)) return;
|
|
10810
|
+
const leadThreadId = scope2.leadThreads?.[0];
|
|
10811
|
+
if (leadThreadId === void 0) return;
|
|
10812
|
+
return {
|
|
10813
|
+
leadThreadId,
|
|
10814
|
+
failure: project2.worktreeFailures?.[threadId],
|
|
10815
|
+
// 只在要建树或报失败时读目标取名字,叫醒的热路径不多读。
|
|
10816
|
+
name: async () => (await goals.read(projectId, { forThread: threadId }))?.members.find(
|
|
10817
|
+
(member) => member.threadId === threadId
|
|
10818
|
+
)?.name ?? scope2.memberIds?.[threadId] ?? threadId
|
|
10819
|
+
};
|
|
10820
|
+
}
|
|
10821
|
+
var compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
10822
|
+
var compareWakeItems = (a, b) => a.sequenceId - b.sequenceId || compare(a.workItemId, b.workItemId);
|
|
10823
|
+
var OPEN_ITEM_GROUPS = ["backlog", "unstarted", "started"];
|
|
10824
|
+
var isClosed = (item) => item?.stateGroup === "completed" || item?.stateGroup === "cancelled";
|
|
10825
|
+
var hasOpenBlocker = (project2, workItemId) => (readFact(project2.blockers, workItemId) ?? []).some(
|
|
10826
|
+
(blocker) => !isClosed(readFact(project2.items, blocker))
|
|
10827
|
+
);
|
|
10828
|
+
var isAssignedOpen = (project2, workItemId, threadId) => {
|
|
10829
|
+
const item = readFact(project2.items, workItemId);
|
|
10830
|
+
return item !== null && item !== void 0 && !isClosed(item) && item.assigneeThreads.includes(threadId);
|
|
10831
|
+
};
|
|
10832
|
+
var isWorkable = (project2, workItemId) => !isClosed(readFact(project2.items, workItemId)) && !hasOpenBlocker(project2, workItemId);
|
|
10833
|
+
var isOpenWorkFor = (project2, workItemId, threadId) => isAssignedOpen(project2, workItemId, threadId) && !hasOpenBlocker(project2, workItemId);
|
|
10834
|
+
var isHandedOver = (item, threadId) => {
|
|
10835
|
+
if (item.stateGroup === "started") return true;
|
|
10836
|
+
const status = threadId === void 0 ? void 0 : item.wakeStatus?.[threadId];
|
|
10837
|
+
return status === "active" || status === "released";
|
|
10838
|
+
};
|
|
10839
|
+
var memberOfThread = (item, threadId) => {
|
|
10840
|
+
for (const [memberId, thread] of Object.entries(item.memberThreads ?? {}))
|
|
10841
|
+
if (thread === threadId) return memberId;
|
|
10842
|
+
return void 0;
|
|
10843
|
+
};
|
|
10844
|
+
var isPinnedTo = (item, threadId) => !isClosed(item) && memberOfThread(item, threadId) !== void 0 && isHandedOver(item, threadId);
|
|
10845
|
+
var hasPinnedOpenItem = (project2, threadId) => Object.values(project2.items).some((item) => isPinnedTo(item, threadId));
|
|
10846
|
+
var pinnedThreadsOf = (item) => Object.values(item.memberThreads ?? {}).filter((threadId) => isPinnedTo(item, threadId));
|
|
10847
|
+
var pinnedOpenThreads = (project2) => {
|
|
10848
|
+
const threads = /* @__PURE__ */ new Set();
|
|
10849
|
+
for (const item of Object.values(project2.items))
|
|
10850
|
+
for (const threadId of pinnedThreadsOf(item)) threads.add(threadId);
|
|
10851
|
+
return threads;
|
|
10852
|
+
};
|
|
10853
|
+
var memberLookup = (project2) => {
|
|
10854
|
+
let pinned;
|
|
10855
|
+
return (threadId) => isGoalThread(project2, threadId) || (pinned ??= pinnedOpenThreads(project2)).has(threadId);
|
|
10856
|
+
};
|
|
10857
|
+
var isMember = (project2, recipient) => "threadId" in recipient ? isGoalThread(project2, recipient.threadId) || hasPinnedOpenItem(project2, recipient.threadId) : isRemoteMember2(project2, recipient.principalId);
|
|
10858
|
+
var isQueuedUnclaimed = (item, threadId) => item.wakeStatus?.[threadId] === "pending" && !item.claimedBy.includes(threadId);
|
|
10859
|
+
var isDeferredWake = (project2, item, threadId) => isGoalThread(project2, threadId) && !isLeadThread(project2, threadId) && item.assigneeThreads.includes(threadId) && isQueuedUnclaimed(item, threadId) && !isClosed(item);
|
|
10860
|
+
function countDeferredWakes(project2, threadId) {
|
|
10861
|
+
let count2 = 0;
|
|
10862
|
+
for (const workItemId in project2.items) {
|
|
10863
|
+
const item = readFact(project2.items, workItemId);
|
|
10864
|
+
if (item !== null && isDeferredWake(project2, item, threadId)) count2++;
|
|
10865
|
+
}
|
|
10866
|
+
return count2;
|
|
10867
|
+
}
|
|
10868
|
+
var exemptFromTrial = (project2, recipient, workItemId) => {
|
|
10869
|
+
if (project2 === void 0 || !("threadId" in recipient)) return false;
|
|
10870
|
+
if (isLeadThread(project2, recipient.threadId)) return true;
|
|
10871
|
+
if (workItemId === void 0) return false;
|
|
10872
|
+
const item = readFact(project2.items, workItemId);
|
|
10873
|
+
return item !== null && item !== void 0 && pinnedThreadsOf(item).includes(recipient.threadId);
|
|
10874
|
+
};
|
|
10875
|
+
function memberOfRecipient(project2, recipient) {
|
|
10876
|
+
if (project2 === void 0) return void 0;
|
|
10877
|
+
const key = recipientKey(recipient);
|
|
10878
|
+
for (const scope2 of scopesOf(project2))
|
|
10879
|
+
for (const [memberId, bound] of Object.entries(scope2.bindings ?? {}))
|
|
10880
|
+
if (recipientKey(bound) === key) return memberId;
|
|
10881
|
+
return void 0;
|
|
10882
|
+
}
|
|
10883
|
+
function executorOf(project2, workItemId, memberId) {
|
|
10884
|
+
if (project2 === void 0) return void 0;
|
|
10885
|
+
const item = readFact(project2.items, workItemId);
|
|
10886
|
+
const target = targetOf(
|
|
10887
|
+
scopeForLine(project2, item?.workLineId).bindings,
|
|
10888
|
+
{ kind: "member", memberId },
|
|
10889
|
+
item?.memberThreads
|
|
10890
|
+
);
|
|
10891
|
+
if (target === void 0) return void 0;
|
|
10892
|
+
if ("threadId" in target && isLeadThread(project2, target.threadId)) return void 0;
|
|
10893
|
+
return isMember(project2, target) ? target : void 0;
|
|
10894
|
+
}
|
|
10895
|
+
|
|
10896
|
+
// src/runtime/reviewWakes.ts
|
|
10897
|
+
var decodeCompletion = decodeUnknownOption2(
|
|
10898
|
+
Struct({
|
|
10899
|
+
projectId: String4,
|
|
10900
|
+
workItemId: String4,
|
|
10901
|
+
state: Struct({ group: String4 }),
|
|
10902
|
+
actor: Union2([
|
|
10903
|
+
Struct({ kind: Literal2("agent"), threadId: String4 }),
|
|
10904
|
+
Struct({ kind: Literal2("remote-agent"), principalId: String4 })
|
|
10905
|
+
])
|
|
10906
|
+
})
|
|
10907
|
+
);
|
|
10908
|
+
var openLeadItemsBlockedBy = (project2, workItemId, lead) => lead === void 0 ? [] : Object.entries(project2.items).filter(
|
|
10909
|
+
([id]) => isAssignedOpen(project2, id, lead) && readFact(project2.blockers, id)?.includes(workItemId) === true
|
|
10910
|
+
);
|
|
10911
|
+
function reviewOnUpdate(previous, next, event) {
|
|
10912
|
+
const decoded = decodeCompletion(event.payload);
|
|
10913
|
+
if (isNone2(decoded) || decoded.value.state.group !== "completed") return null;
|
|
10914
|
+
const { projectId, workItemId, actor } = decoded.value;
|
|
10915
|
+
if (readFact(previous.items, workItemId)?.stateGroup === "completed") return null;
|
|
10916
|
+
const by = actor.kind === "agent" ? { threadId: actor.threadId } : { principalId: actor.principalId };
|
|
10917
|
+
const lead = scopeOfRecipient(next, by, readFact(next.items, workItemId)?.workLineId)?.leadThreads?.[0] ?? next.leadThreads?.[0];
|
|
10918
|
+
if (lead === void 0) return null;
|
|
10919
|
+
if (!isMember(next, by) || "threadId" in by && isLeadThread(next, by.threadId)) return null;
|
|
10920
|
+
const goals = openLeadItemsBlockedBy(next, workItemId, lead);
|
|
10921
|
+
if (goals.length === 0 || goals.some(([id]) => isWorkable(next, id))) return null;
|
|
10922
|
+
return {
|
|
10923
|
+
key: `review:${workItemId}:${lead}#${event.sequence}`,
|
|
10924
|
+
projectId,
|
|
10925
|
+
workItemId,
|
|
10926
|
+
threadId: lead,
|
|
10927
|
+
by
|
|
10928
|
+
};
|
|
10929
|
+
}
|
|
10930
|
+
var isLiveReview = (project2, review) => isLeadThread(project2, review.threadId) && readFact(project2.items, review.workItemId)?.stateGroup === "completed" && openLeadItemsBlockedBy(project2, review.workItemId, review.threadId).length > 0;
|
|
10931
|
+
var isReviewDue = (project2, key) => project2.pendingReviews?.some((review) => review.key === key && isLiveReview(project2, review)) === true;
|
|
10932
|
+
var dueReviews = (project2) => (project2.pendingReviews ?? []).filter((review) => isLiveReview(project2, review)).map((review) => {
|
|
10933
|
+
const item = readFact(project2.items, review.workItemId);
|
|
10934
|
+
return {
|
|
10935
|
+
...review,
|
|
10936
|
+
kind: "review",
|
|
10937
|
+
lead: true,
|
|
10938
|
+
...item === null ? {} : { sequenceId: item.sequenceId }
|
|
10939
|
+
};
|
|
10940
|
+
});
|
|
10941
|
+
function pruneReviews(previous, state) {
|
|
10942
|
+
let next = state;
|
|
10943
|
+
for (const [projectId, project2] of Object.entries(state)) {
|
|
10944
|
+
const pending = project2.pendingReviews;
|
|
10945
|
+
if (pending === void 0 || pending.length === 0) continue;
|
|
10946
|
+
const before = previous[projectId];
|
|
10947
|
+
if (before !== void 0 && before.leadThreads === project2.leadThreads && before.lineScopes === project2.lineScopes && before.items === project2.items && before.blockers === project2.blockers)
|
|
10948
|
+
continue;
|
|
10949
|
+
const live = pending.filter((review) => isLiveReview(project2, review));
|
|
10950
|
+
if (live.length !== pending.length)
|
|
10951
|
+
next = { ...next, [projectId]: { ...project2, pendingReviews: live } };
|
|
10952
|
+
}
|
|
10953
|
+
return next;
|
|
10954
|
+
}
|
|
10955
|
+
function reviewFacts(project2, queues, lead) {
|
|
10956
|
+
const { busy, waiting } = queues;
|
|
10957
|
+
const team = scopeOfThread(project2, lead)?.threads ?? project2.threads;
|
|
10958
|
+
return {
|
|
10959
|
+
idle: team.filter(
|
|
10960
|
+
(threadId) => !isLeadThread(project2, threadId) && !busy.has(threadId) && (waiting.get(threadId) ?? []).length === 0
|
|
10961
|
+
),
|
|
10962
|
+
queued: [...busy].filter((threadId) => team.includes(threadId)).flatMap(
|
|
10963
|
+
(threadId) => [...waiting.get(threadId) ?? []].sort(compareWakeItems).map(({ workItemId, sequenceId }) => ({ workItemId, sequenceId, threadId }))
|
|
10964
|
+
)
|
|
10965
|
+
};
|
|
10966
|
+
}
|
|
10967
|
+
|
|
10968
|
+
// src/runtime/wakeDue.ts
|
|
10969
|
+
var itemWakeKey = (workItemId, threadId, generation) => generation === 0 ? `item:${workItemId}:${threadId}` : `item:${workItemId}:${threadId}#${generation}`;
|
|
10970
|
+
var unblockedWakeKey = (workItemId, threadId, generation) => `unblocked:${workItemId}:${threadId}#${generation}`;
|
|
10971
|
+
var compare2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
10972
|
+
var itemWakeCandidate = (projectId, project2, workItemId, item, threadId, woken, isMemberThread) => {
|
|
10973
|
+
if (!isWorkable(project2, workItemId) || !isMemberThread(threadId)) return null;
|
|
10974
|
+
if (isThreadGated(project2, threadId)) return null;
|
|
10975
|
+
const unblocked = readFact(project2.blockedAfterClaim, workItemId) ?? 0;
|
|
10976
|
+
const finishing = unblocked > 0 && item.claimedBy.includes(threadId);
|
|
10977
|
+
if (!finishing && !item.assigneeThreads.includes(threadId)) return null;
|
|
10978
|
+
const lead = isLeadThread(project2, threadId);
|
|
10979
|
+
const leadThreadId = leadOfThread(project2, threadId);
|
|
10980
|
+
const key = finishing ? unblockedWakeKey(workItemId, threadId, unblocked) : itemWakeKey(workItemId, threadId, readFact(project2.rearms, `${workItemId}:${threadId}`) ?? 0);
|
|
10981
|
+
if (woken.has(key) || !finishing && !lead && item.wakeStatus?.[threadId] === "released")
|
|
10982
|
+
return null;
|
|
10983
|
+
const memberId = finishing ? void 0 : memberOfThread(item, threadId);
|
|
10984
|
+
return {
|
|
10985
|
+
key,
|
|
10986
|
+
projectId,
|
|
10987
|
+
threadId,
|
|
10988
|
+
kind: finishing ? "unblocked" : "item",
|
|
10989
|
+
workItemId,
|
|
10990
|
+
sequenceId: item.sequenceId,
|
|
10991
|
+
...memberId === void 0 ? {} : { memberId },
|
|
10992
|
+
// 成员的叫醒话里点名负责人(卡住时找谁);带队自己和解挡续做不带。
|
|
10993
|
+
...lead ? { lead: true } : finishing || leadThreadId === void 0 ? {} : { leadThreadId }
|
|
10994
|
+
};
|
|
10995
|
+
};
|
|
10996
|
+
var engineDispatches = (project2, wake) => wake.kind === "item" && wake.memberId !== void 0 && "threadId" in wake && wake.key === itemWakeKey(wake.workItemId, wake.threadId, 0) && lineScopeOfThread(project2, wake.threadId) !== void 0;
|
|
10997
|
+
var wakeGated = (project2, wake) => isRecipientGated(project2, wake, readFact(project2.items, wake.workItemId)?.workLineId);
|
|
10998
|
+
var needsMemberSlot = (wake) => wake.kind === "item" && wake.lead !== true;
|
|
10999
|
+
function memberQueues(projectId, project2, woken = new Set(project2.woken), onlyThreadId) {
|
|
11000
|
+
const isMemberThread = memberLookup(project2);
|
|
11001
|
+
const busy = /* @__PURE__ */ new Set();
|
|
11002
|
+
const waiting = /* @__PURE__ */ new Map();
|
|
11003
|
+
for (const [workItemId, item] of Object.entries(project2.items)) {
|
|
11004
|
+
if (onlyThreadId !== void 0 && !item.assigneeThreads.includes(onlyThreadId)) continue;
|
|
11005
|
+
if (!isWorkable(project2, workItemId)) continue;
|
|
11006
|
+
for (const threadId of item.assigneeThreads) {
|
|
11007
|
+
if (onlyThreadId !== void 0 && threadId !== onlyThreadId || isLeadThread(project2, threadId) || !isMemberThread(threadId))
|
|
11008
|
+
continue;
|
|
11009
|
+
if (item.wakeStatus?.[threadId] === "active") busy.add(threadId);
|
|
11010
|
+
const candidate = itemWakeCandidate(
|
|
11011
|
+
projectId,
|
|
11012
|
+
project2,
|
|
11013
|
+
workItemId,
|
|
11014
|
+
item,
|
|
11015
|
+
threadId,
|
|
11016
|
+
woken,
|
|
11017
|
+
isMemberThread
|
|
11018
|
+
);
|
|
11019
|
+
if (candidate === null || !needsMemberSlot(candidate)) continue;
|
|
11020
|
+
const queue = waiting.get(threadId);
|
|
11021
|
+
if (queue === void 0) waiting.set(threadId, [candidate]);
|
|
11022
|
+
else queue.push(candidate);
|
|
11023
|
+
}
|
|
11024
|
+
}
|
|
11025
|
+
return { busy, waiting };
|
|
11026
|
+
}
|
|
11027
|
+
function memberItemSlots(projectId, project2, woken, onlyThreadId) {
|
|
11028
|
+
const { busy, waiting } = memberQueues(projectId, project2, woken, onlyThreadId);
|
|
11029
|
+
const slots = /* @__PURE__ */ new Map();
|
|
11030
|
+
for (const [threadId, candidates] of waiting)
|
|
11031
|
+
if (!busy.has(threadId))
|
|
11032
|
+
slots.set(
|
|
11033
|
+
threadId,
|
|
11034
|
+
candidates.reduce(
|
|
11035
|
+
(first, candidate) => compareWakeItems(candidate, first) < 0 ? candidate : first
|
|
11036
|
+
)
|
|
11037
|
+
);
|
|
11038
|
+
return slots;
|
|
11039
|
+
}
|
|
11040
|
+
function isWakeDue(state, wake) {
|
|
11041
|
+
const project2 = readFact(state, wake.projectId);
|
|
11042
|
+
if (project2 === null || engineDispatches(project2, wake)) return false;
|
|
11043
|
+
if (wake.kind === "review")
|
|
11044
|
+
return isReviewDue(project2, wake.key) && !wakeGated(project2, wake);
|
|
11045
|
+
if (!("threadId" in wake)) return false;
|
|
11046
|
+
const item = readFact(project2.items, wake.workItemId);
|
|
11047
|
+
if (item === null) return false;
|
|
11048
|
+
const woken = new Set(project2.woken);
|
|
11049
|
+
const candidate = itemWakeCandidate(
|
|
11050
|
+
wake.projectId,
|
|
11051
|
+
project2,
|
|
11052
|
+
wake.workItemId,
|
|
11053
|
+
item,
|
|
11054
|
+
wake.threadId,
|
|
11055
|
+
woken,
|
|
11056
|
+
memberLookup(project2)
|
|
11057
|
+
);
|
|
11058
|
+
if (candidate?.key !== wake.key) return false;
|
|
11059
|
+
return !needsMemberSlot(candidate) || memberItemSlots(wake.projectId, project2, woken, wake.threadId).get(wake.threadId)?.key === wake.key;
|
|
11060
|
+
}
|
|
11061
|
+
function dueWakes(state) {
|
|
11062
|
+
const due = [];
|
|
11063
|
+
for (const [projectId, project2] of Object.entries(state)) {
|
|
11064
|
+
const woken = new Set(project2.woken);
|
|
11065
|
+
const isMemberThread = memberLookup(project2);
|
|
11066
|
+
const slots = memberItemSlots(projectId, project2, woken);
|
|
11067
|
+
for (const [workItemId, item] of Object.entries(project2.items)) {
|
|
11068
|
+
const unblocked = readFact(project2.blockedAfterClaim, workItemId) ?? 0;
|
|
11069
|
+
const recipients = /* @__PURE__ */ new Set([
|
|
11070
|
+
...item.assigneeThreads,
|
|
11071
|
+
...unblocked > 0 ? item.claimedBy : []
|
|
11072
|
+
]);
|
|
11073
|
+
for (const threadId of recipients) {
|
|
11074
|
+
const candidate = itemWakeCandidate(
|
|
11075
|
+
projectId,
|
|
11076
|
+
project2,
|
|
11077
|
+
workItemId,
|
|
11078
|
+
item,
|
|
11079
|
+
threadId,
|
|
11080
|
+
woken,
|
|
11081
|
+
isMemberThread
|
|
11082
|
+
);
|
|
11083
|
+
if (candidate === null || engineDispatches(project2, candidate)) continue;
|
|
11084
|
+
if (needsMemberSlot(candidate) && slots.get(threadId)?.key !== candidate.key) continue;
|
|
11085
|
+
due.push(candidate);
|
|
11086
|
+
}
|
|
11087
|
+
}
|
|
11088
|
+
due.push(...dueReviews(project2).filter((review) => !wakeGated(project2, review)));
|
|
11089
|
+
}
|
|
11090
|
+
return due.sort((a, b) => compare2(a.projectId, b.projectId) || compare2(a.key, b.key));
|
|
11091
|
+
}
|
|
11092
|
+
function teamItemDecision(project2, projectId, workItemId, threadId) {
|
|
11093
|
+
const item = readFact(project2.items, workItemId);
|
|
11094
|
+
if (item === null) return { kind: "held", reason: "the team has not seen this work item yet" };
|
|
11095
|
+
if (isClosed(item)) return { kind: "held", reason: "the work item is closed" };
|
|
11096
|
+
if (hasOpenBlocker(project2, workItemId))
|
|
11097
|
+
return { kind: "held", reason: "the work item is blocked by unfinished work items" };
|
|
11098
|
+
if (isThreadGated(project2, threadId))
|
|
11099
|
+
return { kind: "held", reason: "the team is stopped or paused" };
|
|
11100
|
+
const woken = new Set(project2.woken);
|
|
11101
|
+
const candidate = itemWakeCandidate(
|
|
11102
|
+
projectId,
|
|
11103
|
+
project2,
|
|
11104
|
+
workItemId,
|
|
11105
|
+
item,
|
|
11106
|
+
threadId,
|
|
11107
|
+
woken,
|
|
11108
|
+
memberLookup(project2)
|
|
11109
|
+
);
|
|
11110
|
+
if (candidate === null)
|
|
11111
|
+
return {
|
|
11112
|
+
kind: "held",
|
|
11113
|
+
reason: item.assigneeThreads.includes(threadId) ? "the team already handed this work item over" : "the team runs this member in another session"
|
|
11114
|
+
};
|
|
11115
|
+
if (needsMemberSlot(candidate)) {
|
|
11116
|
+
const slot = memberItemSlots(projectId, project2, woken, threadId).get(threadId);
|
|
11117
|
+
if (slot?.key !== candidate.key)
|
|
11118
|
+
return {
|
|
11119
|
+
kind: "held",
|
|
11120
|
+
reason: slot === void 0 ? "the member is still working on another work item" : `the member gets W${slot.sequenceId} first`
|
|
11121
|
+
};
|
|
11122
|
+
}
|
|
11123
|
+
return { kind: "due", wake: candidate };
|
|
11124
|
+
}
|
|
11125
|
+
|
|
11126
|
+
// src/runtime/dispatchGate.ts
|
|
11127
|
+
var allow = { allowed: true };
|
|
11128
|
+
var hold = (detail) => ({ allowed: false, detail });
|
|
11129
|
+
var allowIn = (threadId, picked) => threadId === picked ? allow : { allowed: true, threadId };
|
|
11130
|
+
var JOINING = "the member is joining this team; its team session opens within a couple of minutes";
|
|
11131
|
+
function registerDispatchGate(ctx, deps) {
|
|
11393
11132
|
const pacing = createDeliveryPacing(
|
|
11394
11133
|
ctx.derivedState(deliveryPacingStateDefinition),
|
|
11395
11134
|
async (threadId) => waitingOnSomeone(await readMemberExecution(ctx, threadId))
|
|
11396
11135
|
);
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
|
|
11412
|
-
|
|
11413
|
-
|
|
11414
|
-
};
|
|
11415
|
-
const scopeUsable = async (projectId, project2, workLineId, memberId) => project2 !== void 0 && !isLineGated(project2, workLineId) && !isMemberPausedOnLine(project2, workLineId, memberId) && await memberOnLine(ctx, projectId, workLineId, memberId).catch(() => false);
|
|
11416
|
-
const boundRecipient = async (project2, workLineId, memberId) => {
|
|
11417
|
-
const scope2 = project2.lineScopes?.[workLineId];
|
|
11418
|
-
const recipient = scope2?.bindings?.[memberId];
|
|
11419
|
-
if (recipient === void 0) return null;
|
|
11420
|
-
const execution = "threadId" in recipient ? await ctx.projections.getThreadExecution(recipient.threadId) : null;
|
|
11421
|
-
if ("threadId" in recipient && scope2?.leadThreads?.includes(recipient.threadId) === true && (execution?.session?.status === "error" || execution?.latestTurn?.state === "error"))
|
|
11422
|
-
return null;
|
|
11423
|
-
return { recipient, execution };
|
|
11424
|
-
};
|
|
11425
|
-
const candidate = async (projectId, project2, workLineId, memberId) => await scopeUsable(projectId, project2, workLineId, memberId) ? boundRecipient(project2, workLineId, memberId) : null;
|
|
11426
|
-
const resolve2 = async (projectId, project2, target) => {
|
|
11427
|
-
const scopeLineId = target.scope?.workLineId;
|
|
11428
|
-
if (scopeLineId !== void 0 && !await scopeUsable(projectId, project2, scopeLineId, target.member))
|
|
11429
|
-
return null;
|
|
11430
|
-
const member = await findMember(ctx, projectId, target.member);
|
|
11431
|
-
if (member === null) return null;
|
|
11432
|
-
if (member.kind === "human")
|
|
11433
|
-
return member.identity?.kind === "human" ? { person: member.identity.principal } : null;
|
|
11434
|
-
if (scopeLineId !== void 0)
|
|
11435
|
-
return (await boundRecipient(project2, scopeLineId, target.member))?.recipient ?? null;
|
|
11436
|
-
let best = null;
|
|
11437
|
-
for (const workLineId of Object.keys(project2?.lineScopes ?? {}).sort()) {
|
|
11438
|
-
const found = await candidate(projectId, project2, workLineId, target.member);
|
|
11439
|
-
if (found === null) continue;
|
|
11440
|
-
const at = Date.parse(found.execution?.latestTurn?.startedAt ?? "") || 0;
|
|
11441
|
-
if (best === null || at > best.at) best = { recipient: found.recipient, at };
|
|
11442
|
-
}
|
|
11443
|
-
return best?.recipient ?? null;
|
|
11136
|
+
ctx.reactor({
|
|
11137
|
+
name: "team-delivery-pacing",
|
|
11138
|
+
events: ["thread.session-set"],
|
|
11139
|
+
handle: (event) => pacing.observe(event)
|
|
11140
|
+
});
|
|
11141
|
+
const legacyProjectGoal = async (project2, input) => {
|
|
11142
|
+
if (project2.goalId === void 0) return allow;
|
|
11143
|
+
if (readFact(project2.bindings ?? {}, input.memberId) !== null)
|
|
11144
|
+
return hold("the project's older team goal dispatches this member");
|
|
11145
|
+
if (isClosed(readFact(project2.items, teamGoalItemId(input.projectId, project2.goalId))))
|
|
11146
|
+
return allow;
|
|
11147
|
+
const lines = await ctx.work.lines.list({
|
|
11148
|
+
projectId: input.projectId,
|
|
11149
|
+
includeArchived: true,
|
|
11150
|
+
limit: 1
|
|
11151
|
+
});
|
|
11152
|
+
return lines.items.length === 0 ? hold("the project's older team goal takes this member in and dispatches it") : allow;
|
|
11444
11153
|
};
|
|
11445
|
-
const
|
|
11446
|
-
|
|
11447
|
-
const
|
|
11448
|
-
|
|
11449
|
-
|
|
11450
|
-
);
|
|
11451
|
-
|
|
11452
|
-
const
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
|
|
11458
|
-
|
|
11459
|
-
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
|
|
11463
|
-
|
|
11464
|
-
|
|
11465
|
-
|
|
11466
|
-
}
|
|
11467
|
-
await bind4(projectId, target, recipient);
|
|
11468
|
-
} catch (error) {
|
|
11469
|
-
ctx.log.warn("team group delivery sweep target failed", {
|
|
11470
|
-
recordId: target.recordId,
|
|
11471
|
-
targetKey: target.targetKey,
|
|
11472
|
-
error
|
|
11473
|
-
});
|
|
11154
|
+
const memberThreadsOf = (scope2, memberId) => teamSessions(scope2).filter((threadId) => scope2.memberIds?.[threadId] === memberId);
|
|
11155
|
+
const itemGate = async (project2, scope2, input) => {
|
|
11156
|
+
const workItemId = input.workItemId;
|
|
11157
|
+
const binding = readFact(scope2.bindings ?? {}, input.memberId);
|
|
11158
|
+
if (binding === null) return hold(JOINING);
|
|
11159
|
+
if (!("threadId" in binding)) return hold("the team runs this member on another machine");
|
|
11160
|
+
const lead = scope2.leadThreads?.includes(binding.threadId) === true;
|
|
11161
|
+
const executor = lead ? { threadId: binding.threadId } : executorOf(project2, workItemId, input.memberId);
|
|
11162
|
+
if (executor === void 0 || !("threadId" in executor)) return hold(JOINING);
|
|
11163
|
+
const threadId = executor.threadId;
|
|
11164
|
+
const decision = teamItemDecision(project2, input.projectId, workItemId, threadId);
|
|
11165
|
+
if (decision.kind === "held") return hold(decision.reason);
|
|
11166
|
+
const isReady2 = await deps.readiness();
|
|
11167
|
+
if (!exemptFromTrial(project2, { threadId }, workItemId) && !isReady2(input.projectId, input.memberId, scope2.goalId))
|
|
11168
|
+
return hold("the member has not passed its trial run yet");
|
|
11169
|
+
const worktree = lead ? void 0 : memberWorktreeFor(deps.goals, project2, input.projectId, { threadId });
|
|
11170
|
+
if (worktree !== void 0 && worktree.failure === void 0) {
|
|
11171
|
+
const execution = await ctx.projections.getThreadExecution(threadId);
|
|
11172
|
+
if (execution !== null && !execution.worktreePath) {
|
|
11173
|
+
deps.requestWorktree(input.projectId, threadId);
|
|
11174
|
+
return hold("the member's own worktree is being prepared");
|
|
11474
11175
|
}
|
|
11475
11176
|
}
|
|
11177
|
+
return allowIn(threadId, input.threadId);
|
|
11476
11178
|
};
|
|
11477
|
-
const
|
|
11478
|
-
const
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
}
|
|
11179
|
+
const messageGate = async (project2, scope2, input) => {
|
|
11180
|
+
const binding = readFact(scope2.bindings ?? {}, input.memberId);
|
|
11181
|
+
if (binding === null) return hold(JOINING);
|
|
11182
|
+
if (!("threadId" in binding)) return allow;
|
|
11183
|
+
const threadId = input.threadId !== null && memberThreadsOf(scope2, input.memberId).includes(input.threadId) ? input.threadId : binding.threadId;
|
|
11184
|
+
const isReady2 = await deps.readiness();
|
|
11185
|
+
if (!exemptFromTrial(project2, { threadId }, input.workItemId ?? void 0) && !isReady2(input.projectId, input.memberId, scope2.goalId))
|
|
11186
|
+
return hold("the member has not passed its trial run yet");
|
|
11187
|
+
if (input.reason === "group" && input.recordId !== void 0) {
|
|
11188
|
+
const [record2] = await ctx.communication.records.get({ recordIds: [input.recordId] });
|
|
11189
|
+
const fromAgent = record2 !== void 0 && record2.from.kind !== "user" && record2.from.kind !== "local-owner";
|
|
11190
|
+
if (fromAgent && !await pacing.allows(threadId, await deps.now()))
|
|
11191
|
+
return hold("slowed down: the member made no progress in its last turns");
|
|
11192
|
+
}
|
|
11193
|
+
return allowIn(threadId, input.threadId);
|
|
11484
11194
|
};
|
|
11485
|
-
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
|
|
11492
|
-
|
|
11493
|
-
|
|
11494
|
-
|
|
11495
|
-
"member.updated",
|
|
11496
|
-
"member.restored"
|
|
11497
|
-
],
|
|
11498
|
-
handle: (event) => {
|
|
11499
|
-
const projectId = decodeProjectEvent(event.payload);
|
|
11500
|
-
if (isSome2(projectId)) return sweep(projectId.value.projectId);
|
|
11501
|
-
const fact = decodeFact5(event.payload);
|
|
11502
|
-
return isSome2(fact) ? sweep(fact.value.data.projectId) : Promise.resolve();
|
|
11503
|
-
}
|
|
11504
|
-
});
|
|
11505
|
-
ctx.reactor({
|
|
11506
|
-
name: "team-group-delivery-pacing",
|
|
11507
|
-
events: ["thread.session-set"],
|
|
11508
|
-
handle: async (event) => {
|
|
11509
|
-
const threadId = event.payload?.threadId;
|
|
11510
|
-
if (typeof threadId !== "string" || !Object.values(await wakes.get()).some((project2) => isGoalThread(project2, threadId)))
|
|
11511
|
-
return;
|
|
11512
|
-
return pacing.observe(event);
|
|
11195
|
+
const check = async (input) => {
|
|
11196
|
+
const project2 = readFact(
|
|
11197
|
+
await deps.wakes.get({ throughSequence: input.throughSequence }),
|
|
11198
|
+
input.projectId
|
|
11199
|
+
);
|
|
11200
|
+
if (project2 === null) return allow;
|
|
11201
|
+
const scope2 = input.workLineId === null ? void 0 : project2.lineScopes?.[input.workLineId];
|
|
11202
|
+
if (scope2 === void 0) {
|
|
11203
|
+
if (input.reason === "item") return legacyProjectGoal(project2, input);
|
|
11204
|
+
return project2.goalId !== void 0 && readFact(project2.bindings ?? {}, input.memberId) !== null ? messageGate(project2, project2, input) : allow;
|
|
11513
11205
|
}
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
);
|
|
11519
|
-
return { ready };
|
|
11206
|
+
if (project2.lineStops?.[input.workLineId] !== void 0)
|
|
11207
|
+
return hold("the team on this work line is stopped");
|
|
11208
|
+
return input.reason === "item" ? itemGate(project2, scope2, input) : messageGate(project2, scope2, input);
|
|
11209
|
+
};
|
|
11210
|
+
return ctx.operations.guard({ operations: ["work.dispatch"], check });
|
|
11520
11211
|
}
|
|
11521
11212
|
|
|
11522
11213
|
// src/runtime/memberBinding.ts
|
|
@@ -12189,261 +11880,85 @@ function foldRecovery(state, event, previous) {
|
|
|
12189
11880
|
remindedItemIds,
|
|
12190
11881
|
escalatedItemIds,
|
|
12191
11882
|
unprogressedRetryItemIds,
|
|
12192
|
-
pending,
|
|
12193
|
-
handledTurnIds: pending === null && member.pending !== null ? [.../* @__PURE__ */ new Set([...member.handledTurnIds, member.pending.turnId])] : member.handledTurnIds
|
|
12194
|
-
};
|
|
12195
|
-
}
|
|
12196
|
-
return changed ? { ...state, [work.projectId]: { ...project2, recovery } } : state;
|
|
12197
|
-
}
|
|
12198
|
-
return state;
|
|
12199
|
-
}
|
|
12200
|
-
function dueRecoveries(state, changedThreadId) {
|
|
12201
|
-
return Object.entries(state).flatMap(
|
|
12202
|
-
([projectId, project2]) => Object.entries(project2.recovery ?? {}).flatMap(([threadId, member]) => {
|
|
12203
|
-
const scope2 = scopeOfThread(project2, threadId);
|
|
12204
|
-
const memberId = scope2?.memberIds?.[threadId];
|
|
12205
|
-
const leadThreadId = scope2?.leadThreads?.[0];
|
|
12206
|
-
if (member.pending === null || changedThreadId !== void 0 && threadId !== changedThreadId && member.pending.plan?.recipientThreadId !== changedThreadId || memberId === void 0 || leadThreadId === void 0 || threadId === leadThreadId || isThreadGated(project2, threadId) || !isMember(project2, { threadId }))
|
|
12207
|
-
return [];
|
|
12208
|
-
const stalled = member.pending.kind === "stall";
|
|
12209
|
-
if (member.handledTurnIds.includes(member.pending.turnId)) return [];
|
|
12210
|
-
const items = Object.entries(project2.items).filter(
|
|
12211
|
-
([workItemId, item]) => (stalled ? item.stateGroup === "started" && item.assigneeThreads.includes(threadId) : isOpenWorkFor(project2, workItemId, threadId) && !isQueuedUnclaimed(item, threadId)) && (!stalled || (member.pending?.plan?.workItemIds.includes(workItemId) || !(member.escalatedItemIds ?? []).includes(workItemId)) && !hasOpenBlocker(project2, workItemId))
|
|
12212
|
-
).map(([workItemId, item]) => ({
|
|
12213
|
-
workItemId,
|
|
12214
|
-
sequenceId: item.sequenceId,
|
|
12215
|
-
lastCommentId: item.lastCommentId,
|
|
12216
|
-
waitingForReply: item.lastActionCommentThreadId === threadId
|
|
12217
|
-
})).sort((a, b) => a.sequenceId - b.sequenceId);
|
|
12218
|
-
const deferredWakeCount = countDeferredWakes(project2, threadId);
|
|
12219
|
-
return items.length === 0 ? [] : [
|
|
12220
|
-
{
|
|
12221
|
-
...member.pending,
|
|
12222
|
-
projectId,
|
|
12223
|
-
threadId,
|
|
12224
|
-
memberId,
|
|
12225
|
-
leadThreadId,
|
|
12226
|
-
key: JSON.stringify([threadId, member.pending.turnId]),
|
|
12227
|
-
alreadyRetried: items.some(
|
|
12228
|
-
(item) => member.retriedItemIds.includes(item.workItemId) || (member.remindedItemIds ?? []).includes(item.workItemId) || (member.escalatedItemIds ?? []).includes(item.workItemId) || (member.pending?.continuedItemIds ?? []).includes(item.workItemId)
|
|
12229
|
-
),
|
|
12230
|
-
items,
|
|
12231
|
-
...deferredWakeCount > 0 ? { deferredWakeCount } : {}
|
|
12232
|
-
}
|
|
12233
|
-
];
|
|
12234
|
-
})
|
|
12235
|
-
);
|
|
12236
|
-
}
|
|
12237
|
-
|
|
12238
|
-
// src/runtime/reviewWakes.ts
|
|
12239
|
-
var decodeCompletion = decodeUnknownOption2(
|
|
12240
|
-
Struct({
|
|
12241
|
-
projectId: String4,
|
|
12242
|
-
workItemId: String4,
|
|
12243
|
-
state: Struct({ group: String4 }),
|
|
12244
|
-
actor: Union2([
|
|
12245
|
-
Struct({ kind: Literal2("agent"), threadId: String4 }),
|
|
12246
|
-
Struct({ kind: Literal2("remote-agent"), principalId: String4 })
|
|
12247
|
-
])
|
|
12248
|
-
})
|
|
12249
|
-
);
|
|
12250
|
-
var openLeadItemsBlockedBy = (project2, workItemId, lead) => lead === void 0 ? [] : Object.entries(project2.items).filter(
|
|
12251
|
-
([id]) => isAssignedOpen(project2, id, lead) && readFact(project2.blockers, id)?.includes(workItemId) === true
|
|
12252
|
-
);
|
|
12253
|
-
function reviewOnUpdate(previous, next, event) {
|
|
12254
|
-
const decoded = decodeCompletion(event.payload);
|
|
12255
|
-
if (isNone2(decoded) || decoded.value.state.group !== "completed") return null;
|
|
12256
|
-
const { projectId, workItemId, actor } = decoded.value;
|
|
12257
|
-
if (readFact(previous.items, workItemId)?.stateGroup === "completed") return null;
|
|
12258
|
-
const by = actor.kind === "agent" ? { threadId: actor.threadId } : { principalId: actor.principalId };
|
|
12259
|
-
const lead = scopeOfRecipient(next, by, readFact(next.items, workItemId)?.workLineId)?.leadThreads?.[0] ?? next.leadThreads?.[0];
|
|
12260
|
-
if (lead === void 0) return null;
|
|
12261
|
-
if (!isMember(next, by) || "threadId" in by && isLeadThread(next, by.threadId)) return null;
|
|
12262
|
-
const goals = openLeadItemsBlockedBy(next, workItemId, lead);
|
|
12263
|
-
if (goals.length === 0 || goals.some(([id]) => isWorkable(next, id))) return null;
|
|
12264
|
-
return {
|
|
12265
|
-
key: `review:${workItemId}:${lead}#${event.sequence}`,
|
|
12266
|
-
projectId,
|
|
12267
|
-
workItemId,
|
|
12268
|
-
threadId: lead,
|
|
12269
|
-
by
|
|
12270
|
-
};
|
|
12271
|
-
}
|
|
12272
|
-
var isLiveReview = (project2, review) => isLeadThread(project2, review.threadId) && readFact(project2.items, review.workItemId)?.stateGroup === "completed" && openLeadItemsBlockedBy(project2, review.workItemId, review.threadId).length > 0;
|
|
12273
|
-
var isReviewDue = (project2, key) => project2.pendingReviews?.some((review) => review.key === key && isLiveReview(project2, review)) === true;
|
|
12274
|
-
var dueReviews = (project2) => (project2.pendingReviews ?? []).filter((review) => isLiveReview(project2, review)).map((review) => {
|
|
12275
|
-
const item = readFact(project2.items, review.workItemId);
|
|
12276
|
-
return {
|
|
12277
|
-
...review,
|
|
12278
|
-
kind: "review",
|
|
12279
|
-
lead: true,
|
|
12280
|
-
...item === null ? {} : { sequenceId: item.sequenceId }
|
|
12281
|
-
};
|
|
12282
|
-
});
|
|
12283
|
-
function pruneReviews(previous, state) {
|
|
12284
|
-
let next = state;
|
|
12285
|
-
for (const [projectId, project2] of Object.entries(state)) {
|
|
12286
|
-
const pending = project2.pendingReviews;
|
|
12287
|
-
if (pending === void 0 || pending.length === 0) continue;
|
|
12288
|
-
const before = previous[projectId];
|
|
12289
|
-
if (before !== void 0 && before.leadThreads === project2.leadThreads && before.lineScopes === project2.lineScopes && before.items === project2.items && before.blockers === project2.blockers)
|
|
12290
|
-
continue;
|
|
12291
|
-
const live = pending.filter((review) => isLiveReview(project2, review));
|
|
12292
|
-
if (live.length !== pending.length)
|
|
12293
|
-
next = { ...next, [projectId]: { ...project2, pendingReviews: live } };
|
|
12294
|
-
}
|
|
12295
|
-
return next;
|
|
12296
|
-
}
|
|
12297
|
-
function reviewFacts(project2, queues, lead) {
|
|
12298
|
-
const { busy, waiting } = queues;
|
|
12299
|
-
const team = scopeOfThread(project2, lead)?.threads ?? project2.threads;
|
|
12300
|
-
return {
|
|
12301
|
-
idle: team.filter(
|
|
12302
|
-
(threadId) => !isLeadThread(project2, threadId) && !busy.has(threadId) && (waiting.get(threadId) ?? []).length === 0
|
|
12303
|
-
),
|
|
12304
|
-
queued: [...busy].filter((threadId) => team.includes(threadId)).flatMap(
|
|
12305
|
-
(threadId) => [...waiting.get(threadId) ?? []].sort(compareWakeItems).map(({ workItemId, sequenceId }) => ({ workItemId, sequenceId, threadId }))
|
|
12306
|
-
)
|
|
12307
|
-
};
|
|
12308
|
-
}
|
|
12309
|
-
|
|
12310
|
-
// src/runtime/wakeDue.ts
|
|
12311
|
-
var itemWakeKey = (workItemId, threadId, generation) => generation === 0 ? `item:${workItemId}:${threadId}` : `item:${workItemId}:${threadId}#${generation}`;
|
|
12312
|
-
var unblockedWakeKey = (workItemId, threadId, generation) => `unblocked:${workItemId}:${threadId}#${generation}`;
|
|
12313
|
-
var compare2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
12314
|
-
var itemWakeCandidate = (projectId, project2, workItemId, item, threadId, woken, isMemberThread) => {
|
|
12315
|
-
if (!isWorkable(project2, workItemId) || !isMemberThread(threadId)) return null;
|
|
12316
|
-
if (isThreadGated(project2, threadId)) return null;
|
|
12317
|
-
const unblocked = readFact(project2.blockedAfterClaim, workItemId) ?? 0;
|
|
12318
|
-
const finishing = unblocked > 0 && item.claimedBy.includes(threadId);
|
|
12319
|
-
if (!finishing && !item.assigneeThreads.includes(threadId)) return null;
|
|
12320
|
-
const lead = isLeadThread(project2, threadId);
|
|
12321
|
-
const leadThreadId = leadOfThread(project2, threadId);
|
|
12322
|
-
const key = finishing ? unblockedWakeKey(workItemId, threadId, unblocked) : itemWakeKey(workItemId, threadId, readFact(project2.rearms, `${workItemId}:${threadId}`) ?? 0);
|
|
12323
|
-
if (woken.has(key) || !finishing && !lead && item.wakeStatus?.[threadId] === "released")
|
|
12324
|
-
return null;
|
|
12325
|
-
const memberId = finishing ? void 0 : memberOfThread(item, threadId);
|
|
12326
|
-
return {
|
|
12327
|
-
key,
|
|
12328
|
-
projectId,
|
|
12329
|
-
threadId,
|
|
12330
|
-
kind: finishing ? "unblocked" : "item",
|
|
12331
|
-
workItemId,
|
|
12332
|
-
sequenceId: item.sequenceId,
|
|
12333
|
-
...memberId === void 0 ? {} : { memberId },
|
|
12334
|
-
// 成员的叫醒话里点名负责人(卡住时找谁);带队自己和解挡续做不带。
|
|
12335
|
-
...lead ? { lead: true } : finishing || leadThreadId === void 0 ? {} : { leadThreadId }
|
|
12336
|
-
};
|
|
12337
|
-
};
|
|
12338
|
-
var wakeGated = (project2, wake) => isRecipientGated(project2, wake, readFact(project2.items, wake.workItemId)?.workLineId);
|
|
12339
|
-
var needsMemberSlot = (wake) => wake.kind === "item" && wake.lead !== true;
|
|
12340
|
-
function memberQueues(projectId, project2, woken = new Set(project2.woken), onlyThreadId) {
|
|
12341
|
-
const isMemberThread = memberLookup(project2);
|
|
12342
|
-
const busy = /* @__PURE__ */ new Set();
|
|
12343
|
-
const waiting = /* @__PURE__ */ new Map();
|
|
12344
|
-
for (const [workItemId, item] of Object.entries(project2.items)) {
|
|
12345
|
-
if (onlyThreadId !== void 0 && !item.assigneeThreads.includes(onlyThreadId)) continue;
|
|
12346
|
-
if (!isWorkable(project2, workItemId)) continue;
|
|
12347
|
-
for (const threadId of item.assigneeThreads) {
|
|
12348
|
-
if (onlyThreadId !== void 0 && threadId !== onlyThreadId || isLeadThread(project2, threadId) || !isMemberThread(threadId))
|
|
12349
|
-
continue;
|
|
12350
|
-
if (item.wakeStatus?.[threadId] === "active") busy.add(threadId);
|
|
12351
|
-
const candidate = itemWakeCandidate(
|
|
12352
|
-
projectId,
|
|
12353
|
-
project2,
|
|
12354
|
-
workItemId,
|
|
12355
|
-
item,
|
|
12356
|
-
threadId,
|
|
12357
|
-
woken,
|
|
12358
|
-
isMemberThread
|
|
12359
|
-
);
|
|
12360
|
-
if (candidate === null || !needsMemberSlot(candidate)) continue;
|
|
12361
|
-
const queue = waiting.get(threadId);
|
|
12362
|
-
if (queue === void 0) waiting.set(threadId, [candidate]);
|
|
12363
|
-
else queue.push(candidate);
|
|
11883
|
+
pending,
|
|
11884
|
+
handledTurnIds: pending === null && member.pending !== null ? [.../* @__PURE__ */ new Set([...member.handledTurnIds, member.pending.turnId])] : member.handledTurnIds
|
|
11885
|
+
};
|
|
12364
11886
|
}
|
|
11887
|
+
return changed ? { ...state, [work.projectId]: { ...project2, recovery } } : state;
|
|
12365
11888
|
}
|
|
12366
|
-
return
|
|
12367
|
-
}
|
|
12368
|
-
function memberItemSlots(projectId, project2, woken, onlyThreadId) {
|
|
12369
|
-
const { busy, waiting } = memberQueues(projectId, project2, woken, onlyThreadId);
|
|
12370
|
-
const slots = /* @__PURE__ */ new Map();
|
|
12371
|
-
for (const [threadId, candidates] of waiting)
|
|
12372
|
-
if (!busy.has(threadId))
|
|
12373
|
-
slots.set(
|
|
12374
|
-
threadId,
|
|
12375
|
-
candidates.reduce(
|
|
12376
|
-
(first, candidate) => compareWakeItems(candidate, first) < 0 ? candidate : first
|
|
12377
|
-
)
|
|
12378
|
-
);
|
|
12379
|
-
return slots;
|
|
12380
|
-
}
|
|
12381
|
-
function isWakeDue(state, wake) {
|
|
12382
|
-
const project2 = readFact(state, wake.projectId);
|
|
12383
|
-
if (project2 === null) return false;
|
|
12384
|
-
if (wake.kind === "comment")
|
|
12385
|
-
return project2.pendingComments.some(
|
|
12386
|
-
(comment) => comment.key === wake.key && !wakeGated(project2, comment)
|
|
12387
|
-
);
|
|
12388
|
-
if (wake.kind === "review")
|
|
12389
|
-
return isReviewDue(project2, wake.key) && !wakeGated(project2, wake);
|
|
12390
|
-
if (!("threadId" in wake)) return false;
|
|
12391
|
-
const item = readFact(project2.items, wake.workItemId);
|
|
12392
|
-
if (item === null) return false;
|
|
12393
|
-
const woken = new Set(project2.woken);
|
|
12394
|
-
const candidate = itemWakeCandidate(
|
|
12395
|
-
wake.projectId,
|
|
12396
|
-
project2,
|
|
12397
|
-
wake.workItemId,
|
|
12398
|
-
item,
|
|
12399
|
-
wake.threadId,
|
|
12400
|
-
woken,
|
|
12401
|
-
memberLookup(project2)
|
|
12402
|
-
);
|
|
12403
|
-
if (candidate?.key !== wake.key) return false;
|
|
12404
|
-
return !needsMemberSlot(candidate) || memberItemSlots(wake.projectId, project2, woken, wake.threadId).get(wake.threadId)?.key === wake.key;
|
|
11889
|
+
return state;
|
|
12405
11890
|
}
|
|
12406
|
-
function
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
const
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
|
|
12418
|
-
|
|
12419
|
-
|
|
11891
|
+
function dueRecoveries(state, changedThreadId) {
|
|
11892
|
+
return Object.entries(state).flatMap(
|
|
11893
|
+
([projectId, project2]) => Object.entries(project2.recovery ?? {}).flatMap(([threadId, member]) => {
|
|
11894
|
+
const scope2 = scopeOfThread(project2, threadId);
|
|
11895
|
+
const memberId = scope2?.memberIds?.[threadId];
|
|
11896
|
+
const leadThreadId = scope2?.leadThreads?.[0];
|
|
11897
|
+
if (member.pending === null || changedThreadId !== void 0 && threadId !== changedThreadId && member.pending.plan?.recipientThreadId !== changedThreadId || memberId === void 0 || leadThreadId === void 0 || threadId === leadThreadId || isThreadGated(project2, threadId) || !isMember(project2, { threadId }))
|
|
11898
|
+
return [];
|
|
11899
|
+
const stalled = member.pending.kind === "stall";
|
|
11900
|
+
if (member.handledTurnIds.includes(member.pending.turnId)) return [];
|
|
11901
|
+
const items = Object.entries(project2.items).filter(
|
|
11902
|
+
([workItemId, item]) => (stalled ? item.stateGroup === "started" && item.assigneeThreads.includes(threadId) : isOpenWorkFor(project2, workItemId, threadId) && !isQueuedUnclaimed(item, threadId)) && (!stalled || (member.pending?.plan?.workItemIds.includes(workItemId) || !(member.escalatedItemIds ?? []).includes(workItemId)) && !hasOpenBlocker(project2, workItemId))
|
|
11903
|
+
).map(([workItemId, item]) => ({
|
|
11904
|
+
workItemId,
|
|
11905
|
+
sequenceId: item.sequenceId,
|
|
11906
|
+
lastCommentId: item.lastCommentId,
|
|
11907
|
+
waitingForReply: item.lastActionCommentThreadId === threadId
|
|
11908
|
+
})).sort((a, b) => a.sequenceId - b.sequenceId);
|
|
11909
|
+
const deferredWakeCount = countDeferredWakes(project2, threadId);
|
|
11910
|
+
return items.length === 0 ? [] : [
|
|
11911
|
+
{
|
|
11912
|
+
...member.pending,
|
|
12420
11913
|
projectId,
|
|
12421
|
-
project2,
|
|
12422
|
-
workItemId,
|
|
12423
|
-
item,
|
|
12424
11914
|
threadId,
|
|
12425
|
-
|
|
12426
|
-
|
|
12427
|
-
|
|
12428
|
-
|
|
12429
|
-
|
|
12430
|
-
|
|
12431
|
-
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
|
|
12435
|
-
|
|
12436
|
-
|
|
12437
|
-
due.push({
|
|
12438
|
-
...comment,
|
|
12439
|
-
kind: "comment",
|
|
12440
|
-
...item === null ? {} : { sequenceId: item.sequenceId }
|
|
12441
|
-
});
|
|
12442
|
-
}
|
|
12443
|
-
}
|
|
12444
|
-
return due.sort((a, b) => compare2(a.projectId, b.projectId) || compare2(a.key, b.key));
|
|
11915
|
+
memberId,
|
|
11916
|
+
leadThreadId,
|
|
11917
|
+
key: JSON.stringify([threadId, member.pending.turnId]),
|
|
11918
|
+
alreadyRetried: items.some(
|
|
11919
|
+
(item) => member.retriedItemIds.includes(item.workItemId) || (member.remindedItemIds ?? []).includes(item.workItemId) || (member.escalatedItemIds ?? []).includes(item.workItemId) || (member.pending?.continuedItemIds ?? []).includes(item.workItemId)
|
|
11920
|
+
),
|
|
11921
|
+
items,
|
|
11922
|
+
...deferredWakeCount > 0 ? { deferredWakeCount } : {}
|
|
11923
|
+
}
|
|
11924
|
+
];
|
|
11925
|
+
})
|
|
11926
|
+
);
|
|
12445
11927
|
}
|
|
12446
11928
|
|
|
11929
|
+
// src/runtime/wakeTexts.ts
|
|
11930
|
+
var workLabel = (workItemId, sequenceId) => sequenceId === void 0 ? `the work item with workItemId ${workItemId}` : `work item W${sequenceId} (workItemId ${workItemId})`;
|
|
11931
|
+
var titled = (workItemId, sequenceId, title) => `${workLabel(workItemId, sequenceId)}${title ? `: ${title}` : ""}`;
|
|
11932
|
+
var ITEM_SUMMARY_MAX_CHARS = 300;
|
|
11933
|
+
var descriptionStart = (description) => {
|
|
11934
|
+
const first = description?.trim().split(/\n\s*\n/u)[0]?.trim() ?? "";
|
|
11935
|
+
if (first === "") return "";
|
|
11936
|
+
const points = Array.from(first);
|
|
11937
|
+
const summary = points.length > ITEM_SUMMARY_MAX_CHARS ? `${points.slice(0, ITEM_SUMMARY_MAX_CHARS).join("")}\u2026` : first;
|
|
11938
|
+
return `Its description starts: ${summary}`;
|
|
11939
|
+
};
|
|
11940
|
+
var itemHeadline = (sequenceId, item) => {
|
|
11941
|
+
const title = item?.title ? `${sequenceId === void 0 ? "Work item" : `W${sequenceId}`}: ${item.title}.` : "";
|
|
11942
|
+
const parts = [title, descriptionStart(item?.description)].filter((part2) => part2 !== "");
|
|
11943
|
+
return parts.length === 0 ? "" : `${parts.join(" ")} `;
|
|
11944
|
+
};
|
|
11945
|
+
var MEMBER_INSTRUCTIONS_LIMIT = 2e3;
|
|
11946
|
+
var startClause = (member) => member === void 0 ? "Otherwise claim it with work_claim_item before you change any file." : "Otherwise start it before you change any file: use work_update_item to move it into an in-progress state (see work_list_states) and leave its assignees as they are. It is assigned to you as a team member, so do not claim it with work_claim_item; claiming is for work nobody holds.";
|
|
11947
|
+
var memberInstructionsClause = (member) => member?.instructions == null || member.instructions.trim() === "" ? "" : ` Your standing work instructions as a member of this team: ${member.instructions}${member.nextOffset === null ? "" : ` (This is the first part only. Read the rest with work_read_member, passing memberId "${member.memberId}" and textOffset ${member.nextOffset}.)`}`;
|
|
11948
|
+
var itemText = (workItemId, sequenceId, item, leadThreadId, member) => `${itemHeadline(sequenceId, item)}You have ${workLabel(workItemId, sequenceId)}. ${handbookMessage("memberBrief")} Then read it with work_read_items, passing workItemIds: ["${workItemId}"]. If it is blocked by items that are not done yet, do not start it; you will be told again when they are done. ${startClause(member)}${memberInstructionsClause(member)} Before you change anything, search this repository's rules and checks with memory_search and follow what applies. Then work on it. ${MEMBER_READ_RANGES_RULE} ${MEMBER_NO_STASH_RULE} ${MEMBER_ASK_BEFORE_OUTSIDE_RULE} ${MEMBER_CHECKS_RULE} ${MEMBER_PROGRESS_RULE} ${memberStuckRule(leadThreadId)}${memberGroupRule(leadThreadId)} ${PERSON_MESSAGE_RULE}`;
|
|
11949
|
+
var leadItemText = (workItemId, sequenceId, title) => `You have ${titled(workItemId, sequenceId, title)}. You lead this team, so this item is the goal itself: do not claim it or do its work yourself. Read it with work_read_items, passing workItemIds: ["${workItemId}"]. If it has no work items yet, split it as your team brief says. ${LEAD_SPLIT_RULE} ${LEAD_OWN_ITEM_RULE} Record dependencies and assign each item to one member as the brief describes. ${LEAD_NO_MEMBER_TASKS} ${PERSON_MESSAGE_RULE}`;
|
|
11950
|
+
var leadUnblockedText = (workItemId, sequenceId, title) => `Everything blocking ${titled(workItemId, sequenceId, title)} is done now. Read those items with work_read_items and check the results. ${LEAD_ACCEPT_RULE} ${LEAD_SEND_BACK_RULE} When all of them are acceptable, mark this item done with work_update_item. ${LEAD_NO_MEMBER_TASKS}`;
|
|
11951
|
+
var unblockedText = (workItemId, sequenceId, title) => `Everything blocking ${titled(workItemId, sequenceId, title)} is done now. Read those items with work_read_items, finish this one, and mark it done with work_update_item.`;
|
|
11952
|
+
var leadReviewText = (workItemId, sequenceId, title, by, facts) => [
|
|
11953
|
+
`${by} marked ${titled(workItemId, sequenceId, title)} done. Read it with work_read_items, passing workItemIds: ["${workItemId}"], and check it now.`,
|
|
11954
|
+
LEAD_ACCEPT_RULE,
|
|
11955
|
+
LEAD_SEND_BACK_RULE,
|
|
11956
|
+
...facts.idle.length === 0 ? [] : [`Nothing in progress now: ${facts.idle.join("; ")}.`],
|
|
11957
|
+
...facts.queued.length === 0 ? [] : [`Waiting in line, not blocked: ${facts.queued.join("; ")}.`],
|
|
11958
|
+
...facts.idle.length > 0 && facts.queued.length > 0 ? [LEAD_REBALANCE_RULE] : [],
|
|
11959
|
+
LEAD_NO_MEMBER_TASKS
|
|
11960
|
+
].join(" ");
|
|
11961
|
+
|
|
12447
11962
|
// src/runtime/memberAssignments.ts
|
|
12448
11963
|
var threadOf = (bindings, memberId) => {
|
|
12449
11964
|
const binding = bindings === void 0 ? null : readFact(bindings, memberId);
|
|
@@ -12583,6 +12098,8 @@ var WAKE_EVENTS = [
|
|
|
12583
12098
|
"work.relation-added",
|
|
12584
12099
|
"work.relation-removed",
|
|
12585
12100
|
"work.comment-posted",
|
|
12101
|
+
// 看板把件交到了成员会话上(引擎叫醒了它):当成这一次「你有活」已经叫过,占名额、固定执行者都照旧。
|
|
12102
|
+
"work.item-dispatched",
|
|
12586
12103
|
"plugin.event-appended",
|
|
12587
12104
|
"thread.session-set",
|
|
12588
12105
|
// 线与线上成员的暂停:引擎的看板事实,派发闸读它(见 `linePauses` / `pausedMembers`)。
|
|
@@ -12599,7 +12116,6 @@ var emptyProject = () => ({
|
|
|
12599
12116
|
remoteMembers: [],
|
|
12600
12117
|
items: {},
|
|
12601
12118
|
blockers: {},
|
|
12602
|
-
pendingComments: [],
|
|
12603
12119
|
woken: [],
|
|
12604
12120
|
rearms: {},
|
|
12605
12121
|
blockedAfterClaim: {}
|
|
@@ -12665,6 +12181,24 @@ var withoutInitialLeadWake = (project2, projectId, workItemId) => {
|
|
|
12665
12181
|
woken: [...project2.woken, ...leads.map((threadId) => itemWakeKey(workItemId, threadId, 0))]
|
|
12666
12182
|
};
|
|
12667
12183
|
};
|
|
12184
|
+
var decodeDispatched = decodeUnknownOption2(
|
|
12185
|
+
Struct({ projectId: String4, workItemId: String4, threadId: String4 })
|
|
12186
|
+
);
|
|
12187
|
+
var markWoken = (project2, key) => {
|
|
12188
|
+
if (project2.woken.includes(key)) return project2;
|
|
12189
|
+
const items = { ...project2.items };
|
|
12190
|
+
for (const [workItemId, item] of Object.entries(items)) {
|
|
12191
|
+
for (const threadId of item.assigneeThreads) {
|
|
12192
|
+
if (item.wakeStatus?.[threadId] !== "released" && isWorkable(project2, workItemId) && key === itemWakeKey(
|
|
12193
|
+
workItemId,
|
|
12194
|
+
threadId,
|
|
12195
|
+
readFact(project2.rearms, `${workItemId}:${threadId}`) ?? 0
|
|
12196
|
+
))
|
|
12197
|
+
items[workItemId] = { ...item, wakeStatus: { ...item.wakeStatus, [threadId]: "active" } };
|
|
12198
|
+
}
|
|
12199
|
+
}
|
|
12200
|
+
return { ...project2, items, woken: [...project2.woken, key] };
|
|
12201
|
+
};
|
|
12668
12202
|
var markBlockedAfterClaim = (project2, workItemId) => ({
|
|
12669
12203
|
...project2,
|
|
12670
12204
|
blockedAfterClaim: {
|
|
@@ -12692,14 +12226,7 @@ function foldWorkWakes(state, event) {
|
|
|
12692
12226
|
)
|
|
12693
12227
|
};
|
|
12694
12228
|
}
|
|
12695
|
-
|
|
12696
|
-
return {
|
|
12697
|
-
...state,
|
|
12698
|
-
[goal.projectId]: {
|
|
12699
|
-
...next2,
|
|
12700
|
-
pendingComments: project4.pendingComments.filter((comment) => isMember(next2, comment))
|
|
12701
|
-
}
|
|
12702
|
-
};
|
|
12229
|
+
return { ...state, [goal.projectId]: rebindItems({ ...project4, ...scope2 }) };
|
|
12703
12230
|
}
|
|
12704
12231
|
if (fact.name === "team/member-bound") {
|
|
12705
12232
|
const { projectId: projectId3, memberId } = fact.data;
|
|
@@ -12714,17 +12241,17 @@ function foldWorkWakes(state, event) {
|
|
|
12714
12241
|
lineId === void 0 ? project4 : project4.lineScopes[lineId],
|
|
12715
12242
|
fact.data
|
|
12716
12243
|
);
|
|
12717
|
-
const
|
|
12244
|
+
const next3 = rebindItems(
|
|
12718
12245
|
lineId === void 0 ? { ...project4, ...bound } : { ...project4, lineScopes: { ...project4.lineScopes, [lineId]: bound } },
|
|
12719
12246
|
memberId,
|
|
12720
12247
|
lineId
|
|
12721
12248
|
);
|
|
12722
|
-
return { ...state, [projectId3]:
|
|
12249
|
+
return { ...state, [projectId3]: next3 };
|
|
12723
12250
|
}
|
|
12724
12251
|
if (fact.name === "team/line-paused" || fact.name === "team/line-member-paused") {
|
|
12725
12252
|
const { projectId: projectId3, workLineId, status } = fact.data;
|
|
12726
12253
|
const project4 = readFact(state, projectId3) ?? emptyProject();
|
|
12727
|
-
const
|
|
12254
|
+
const next3 = withPause(
|
|
12728
12255
|
project4,
|
|
12729
12256
|
{
|
|
12730
12257
|
projectId: projectId3,
|
|
@@ -12734,22 +12261,7 @@ function foldWorkWakes(state, event) {
|
|
|
12734
12261
|
},
|
|
12735
12262
|
event.eventId
|
|
12736
12263
|
);
|
|
12737
|
-
return
|
|
12738
|
-
}
|
|
12739
|
-
if (fact.name === COMMENT_MENTIONS_EVENT) {
|
|
12740
|
-
const { projectId: projectId3, workItemId: workItemId2, commentId, recipients } = fact.data;
|
|
12741
|
-
const project4 = readFact(state, projectId3) ?? emptyProject();
|
|
12742
|
-
return {
|
|
12743
|
-
...state,
|
|
12744
|
-
[projectId3]: {
|
|
12745
|
-
...project4,
|
|
12746
|
-
pendingComments: queueCommentWakes(
|
|
12747
|
-
project4,
|
|
12748
|
-
{ projectId: projectId3, workItemId: workItemId2, commentId },
|
|
12749
|
-
recipients.filter((recipient) => isMember(project4, recipient))
|
|
12750
|
-
)
|
|
12751
|
-
}
|
|
12752
|
-
};
|
|
12264
|
+
return next3 === project4 ? state : { ...state, [projectId3]: next3 };
|
|
12753
12265
|
}
|
|
12754
12266
|
if (fact.name === "team/member-worktree-failed" || fact.name === "team/member-worktree-reported") {
|
|
12755
12267
|
const { projectId: projectId3, threadId } = fact.data;
|
|
@@ -12767,15 +12279,6 @@ function foldWorkWakes(state, event) {
|
|
|
12767
12279
|
}
|
|
12768
12280
|
const { projectId: projectId2, key } = fact.data;
|
|
12769
12281
|
const project3 = readFact(state, projectId2) ?? emptyProject();
|
|
12770
|
-
if (project3.pendingComments.some((comment) => comment.key === key)) {
|
|
12771
|
-
return {
|
|
12772
|
-
...state,
|
|
12773
|
-
[projectId2]: {
|
|
12774
|
-
...project3,
|
|
12775
|
-
pendingComments: project3.pendingComments.filter((comment) => comment.key !== key)
|
|
12776
|
-
}
|
|
12777
|
-
};
|
|
12778
|
-
}
|
|
12779
12282
|
if (project3.pendingReviews?.some((review) => review.key === key)) {
|
|
12780
12283
|
return {
|
|
12781
12284
|
...state,
|
|
@@ -12785,19 +12288,22 @@ function foldWorkWakes(state, event) {
|
|
|
12785
12288
|
}
|
|
12786
12289
|
};
|
|
12787
12290
|
}
|
|
12788
|
-
|
|
12789
|
-
|
|
12790
|
-
|
|
12791
|
-
|
|
12792
|
-
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
12798
|
-
|
|
12799
|
-
|
|
12800
|
-
|
|
12291
|
+
const next2 = markWoken(project3, key);
|
|
12292
|
+
return next2 === project3 ? state : { ...state, [projectId2]: next2 };
|
|
12293
|
+
}
|
|
12294
|
+
if (event.type === "work.item-dispatched") {
|
|
12295
|
+
const decoded2 = decodeDispatched(event.payload);
|
|
12296
|
+
if (isNone2(decoded2)) return state;
|
|
12297
|
+
const { projectId: projectId2, workItemId: workItemId2, threadId } = decoded2.value;
|
|
12298
|
+
const project3 = readFact(state, projectId2);
|
|
12299
|
+
if (project3 === null) return state;
|
|
12300
|
+
const key = itemWakeKey(
|
|
12301
|
+
workItemId2,
|
|
12302
|
+
threadId,
|
|
12303
|
+
readFact(project3.rearms, `${workItemId2}:${threadId}`) ?? 0
|
|
12304
|
+
);
|
|
12305
|
+
const next2 = markWoken(project3, key);
|
|
12306
|
+
return next2 === project3 ? state : { ...state, [projectId2]: next2 };
|
|
12801
12307
|
}
|
|
12802
12308
|
const decoded = decodeWorkEvent(event);
|
|
12803
12309
|
if (isNone2(decoded)) return state;
|
|
@@ -12928,20 +12434,11 @@ function foldWorkWakes(state, event) {
|
|
|
12928
12434
|
}
|
|
12929
12435
|
break;
|
|
12930
12436
|
}
|
|
12437
|
+
// 评论里 @ 谁、回复谁由引擎投递(提案 0085 切片 3);这里只记最近一条评论,恢复与问进度要用。
|
|
12931
12438
|
case "work.comment-posted": {
|
|
12932
|
-
const { actor,
|
|
12933
|
-
const recipients = commentRecipients(
|
|
12934
|
-
project2,
|
|
12935
|
-
actor,
|
|
12936
|
-
commentPeople({ parentAuthor, mentions })
|
|
12937
|
-
);
|
|
12439
|
+
const { actor, commentId } = work.payload;
|
|
12938
12440
|
next = {
|
|
12939
12441
|
...project2,
|
|
12940
|
-
pendingComments: queueCommentWakes(
|
|
12941
|
-
project2,
|
|
12942
|
-
{ projectId, workItemId, commentId },
|
|
12943
|
-
recipients
|
|
12944
|
-
),
|
|
12945
12442
|
items: currentItem === null ? project2.items : {
|
|
12946
12443
|
...project2.items,
|
|
12947
12444
|
[workItemId]: {
|
|
@@ -13020,38 +12517,6 @@ function foldWakes(state, event) {
|
|
|
13020
12517
|
}
|
|
13021
12518
|
|
|
13022
12519
|
// src/runtime/wake.ts
|
|
13023
|
-
var workLabel = (workItemId, sequenceId) => sequenceId === void 0 ? `the work item with workItemId ${workItemId}` : `work item W${sequenceId} (workItemId ${workItemId})`;
|
|
13024
|
-
var titled = (workItemId, sequenceId, title) => `${workLabel(workItemId, sequenceId)}${title ? `: ${title}` : ""}`;
|
|
13025
|
-
var ITEM_SUMMARY_MAX_CHARS = 300;
|
|
13026
|
-
var descriptionStart = (description) => {
|
|
13027
|
-
const first = description?.trim().split(/\n\s*\n/u)[0]?.trim() ?? "";
|
|
13028
|
-
if (first === "") return "";
|
|
13029
|
-
const points = Array.from(first);
|
|
13030
|
-
const summary = points.length > ITEM_SUMMARY_MAX_CHARS ? `${points.slice(0, ITEM_SUMMARY_MAX_CHARS).join("")}\u2026` : first;
|
|
13031
|
-
return `Its description starts: ${summary}`;
|
|
13032
|
-
};
|
|
13033
|
-
var itemHeadline = (sequenceId, item) => {
|
|
13034
|
-
const title = item?.title ? `${sequenceId === void 0 ? "Work item" : `W${sequenceId}`}: ${item.title}.` : "";
|
|
13035
|
-
const parts = [title, descriptionStart(item?.description)].filter((part2) => part2 !== "");
|
|
13036
|
-
return parts.length === 0 ? "" : `${parts.join(" ")} `;
|
|
13037
|
-
};
|
|
13038
|
-
var MEMBER_INSTRUCTIONS_LIMIT = 2e3;
|
|
13039
|
-
var startClause = (member) => member === void 0 ? "Otherwise claim it with work_claim_item before you change any file." : "Otherwise start it before you change any file: use work_update_item to move it into an in-progress state (see work_list_states) and leave its assignees as they are. It is assigned to you as a team member, so do not claim it with work_claim_item; claiming is for work nobody holds.";
|
|
13040
|
-
var memberInstructionsClause = (member) => member?.instructions == null || member.instructions.trim() === "" ? "" : ` Your standing work instructions as a member of this team: ${member.instructions}${member.nextOffset === null ? "" : ` (This is the first part only. Read the rest with work_read_member, passing memberId "${member.memberId}" and textOffset ${member.nextOffset}.)`}`;
|
|
13041
|
-
var itemText = (workItemId, sequenceId, item, leadThreadId, member) => `${itemHeadline(sequenceId, item)}You have ${workLabel(workItemId, sequenceId)}. ${handbookMessage("memberBrief")} Then read it with work_read_items, passing workItemIds: ["${workItemId}"]. If it is blocked by items that are not done yet, do not start it; you will be told again when they are done. ${startClause(member)}${memberInstructionsClause(member)} Before you change anything, search this repository's rules and checks with memory_search and follow what applies. Then work on it. ${MEMBER_READ_RANGES_RULE} ${MEMBER_NO_STASH_RULE} ${MEMBER_ASK_BEFORE_OUTSIDE_RULE} ${MEMBER_CHECKS_RULE} ${MEMBER_PROGRESS_RULE} ${memberStuckRule(leadThreadId)}${memberGroupRule(leadThreadId)} ${PERSON_MESSAGE_RULE}`;
|
|
13042
|
-
var leadItemText = (workItemId, sequenceId, title) => `You have ${titled(workItemId, sequenceId, title)}. You lead this team, so this item is the goal itself: do not claim it or do its work yourself. Read it with work_read_items, passing workItemIds: ["${workItemId}"]. If it has no work items yet, split it as your team brief says. ${LEAD_SPLIT_RULE} ${LEAD_OWN_ITEM_RULE} Record dependencies and assign each item to one member as the brief describes. ${LEAD_NO_MEMBER_TASKS} ${PERSON_MESSAGE_RULE}`;
|
|
13043
|
-
var leadUnblockedText = (workItemId, sequenceId, title) => `Everything blocking ${titled(workItemId, sequenceId, title)} is done now. Read those items with work_read_items and check the results. ${LEAD_ACCEPT_RULE} ${LEAD_SEND_BACK_RULE} When all of them are acceptable, mark this item done with work_update_item. ${LEAD_NO_MEMBER_TASKS}`;
|
|
13044
|
-
var unblockedText = (workItemId, sequenceId, title) => `Everything blocking ${titled(workItemId, sequenceId, title)} is done now. Read those items with work_read_items, finish this one, and mark it done with work_update_item.`;
|
|
13045
|
-
var leadReviewText = (workItemId, sequenceId, title, by, facts) => [
|
|
13046
|
-
`${by} marked ${titled(workItemId, sequenceId, title)} done. Read it with work_read_items, passing workItemIds: ["${workItemId}"], and check it now.`,
|
|
13047
|
-
LEAD_ACCEPT_RULE,
|
|
13048
|
-
LEAD_SEND_BACK_RULE,
|
|
13049
|
-
...facts.idle.length === 0 ? [] : [`Nothing in progress now: ${facts.idle.join("; ")}.`],
|
|
13050
|
-
...facts.queued.length === 0 ? [] : [`Waiting in line, not blocked: ${facts.queued.join("; ")}.`],
|
|
13051
|
-
...facts.idle.length > 0 && facts.queued.length > 0 ? [LEAD_REBALANCE_RULE] : [],
|
|
13052
|
-
LEAD_NO_MEMBER_TASKS
|
|
13053
|
-
].join(" ");
|
|
13054
|
-
var commentText = (workItemId, sequenceId) => `There is a new comment for you on ${workLabel(workItemId, sequenceId)}. Read it with work_list_comments, passing workItemId: "${workItemId}", and reply there if needed.`;
|
|
13055
12520
|
function startWakeRuntime(ctx, goals, options = {}) {
|
|
13056
12521
|
const wakes = ctx.derivedState({
|
|
13057
12522
|
key: WAKE_STATE_KEY,
|
|
@@ -13078,8 +12543,6 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13078
12543
|
};
|
|
13079
12544
|
};
|
|
13080
12545
|
const baseText = async (wake, state) => {
|
|
13081
|
-
if ("principalId" in wake || wake.kind === "comment")
|
|
13082
|
-
return commentText(wake.workItemId, wake.sequenceId);
|
|
13083
12546
|
const item = await readItem(wake.projectId, wake.workItemId);
|
|
13084
12547
|
const title = item?.title;
|
|
13085
12548
|
if (wake.kind === "review") {
|
|
@@ -13090,7 +12553,7 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13090
12553
|
const key = "threadId" in id ? id.threadId : id.principalId;
|
|
13091
12554
|
return `${member?.name ?? key} (${"threadId" in id ? "threadId" : "principalId"} ${key})`;
|
|
13092
12555
|
};
|
|
13093
|
-
const facts = project2 === void 0 ? { idle: [], queued: [] } : reviewFacts(project2, memberQueues(wake.projectId, project2), wake.threadId);
|
|
12556
|
+
const facts = project2 === void 0 || !("threadId" in wake) ? { idle: [], queued: [] } : reviewFacts(project2, memberQueues(wake.projectId, project2), wake.threadId);
|
|
13094
12557
|
return leadReviewText(
|
|
13095
12558
|
wake.workItemId,
|
|
13096
12559
|
wake.sequenceId,
|
|
@@ -13118,6 +12581,42 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13118
12581
|
title
|
|
13119
12582
|
);
|
|
13120
12583
|
};
|
|
12584
|
+
const compose = async (wake, state) => {
|
|
12585
|
+
const team = "threadId" in wake ? lineScopeOfThread(state[wake.projectId], wake.threadId) : void 0;
|
|
12586
|
+
const memberId = team === void 0 || !("threadId" in wake) ? void 0 : team.scope.memberIds?.[wake.threadId];
|
|
12587
|
+
const digest = team === void 0 || memberId === void 0 || !("threadId" in wake) || team.scope.leadThreads?.includes(wake.threadId) === true || options.groupDigest === void 0 ? null : await options.groupDigest.prepare({
|
|
12588
|
+
projectId: wake.projectId,
|
|
12589
|
+
workLineId: team.workLineId,
|
|
12590
|
+
memberId,
|
|
12591
|
+
threadId: wake.threadId,
|
|
12592
|
+
leadThreadId: team.scope.leadThreads?.[0] ?? "",
|
|
12593
|
+
wakeKey: wake.key,
|
|
12594
|
+
// 群记录的发件人取成员名(会话号 → 成员号 → 名单),读不到就退回 Lead / Member。
|
|
12595
|
+
// 名单在这一次摘要里只读一次:惰性缓存同一个 Promise,不随每条记录重读。
|
|
12596
|
+
nameOfThread: /* @__PURE__ */ (() => {
|
|
12597
|
+
let roster;
|
|
12598
|
+
return async (threadId) => {
|
|
12599
|
+
if (team.scope.memberIds?.[threadId] === void 0) return null;
|
|
12600
|
+
roster ??= goals.read(wake.projectId, { forLine: team.workLineId });
|
|
12601
|
+
return findGoalMember((await roster)?.members ?? [], { threadId })?.name ?? null;
|
|
12602
|
+
};
|
|
12603
|
+
})()
|
|
12604
|
+
});
|
|
12605
|
+
const waiting = team === void 0 || !("threadId" in wake) || team.scope.leadThreads?.includes(wake.threadId) !== true || options.teamWaiting === void 0 ? null : await (async () => {
|
|
12606
|
+
const members = (await goals.read(wake.projectId, { forThread: wake.threadId }))?.members ?? [];
|
|
12607
|
+
return options.teamWaiting(
|
|
12608
|
+
team.scope.threads.filter((id) => id !== wake.threadId),
|
|
12609
|
+
(id) => findGoalMember(members, { threadId: id })?.name ?? id
|
|
12610
|
+
);
|
|
12611
|
+
})().catch(() => null);
|
|
12612
|
+
return {
|
|
12613
|
+
digest,
|
|
12614
|
+
text: async () => {
|
|
12615
|
+
const body = await baseText(wake, state);
|
|
12616
|
+
return [digest?.body, body, waiting].filter((part2) => part2 != null).join("\n\n");
|
|
12617
|
+
}
|
|
12618
|
+
};
|
|
12619
|
+
};
|
|
13121
12620
|
const execute = async () => {
|
|
13122
12621
|
let state = await wakes.get();
|
|
13123
12622
|
const isReady2 = options.readiness === void 0 ? () => true : await options.readiness();
|
|
@@ -13137,33 +12636,7 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13137
12636
|
try {
|
|
13138
12637
|
const id = hash2(wake.key);
|
|
13139
12638
|
const worktree = memberWorktreeFor(goals, state[wake.projectId], wake.projectId, wake);
|
|
13140
|
-
const
|
|
13141
|
-
const memberId2 = team === void 0 || !("threadId" in wake) ? void 0 : team.scope.memberIds?.[wake.threadId];
|
|
13142
|
-
const digest = team === void 0 || memberId2 === void 0 || !("threadId" in wake) || team.scope.leadThreads?.includes(wake.threadId) === true || options.groupDigest === void 0 ? null : await options.groupDigest.prepare({
|
|
13143
|
-
projectId: wake.projectId,
|
|
13144
|
-
workLineId: team.workLineId,
|
|
13145
|
-
memberId: memberId2,
|
|
13146
|
-
threadId: wake.threadId,
|
|
13147
|
-
leadThreadId: team.scope.leadThreads?.[0] ?? "",
|
|
13148
|
-
wakeKey: wake.key,
|
|
13149
|
-
// 群记录的发件人取成员名(会话号 → 成员号 → 名单),读不到就退回 Lead / Member。
|
|
13150
|
-
// 名单在这一次摘要里只读一次:惰性缓存同一个 Promise,不随每条记录重读。
|
|
13151
|
-
nameOfThread: /* @__PURE__ */ (() => {
|
|
13152
|
-
let roster;
|
|
13153
|
-
return async (threadId) => {
|
|
13154
|
-
if (team.scope.memberIds?.[threadId] === void 0) return null;
|
|
13155
|
-
roster ??= goals.read(wake.projectId, { forLine: team.workLineId });
|
|
13156
|
-
return findGoalMember((await roster)?.members ?? [], { threadId })?.name ?? null;
|
|
13157
|
-
};
|
|
13158
|
-
})()
|
|
13159
|
-
});
|
|
13160
|
-
const waiting = team === void 0 || !("threadId" in wake) || team.scope.leadThreads?.includes(wake.threadId) !== true || options.teamWaiting === void 0 ? null : await (async () => {
|
|
13161
|
-
const members = (await goals.read(wake.projectId, { forThread: wake.threadId }))?.members ?? [];
|
|
13162
|
-
return options.teamWaiting(
|
|
13163
|
-
team.scope.threads.filter((id2) => id2 !== wake.threadId),
|
|
13164
|
-
(id2) => findGoalMember(members, { threadId: id2 })?.name ?? id2
|
|
13165
|
-
);
|
|
13166
|
-
})().catch(() => null);
|
|
12639
|
+
const { digest, text } = await compose(wake, state);
|
|
13167
12640
|
const delivered = await deliverWake(ctx, {
|
|
13168
12641
|
projectId: wake.projectId,
|
|
13169
12642
|
recipient: wake,
|
|
@@ -13171,12 +12644,7 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13171
12644
|
messageId: `team-wake-msg:${id}`,
|
|
13172
12645
|
wake: { reason: "work", sequenceId: wake.sequenceId },
|
|
13173
12646
|
memberWorktree: worktree === void 0 ? void 0 : { ...worktree, lane: worktrees },
|
|
13174
|
-
|
|
13175
|
-
...wake.kind === "comment" ? { steer: true } : {},
|
|
13176
|
-
text: async () => {
|
|
13177
|
-
const body = await baseText(wake, state);
|
|
13178
|
-
return [digest?.body, body, waiting].filter((part2) => part2 != null).join("\n\n");
|
|
13179
|
-
}
|
|
12647
|
+
text
|
|
13180
12648
|
});
|
|
13181
12649
|
if (!delivered) continue;
|
|
13182
12650
|
if (digest !== null) await options.groupDigest.confirm(wake.projectId, digest);
|
|
@@ -13212,7 +12680,73 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13212
12680
|
});
|
|
13213
12681
|
const ready = flush();
|
|
13214
12682
|
void ready.catch((error) => ctx.log?.warn("team wake catch-up failed", { error }));
|
|
13215
|
-
return { flush, ready, state: wakes, worktrees };
|
|
12683
|
+
return { flush, ready, state: wakes, worktrees, compose };
|
|
12684
|
+
}
|
|
12685
|
+
|
|
12686
|
+
// src/runtime/wakeSupplement.ts
|
|
12687
|
+
var decodeDispatched2 = decodeUnknownOption2(
|
|
12688
|
+
Struct({ projectId: String4, threadId: String4 })
|
|
12689
|
+
);
|
|
12690
|
+
function registerWakeSupplement(ctx, wakes, groupDigest) {
|
|
12691
|
+
const add3 = async (input) => {
|
|
12692
|
+
const state = await wakes.state.get({ throughSequence: input.throughSequence });
|
|
12693
|
+
const project2 = readFact(state, input.projectId);
|
|
12694
|
+
if (project2 === null || lineScopeOfThread(project2, input.threadId) === void 0) return null;
|
|
12695
|
+
const decision = teamItemDecision(project2, input.projectId, input.workItemId, input.threadId);
|
|
12696
|
+
if (decision.kind === "held")
|
|
12697
|
+
throw new Error(`the team cannot hand this work item over now: ${decision.reason}`);
|
|
12698
|
+
const { text } = await wakes.compose(decision.wake, state);
|
|
12699
|
+
return text();
|
|
12700
|
+
};
|
|
12701
|
+
ctx.reactor({
|
|
12702
|
+
name: "team-board-handover",
|
|
12703
|
+
events: ["work.item-dispatched"],
|
|
12704
|
+
handle: async (event) => {
|
|
12705
|
+
const decoded = decodeDispatched2(event.payload);
|
|
12706
|
+
if (isNone2(decoded) || groupDigest === void 0) return;
|
|
12707
|
+
await groupDigest.confirmPrepared(decoded.value.projectId, decoded.value.threadId);
|
|
12708
|
+
}
|
|
12709
|
+
});
|
|
12710
|
+
return ctx.operations.supplement({ operations: ["work.dispatch"], add: add3 });
|
|
12711
|
+
}
|
|
12712
|
+
|
|
12713
|
+
// src/runtime/worktreeSetup.ts
|
|
12714
|
+
var WORKTREE_SETUP_TEXT = "You joined this team. Before your first work item, get your own worktree ready. The work item arrives in a separate message, so do not look for work yet.";
|
|
12715
|
+
function startWorktreeSetupRuntime(ctx, deps) {
|
|
12716
|
+
const requested = /* @__PURE__ */ new Map();
|
|
12717
|
+
let running = Promise.resolve();
|
|
12718
|
+
const setUp = async (projectId, threadId) => {
|
|
12719
|
+
const project2 = (await deps.wakes.get())[projectId];
|
|
12720
|
+
const worktree = memberWorktreeFor(deps.goals, project2, projectId, { threadId });
|
|
12721
|
+
if (worktree === void 0 || worktree.failure !== void 0) return;
|
|
12722
|
+
const execution = await ctx.projections.getThreadExecution(threadId);
|
|
12723
|
+
if (execution === null || execution.archivedAt !== null || execution.worktreePath) return;
|
|
12724
|
+
const id = stableHash(threadId);
|
|
12725
|
+
await deliverWake(ctx, {
|
|
12726
|
+
projectId,
|
|
12727
|
+
recipient: { threadId },
|
|
12728
|
+
requestId: `team-worktree-setup:${id}`,
|
|
12729
|
+
messageId: `team-worktree-setup-msg:${id}`,
|
|
12730
|
+
wake: { reason: "notice" },
|
|
12731
|
+
memberWorktree: { ...worktree, lane: deps.lane },
|
|
12732
|
+
text: WORKTREE_SETUP_TEXT
|
|
12733
|
+
});
|
|
12734
|
+
};
|
|
12735
|
+
const drain = async () => {
|
|
12736
|
+
for (const [key, entry] of requested) {
|
|
12737
|
+
requested.delete(key);
|
|
12738
|
+
try {
|
|
12739
|
+
await setUp(entry.projectId, entry.threadId);
|
|
12740
|
+
} catch (error) {
|
|
12741
|
+
ctx.log.warn("team member worktree setup failed", { ...entry, error });
|
|
12742
|
+
}
|
|
12743
|
+
}
|
|
12744
|
+
};
|
|
12745
|
+
const request = (projectId, threadId) => {
|
|
12746
|
+
requested.set(`${projectId}|${threadId}`, { projectId, threadId });
|
|
12747
|
+
running = running.then(drain, drain);
|
|
12748
|
+
};
|
|
12749
|
+
return { request, idle: () => running };
|
|
13216
12750
|
}
|
|
13217
12751
|
|
|
13218
12752
|
// src/runtime/recovery.ts
|
|
@@ -13863,7 +13397,7 @@ var emptyHandbookProject = () => ({
|
|
|
13863
13397
|
acknowledgements: {},
|
|
13864
13398
|
reminded: {}
|
|
13865
13399
|
});
|
|
13866
|
-
var
|
|
13400
|
+
var decodeFact5 = decodeUnknownOption2(
|
|
13867
13401
|
Union2([
|
|
13868
13402
|
factEnvelope("goal-started", GoalStartedFact),
|
|
13869
13403
|
factEnvelope("member-bound", MemberBoundFact),
|
|
@@ -13947,7 +13481,7 @@ function foldHandbook(state, event) {
|
|
|
13947
13481
|
};
|
|
13948
13482
|
}
|
|
13949
13483
|
if (event.type !== "plugin.event-appended") return state;
|
|
13950
|
-
const decoded =
|
|
13484
|
+
const decoded = decodeFact5(event.payload);
|
|
13951
13485
|
if (isNone2(decoded)) return state;
|
|
13952
13486
|
const fact = decoded.value;
|
|
13953
13487
|
const projectId = fact.name === "team/goal-started" ? fact.data.goal.projectId : fact.name === "team/roster-set" ? fact.data.roster.projectId : fact.data.projectId;
|
|
@@ -14831,12 +14365,6 @@ var LineChangeCompleted = Struct({
|
|
|
14831
14365
|
])
|
|
14832
14366
|
});
|
|
14833
14367
|
|
|
14834
|
-
// src/messages.ts
|
|
14835
|
-
var interpolateMessage = (template, values) => template.replace(
|
|
14836
|
-
/{{(\w+)}}/g,
|
|
14837
|
-
(whole, name) => Object.hasOwn(values, name) ? String(values[name]) : whole
|
|
14838
|
-
);
|
|
14839
|
-
|
|
14840
14368
|
// src/team/messages.ts
|
|
14841
14369
|
function teamMessage(key, values = {}) {
|
|
14842
14370
|
return interpolateMessage(en_default.team[key], values);
|
|
@@ -14991,7 +14519,7 @@ function teamLeadBrief(team) {
|
|
|
14991
14519
|
'Then use work_add_relation with type "blocked_by" to record dependencies: the dependent workItemId is blocked by the prerequisite relatedWorkItemId.',
|
|
14992
14520
|
LEAD_OWN_ITEM_RULE,
|
|
14993
14521
|
memberAssignRule(true),
|
|
14994
|
-
"Add or remove members of the team with team_set_members. To add someone who is not in the project yet, create them first with team_create_member (it starts their trial run), then add them. Use team_roster_overview to see everyone in the project and which teams they are in; work_list_machines lists the other machines that joined this project and the providers and models each one offers
|
|
14522
|
+
"Add or remove members of the team with team_set_members. To add someone who is not in the project yet, create them first with team_create_member (it starts their trial run), then add them. Use team_roster_overview to see everyone in the project and which teams they are in; work_list_machines lists the other machines that joined this project and the providers and models each one offers; to place a member on one of them, pass its environmentId to team_create_member or team_update_member.",
|
|
14995
14523
|
LEAD_SEND_BACK_RULE,
|
|
14996
14524
|
LEAD_ACCEPT_RULE,
|
|
14997
14525
|
LEAD_STUCK_RULE,
|
|
@@ -15977,6 +15505,14 @@ function createGroupDigest(ctx, state) {
|
|
|
15977
15505
|
await state.get({ throughSequence: receipt.sequence });
|
|
15978
15506
|
return { digestId, threadId: input.threadId, body };
|
|
15979
15507
|
},
|
|
15508
|
+
/**
|
|
15509
|
+
* 引擎叫醒了这条会话(看板交件):随那次叫醒补充出去的那一份算已投递,水位前进。没有装配好的就什么也不做。
|
|
15510
|
+
*/
|
|
15511
|
+
async confirmPrepared(projectId, threadId) {
|
|
15512
|
+
const prepared = readFact(await state.get(), threadId)?.prepared;
|
|
15513
|
+
if (prepared == null) return;
|
|
15514
|
+
await this.confirm(projectId, { digestId: prepared.digestId, threadId, body: prepared.body });
|
|
15515
|
+
},
|
|
15980
15516
|
/** 叫醒已被宿主受理:水位前进。同一份只落一次。 */
|
|
15981
15517
|
async confirm(projectId, digest) {
|
|
15982
15518
|
const receipt = await ctx.events.append({
|
|
@@ -15998,6 +15534,10 @@ function createGroupDigest(ctx, state) {
|
|
|
15998
15534
|
|
|
15999
15535
|
// locales/zh-CN.json
|
|
16000
15536
|
var zh_CN_default = {
|
|
15537
|
+
presentation: {
|
|
15538
|
+
name: "\u56E2\u961F",
|
|
15539
|
+
description: "\u7ED9\u9879\u76EE\u56E2\u961F\u4E00\u4E2A\u76EE\u6807\uFF1A\u8D1F\u8D23\u4EBA\u5728\u770B\u677F\u4E0A\u62C6\u6D3B\uFF0C\u6D3E\u7ED9\u6210\u5458\u53BB\u505A\u3002"
|
|
15540
|
+
},
|
|
16001
15541
|
handbook: {
|
|
16002
15542
|
requestConflict: "\u8FD9\u4E2A requestId \u5DF2\u7528\u4E8E\u53E6\u4E00\u4EFD\u624B\u518C\u8BF7\u6C42\uFF0C\u8BF7\u6362\u4E00\u4E2A\u65B0\u7684 requestId\u3002",
|
|
16003
15543
|
requestVoided: "\u8FD9\u4E2A requestId \u5728\u624B\u518C\u6536\u5230\u4E4B\u524D\u5C31\u4F5C\u5E9F\u4E86\uFF0C\u8BF7\u6362\u4E00\u4E2A\u65B0\u7684 requestId\u3002",
|
|
@@ -16042,8 +15582,8 @@ var zh_CN_default = {
|
|
|
16042
15582
|
versionConflict: "\u56E2\u961F\u521A\u597D\u540C\u65F6\u88AB\u6539\u4E86\u3002\u91CD\u65B0\u8BFB\u4E00\u904D\uFF0C\u7528\u65B0\u7684 requestId \u518D\u8BD5\u3002"
|
|
16043
15583
|
},
|
|
16044
15584
|
coordinator: {
|
|
16045
|
-
createTool: '\u4EE5\u5F53\u524D\u76EE\u6807\u8D1F\u8D23\u4EBA\u7684\u8EAB\u4EFD\uFF0C\u7ED9\u8FD9\u4E2A\u9879\u76EE\u7684\u56E2\u961F\
|
|
16046
|
-
updateTool: "\u4EE5\u5F53\u524D\u76EE\u6807\u8D1F\u8D23\u4EBA\u7684\u8EAB\u4EFD\
|
|
15585
|
+
createTool: '\u4EE5\u5F53\u524D\u76EE\u6807\u8D1F\u8D23\u4EBA\u7684\u8EAB\u4EFD\uFF0C\u7ED9\u8FD9\u4E2A\u9879\u76EE\u7684\u56E2\u961F\u52A0\u4E00\u4E2A AI \u961F\u53CB\u3002requestId \u8981\u7528\u65B0\u7684\uFF0C\u53EA\u6709\u91CD\u8BD5\u540C\u4E00\u6B21\u8BF7\u6C42\u65F6\u624D\u6CBF\u7528\u3002\u6210\u5458\u8DD1\u5728\u8FD9\u53F0\u673A\u5668\u4E0A\uFF0C\u9664\u975E\u4F60\u7ED9 environmentId\uFF1A\u52A0\u8FDB\u8FD9\u4E2A\u9879\u76EE\u7684\u53E6\u4E00\u53F0\u673A\u5668\uFF08work_list_machines \u5217\u51FA\u8FD9\u4E9B\u673A\u5668\u548C\u5404\u81EA\u63D0\u4F9B\u7684 provider\uFF09\u3002provider \u7684 instanceId \u548C model \u8981\u4E48\u90FD\u7ED9\uFF0C\u8981\u4E48\u90FD\u4E0D\u7ED9\uFF1B\u5728\u8FD9\u53F0\u673A\u5668\u4E0A\u4E0D\u7ED9\u5C31\u7528\u9879\u76EE\u7684\u9ED8\u8BA4\u6A21\u578B\uFF0C\u5728\u522B\u7684\u673A\u5668\u4E0A\u5FC5\u987B\u7ED9\uFF0C\u800C\u4E14\u5FC5\u987B\u662F\u90A3\u53F0\u673A\u5668\u62A5\u6765\u7684\u3001\u5DF2\u5C31\u7EEA\u7684 provider \u5B9E\u4F8B\u3002\u65B0\u6210\u5458\u52A0\u5165\u5F53\u524D\u76EE\u6807\uFF0C\u5728\u4F60\u7684\u4F1A\u8BDD\u540D\u4E0B\u5F97\u5230\u81EA\u5DF1\u7684\u4F1A\u8BDD\uFF0C\u901A\u5E38\u7247\u523B\u5C31\u597D\uFF08\u5931\u8D25\u4F1A\u544A\u8BC9\u4F60\u539F\u56E0\uFF0C\u5E76\u6BCF\u9694\u51E0\u5206\u949F\u91CD\u8BD5\uFF09\uFF1B\u5728 team_open \u5F00\u7684\u56E2\u961F\u91CC\uFF0C\u8981\u7B49\u4F60\u7528 team_set_members \u628A\u5B83\u62C9\u8FDB\u6765\u624D\u5F00\u59CB\uFF1B\u5C31\u7EEA\u540E\u53EF\u4EE5\u7528 work_update_item \u5E76\u5E26 assignees [{ "kind": "member", "memberId": <\u8FD9\u4E2A\u5DE5\u5177\u8FD4\u56DE\u7684 memberId> }] \u7ED9\u5B83\u6D3E\u6D3B\u3002\u5148\u7528 work_list_members \u770B\u56E2\u961F\u91CC\u6709\u8C01\u3002',
|
|
15586
|
+
updateTool: "\u4EE5\u5F53\u524D\u76EE\u6807\u8D1F\u8D23\u4EBA\u7684\u8EAB\u4EFD\u6539\u4E00\u4E2A\u961F\u53CB\uFF1A\u540D\u5B57\u3001\u5934\u8854\u3001\u804C\u8D23\u3001\u5DE5\u4F5C\u8981\u6C42\uFF08\u7A7A\u5B57\u7B26\u4E32\u8868\u793A\u6E05\u7A7A\uFF09\u3001\u5B83\u8DD1\u5728\u54EA\u53F0\u673A\u5668\u4E0A\uFF08environmentId\uFF1A\u8FD9\u53F0\u673A\u5668\u7684\u53F7\uFF0C\u6216 work_list_machines \u91CC\u7684\u53E6\u4E00\u53F0\u673A\u5668\uFF09\uFF0C\u6216 provider \u7684 instanceId \u548C model\uFF08\u8981\u4E48\u90FD\u7ED9\uFF0C\u8981\u4E48\u90FD\u4E0D\u7ED9\uFF09\u3002\u4E0D\u7ED9 environmentId \u65F6\u6210\u5458\u7559\u5728\u539F\u6765\u7684\u673A\u5668\u4E0A\u3002\u632A\u5230\u53E6\u4E00\u53F0\u673A\u5668\u65F6\uFF0C\u53EA\u6709\u90A3\u53F0\u673A\u5668\u62A5\u4E86\u540C\u4E00\u4E2A\u5DF2\u5C31\u7EEA\u7684\u5B9E\u4F8B\u624D\u6CBF\u7528\u6210\u5458\u539F\u6765\u7684 provider \u5B9E\u4F8B\uFF1B\u5426\u5219\u540C\u65F6\u7ED9\u51FA\u90A3\u53F0\u673A\u5668\u4E0A\u7684 instanceId \u548C model\u3002\u65B0\u673A\u5668\u6216\u65B0\u6A21\u578B\u53EA\u5BF9\u4E4B\u540E\u5F00\u7684\u4F1A\u8BDD\u751F\u6548\uFF0C\u5DF2\u7ECF\u5728\u8DD1\u7684\u4F1A\u8BDD\u4FDD\u6301\u539F\u6765\u7684\u8BBE\u7F6E\u3002expectedVersion \u586B work_read_member \u8BFB\u5230\u7684\u6210\u5458\u7248\u672C\uFF1B\u7248\u672C\u53D8\u4E86\u4F1A\u5F97\u5230 stale-version\uFF0C\u91CD\u65B0\u8BFB\u4E00\u6B21\u6210\u5458\u3002\u4E0D\u80FD\u6539\u81EA\u5DF1\u7684\u673A\u5668\u3001provider \u548C\u6A21\u578B\u3002\u53EA\u6709\u91CD\u8BD5\u540C\u4E00\u6B21\u8BF7\u6C42\u65F6\u624D\u6CBF\u7528 requestId\u3002",
|
|
16047
15587
|
removeTool: "\u4EE5\u5F53\u524D\u76EE\u6807\u8D1F\u8D23\u4EBA\u7684\u8EAB\u4EFD\u628A\u4E00\u540D\u6210\u5458\u79FB\u51FA\u56E2\u961F\u3002\u8BB0\u5F55\u4F1A\u4FDD\u7559\uFF0C\u4EE5\u540E\u53EF\u4EE5\u6062\u590D\u3002\u6D3E\u7ED9\u5B83\u3001\u4F46\u8FD8\u6CA1\u5230\u5B83\u624B\u4E0A\u7684\u6D3B\u4F1A\u88AB\u6536\u56DE\u5E76\u901A\u77E5\u4F60\uFF1B\u5DF2\u7ECF\u5728\u5B83\u624B\u4E0A\u7684\u6D3B\u7559\u5728\u5B83\u90A3\u91CC\uFF0C\u7531\u4F60\u51B3\u5B9A\u3002\u4E0D\u80FD\u79FB\u9664\u81EA\u5DF1\u3002requestId \u53EA\u6709\u91CD\u8BD5\u540C\u4E00\u4E2A\u8BF7\u6C42\u65F6\u624D\u6CBF\u7528\u3002",
|
|
16048
15588
|
restoreTool: "\u4EE5\u5F53\u524D\u76EE\u6807\u8D1F\u8D23\u4EBA\u7684\u8EAB\u4EFD\u628A\u5DF2\u79FB\u9664\u7684\u6210\u5458\u8BF7\u56DE\u56E2\u961F\u3002requestId \u53EA\u6709\u91CD\u8BD5\u540C\u4E00\u4E2A\u8BF7\u6C42\u65F6\u624D\u6CBF\u7528\u3002",
|
|
16049
15589
|
noProject: "\u8FD9\u6B21\u8C03\u7528\u4E0D\u5C5E\u4E8E\u4EFB\u4F55\u9879\u76EE\uFF0C\u6CA1\u6709\u53EF\u6539\u7684\u56E2\u961F\u3002",
|
|
@@ -16061,7 +15601,12 @@ var zh_CN_default = {
|
|
|
16061
15601
|
notAgentMember: "\u8FD9\u4E2A\u5DE5\u5177\u53EA\u80FD\u6539 agent \u6210\u5458\u3002",
|
|
16062
15602
|
memberNotFound: "\u8FD9\u4E2A\u9879\u76EE\u91CC\u6CA1\u6709\u8FD9\u540D\u6210\u5458\u3002\u5148\u7528 work_list_members \u5217\u51FA\u6210\u5458\u3002",
|
|
16063
15603
|
cannotRemoveLead: "\u4E0D\u80FD\u79FB\u9664\u81EA\u5DF1\uFF08\u5F53\u524D\u76EE\u6807\u7684\u8D1F\u8D23\u4EBA\uFF09\u3002",
|
|
16064
|
-
cannotReplaceLead: "\u4E0D\u80FD\u6539\u81EA\u5DF1\u7684
|
|
15604
|
+
cannotReplaceLead: "\u4E0D\u80FD\u6539\u81EA\u5DF1\u7684\u673A\u5668\u3001provider \u548C\u6A21\u578B\u3002",
|
|
15605
|
+
machineNotInProject: "\u673A\u5668 {{environmentId}} \u4E0D\u5728\u8FD9\u4E2A\u9879\u76EE\u91CC\u3002\u8C03 work_list_machines \u770B\u52A0\u8FDB\u8FD9\u4E2A\u9879\u76EE\u7684\u673A\u5668\uFF0C\u6216\u8005\u4E0D\u7ED9 environmentId\uFF0C\u7528\u8FD9\u53F0\u673A\u5668\u3002",
|
|
15606
|
+
machineNeedsModel: "\u653E\u5728\u673A\u5668 {{environmentId}} \u4E0A\u7684\u6210\u5458\u8981\u7528\u90A3\u53F0\u673A\u5668\u4E0A\u7684 provider\u3002\u6309 work_list_machines \u5BF9\u90A3\u53F0\u673A\u5668\u62A5\u7684\u5185\u5BB9\u7ED9\u51FA instanceId \u548C model\u3002",
|
|
15607
|
+
machineInstanceNotFound: "\u673A\u5668 {{environmentId}} \u6CA1\u6709\u62A5 provider \u5B9E\u4F8B {{instanceId}}\u3002\u8C03 work_list_machines\uFF08\u5E26 includeModels\uFF09\uFF0C\u7ED9\u51FA\u90A3\u53F0\u673A\u5668\u62A5\u8FC7\u7684 instanceId \u548C model\u3002\u8FD9\u4EFD\u6E05\u5355\u662F\u90A3\u53F0\u673A\u5668\u4E0A\u6B21\u8FDE\u4E0A\u65F6\u62A5\u7684\uFF1A\u5982\u679C\u4E4B\u540E\u624D\u5728\u90A3\u53F0\u673A\u5668\u4E0A\u88C5\u597D\u8FD9\u4E2A provider\uFF0C\u8BF7\u4EBA\u91CD\u65B0\u8FDE\u63A5\u90A3\u53F0\u673A\u5668\uFF08\u6216\u91CD\u542F\u5B83\u4E0A\u9762\u7684 Ycodium\uFF09\u5237\u65B0\u6E05\u5355\uFF0C\u518D\u8C03 work_list_machines\u3002",
|
|
15608
|
+
machineInstanceNotReady: "\u673A\u5668 {{environmentId}} \u4E0A\u7684 provider \u5B9E\u4F8B {{instanceId}} \u8FD8\u4E0D\u80FD\u63A5\u6D3B\u3002\u8C03 work_list_machines \u6311\u4E00\u4E2A\u5DF2\u5C31\u7EEA\u7684\u5B9E\u4F8B\uFF0C\u6216\u8005\u8BF7\u4EBA\u5230\u90A3\u53F0\u673A\u5668\u4E0A\u628A\u8FD9\u4E2A provider \u4FEE\u597D\u3002\u5C31\u7EEA\u72B6\u6001\u662F\u90A3\u53F0\u673A\u5668\u4E0A\u6B21\u8FDE\u4E0A\u65F6\u62A5\u7684\uFF1A\u5982\u679C\u4E4B\u540E\u5DF2\u7ECF\u4FEE\u597D\uFF0C\u8BF7\u4EBA\u91CD\u65B0\u8FDE\u63A5\u90A3\u53F0\u673A\u5668\uFF08\u6216\u91CD\u542F\u5B83\u4E0A\u9762\u7684 Ycodium\uFF09\u5237\u65B0\u6E05\u5355\uFF0C\u518D\u8C03 work_list_machines\u3002",
|
|
15609
|
+
machinesUnavailable: "\u73B0\u5728\u8BFB\u4E0D\u51FA\u8FD9\u4E2A\u9879\u76EE\u7684\u673A\u5668\uFF0C\u7A0D\u540E\u518D\u8BD5\u3002"
|
|
16065
15610
|
},
|
|
16066
15611
|
board: {
|
|
16067
15612
|
openTeam: "\u5728\u770B\u677F\u4E0A\u6253\u5F00\u8FD9\u4E2A\u56E2\u961F",
|
|
@@ -16247,7 +15792,8 @@ var zh_CN_default = {
|
|
|
16247
15792
|
thisMachine: "\u8FD9\u53F0\u673A\u5668",
|
|
16248
15793
|
machineOffline: "{{name}}\uFF08\u79BB\u7EBF\uFF09",
|
|
16249
15794
|
machineRemoved: "\u5DF2\u79FB\u51FA\u9879\u76EE\u7684\u673A\u5668",
|
|
16250
|
-
noMachine: "\u8FD8\u6CA1\u9009\u673A\u5668"
|
|
15795
|
+
noMachine: "\u8FD8\u6CA1\u9009\u673A\u5668",
|
|
15796
|
+
machineJoining: "\u6B63\u5728\u628A {{name}} \u63A5\u5165\u8FD9\u4E2A\u9879\u76EE\u2026"
|
|
16251
15797
|
},
|
|
16252
15798
|
handbookPanel: {
|
|
16253
15799
|
title: "\u624B\u518C",
|
|
@@ -17224,7 +16770,7 @@ function startTrialRuntime(ctx, deps, options = {}) {
|
|
|
17224
16770
|
// src/index.ts
|
|
17225
16771
|
var index_default = definePlugin({
|
|
17226
16772
|
id: "team",
|
|
17227
|
-
apiVersion:
|
|
16773
|
+
apiVersion: 56,
|
|
17228
16774
|
activate(ctx) {
|
|
17229
16775
|
const trialState = ctx.derivedState(trialStateDefinition);
|
|
17230
16776
|
const rosters = createRosterService(ctx);
|
|
@@ -17256,7 +16802,19 @@ var index_default = definePlugin({
|
|
|
17256
16802
|
},
|
|
17257
16803
|
memberQueue
|
|
17258
16804
|
);
|
|
17259
|
-
|
|
16805
|
+
const worktreeSetup = startWorktreeSetupRuntime(ctx, {
|
|
16806
|
+
wakes: wakes.state,
|
|
16807
|
+
goals,
|
|
16808
|
+
lane: wakes.worktrees
|
|
16809
|
+
});
|
|
16810
|
+
registerDispatchGate(ctx, {
|
|
16811
|
+
wakes: wakes.state,
|
|
16812
|
+
goals,
|
|
16813
|
+
readiness,
|
|
16814
|
+
requestWorktree: worktreeSetup.request,
|
|
16815
|
+
now: () => runPromise2(map5(now2, toEpochMillis2))
|
|
16816
|
+
});
|
|
16817
|
+
registerWakeSupplement(ctx, wakes, groupDigest);
|
|
17260
16818
|
registerPauseCommands(ctx, { wakes: wakes.state, queue: memberQueue });
|
|
17261
16819
|
startArchiveMirror(
|
|
17262
16820
|
ctx,
|
|
@@ -17268,9 +16826,7 @@ var index_default = definePlugin({
|
|
|
17268
16826
|
rebindTargets: rebindReader(trialState)
|
|
17269
16827
|
});
|
|
17270
16828
|
startMemberRemovalRuntime(ctx, goals, wakes.state);
|
|
17271
|
-
|
|
17272
|
-
startGroupDeliveryRuntime(ctx, wakes.state);
|
|
17273
|
-
registerBoardCommands(ctx, goals, rosters, wakes.state);
|
|
16829
|
+
registerBoardCommands(ctx, goals, rosters);
|
|
17274
16830
|
startRecoveryRuntime(ctx, goals, wakes.state, wakes.worktrees);
|
|
17275
16831
|
startLeadCheckinRuntime(ctx, wakes.state, goals);
|
|
17276
16832
|
startProgressCheckinRuntime(ctx, goals, wakes.state);
|