@ycodium-ai/plugin-team 0.2.3681 → 0.2.3710
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 +7 -7
- package/dist/index.js +1472 -1964
- package/package.json +2 -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 });
|
|
@@ -9601,7 +9088,7 @@ function createGoalService(ctx, rosterService, options = {}) {
|
|
|
9601
9088
|
rosterMemberName(roster, member.memberId)
|
|
9602
9089
|
])
|
|
9603
9090
|
);
|
|
9604
|
-
const others =
|
|
9091
|
+
const others = await engineNames(
|
|
9605
9092
|
projectId,
|
|
9606
9093
|
execution.members.flatMap(
|
|
9607
9094
|
({ memberId }) => teamNames.get(memberId) === null ? [memberId] : []
|
|
@@ -10395,7 +9882,7 @@ function membersSnapshot(view, trialOf = () => null, viewer = null) {
|
|
|
10395
9882
|
name: machine.name,
|
|
10396
9883
|
online: machine.online,
|
|
10397
9884
|
...machine.lastSeenAt === void 0 ? {} : { lastSeenAt: machine.lastSeenAt },
|
|
10398
|
-
providers: machine.
|
|
9885
|
+
providers: readyProviders(machine).map((provider) => ({
|
|
10399
9886
|
instanceId: provider.instanceId,
|
|
10400
9887
|
displayName: provider.displayName,
|
|
10401
9888
|
models: provider.models.map(({ slug, name }) => ({ slug, name })),
|
|
@@ -10952,7 +10439,7 @@ function createMemberWriter(ctx, rosters, queue = createSerial()) {
|
|
|
10952
10439
|
const machines = missing2.some(({ member }) => member.principal !== void 0) ? [...(await readMachines(ctx, projectId))?.values() ?? []] : [];
|
|
10953
10440
|
const remoteAgentOf = (principalId) => {
|
|
10954
10441
|
const machine = machines.find((entry) => entry.principalId === principalId);
|
|
10955
|
-
const provider = machine
|
|
10442
|
+
const provider = machine === void 0 ? void 0 : readyProviders(machine)[0];
|
|
10956
10443
|
const model = provider?.defaultModel ?? provider?.models[0]?.slug;
|
|
10957
10444
|
return machine === void 0 || provider === void 0 || model === void 0 ? void 0 : {
|
|
10958
10445
|
environmentId: machine.environmentId,
|
|
@@ -10988,90 +10475,6 @@ function createMemberWriter(ctx, rosters, queue = createSerial()) {
|
|
|
10988
10475
|
return { create, update, remove, restore, importLegacy };
|
|
10989
10476
|
}
|
|
10990
10477
|
|
|
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
10478
|
// src/domain/pause.ts
|
|
11076
10479
|
var LinePausedEnvelope = factEnvelope(
|
|
11077
10480
|
"line-paused",
|
|
@@ -11119,11 +10522,6 @@ var decodeEnvelope2 = decodeUnknownOption2(
|
|
|
11119
10522
|
name: Literal2("team/member-woken"),
|
|
11120
10523
|
data: MemberWokenFact
|
|
11121
10524
|
}),
|
|
11122
|
-
Struct({
|
|
11123
|
-
pluginId: Literal2("team"),
|
|
11124
|
-
name: Literal2(COMMENT_MENTIONS_EVENT),
|
|
11125
|
-
data: CommentMentionsFact
|
|
11126
|
-
}),
|
|
11127
10525
|
MemberBoundEnvelope,
|
|
11128
10526
|
LinePausedEnvelope,
|
|
11129
10527
|
LineMemberPausedEnvelope,
|
|
@@ -11226,87 +10624,6 @@ var assigneeMembers = (principals) => [
|
|
|
11226
10624
|
...new Set(principals.flatMap((p) => p.kind === "member" ? [p.memberId] : []))
|
|
11227
10625
|
];
|
|
11228
10626
|
|
|
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
10627
|
// src/runtime/deliveryPacing.ts
|
|
11311
10628
|
function foldProgress(state, event) {
|
|
11312
10629
|
const decoded = decodeWorkEvent(event);
|
|
@@ -11375,148 +10692,478 @@ function createDeliveryPacing(progress, waitingOnSomeone2) {
|
|
|
11375
10692
|
return { observe, allows };
|
|
11376
10693
|
}
|
|
11377
10694
|
|
|
11378
|
-
// src/runtime/
|
|
11379
|
-
var
|
|
11380
|
-
|
|
11381
|
-
|
|
11382
|
-
|
|
11383
|
-
|
|
11384
|
-
|
|
11385
|
-
|
|
11386
|
-
|
|
11387
|
-
var
|
|
11388
|
-
|
|
11389
|
-
)
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
10695
|
+
// src/runtime/goalScopes.ts
|
|
10696
|
+
var isLinePaused = (project2, workLineId) => project2.linePauses?.[workLineId] === true;
|
|
10697
|
+
var isMemberPausedOnLine = (project2, workLineId, memberId) => (project2.pausedMembers?.[workLineId] ?? []).includes(memberId);
|
|
10698
|
+
var isLineStopped = (project2, workLineId) => workLineId !== void 0 && project2.lineStops?.[workLineId] !== void 0;
|
|
10699
|
+
var isLineGated = (project2, workLineId) => isLineStopped(project2, workLineId) || workLineId !== void 0 && isLinePaused(project2, workLineId);
|
|
10700
|
+
var scopesOf = (project2) => [
|
|
10701
|
+
project2,
|
|
10702
|
+
...Object.entries(project2.lineScopes ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([, scope2]) => scope2)
|
|
10703
|
+
];
|
|
10704
|
+
var scopeForLine = (project2, workLineId) => (workLineId === void 0 ? void 0 : project2.lineScopes?.[workLineId]) ?? project2;
|
|
10705
|
+
var scopeOfThread = (project2, threadId) => scopesOf(project2).find((scope2) => scope2.threads.includes(threadId));
|
|
10706
|
+
var teamSessions = (scope2) => [
|
|
10707
|
+
.../* @__PURE__ */ new Set([...scope2.threads, ...Object.keys(scope2.memberIds ?? {})])
|
|
10708
|
+
];
|
|
10709
|
+
var lineScopeOfThread = (project2, threadId) => {
|
|
10710
|
+
for (const [workLineId, scope2] of Object.entries(project2.lineScopes ?? {}))
|
|
10711
|
+
if (teamSessions(scope2).includes(threadId)) return { workLineId, scope: scope2 };
|
|
10712
|
+
return void 0;
|
|
10713
|
+
};
|
|
10714
|
+
var scopeOfPrincipal = (project2, principalId) => scopesOf(project2).find((scope2) => scope2.remoteMembers.includes(principalId));
|
|
10715
|
+
var isGoalThread = (project2, threadId) => scopeOfThread(project2, threadId) !== void 0;
|
|
10716
|
+
var isLeadThread = (project2, threadId) => scopesOf(project2).some((scope2) => scope2.leadThreads?.includes(threadId) === true);
|
|
10717
|
+
var isRemoteMember2 = (project2, principalId) => scopeOfPrincipal(project2, principalId) !== void 0;
|
|
10718
|
+
var leadOfThread = (project2, threadId) => scopeOfThread(project2, threadId)?.leadThreads?.[0];
|
|
10719
|
+
var placeOfRecipient = (project2, who, workLineId) => {
|
|
10720
|
+
if ("threadId" in who) {
|
|
10721
|
+
const line = lineScopeOfThread(project2, who.threadId);
|
|
10722
|
+
if (line !== void 0) return line;
|
|
10723
|
+
return project2.threads.includes(who.threadId) ? { scope: project2 } : void 0;
|
|
10724
|
+
}
|
|
10725
|
+
const own = workLineId === void 0 ? void 0 : project2.lineScopes?.[workLineId];
|
|
10726
|
+
if (workLineId !== void 0 && own?.remoteMembers.includes(who.principalId) === true)
|
|
10727
|
+
return { workLineId, scope: own };
|
|
10728
|
+
if (project2.remoteMembers.includes(who.principalId)) return { scope: project2 };
|
|
10729
|
+
const found = Object.entries(project2.lineScopes ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).find(([, scope2]) => scope2.remoteMembers.includes(who.principalId));
|
|
10730
|
+
return found === void 0 ? void 0 : { workLineId: found[0], scope: found[1] };
|
|
10731
|
+
};
|
|
10732
|
+
var scopeOfRecipient = (project2, who, workLineId) => placeOfRecipient(project2, who, workLineId)?.scope;
|
|
10733
|
+
var memberOfRecipientIn = (scope2, who) => {
|
|
10734
|
+
if ("threadId" in who) return scope2.memberIds?.[who.threadId];
|
|
10735
|
+
for (const [memberId, recipient] of Object.entries(scope2.bindings ?? {}))
|
|
10736
|
+
if ("principalId" in recipient && recipient.principalId === who.principalId) return memberId;
|
|
10737
|
+
return void 0;
|
|
10738
|
+
};
|
|
10739
|
+
var isRecipientGated = (project2, who, workLineId) => {
|
|
10740
|
+
const place = placeOfRecipient(project2, who, workLineId);
|
|
10741
|
+
if (place === void 0 || place.workLineId === void 0) return false;
|
|
10742
|
+
if (isLineGated(project2, place.workLineId)) return true;
|
|
10743
|
+
const member = memberOfRecipientIn(place.scope, who);
|
|
10744
|
+
return member !== void 0 && isMemberPausedOnLine(project2, place.workLineId, member);
|
|
10745
|
+
};
|
|
10746
|
+
var isThreadGated = (project2, threadId) => isRecipientGated(project2, { threadId });
|
|
10747
|
+
var teamLeadCandidates = (project2, memberId) => Object.entries(project2.lineScopes ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).flatMap(([workLineId, scope2]) => {
|
|
10748
|
+
const leadThreadId = scope2.leadThreads?.[0];
|
|
10749
|
+
return scope2.bindings?.[memberId] !== void 0 && leadThreadId !== void 0 && !isLineStopped(project2, workLineId) ? [{ workLineId, leadThreadId }] : [];
|
|
10750
|
+
});
|
|
10751
|
+
|
|
10752
|
+
// src/runtime/memberWaiting.ts
|
|
10753
|
+
var readMemberExecution = async (ctx, threadId, known) => {
|
|
10754
|
+
const shell = await ctx.threads.get({ threadId });
|
|
10755
|
+
const summary = known ?? await ctx.threads.execution.summary({ threadId, limit: 1 });
|
|
10756
|
+
return { ...shell, queuePaused: summary.queuePaused, summary };
|
|
10757
|
+
};
|
|
10758
|
+
var waitingOnSomeone = (execution) => execution.summary.queuePaused || execution.summary.pendingApprovalCount > 0 || execution.summary.pendingUserInputCount > 0 || (execution.pendingAsyncQuestionCount ?? 0) > 0 || (execution.awaitingPersonReplyCount ?? 0) > 0;
|
|
10759
|
+
|
|
10760
|
+
// src/runtime/wakeQueries.ts
|
|
10761
|
+
function memberWorktreeFor(goals, project2, projectId, recipient) {
|
|
10762
|
+
if (!("threadId" in recipient) || project2 === void 0) return;
|
|
10763
|
+
const { threadId } = recipient;
|
|
10764
|
+
const scope2 = scopeOfThread(project2, threadId);
|
|
10765
|
+
if (scope2 === void 0 || scope2.leadThreads?.includes(threadId)) return;
|
|
10766
|
+
const leadThreadId = scope2.leadThreads?.[0];
|
|
10767
|
+
if (leadThreadId === void 0) return;
|
|
10768
|
+
return {
|
|
10769
|
+
leadThreadId,
|
|
10770
|
+
failure: project2.worktreeFailures?.[threadId],
|
|
10771
|
+
// 只在要建树或报失败时读目标取名字,叫醒的热路径不多读。
|
|
10772
|
+
name: async () => (await goals.read(projectId, { forThread: threadId }))?.members.find(
|
|
10773
|
+
(member) => member.threadId === threadId
|
|
10774
|
+
)?.name ?? scope2.memberIds?.[threadId] ?? threadId
|
|
10775
|
+
};
|
|
10776
|
+
}
|
|
10777
|
+
var compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
10778
|
+
var compareWakeItems = (a, b) => a.sequenceId - b.sequenceId || compare(a.workItemId, b.workItemId);
|
|
10779
|
+
var OPEN_ITEM_GROUPS = ["backlog", "unstarted", "started"];
|
|
10780
|
+
var isClosed = (item) => item?.stateGroup === "completed" || item?.stateGroup === "cancelled";
|
|
10781
|
+
var hasOpenBlocker = (project2, workItemId) => (readFact(project2.blockers, workItemId) ?? []).some(
|
|
10782
|
+
(blocker) => !isClosed(readFact(project2.items, blocker))
|
|
10783
|
+
);
|
|
10784
|
+
var isAssignedOpen = (project2, workItemId, threadId) => {
|
|
10785
|
+
const item = readFact(project2.items, workItemId);
|
|
10786
|
+
return item !== null && item !== void 0 && !isClosed(item) && item.assigneeThreads.includes(threadId);
|
|
10787
|
+
};
|
|
10788
|
+
var isWorkable = (project2, workItemId) => !isClosed(readFact(project2.items, workItemId)) && !hasOpenBlocker(project2, workItemId);
|
|
10789
|
+
var isOpenWorkFor = (project2, workItemId, threadId) => isAssignedOpen(project2, workItemId, threadId) && !hasOpenBlocker(project2, workItemId);
|
|
10790
|
+
var isHandedOver = (item, threadId) => {
|
|
10791
|
+
if (item.stateGroup === "started") return true;
|
|
10792
|
+
const status = threadId === void 0 ? void 0 : item.wakeStatus?.[threadId];
|
|
10793
|
+
return status === "active" || status === "released";
|
|
10794
|
+
};
|
|
10795
|
+
var memberOfThread = (item, threadId) => {
|
|
10796
|
+
for (const [memberId, thread] of Object.entries(item.memberThreads ?? {}))
|
|
10797
|
+
if (thread === threadId) return memberId;
|
|
10798
|
+
return void 0;
|
|
10799
|
+
};
|
|
10800
|
+
var isPinnedTo = (item, threadId) => !isClosed(item) && memberOfThread(item, threadId) !== void 0 && isHandedOver(item, threadId);
|
|
10801
|
+
var hasPinnedOpenItem = (project2, threadId) => Object.values(project2.items).some((item) => isPinnedTo(item, threadId));
|
|
10802
|
+
var pinnedThreadsOf = (item) => Object.values(item.memberThreads ?? {}).filter((threadId) => isPinnedTo(item, threadId));
|
|
10803
|
+
var pinnedOpenThreads = (project2) => {
|
|
10804
|
+
const threads = /* @__PURE__ */ new Set();
|
|
10805
|
+
for (const item of Object.values(project2.items))
|
|
10806
|
+
for (const threadId of pinnedThreadsOf(item)) threads.add(threadId);
|
|
10807
|
+
return threads;
|
|
10808
|
+
};
|
|
10809
|
+
var memberLookup = (project2) => {
|
|
10810
|
+
let pinned;
|
|
10811
|
+
return (threadId) => isGoalThread(project2, threadId) || (pinned ??= pinnedOpenThreads(project2)).has(threadId);
|
|
10812
|
+
};
|
|
10813
|
+
var isMember = (project2, recipient) => "threadId" in recipient ? isGoalThread(project2, recipient.threadId) || hasPinnedOpenItem(project2, recipient.threadId) : isRemoteMember2(project2, recipient.principalId);
|
|
10814
|
+
var isQueuedUnclaimed = (item, threadId) => item.wakeStatus?.[threadId] === "pending" && !item.claimedBy.includes(threadId);
|
|
10815
|
+
var isDeferredWake = (project2, item, threadId) => isGoalThread(project2, threadId) && !isLeadThread(project2, threadId) && item.assigneeThreads.includes(threadId) && isQueuedUnclaimed(item, threadId) && !isClosed(item);
|
|
10816
|
+
function countDeferredWakes(project2, threadId) {
|
|
10817
|
+
let count2 = 0;
|
|
10818
|
+
for (const workItemId in project2.items) {
|
|
10819
|
+
const item = readFact(project2.items, workItemId);
|
|
10820
|
+
if (item !== null && isDeferredWake(project2, item, threadId)) count2++;
|
|
10821
|
+
}
|
|
10822
|
+
return count2;
|
|
10823
|
+
}
|
|
10824
|
+
var exemptFromTrial = (project2, recipient, workItemId) => {
|
|
10825
|
+
if (project2 === void 0 || !("threadId" in recipient)) return false;
|
|
10826
|
+
if (isLeadThread(project2, recipient.threadId)) return true;
|
|
10827
|
+
if (workItemId === void 0) return false;
|
|
10828
|
+
const item = readFact(project2.items, workItemId);
|
|
10829
|
+
return item !== null && item !== void 0 && pinnedThreadsOf(item).includes(recipient.threadId);
|
|
10830
|
+
};
|
|
10831
|
+
function memberOfRecipient(project2, recipient) {
|
|
10832
|
+
if (project2 === void 0) return void 0;
|
|
10833
|
+
const key = recipientKey(recipient);
|
|
10834
|
+
for (const scope2 of scopesOf(project2))
|
|
10835
|
+
for (const [memberId, bound] of Object.entries(scope2.bindings ?? {}))
|
|
10836
|
+
if (recipientKey(bound) === key) return memberId;
|
|
10837
|
+
return void 0;
|
|
10838
|
+
}
|
|
10839
|
+
function executorOf(project2, workItemId, memberId) {
|
|
10840
|
+
if (project2 === void 0) return void 0;
|
|
10841
|
+
const item = readFact(project2.items, workItemId);
|
|
10842
|
+
const target = targetOf(
|
|
10843
|
+
scopeForLine(project2, item?.workLineId).bindings,
|
|
10844
|
+
{ kind: "member", memberId },
|
|
10845
|
+
item?.memberThreads
|
|
10846
|
+
);
|
|
10847
|
+
if (target === void 0) return void 0;
|
|
10848
|
+
if ("threadId" in target && isLeadThread(project2, target.threadId)) return void 0;
|
|
10849
|
+
return isMember(project2, target) ? target : void 0;
|
|
10850
|
+
}
|
|
10851
|
+
|
|
10852
|
+
// src/runtime/reviewWakes.ts
|
|
10853
|
+
var decodeCompletion = decodeUnknownOption2(
|
|
10854
|
+
Struct({
|
|
10855
|
+
projectId: String4,
|
|
10856
|
+
workItemId: String4,
|
|
10857
|
+
state: Struct({ group: String4 }),
|
|
10858
|
+
actor: Union2([
|
|
10859
|
+
Struct({ kind: Literal2("agent"), threadId: String4 }),
|
|
10860
|
+
Struct({ kind: Literal2("remote-agent"), principalId: String4 })
|
|
10861
|
+
])
|
|
10862
|
+
})
|
|
10863
|
+
);
|
|
10864
|
+
var openLeadItemsBlockedBy = (project2, workItemId, lead) => lead === void 0 ? [] : Object.entries(project2.items).filter(
|
|
10865
|
+
([id]) => isAssignedOpen(project2, id, lead) && readFact(project2.blockers, id)?.includes(workItemId) === true
|
|
10866
|
+
);
|
|
10867
|
+
function reviewOnUpdate(previous, next, event) {
|
|
10868
|
+
const decoded = decodeCompletion(event.payload);
|
|
10869
|
+
if (isNone2(decoded) || decoded.value.state.group !== "completed") return null;
|
|
10870
|
+
const { projectId, workItemId, actor } = decoded.value;
|
|
10871
|
+
if (readFact(previous.items, workItemId)?.stateGroup === "completed") return null;
|
|
10872
|
+
const by = actor.kind === "agent" ? { threadId: actor.threadId } : { principalId: actor.principalId };
|
|
10873
|
+
const lead = scopeOfRecipient(next, by, readFact(next.items, workItemId)?.workLineId)?.leadThreads?.[0] ?? next.leadThreads?.[0];
|
|
10874
|
+
if (lead === void 0) return null;
|
|
10875
|
+
if (!isMember(next, by) || "threadId" in by && isLeadThread(next, by.threadId)) return null;
|
|
10876
|
+
const goals = openLeadItemsBlockedBy(next, workItemId, lead);
|
|
10877
|
+
if (goals.length === 0 || goals.some(([id]) => isWorkable(next, id))) return null;
|
|
10878
|
+
return {
|
|
10879
|
+
key: `review:${workItemId}:${lead}#${event.sequence}`,
|
|
10880
|
+
projectId,
|
|
10881
|
+
workItemId,
|
|
10882
|
+
threadId: lead,
|
|
10883
|
+
by
|
|
10884
|
+
};
|
|
10885
|
+
}
|
|
10886
|
+
var isLiveReview = (project2, review) => isLeadThread(project2, review.threadId) && readFact(project2.items, review.workItemId)?.stateGroup === "completed" && openLeadItemsBlockedBy(project2, review.workItemId, review.threadId).length > 0;
|
|
10887
|
+
var isReviewDue = (project2, key) => project2.pendingReviews?.some((review) => review.key === key && isLiveReview(project2, review)) === true;
|
|
10888
|
+
var dueReviews = (project2) => (project2.pendingReviews ?? []).filter((review) => isLiveReview(project2, review)).map((review) => {
|
|
10889
|
+
const item = readFact(project2.items, review.workItemId);
|
|
10890
|
+
return {
|
|
10891
|
+
...review,
|
|
10892
|
+
kind: "review",
|
|
10893
|
+
lead: true,
|
|
10894
|
+
...item === null ? {} : { sequenceId: item.sequenceId }
|
|
10895
|
+
};
|
|
10896
|
+
});
|
|
10897
|
+
function pruneReviews(previous, state) {
|
|
10898
|
+
let next = state;
|
|
10899
|
+
for (const [projectId, project2] of Object.entries(state)) {
|
|
10900
|
+
const pending = project2.pendingReviews;
|
|
10901
|
+
if (pending === void 0 || pending.length === 0) continue;
|
|
10902
|
+
const before = previous[projectId];
|
|
10903
|
+
if (before !== void 0 && before.leadThreads === project2.leadThreads && before.lineScopes === project2.lineScopes && before.items === project2.items && before.blockers === project2.blockers)
|
|
10904
|
+
continue;
|
|
10905
|
+
const live = pending.filter((review) => isLiveReview(project2, review));
|
|
10906
|
+
if (live.length !== pending.length)
|
|
10907
|
+
next = { ...next, [projectId]: { ...project2, pendingReviews: live } };
|
|
10908
|
+
}
|
|
10909
|
+
return next;
|
|
10910
|
+
}
|
|
10911
|
+
function reviewFacts(project2, queues, lead) {
|
|
10912
|
+
const { busy, waiting } = queues;
|
|
10913
|
+
const team = scopeOfThread(project2, lead)?.threads ?? project2.threads;
|
|
10914
|
+
return {
|
|
10915
|
+
idle: team.filter(
|
|
10916
|
+
(threadId) => !isLeadThread(project2, threadId) && !busy.has(threadId) && (waiting.get(threadId) ?? []).length === 0
|
|
10917
|
+
),
|
|
10918
|
+
queued: [...busy].filter((threadId) => team.includes(threadId)).flatMap(
|
|
10919
|
+
(threadId) => [...waiting.get(threadId) ?? []].sort(compareWakeItems).map(({ workItemId, sequenceId }) => ({ workItemId, sequenceId, threadId }))
|
|
10920
|
+
)
|
|
10921
|
+
};
|
|
10922
|
+
}
|
|
10923
|
+
|
|
10924
|
+
// src/runtime/wakeDue.ts
|
|
10925
|
+
var itemWakeKey = (workItemId, threadId, generation) => generation === 0 ? `item:${workItemId}:${threadId}` : `item:${workItemId}:${threadId}#${generation}`;
|
|
10926
|
+
var unblockedWakeKey = (workItemId, threadId, generation) => `unblocked:${workItemId}:${threadId}#${generation}`;
|
|
10927
|
+
var compare2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
10928
|
+
var itemWakeCandidate = (projectId, project2, workItemId, item, threadId, woken, isMemberThread) => {
|
|
10929
|
+
if (!isWorkable(project2, workItemId) || !isMemberThread(threadId)) return null;
|
|
10930
|
+
if (isThreadGated(project2, threadId)) return null;
|
|
10931
|
+
const unblocked = readFact(project2.blockedAfterClaim, workItemId) ?? 0;
|
|
10932
|
+
const finishing = unblocked > 0 && item.claimedBy.includes(threadId);
|
|
10933
|
+
if (!finishing && !item.assigneeThreads.includes(threadId)) return null;
|
|
10934
|
+
const lead = isLeadThread(project2, threadId);
|
|
10935
|
+
const leadThreadId = leadOfThread(project2, threadId);
|
|
10936
|
+
const key = finishing ? unblockedWakeKey(workItemId, threadId, unblocked) : itemWakeKey(workItemId, threadId, readFact(project2.rearms, `${workItemId}:${threadId}`) ?? 0);
|
|
10937
|
+
if (woken.has(key) || !finishing && !lead && item.wakeStatus?.[threadId] === "released")
|
|
10938
|
+
return null;
|
|
10939
|
+
const memberId = finishing ? void 0 : memberOfThread(item, threadId);
|
|
10940
|
+
return {
|
|
10941
|
+
key,
|
|
10942
|
+
projectId,
|
|
10943
|
+
threadId,
|
|
10944
|
+
kind: finishing ? "unblocked" : "item",
|
|
10945
|
+
workItemId,
|
|
10946
|
+
sequenceId: item.sequenceId,
|
|
10947
|
+
...memberId === void 0 ? {} : { memberId },
|
|
10948
|
+
// 成员的叫醒话里点名负责人(卡住时找谁);带队自己和解挡续做不带。
|
|
10949
|
+
...lead ? { lead: true } : finishing || leadThreadId === void 0 ? {} : { leadThreadId }
|
|
10950
|
+
};
|
|
10951
|
+
};
|
|
10952
|
+
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;
|
|
10953
|
+
var wakeGated = (project2, wake) => isRecipientGated(project2, wake, readFact(project2.items, wake.workItemId)?.workLineId);
|
|
10954
|
+
var needsMemberSlot = (wake) => wake.kind === "item" && wake.lead !== true;
|
|
10955
|
+
function memberQueues(projectId, project2, woken = new Set(project2.woken), onlyThreadId) {
|
|
10956
|
+
const isMemberThread = memberLookup(project2);
|
|
10957
|
+
const busy = /* @__PURE__ */ new Set();
|
|
10958
|
+
const waiting = /* @__PURE__ */ new Map();
|
|
10959
|
+
for (const [workItemId, item] of Object.entries(project2.items)) {
|
|
10960
|
+
if (onlyThreadId !== void 0 && !item.assigneeThreads.includes(onlyThreadId)) continue;
|
|
10961
|
+
if (!isWorkable(project2, workItemId)) continue;
|
|
10962
|
+
for (const threadId of item.assigneeThreads) {
|
|
10963
|
+
if (onlyThreadId !== void 0 && threadId !== onlyThreadId || isLeadThread(project2, threadId) || !isMemberThread(threadId))
|
|
10964
|
+
continue;
|
|
10965
|
+
if (item.wakeStatus?.[threadId] === "active") busy.add(threadId);
|
|
10966
|
+
const candidate = itemWakeCandidate(
|
|
10967
|
+
projectId,
|
|
10968
|
+
project2,
|
|
10969
|
+
workItemId,
|
|
10970
|
+
item,
|
|
10971
|
+
threadId,
|
|
10972
|
+
woken,
|
|
10973
|
+
isMemberThread
|
|
10974
|
+
);
|
|
10975
|
+
if (candidate === null || !needsMemberSlot(candidate)) continue;
|
|
10976
|
+
const queue = waiting.get(threadId);
|
|
10977
|
+
if (queue === void 0) waiting.set(threadId, [candidate]);
|
|
10978
|
+
else queue.push(candidate);
|
|
10979
|
+
}
|
|
10980
|
+
}
|
|
10981
|
+
return { busy, waiting };
|
|
10982
|
+
}
|
|
10983
|
+
function memberItemSlots(projectId, project2, woken, onlyThreadId) {
|
|
10984
|
+
const { busy, waiting } = memberQueues(projectId, project2, woken, onlyThreadId);
|
|
10985
|
+
const slots = /* @__PURE__ */ new Map();
|
|
10986
|
+
for (const [threadId, candidates] of waiting)
|
|
10987
|
+
if (!busy.has(threadId))
|
|
10988
|
+
slots.set(
|
|
10989
|
+
threadId,
|
|
10990
|
+
candidates.reduce(
|
|
10991
|
+
(first, candidate) => compareWakeItems(candidate, first) < 0 ? candidate : first
|
|
10992
|
+
)
|
|
10993
|
+
);
|
|
10994
|
+
return slots;
|
|
10995
|
+
}
|
|
10996
|
+
function isWakeDue(state, wake) {
|
|
10997
|
+
const project2 = readFact(state, wake.projectId);
|
|
10998
|
+
if (project2 === null || engineDispatches(project2, wake)) return false;
|
|
10999
|
+
if (wake.kind === "review")
|
|
11000
|
+
return isReviewDue(project2, wake.key) && !wakeGated(project2, wake);
|
|
11001
|
+
if (!("threadId" in wake)) return false;
|
|
11002
|
+
const item = readFact(project2.items, wake.workItemId);
|
|
11003
|
+
if (item === null) return false;
|
|
11004
|
+
const woken = new Set(project2.woken);
|
|
11005
|
+
const candidate = itemWakeCandidate(
|
|
11006
|
+
wake.projectId,
|
|
11007
|
+
project2,
|
|
11008
|
+
wake.workItemId,
|
|
11009
|
+
item,
|
|
11010
|
+
wake.threadId,
|
|
11011
|
+
woken,
|
|
11012
|
+
memberLookup(project2)
|
|
11013
|
+
);
|
|
11014
|
+
if (candidate?.key !== wake.key) return false;
|
|
11015
|
+
return !needsMemberSlot(candidate) || memberItemSlots(wake.projectId, project2, woken, wake.threadId).get(wake.threadId)?.key === wake.key;
|
|
11016
|
+
}
|
|
11017
|
+
function dueWakes(state) {
|
|
11018
|
+
const due = [];
|
|
11019
|
+
for (const [projectId, project2] of Object.entries(state)) {
|
|
11020
|
+
const woken = new Set(project2.woken);
|
|
11021
|
+
const isMemberThread = memberLookup(project2);
|
|
11022
|
+
const slots = memberItemSlots(projectId, project2, woken);
|
|
11023
|
+
for (const [workItemId, item] of Object.entries(project2.items)) {
|
|
11024
|
+
const unblocked = readFact(project2.blockedAfterClaim, workItemId) ?? 0;
|
|
11025
|
+
const recipients = /* @__PURE__ */ new Set([
|
|
11026
|
+
...item.assigneeThreads,
|
|
11027
|
+
...unblocked > 0 ? item.claimedBy : []
|
|
11028
|
+
]);
|
|
11029
|
+
for (const threadId of recipients) {
|
|
11030
|
+
const candidate = itemWakeCandidate(
|
|
11031
|
+
projectId,
|
|
11032
|
+
project2,
|
|
11033
|
+
workItemId,
|
|
11034
|
+
item,
|
|
11035
|
+
threadId,
|
|
11036
|
+
woken,
|
|
11037
|
+
isMemberThread
|
|
11038
|
+
);
|
|
11039
|
+
if (candidate === null || engineDispatches(project2, candidate)) continue;
|
|
11040
|
+
if (needsMemberSlot(candidate) && slots.get(threadId)?.key !== candidate.key) continue;
|
|
11041
|
+
due.push(candidate);
|
|
11042
|
+
}
|
|
11043
|
+
}
|
|
11044
|
+
due.push(...dueReviews(project2).filter((review) => !wakeGated(project2, review)));
|
|
11045
|
+
}
|
|
11046
|
+
return due.sort((a, b) => compare2(a.projectId, b.projectId) || compare2(a.key, b.key));
|
|
11047
|
+
}
|
|
11048
|
+
function teamItemDecision(project2, projectId, workItemId, threadId) {
|
|
11049
|
+
const item = readFact(project2.items, workItemId);
|
|
11050
|
+
if (item === null) return { kind: "held", reason: "the team has not seen this work item yet" };
|
|
11051
|
+
if (isClosed(item)) return { kind: "held", reason: "the work item is closed" };
|
|
11052
|
+
if (hasOpenBlocker(project2, workItemId))
|
|
11053
|
+
return { kind: "held", reason: "the work item is blocked by unfinished work items" };
|
|
11054
|
+
if (isThreadGated(project2, threadId))
|
|
11055
|
+
return { kind: "held", reason: "the team is stopped or paused" };
|
|
11056
|
+
const woken = new Set(project2.woken);
|
|
11057
|
+
const candidate = itemWakeCandidate(
|
|
11058
|
+
projectId,
|
|
11059
|
+
project2,
|
|
11060
|
+
workItemId,
|
|
11061
|
+
item,
|
|
11062
|
+
threadId,
|
|
11063
|
+
woken,
|
|
11064
|
+
memberLookup(project2)
|
|
11065
|
+
);
|
|
11066
|
+
if (candidate === null)
|
|
11067
|
+
return {
|
|
11068
|
+
kind: "held",
|
|
11069
|
+
reason: item.assigneeThreads.includes(threadId) ? "the team already handed this work item over" : "the team runs this member in another session"
|
|
11070
|
+
};
|
|
11071
|
+
if (needsMemberSlot(candidate)) {
|
|
11072
|
+
const slot = memberItemSlots(projectId, project2, woken, threadId).get(threadId);
|
|
11073
|
+
if (slot?.key !== candidate.key)
|
|
11074
|
+
return {
|
|
11075
|
+
kind: "held",
|
|
11076
|
+
reason: slot === void 0 ? "the member is still working on another work item" : `the member gets W${slot.sequenceId} first`
|
|
11077
|
+
};
|
|
11078
|
+
}
|
|
11079
|
+
return { kind: "due", wake: candidate };
|
|
11080
|
+
}
|
|
11081
|
+
|
|
11082
|
+
// src/runtime/dispatchGate.ts
|
|
11083
|
+
var allow = { allowed: true };
|
|
11084
|
+
var hold = (detail) => ({ allowed: false, detail });
|
|
11085
|
+
var allowIn = (threadId, picked) => threadId === picked ? allow : { allowed: true, threadId };
|
|
11086
|
+
var JOINING = "the member is joining this team; its team session opens within a couple of minutes";
|
|
11087
|
+
function registerDispatchGate(ctx, deps) {
|
|
11393
11088
|
const pacing = createDeliveryPacing(
|
|
11394
11089
|
ctx.derivedState(deliveryPacingStateDefinition),
|
|
11395
11090
|
async (threadId) => waitingOnSomeone(await readMemberExecution(ctx, threadId))
|
|
11396
11091
|
);
|
|
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;
|
|
11092
|
+
ctx.reactor({
|
|
11093
|
+
name: "team-delivery-pacing",
|
|
11094
|
+
events: ["thread.session-set"],
|
|
11095
|
+
handle: (event) => pacing.observe(event)
|
|
11096
|
+
});
|
|
11097
|
+
const legacyProjectGoal = async (project2, input) => {
|
|
11098
|
+
if (project2.goalId === void 0) return allow;
|
|
11099
|
+
if (readFact(project2.bindings ?? {}, input.memberId) !== null)
|
|
11100
|
+
return hold("the project's older team goal dispatches this member");
|
|
11101
|
+
if (isClosed(readFact(project2.items, teamGoalItemId(input.projectId, project2.goalId))))
|
|
11102
|
+
return allow;
|
|
11103
|
+
const lines = await ctx.work.lines.list({
|
|
11104
|
+
projectId: input.projectId,
|
|
11105
|
+
includeArchived: true,
|
|
11106
|
+
limit: 1
|
|
11107
|
+
});
|
|
11108
|
+
return lines.items.length === 0 ? hold("the project's older team goal takes this member in and dispatches it") : allow;
|
|
11444
11109
|
};
|
|
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
|
-
});
|
|
11110
|
+
const memberThreadsOf = (scope2, memberId) => teamSessions(scope2).filter((threadId) => scope2.memberIds?.[threadId] === memberId);
|
|
11111
|
+
const itemGate = async (project2, scope2, input) => {
|
|
11112
|
+
const workItemId = input.workItemId;
|
|
11113
|
+
const binding = readFact(scope2.bindings ?? {}, input.memberId);
|
|
11114
|
+
if (binding === null) return hold(JOINING);
|
|
11115
|
+
if (!("threadId" in binding)) return hold("the team runs this member on another machine");
|
|
11116
|
+
const lead = scope2.leadThreads?.includes(binding.threadId) === true;
|
|
11117
|
+
const executor = lead ? { threadId: binding.threadId } : executorOf(project2, workItemId, input.memberId);
|
|
11118
|
+
if (executor === void 0 || !("threadId" in executor)) return hold(JOINING);
|
|
11119
|
+
const threadId = executor.threadId;
|
|
11120
|
+
const decision = teamItemDecision(project2, input.projectId, workItemId, threadId);
|
|
11121
|
+
if (decision.kind === "held") return hold(decision.reason);
|
|
11122
|
+
const isReady2 = await deps.readiness();
|
|
11123
|
+
if (!exemptFromTrial(project2, { threadId }, workItemId) && !isReady2(input.projectId, input.memberId, scope2.goalId))
|
|
11124
|
+
return hold("the member has not passed its trial run yet");
|
|
11125
|
+
const worktree = lead ? void 0 : memberWorktreeFor(deps.goals, project2, input.projectId, { threadId });
|
|
11126
|
+
if (worktree !== void 0 && worktree.failure === void 0) {
|
|
11127
|
+
const execution = await ctx.projections.getThreadExecution(threadId);
|
|
11128
|
+
if (execution !== null && !execution.worktreePath) {
|
|
11129
|
+
deps.requestWorktree(input.projectId, threadId);
|
|
11130
|
+
return hold("the member's own worktree is being prepared");
|
|
11474
11131
|
}
|
|
11475
11132
|
}
|
|
11133
|
+
return allowIn(threadId, input.threadId);
|
|
11476
11134
|
};
|
|
11477
|
-
const
|
|
11478
|
-
const
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
}
|
|
11135
|
+
const messageGate = async (project2, scope2, input) => {
|
|
11136
|
+
const binding = readFact(scope2.bindings ?? {}, input.memberId);
|
|
11137
|
+
if (binding === null) return hold(JOINING);
|
|
11138
|
+
if (!("threadId" in binding)) return allow;
|
|
11139
|
+
const threadId = input.threadId !== null && memberThreadsOf(scope2, input.memberId).includes(input.threadId) ? input.threadId : binding.threadId;
|
|
11140
|
+
const isReady2 = await deps.readiness();
|
|
11141
|
+
if (!exemptFromTrial(project2, { threadId }, input.workItemId ?? void 0) && !isReady2(input.projectId, input.memberId, scope2.goalId))
|
|
11142
|
+
return hold("the member has not passed its trial run yet");
|
|
11143
|
+
if (input.reason === "group" && input.recordId !== void 0) {
|
|
11144
|
+
const [record2] = await ctx.communication.records.get({ recordIds: [input.recordId] });
|
|
11145
|
+
const fromAgent = record2 !== void 0 && record2.from.kind !== "user" && record2.from.kind !== "local-owner";
|
|
11146
|
+
if (fromAgent && !await pacing.allows(threadId, await deps.now()))
|
|
11147
|
+
return hold("slowed down: the member made no progress in its last turns");
|
|
11148
|
+
}
|
|
11149
|
+
return allowIn(threadId, input.threadId);
|
|
11484
11150
|
};
|
|
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);
|
|
11151
|
+
const check = async (input) => {
|
|
11152
|
+
const project2 = readFact(
|
|
11153
|
+
await deps.wakes.get({ throughSequence: input.throughSequence }),
|
|
11154
|
+
input.projectId
|
|
11155
|
+
);
|
|
11156
|
+
if (project2 === null) return allow;
|
|
11157
|
+
const scope2 = input.workLineId === null ? void 0 : project2.lineScopes?.[input.workLineId];
|
|
11158
|
+
if (scope2 === void 0) {
|
|
11159
|
+
if (input.reason === "item") return legacyProjectGoal(project2, input);
|
|
11160
|
+
return project2.goalId !== void 0 && readFact(project2.bindings ?? {}, input.memberId) !== null ? messageGate(project2, project2, input) : allow;
|
|
11513
11161
|
}
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
);
|
|
11519
|
-
return { ready };
|
|
11162
|
+
if (project2.lineStops?.[input.workLineId] !== void 0)
|
|
11163
|
+
return hold("the team on this work line is stopped");
|
|
11164
|
+
return input.reason === "item" ? itemGate(project2, scope2, input) : messageGate(project2, scope2, input);
|
|
11165
|
+
};
|
|
11166
|
+
return ctx.operations.guard({ operations: ["work.dispatch"], check });
|
|
11520
11167
|
}
|
|
11521
11168
|
|
|
11522
11169
|
// src/runtime/memberBinding.ts
|
|
@@ -12182,268 +11829,92 @@ function foldRecovery(state, event, previous) {
|
|
|
12182
11829
|
}
|
|
12183
11830
|
if (retriedItemIds.length === member.retriedItemIds.length && pending === member.pending && remindedItemIds.length === (member.remindedItemIds?.length ?? 0) && escalatedItemIds.length === (member.escalatedItemIds?.length ?? 0) && unprogressedRetryItemIds.length === (member.unprogressedRetryItemIds?.length ?? 0))
|
|
12184
11831
|
continue;
|
|
12185
|
-
changed = true;
|
|
12186
|
-
recovery[threadId] = {
|
|
12187
|
-
...member,
|
|
12188
|
-
retriedItemIds,
|
|
12189
|
-
remindedItemIds,
|
|
12190
|
-
escalatedItemIds,
|
|
12191
|
-
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);
|
|
11832
|
+
changed = true;
|
|
11833
|
+
recovery[threadId] = {
|
|
11834
|
+
...member,
|
|
11835
|
+
retriedItemIds,
|
|
11836
|
+
remindedItemIds,
|
|
11837
|
+
escalatedItemIds,
|
|
11838
|
+
unprogressedRetryItemIds,
|
|
11839
|
+
pending,
|
|
11840
|
+
handledTurnIds: pending === null && member.pending !== null ? [.../* @__PURE__ */ new Set([...member.handledTurnIds, member.pending.turnId])] : member.handledTurnIds
|
|
11841
|
+
};
|
|
12364
11842
|
}
|
|
11843
|
+
return changed ? { ...state, [work.projectId]: { ...project2, recovery } } : state;
|
|
12365
11844
|
}
|
|
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;
|
|
11845
|
+
return state;
|
|
12405
11846
|
}
|
|
12406
|
-
function
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
const
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
|
|
12418
|
-
|
|
12419
|
-
|
|
11847
|
+
function dueRecoveries(state, changedThreadId) {
|
|
11848
|
+
return Object.entries(state).flatMap(
|
|
11849
|
+
([projectId, project2]) => Object.entries(project2.recovery ?? {}).flatMap(([threadId, member]) => {
|
|
11850
|
+
const scope2 = scopeOfThread(project2, threadId);
|
|
11851
|
+
const memberId = scope2?.memberIds?.[threadId];
|
|
11852
|
+
const leadThreadId = scope2?.leadThreads?.[0];
|
|
11853
|
+
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 }))
|
|
11854
|
+
return [];
|
|
11855
|
+
const stalled = member.pending.kind === "stall";
|
|
11856
|
+
if (member.handledTurnIds.includes(member.pending.turnId)) return [];
|
|
11857
|
+
const items = Object.entries(project2.items).filter(
|
|
11858
|
+
([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))
|
|
11859
|
+
).map(([workItemId, item]) => ({
|
|
11860
|
+
workItemId,
|
|
11861
|
+
sequenceId: item.sequenceId,
|
|
11862
|
+
lastCommentId: item.lastCommentId,
|
|
11863
|
+
waitingForReply: item.lastActionCommentThreadId === threadId
|
|
11864
|
+
})).sort((a, b) => a.sequenceId - b.sequenceId);
|
|
11865
|
+
const deferredWakeCount = countDeferredWakes(project2, threadId);
|
|
11866
|
+
return items.length === 0 ? [] : [
|
|
11867
|
+
{
|
|
11868
|
+
...member.pending,
|
|
12420
11869
|
projectId,
|
|
12421
|
-
project2,
|
|
12422
|
-
workItemId,
|
|
12423
|
-
item,
|
|
12424
11870
|
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));
|
|
11871
|
+
memberId,
|
|
11872
|
+
leadThreadId,
|
|
11873
|
+
key: JSON.stringify([threadId, member.pending.turnId]),
|
|
11874
|
+
alreadyRetried: items.some(
|
|
11875
|
+
(item) => member.retriedItemIds.includes(item.workItemId) || (member.remindedItemIds ?? []).includes(item.workItemId) || (member.escalatedItemIds ?? []).includes(item.workItemId) || (member.pending?.continuedItemIds ?? []).includes(item.workItemId)
|
|
11876
|
+
),
|
|
11877
|
+
items,
|
|
11878
|
+
...deferredWakeCount > 0 ? { deferredWakeCount } : {}
|
|
11879
|
+
}
|
|
11880
|
+
];
|
|
11881
|
+
})
|
|
11882
|
+
);
|
|
12445
11883
|
}
|
|
12446
11884
|
|
|
11885
|
+
// src/runtime/wakeTexts.ts
|
|
11886
|
+
var workLabel = (workItemId, sequenceId) => sequenceId === void 0 ? `the work item with workItemId ${workItemId}` : `work item W${sequenceId} (workItemId ${workItemId})`;
|
|
11887
|
+
var titled = (workItemId, sequenceId, title) => `${workLabel(workItemId, sequenceId)}${title ? `: ${title}` : ""}`;
|
|
11888
|
+
var ITEM_SUMMARY_MAX_CHARS = 300;
|
|
11889
|
+
var descriptionStart = (description) => {
|
|
11890
|
+
const first = description?.trim().split(/\n\s*\n/u)[0]?.trim() ?? "";
|
|
11891
|
+
if (first === "") return "";
|
|
11892
|
+
const points = Array.from(first);
|
|
11893
|
+
const summary = points.length > ITEM_SUMMARY_MAX_CHARS ? `${points.slice(0, ITEM_SUMMARY_MAX_CHARS).join("")}\u2026` : first;
|
|
11894
|
+
return `Its description starts: ${summary}`;
|
|
11895
|
+
};
|
|
11896
|
+
var itemHeadline = (sequenceId, item) => {
|
|
11897
|
+
const title = item?.title ? `${sequenceId === void 0 ? "Work item" : `W${sequenceId}`}: ${item.title}.` : "";
|
|
11898
|
+
const parts = [title, descriptionStart(item?.description)].filter((part2) => part2 !== "");
|
|
11899
|
+
return parts.length === 0 ? "" : `${parts.join(" ")} `;
|
|
11900
|
+
};
|
|
11901
|
+
var MEMBER_INSTRUCTIONS_LIMIT = 2e3;
|
|
11902
|
+
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.";
|
|
11903
|
+
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}.)`}`;
|
|
11904
|
+
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}`;
|
|
11905
|
+
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}`;
|
|
11906
|
+
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}`;
|
|
11907
|
+
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.`;
|
|
11908
|
+
var leadReviewText = (workItemId, sequenceId, title, by, facts) => [
|
|
11909
|
+
`${by} marked ${titled(workItemId, sequenceId, title)} done. Read it with work_read_items, passing workItemIds: ["${workItemId}"], and check it now.`,
|
|
11910
|
+
LEAD_ACCEPT_RULE,
|
|
11911
|
+
LEAD_SEND_BACK_RULE,
|
|
11912
|
+
...facts.idle.length === 0 ? [] : [`Nothing in progress now: ${facts.idle.join("; ")}.`],
|
|
11913
|
+
...facts.queued.length === 0 ? [] : [`Waiting in line, not blocked: ${facts.queued.join("; ")}.`],
|
|
11914
|
+
...facts.idle.length > 0 && facts.queued.length > 0 ? [LEAD_REBALANCE_RULE] : [],
|
|
11915
|
+
LEAD_NO_MEMBER_TASKS
|
|
11916
|
+
].join(" ");
|
|
11917
|
+
|
|
12447
11918
|
// src/runtime/memberAssignments.ts
|
|
12448
11919
|
var threadOf = (bindings, memberId) => {
|
|
12449
11920
|
const binding = bindings === void 0 ? null : readFact(bindings, memberId);
|
|
@@ -12583,6 +12054,8 @@ var WAKE_EVENTS = [
|
|
|
12583
12054
|
"work.relation-added",
|
|
12584
12055
|
"work.relation-removed",
|
|
12585
12056
|
"work.comment-posted",
|
|
12057
|
+
// 看板把件交到了成员会话上(引擎叫醒了它):当成这一次「你有活」已经叫过,占名额、固定执行者都照旧。
|
|
12058
|
+
"work.item-dispatched",
|
|
12586
12059
|
"plugin.event-appended",
|
|
12587
12060
|
"thread.session-set",
|
|
12588
12061
|
// 线与线上成员的暂停:引擎的看板事实,派发闸读它(见 `linePauses` / `pausedMembers`)。
|
|
@@ -12599,7 +12072,6 @@ var emptyProject = () => ({
|
|
|
12599
12072
|
remoteMembers: [],
|
|
12600
12073
|
items: {},
|
|
12601
12074
|
blockers: {},
|
|
12602
|
-
pendingComments: [],
|
|
12603
12075
|
woken: [],
|
|
12604
12076
|
rearms: {},
|
|
12605
12077
|
blockedAfterClaim: {}
|
|
@@ -12665,6 +12137,24 @@ var withoutInitialLeadWake = (project2, projectId, workItemId) => {
|
|
|
12665
12137
|
woken: [...project2.woken, ...leads.map((threadId) => itemWakeKey(workItemId, threadId, 0))]
|
|
12666
12138
|
};
|
|
12667
12139
|
};
|
|
12140
|
+
var decodeDispatched = decodeUnknownOption2(
|
|
12141
|
+
Struct({ projectId: String4, workItemId: String4, threadId: String4 })
|
|
12142
|
+
);
|
|
12143
|
+
var markWoken = (project2, key) => {
|
|
12144
|
+
if (project2.woken.includes(key)) return project2;
|
|
12145
|
+
const items = { ...project2.items };
|
|
12146
|
+
for (const [workItemId, item] of Object.entries(items)) {
|
|
12147
|
+
for (const threadId of item.assigneeThreads) {
|
|
12148
|
+
if (item.wakeStatus?.[threadId] !== "released" && isWorkable(project2, workItemId) && key === itemWakeKey(
|
|
12149
|
+
workItemId,
|
|
12150
|
+
threadId,
|
|
12151
|
+
readFact(project2.rearms, `${workItemId}:${threadId}`) ?? 0
|
|
12152
|
+
))
|
|
12153
|
+
items[workItemId] = { ...item, wakeStatus: { ...item.wakeStatus, [threadId]: "active" } };
|
|
12154
|
+
}
|
|
12155
|
+
}
|
|
12156
|
+
return { ...project2, items, woken: [...project2.woken, key] };
|
|
12157
|
+
};
|
|
12668
12158
|
var markBlockedAfterClaim = (project2, workItemId) => ({
|
|
12669
12159
|
...project2,
|
|
12670
12160
|
blockedAfterClaim: {
|
|
@@ -12692,14 +12182,7 @@ function foldWorkWakes(state, event) {
|
|
|
12692
12182
|
)
|
|
12693
12183
|
};
|
|
12694
12184
|
}
|
|
12695
|
-
|
|
12696
|
-
return {
|
|
12697
|
-
...state,
|
|
12698
|
-
[goal.projectId]: {
|
|
12699
|
-
...next2,
|
|
12700
|
-
pendingComments: project4.pendingComments.filter((comment) => isMember(next2, comment))
|
|
12701
|
-
}
|
|
12702
|
-
};
|
|
12185
|
+
return { ...state, [goal.projectId]: rebindItems({ ...project4, ...scope2 }) };
|
|
12703
12186
|
}
|
|
12704
12187
|
if (fact.name === "team/member-bound") {
|
|
12705
12188
|
const { projectId: projectId3, memberId } = fact.data;
|
|
@@ -12714,17 +12197,17 @@ function foldWorkWakes(state, event) {
|
|
|
12714
12197
|
lineId === void 0 ? project4 : project4.lineScopes[lineId],
|
|
12715
12198
|
fact.data
|
|
12716
12199
|
);
|
|
12717
|
-
const
|
|
12200
|
+
const next3 = rebindItems(
|
|
12718
12201
|
lineId === void 0 ? { ...project4, ...bound } : { ...project4, lineScopes: { ...project4.lineScopes, [lineId]: bound } },
|
|
12719
12202
|
memberId,
|
|
12720
12203
|
lineId
|
|
12721
12204
|
);
|
|
12722
|
-
return { ...state, [projectId3]:
|
|
12205
|
+
return { ...state, [projectId3]: next3 };
|
|
12723
12206
|
}
|
|
12724
12207
|
if (fact.name === "team/line-paused" || fact.name === "team/line-member-paused") {
|
|
12725
12208
|
const { projectId: projectId3, workLineId, status } = fact.data;
|
|
12726
12209
|
const project4 = readFact(state, projectId3) ?? emptyProject();
|
|
12727
|
-
const
|
|
12210
|
+
const next3 = withPause(
|
|
12728
12211
|
project4,
|
|
12729
12212
|
{
|
|
12730
12213
|
projectId: projectId3,
|
|
@@ -12734,22 +12217,7 @@ function foldWorkWakes(state, event) {
|
|
|
12734
12217
|
},
|
|
12735
12218
|
event.eventId
|
|
12736
12219
|
);
|
|
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
|
-
};
|
|
12220
|
+
return next3 === project4 ? state : { ...state, [projectId3]: next3 };
|
|
12753
12221
|
}
|
|
12754
12222
|
if (fact.name === "team/member-worktree-failed" || fact.name === "team/member-worktree-reported") {
|
|
12755
12223
|
const { projectId: projectId3, threadId } = fact.data;
|
|
@@ -12767,15 +12235,6 @@ function foldWorkWakes(state, event) {
|
|
|
12767
12235
|
}
|
|
12768
12236
|
const { projectId: projectId2, key } = fact.data;
|
|
12769
12237
|
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
12238
|
if (project3.pendingReviews?.some((review) => review.key === key)) {
|
|
12780
12239
|
return {
|
|
12781
12240
|
...state,
|
|
@@ -12785,19 +12244,22 @@ function foldWorkWakes(state, event) {
|
|
|
12785
12244
|
}
|
|
12786
12245
|
};
|
|
12787
12246
|
}
|
|
12788
|
-
|
|
12789
|
-
|
|
12790
|
-
|
|
12791
|
-
|
|
12792
|
-
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
12798
|
-
|
|
12799
|
-
|
|
12800
|
-
|
|
12247
|
+
const next2 = markWoken(project3, key);
|
|
12248
|
+
return next2 === project3 ? state : { ...state, [projectId2]: next2 };
|
|
12249
|
+
}
|
|
12250
|
+
if (event.type === "work.item-dispatched") {
|
|
12251
|
+
const decoded2 = decodeDispatched(event.payload);
|
|
12252
|
+
if (isNone2(decoded2)) return state;
|
|
12253
|
+
const { projectId: projectId2, workItemId: workItemId2, threadId } = decoded2.value;
|
|
12254
|
+
const project3 = readFact(state, projectId2);
|
|
12255
|
+
if (project3 === null) return state;
|
|
12256
|
+
const key = itemWakeKey(
|
|
12257
|
+
workItemId2,
|
|
12258
|
+
threadId,
|
|
12259
|
+
readFact(project3.rearms, `${workItemId2}:${threadId}`) ?? 0
|
|
12260
|
+
);
|
|
12261
|
+
const next2 = markWoken(project3, key);
|
|
12262
|
+
return next2 === project3 ? state : { ...state, [projectId2]: next2 };
|
|
12801
12263
|
}
|
|
12802
12264
|
const decoded = decodeWorkEvent(event);
|
|
12803
12265
|
if (isNone2(decoded)) return state;
|
|
@@ -12928,20 +12390,11 @@ function foldWorkWakes(state, event) {
|
|
|
12928
12390
|
}
|
|
12929
12391
|
break;
|
|
12930
12392
|
}
|
|
12393
|
+
// 评论里 @ 谁、回复谁由引擎投递(提案 0085 切片 3);这里只记最近一条评论,恢复与问进度要用。
|
|
12931
12394
|
case "work.comment-posted": {
|
|
12932
|
-
const { actor,
|
|
12933
|
-
const recipients = commentRecipients(
|
|
12934
|
-
project2,
|
|
12935
|
-
actor,
|
|
12936
|
-
commentPeople({ parentAuthor, mentions })
|
|
12937
|
-
);
|
|
12395
|
+
const { actor, commentId } = work.payload;
|
|
12938
12396
|
next = {
|
|
12939
12397
|
...project2,
|
|
12940
|
-
pendingComments: queueCommentWakes(
|
|
12941
|
-
project2,
|
|
12942
|
-
{ projectId, workItemId, commentId },
|
|
12943
|
-
recipients
|
|
12944
|
-
),
|
|
12945
12398
|
items: currentItem === null ? project2.items : {
|
|
12946
12399
|
...project2.items,
|
|
12947
12400
|
[workItemId]: {
|
|
@@ -13020,38 +12473,6 @@ function foldWakes(state, event) {
|
|
|
13020
12473
|
}
|
|
13021
12474
|
|
|
13022
12475
|
// 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
12476
|
function startWakeRuntime(ctx, goals, options = {}) {
|
|
13056
12477
|
const wakes = ctx.derivedState({
|
|
13057
12478
|
key: WAKE_STATE_KEY,
|
|
@@ -13078,8 +12499,6 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13078
12499
|
};
|
|
13079
12500
|
};
|
|
13080
12501
|
const baseText = async (wake, state) => {
|
|
13081
|
-
if ("principalId" in wake || wake.kind === "comment")
|
|
13082
|
-
return commentText(wake.workItemId, wake.sequenceId);
|
|
13083
12502
|
const item = await readItem(wake.projectId, wake.workItemId);
|
|
13084
12503
|
const title = item?.title;
|
|
13085
12504
|
if (wake.kind === "review") {
|
|
@@ -13090,7 +12509,7 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13090
12509
|
const key = "threadId" in id ? id.threadId : id.principalId;
|
|
13091
12510
|
return `${member?.name ?? key} (${"threadId" in id ? "threadId" : "principalId"} ${key})`;
|
|
13092
12511
|
};
|
|
13093
|
-
const facts = project2 === void 0 ? { idle: [], queued: [] } : reviewFacts(project2, memberQueues(wake.projectId, project2), wake.threadId);
|
|
12512
|
+
const facts = project2 === void 0 || !("threadId" in wake) ? { idle: [], queued: [] } : reviewFacts(project2, memberQueues(wake.projectId, project2), wake.threadId);
|
|
13094
12513
|
return leadReviewText(
|
|
13095
12514
|
wake.workItemId,
|
|
13096
12515
|
wake.sequenceId,
|
|
@@ -13118,6 +12537,42 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13118
12537
|
title
|
|
13119
12538
|
);
|
|
13120
12539
|
};
|
|
12540
|
+
const compose = async (wake, state) => {
|
|
12541
|
+
const team = "threadId" in wake ? lineScopeOfThread(state[wake.projectId], wake.threadId) : void 0;
|
|
12542
|
+
const memberId = team === void 0 || !("threadId" in wake) ? void 0 : team.scope.memberIds?.[wake.threadId];
|
|
12543
|
+
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({
|
|
12544
|
+
projectId: wake.projectId,
|
|
12545
|
+
workLineId: team.workLineId,
|
|
12546
|
+
memberId,
|
|
12547
|
+
threadId: wake.threadId,
|
|
12548
|
+
leadThreadId: team.scope.leadThreads?.[0] ?? "",
|
|
12549
|
+
wakeKey: wake.key,
|
|
12550
|
+
// 群记录的发件人取成员名(会话号 → 成员号 → 名单),读不到就退回 Lead / Member。
|
|
12551
|
+
// 名单在这一次摘要里只读一次:惰性缓存同一个 Promise,不随每条记录重读。
|
|
12552
|
+
nameOfThread: /* @__PURE__ */ (() => {
|
|
12553
|
+
let roster;
|
|
12554
|
+
return async (threadId) => {
|
|
12555
|
+
if (team.scope.memberIds?.[threadId] === void 0) return null;
|
|
12556
|
+
roster ??= goals.read(wake.projectId, { forLine: team.workLineId });
|
|
12557
|
+
return findGoalMember((await roster)?.members ?? [], { threadId })?.name ?? null;
|
|
12558
|
+
};
|
|
12559
|
+
})()
|
|
12560
|
+
});
|
|
12561
|
+
const waiting = team === void 0 || !("threadId" in wake) || team.scope.leadThreads?.includes(wake.threadId) !== true || options.teamWaiting === void 0 ? null : await (async () => {
|
|
12562
|
+
const members = (await goals.read(wake.projectId, { forThread: wake.threadId }))?.members ?? [];
|
|
12563
|
+
return options.teamWaiting(
|
|
12564
|
+
team.scope.threads.filter((id) => id !== wake.threadId),
|
|
12565
|
+
(id) => findGoalMember(members, { threadId: id })?.name ?? id
|
|
12566
|
+
);
|
|
12567
|
+
})().catch(() => null);
|
|
12568
|
+
return {
|
|
12569
|
+
digest,
|
|
12570
|
+
text: async () => {
|
|
12571
|
+
const body = await baseText(wake, state);
|
|
12572
|
+
return [digest?.body, body, waiting].filter((part2) => part2 != null).join("\n\n");
|
|
12573
|
+
}
|
|
12574
|
+
};
|
|
12575
|
+
};
|
|
13121
12576
|
const execute = async () => {
|
|
13122
12577
|
let state = await wakes.get();
|
|
13123
12578
|
const isReady2 = options.readiness === void 0 ? () => true : await options.readiness();
|
|
@@ -13137,33 +12592,7 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13137
12592
|
try {
|
|
13138
12593
|
const id = hash2(wake.key);
|
|
13139
12594
|
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);
|
|
12595
|
+
const { digest, text } = await compose(wake, state);
|
|
13167
12596
|
const delivered = await deliverWake(ctx, {
|
|
13168
12597
|
projectId: wake.projectId,
|
|
13169
12598
|
recipient: wake,
|
|
@@ -13171,12 +12600,7 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13171
12600
|
messageId: `team-wake-msg:${id}`,
|
|
13172
12601
|
wake: { reason: "work", sequenceId: wake.sequenceId },
|
|
13173
12602
|
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
|
-
}
|
|
12603
|
+
text
|
|
13180
12604
|
});
|
|
13181
12605
|
if (!delivered) continue;
|
|
13182
12606
|
if (digest !== null) await options.groupDigest.confirm(wake.projectId, digest);
|
|
@@ -13212,7 +12636,73 @@ function startWakeRuntime(ctx, goals, options = {}) {
|
|
|
13212
12636
|
});
|
|
13213
12637
|
const ready = flush();
|
|
13214
12638
|
void ready.catch((error) => ctx.log?.warn("team wake catch-up failed", { error }));
|
|
13215
|
-
return { flush, ready, state: wakes, worktrees };
|
|
12639
|
+
return { flush, ready, state: wakes, worktrees, compose };
|
|
12640
|
+
}
|
|
12641
|
+
|
|
12642
|
+
// src/runtime/wakeSupplement.ts
|
|
12643
|
+
var decodeDispatched2 = decodeUnknownOption2(
|
|
12644
|
+
Struct({ projectId: String4, threadId: String4 })
|
|
12645
|
+
);
|
|
12646
|
+
function registerWakeSupplement(ctx, wakes, groupDigest) {
|
|
12647
|
+
const add3 = async (input) => {
|
|
12648
|
+
const state = await wakes.state.get({ throughSequence: input.throughSequence });
|
|
12649
|
+
const project2 = readFact(state, input.projectId);
|
|
12650
|
+
if (project2 === null || lineScopeOfThread(project2, input.threadId) === void 0) return null;
|
|
12651
|
+
const decision = teamItemDecision(project2, input.projectId, input.workItemId, input.threadId);
|
|
12652
|
+
if (decision.kind === "held")
|
|
12653
|
+
throw new Error(`the team cannot hand this work item over now: ${decision.reason}`);
|
|
12654
|
+
const { text } = await wakes.compose(decision.wake, state);
|
|
12655
|
+
return text();
|
|
12656
|
+
};
|
|
12657
|
+
ctx.reactor({
|
|
12658
|
+
name: "team-board-handover",
|
|
12659
|
+
events: ["work.item-dispatched"],
|
|
12660
|
+
handle: async (event) => {
|
|
12661
|
+
const decoded = decodeDispatched2(event.payload);
|
|
12662
|
+
if (isNone2(decoded) || groupDigest === void 0) return;
|
|
12663
|
+
await groupDigest.confirmPrepared(decoded.value.projectId, decoded.value.threadId);
|
|
12664
|
+
}
|
|
12665
|
+
});
|
|
12666
|
+
return ctx.operations.supplement({ operations: ["work.dispatch"], add: add3 });
|
|
12667
|
+
}
|
|
12668
|
+
|
|
12669
|
+
// src/runtime/worktreeSetup.ts
|
|
12670
|
+
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.";
|
|
12671
|
+
function startWorktreeSetupRuntime(ctx, deps) {
|
|
12672
|
+
const requested = /* @__PURE__ */ new Map();
|
|
12673
|
+
let running = Promise.resolve();
|
|
12674
|
+
const setUp = async (projectId, threadId) => {
|
|
12675
|
+
const project2 = (await deps.wakes.get())[projectId];
|
|
12676
|
+
const worktree = memberWorktreeFor(deps.goals, project2, projectId, { threadId });
|
|
12677
|
+
if (worktree === void 0 || worktree.failure !== void 0) return;
|
|
12678
|
+
const execution = await ctx.projections.getThreadExecution(threadId);
|
|
12679
|
+
if (execution === null || execution.archivedAt !== null || execution.worktreePath) return;
|
|
12680
|
+
const id = stableHash(threadId);
|
|
12681
|
+
await deliverWake(ctx, {
|
|
12682
|
+
projectId,
|
|
12683
|
+
recipient: { threadId },
|
|
12684
|
+
requestId: `team-worktree-setup:${id}`,
|
|
12685
|
+
messageId: `team-worktree-setup-msg:${id}`,
|
|
12686
|
+
wake: { reason: "notice" },
|
|
12687
|
+
memberWorktree: { ...worktree, lane: deps.lane },
|
|
12688
|
+
text: WORKTREE_SETUP_TEXT
|
|
12689
|
+
});
|
|
12690
|
+
};
|
|
12691
|
+
const drain = async () => {
|
|
12692
|
+
for (const [key, entry] of requested) {
|
|
12693
|
+
requested.delete(key);
|
|
12694
|
+
try {
|
|
12695
|
+
await setUp(entry.projectId, entry.threadId);
|
|
12696
|
+
} catch (error) {
|
|
12697
|
+
ctx.log.warn("team member worktree setup failed", { ...entry, error });
|
|
12698
|
+
}
|
|
12699
|
+
}
|
|
12700
|
+
};
|
|
12701
|
+
const request = (projectId, threadId) => {
|
|
12702
|
+
requested.set(`${projectId}|${threadId}`, { projectId, threadId });
|
|
12703
|
+
running = running.then(drain, drain);
|
|
12704
|
+
};
|
|
12705
|
+
return { request, idle: () => running };
|
|
13216
12706
|
}
|
|
13217
12707
|
|
|
13218
12708
|
// src/runtime/recovery.ts
|
|
@@ -13863,7 +13353,7 @@ var emptyHandbookProject = () => ({
|
|
|
13863
13353
|
acknowledgements: {},
|
|
13864
13354
|
reminded: {}
|
|
13865
13355
|
});
|
|
13866
|
-
var
|
|
13356
|
+
var decodeFact5 = decodeUnknownOption2(
|
|
13867
13357
|
Union2([
|
|
13868
13358
|
factEnvelope("goal-started", GoalStartedFact),
|
|
13869
13359
|
factEnvelope("member-bound", MemberBoundFact),
|
|
@@ -13947,7 +13437,7 @@ function foldHandbook(state, event) {
|
|
|
13947
13437
|
};
|
|
13948
13438
|
}
|
|
13949
13439
|
if (event.type !== "plugin.event-appended") return state;
|
|
13950
|
-
const decoded =
|
|
13440
|
+
const decoded = decodeFact5(event.payload);
|
|
13951
13441
|
if (isNone2(decoded)) return state;
|
|
13952
13442
|
const fact = decoded.value;
|
|
13953
13443
|
const projectId = fact.name === "team/goal-started" ? fact.data.goal.projectId : fact.name === "team/roster-set" ? fact.data.roster.projectId : fact.data.projectId;
|
|
@@ -15977,6 +15467,14 @@ function createGroupDigest(ctx, state) {
|
|
|
15977
15467
|
await state.get({ throughSequence: receipt.sequence });
|
|
15978
15468
|
return { digestId, threadId: input.threadId, body };
|
|
15979
15469
|
},
|
|
15470
|
+
/**
|
|
15471
|
+
* 引擎叫醒了这条会话(看板交件):随那次叫醒补充出去的那一份算已投递,水位前进。没有装配好的就什么也不做。
|
|
15472
|
+
*/
|
|
15473
|
+
async confirmPrepared(projectId, threadId) {
|
|
15474
|
+
const prepared = readFact(await state.get(), threadId)?.prepared;
|
|
15475
|
+
if (prepared == null) return;
|
|
15476
|
+
await this.confirm(projectId, { digestId: prepared.digestId, threadId, body: prepared.body });
|
|
15477
|
+
},
|
|
15980
15478
|
/** 叫醒已被宿主受理:水位前进。同一份只落一次。 */
|
|
15981
15479
|
async confirm(projectId, digest) {
|
|
15982
15480
|
const receipt = await ctx.events.append({
|
|
@@ -17224,7 +16722,7 @@ function startTrialRuntime(ctx, deps, options = {}) {
|
|
|
17224
16722
|
// src/index.ts
|
|
17225
16723
|
var index_default = definePlugin({
|
|
17226
16724
|
id: "team",
|
|
17227
|
-
apiVersion:
|
|
16725
|
+
apiVersion: 53,
|
|
17228
16726
|
activate(ctx) {
|
|
17229
16727
|
const trialState = ctx.derivedState(trialStateDefinition);
|
|
17230
16728
|
const rosters = createRosterService(ctx);
|
|
@@ -17256,7 +16754,19 @@ var index_default = definePlugin({
|
|
|
17256
16754
|
},
|
|
17257
16755
|
memberQueue
|
|
17258
16756
|
);
|
|
17259
|
-
|
|
16757
|
+
const worktreeSetup = startWorktreeSetupRuntime(ctx, {
|
|
16758
|
+
wakes: wakes.state,
|
|
16759
|
+
goals,
|
|
16760
|
+
lane: wakes.worktrees
|
|
16761
|
+
});
|
|
16762
|
+
registerDispatchGate(ctx, {
|
|
16763
|
+
wakes: wakes.state,
|
|
16764
|
+
goals,
|
|
16765
|
+
readiness,
|
|
16766
|
+
requestWorktree: worktreeSetup.request,
|
|
16767
|
+
now: () => runPromise2(map5(now2, toEpochMillis2))
|
|
16768
|
+
});
|
|
16769
|
+
registerWakeSupplement(ctx, wakes, groupDigest);
|
|
17260
16770
|
registerPauseCommands(ctx, { wakes: wakes.state, queue: memberQueue });
|
|
17261
16771
|
startArchiveMirror(
|
|
17262
16772
|
ctx,
|
|
@@ -17268,9 +16778,7 @@ var index_default = definePlugin({
|
|
|
17268
16778
|
rebindTargets: rebindReader(trialState)
|
|
17269
16779
|
});
|
|
17270
16780
|
startMemberRemovalRuntime(ctx, goals, wakes.state);
|
|
17271
|
-
|
|
17272
|
-
startGroupDeliveryRuntime(ctx, wakes.state);
|
|
17273
|
-
registerBoardCommands(ctx, goals, rosters, wakes.state);
|
|
16781
|
+
registerBoardCommands(ctx, goals, rosters);
|
|
17274
16782
|
startRecoveryRuntime(ctx, goals, wakes.state, wakes.worktrees);
|
|
17275
16783
|
startLeadCheckinRuntime(ctx, wakes.state, goals);
|
|
17276
16784
|
startProgressCheckinRuntime(ctx, goals, wakes.state);
|