@wrongstack/core 0.299.0 → 0.300.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/coordination/director.d.ts +8 -0
- package/dist/coordination/fleet-manager.d.ts +48 -3
- package/dist/coordination/ifleet-manager.d.ts +2 -0
- package/dist/coordination/index.js +120 -20
- package/dist/coordination/multi-agent-coordinator.d.ts +1 -0
- package/dist/core/fallback-model.d.ts +48 -0
- package/dist/core/index.d.ts +3 -2
- package/dist/core/index.js +226 -26
- package/dist/core/instruction-template.d.ts +80 -0
- package/dist/core/system-prompt-blocks.d.ts +10 -1
- package/dist/core/system-prompt-builder.d.ts +35 -1
- package/dist/defaults/index.js +238 -99
- package/dist/execution/autonomy-brain.d.ts +7 -0
- package/dist/execution/council-brain.d.ts +11 -0
- package/dist/execution/council-orchestrator.d.ts +23 -4
- package/dist/execution/council-prompts.d.ts +12 -1
- package/dist/execution/index.js +355 -138
- package/dist/fleet-notifier.d.ts +9 -2
- package/dist/hooks/index.js +8 -4
- package/dist/hq/index.js +18 -4
- package/dist/hq/protocol/fleet.d.ts +20 -0
- package/dist/hq/protocol.js +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1512 -707
- package/dist/kernel/events/brain-events.d.ts +9 -0
- package/dist/kernel/events/provider-events.d.ts +42 -1
- package/dist/models/index.js +1 -1
- package/dist/plugin/api.d.ts +6 -0
- package/dist/plugin/config.d.ts +55 -0
- package/dist/plugin/index.d.ts +1 -1
- package/dist/plugin/index.js +134 -21
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +157 -42
- package/dist/security/permission-helpers.d.ts +23 -6
- package/dist/security/permission-policy.d.ts +16 -0
- package/dist/security/totp.d.ts +14 -0
- package/dist/storage/director-state.d.ts +7 -0
- package/dist/storage/index.js +33 -8
- package/dist/tools/fallback-system-config-view-tool.d.ts +1 -1
- package/dist/tools/index.js +388 -102
- package/dist/types/council.d.ts +11 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/multi-agent.d.ts +10 -0
- package/dist/types/one-shot-llm.d.ts +9 -0
- package/dist/types/plugin.d.ts +28 -0
- package/dist/worktree/index.js +4 -4
- package/instructions/system-lite.md +81 -3
- package/instructions/system-pro.md +275 -90
- package/instructions/system.md +228 -81
- package/package.json +3 -3
package/dist/tools/index.js
CHANGED
|
@@ -472,22 +472,29 @@ function buildCouncilJudgeUserPrompt(question, votes, opts = {}) {
|
|
|
472
472
|
"</council-ballots>"
|
|
473
473
|
].filter(Boolean).join("\n\n");
|
|
474
474
|
}
|
|
475
|
-
function
|
|
476
|
-
|
|
475
|
+
function validateCouncilOptions(options) {
|
|
476
|
+
const errors = [];
|
|
477
477
|
const seen = /* @__PURE__ */ new Set();
|
|
478
|
-
|
|
478
|
+
for (const option of options ?? []) {
|
|
479
479
|
const id = option.id.trim();
|
|
480
|
-
|
|
481
|
-
if (!
|
|
482
|
-
if (
|
|
483
|
-
if (seen.has(id)) throw new Error(`buildCouncilQuestionPrompt: duplicate option id "${id}".`);
|
|
480
|
+
if (!id) errors.push("Every option must have a non-empty `id`.");
|
|
481
|
+
if (!option.label.trim()) errors.push(`Option "${id || "<empty>"}" must have a label.`);
|
|
482
|
+
if (seen.has(id)) errors.push(`Duplicate option id "${id}".`);
|
|
484
483
|
seen.add(id);
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
484
|
+
}
|
|
485
|
+
return errors;
|
|
486
|
+
}
|
|
487
|
+
function normalizeOptions(options) {
|
|
488
|
+
if (!options) return [];
|
|
489
|
+
const errors = validateCouncilOptions(options);
|
|
490
|
+
if (errors.length > 0) {
|
|
491
|
+
throw new Error(`buildCouncilQuestionPrompt: ${errors.join("; ")}`);
|
|
492
|
+
}
|
|
493
|
+
return options.map((option) => ({
|
|
494
|
+
id: option.id.trim(),
|
|
495
|
+
label: option.label.trim(),
|
|
496
|
+
...option.consequence?.trim() ? { consequence: option.consequence.trim() } : {}
|
|
497
|
+
}));
|
|
491
498
|
}
|
|
492
499
|
function requiredInstruction(path7) {
|
|
493
500
|
const text = readBundledInstructionText(path7);
|
|
@@ -595,6 +602,8 @@ function requireFraction(value, label) {
|
|
|
595
602
|
var COUNCIL_REFUSAL_OPTION_ID = "council_refuse";
|
|
596
603
|
var DEFAULT_COUNCIL_MAX_CONCURRENCY = 3;
|
|
597
604
|
var MAX_COUNCIL_CONCURRENCY = 8;
|
|
605
|
+
var OVERALL_TIMEOUT_REASON = "Council overall timeout exceeded.";
|
|
606
|
+
var CALL_CANCELLED_REASON = "Cancelled.";
|
|
598
607
|
var CouncilOrchestrator = class {
|
|
599
608
|
caller;
|
|
600
609
|
personas;
|
|
@@ -605,6 +614,17 @@ var CouncilOrchestrator = class {
|
|
|
605
614
|
fallbackProfileManager;
|
|
606
615
|
seatCaller;
|
|
607
616
|
judgeCaller;
|
|
617
|
+
/**
|
|
618
|
+
* Normalized ad-hoc profiles keyed by the caller's config object identity.
|
|
619
|
+
* The Brain adapter reuses ONE profile object for every decision, so this
|
|
620
|
+
* avoids re-validating + re-freezing it on every ask() without caching
|
|
621
|
+
* string-keyed registry lookups (those are already O(1)).
|
|
622
|
+
*
|
|
623
|
+
* Hosts must treat ad-hoc profile configs as IMMUTABLE once passed to
|
|
624
|
+
* ask(): the cache is keyed by object identity and never invalidated, so
|
|
625
|
+
* mutating a cached profile would silently serve the first snapshot.
|
|
626
|
+
*/
|
|
627
|
+
profileCache = /* @__PURE__ */ new WeakMap();
|
|
608
628
|
constructor(opts) {
|
|
609
629
|
if (!opts.caller && !opts.seatCaller && !opts.judgeCaller) {
|
|
610
630
|
throw new Error(
|
|
@@ -623,13 +643,33 @@ var CouncilOrchestrator = class {
|
|
|
623
643
|
this.seatCaller = opts.seatCaller;
|
|
624
644
|
this.judgeCaller = opts.judgeCaller;
|
|
625
645
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
646
|
+
/**
|
|
647
|
+
* Resolve the effective profile for a question. String ids and the default
|
|
648
|
+
* go through the registry (already O(1)); ad-hoc config objects are
|
|
649
|
+
* normalized once per stable object identity and cached, because hosts such
|
|
650
|
+
* as the Brain adapter pass the same profile object on every ask().
|
|
651
|
+
*/
|
|
652
|
+
resolveProfile(profile) {
|
|
653
|
+
if (typeof profile === "string" || profile === void 0) {
|
|
654
|
+
return resolveCouncilProfile(profile, {
|
|
655
|
+
registry: this.profiles,
|
|
656
|
+
personas: this.personas,
|
|
657
|
+
defaultProfile: this.defaultProfile
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
const cached = this.profileCache.get(profile);
|
|
661
|
+
if (cached) return cached;
|
|
662
|
+
const resolved = resolveCouncilProfile(profile, {
|
|
629
663
|
registry: this.profiles,
|
|
630
664
|
personas: this.personas,
|
|
631
665
|
defaultProfile: this.defaultProfile
|
|
632
666
|
});
|
|
667
|
+
this.profileCache.set(profile, resolved);
|
|
668
|
+
return resolved;
|
|
669
|
+
}
|
|
670
|
+
async ask(question) {
|
|
671
|
+
const startedAt = Date.now();
|
|
672
|
+
const profile = this.resolveProfile(question.profile);
|
|
633
673
|
validateRefusalCollision(question, this.refusalOptionId);
|
|
634
674
|
const timeoutSignal = AbortSignal.timeout(profile.overallTimeoutMs);
|
|
635
675
|
const signal = question.signal ? AbortSignal.any([question.signal, timeoutSignal]) : timeoutSignal;
|
|
@@ -646,11 +686,16 @@ var CouncilOrchestrator = class {
|
|
|
646
686
|
try {
|
|
647
687
|
return await this.callSeat(question, profile, seat, i, signal, usage);
|
|
648
688
|
} catch (error) {
|
|
689
|
+
const timedOut = signal.aborted && !question.signal?.aborted;
|
|
649
690
|
return {
|
|
650
691
|
seatId: seat.id,
|
|
651
692
|
persona: seat.persona,
|
|
652
|
-
|
|
653
|
-
|
|
693
|
+
// Only the caller's own cancel is a "cancelled" vote; the overall
|
|
694
|
+
// budget expiring is a failure (timeout), matching the envelope.
|
|
695
|
+
status: question.signal?.aborted ? "cancelled" : "failed",
|
|
696
|
+
// Canonical text for aborted-by-budget or cancelled seats, so one
|
|
697
|
+
// event does not surface a different string per code path.
|
|
698
|
+
error: question.signal?.aborted ? CALL_CANCELLED_REASON : timedOut ? OVERALL_TIMEOUT_REASON : errorMessage(error)
|
|
654
699
|
};
|
|
655
700
|
}
|
|
656
701
|
}
|
|
@@ -660,7 +705,7 @@ var CouncilOrchestrator = class {
|
|
|
660
705
|
if (question.signal?.aborted) {
|
|
661
706
|
return resultEnvelope({
|
|
662
707
|
status: "cancelled",
|
|
663
|
-
reason:
|
|
708
|
+
reason: CALL_CANCELLED_REASON,
|
|
664
709
|
resolution: "none",
|
|
665
710
|
votes,
|
|
666
711
|
profile,
|
|
@@ -673,14 +718,17 @@ var CouncilOrchestrator = class {
|
|
|
673
718
|
if (timeoutSignal.aborted) {
|
|
674
719
|
return resultEnvelope({
|
|
675
720
|
status: "failed",
|
|
676
|
-
reason:
|
|
721
|
+
reason: OVERALL_TIMEOUT_REASON,
|
|
677
722
|
resolution: "none",
|
|
678
723
|
votes,
|
|
679
724
|
profile,
|
|
680
725
|
usage,
|
|
681
726
|
startedAt,
|
|
682
727
|
warnings,
|
|
683
|
-
|
|
728
|
+
// Seat-prefixed errors normally carry the canonical timeout text, but
|
|
729
|
+
// a signal-blind caller can resolve valid votes even after the budget
|
|
730
|
+
// expired — append the standalone entry only when nothing carries it.
|
|
731
|
+
errors: errors.some((entry) => entry.includes(OVERALL_TIMEOUT_REASON)) ? errors : [...errors, OVERALL_TIMEOUT_REASON]
|
|
684
732
|
});
|
|
685
733
|
}
|
|
686
734
|
if (!question.options || question.options.length === 0) {
|
|
@@ -707,7 +755,17 @@ var CouncilOrchestrator = class {
|
|
|
707
755
|
);
|
|
708
756
|
}
|
|
709
757
|
async callSeat(question, profile, seat, seatIndex, signal, usage) {
|
|
710
|
-
if (signal.aborted)
|
|
758
|
+
if (signal.aborted) {
|
|
759
|
+
return question.signal?.aborted ? cancelledVote(seat) : {
|
|
760
|
+
seatId: seat.id,
|
|
761
|
+
persona: seat.persona,
|
|
762
|
+
status: "failed",
|
|
763
|
+
...seat.target?.providerId ? { provider: seat.target.providerId } : {},
|
|
764
|
+
...seat.target?.model ? { model: seat.target.model } : {},
|
|
765
|
+
durationMs: 0,
|
|
766
|
+
error: OVERALL_TIMEOUT_REASON
|
|
767
|
+
};
|
|
768
|
+
}
|
|
711
769
|
let persona;
|
|
712
770
|
try {
|
|
713
771
|
persona = this.personas.require(seat.persona);
|
|
@@ -733,12 +791,15 @@ var CouncilOrchestrator = class {
|
|
|
733
791
|
});
|
|
734
792
|
const metadata = callMetadata(result);
|
|
735
793
|
if (result.error) {
|
|
794
|
+
const timedOut = signal.aborted && !question.signal?.aborted;
|
|
736
795
|
return {
|
|
737
796
|
seatId: seat.id,
|
|
738
797
|
persona: seat.persona,
|
|
739
|
-
status: signal
|
|
798
|
+
status: question.signal?.aborted ? "cancelled" : "failed",
|
|
740
799
|
...metadata,
|
|
741
|
-
|
|
800
|
+
// Canonical text for cancelled or aborted-by-budget seats, so one
|
|
801
|
+
// cancel/timeout event does not surface a raw provider string.
|
|
802
|
+
error: question.signal?.aborted ? CALL_CANCELLED_REASON : timedOut ? OVERALL_TIMEOUT_REASON : result.error
|
|
742
803
|
};
|
|
743
804
|
}
|
|
744
805
|
const parsed = parseVote(result.text, question, this.refusalOptionId);
|
|
@@ -837,9 +898,27 @@ var CouncilOrchestrator = class {
|
|
|
837
898
|
signal,
|
|
838
899
|
usage
|
|
839
900
|
);
|
|
901
|
+
if (signal.aborted) {
|
|
902
|
+
const cancelled = question.signal?.aborted === true;
|
|
903
|
+
const reason = cancelled ? CALL_CANCELLED_REASON : OVERALL_TIMEOUT_REASON;
|
|
904
|
+
return resultEnvelope({
|
|
905
|
+
status: cancelled ? "cancelled" : "failed",
|
|
906
|
+
reason,
|
|
907
|
+
resolution: "none",
|
|
908
|
+
votes,
|
|
909
|
+
profile,
|
|
910
|
+
usage,
|
|
911
|
+
startedAt,
|
|
912
|
+
warnings,
|
|
913
|
+
errors: errors.some((entry) => entry.includes(reason)) ? errors : [...errors, reason],
|
|
914
|
+
judgeUsed: true
|
|
915
|
+
});
|
|
916
|
+
}
|
|
840
917
|
if (!judged.ok) {
|
|
841
918
|
return resultEnvelope({
|
|
842
|
-
|
|
919
|
+
// User cancel -> cancelled; overall budget expired mid-judge -> failed;
|
|
920
|
+
// otherwise the judge simply failed -> abstained (can't decide).
|
|
921
|
+
status: question.signal?.aborted ? "cancelled" : signal.aborted ? "failed" : "abstained",
|
|
843
922
|
reason: judged.error,
|
|
844
923
|
resolution: "none",
|
|
845
924
|
votes,
|
|
@@ -899,6 +978,19 @@ var CouncilOrchestrator = class {
|
|
|
899
978
|
});
|
|
900
979
|
}
|
|
901
980
|
if (!profile.judge) {
|
|
981
|
+
if (divergentStances(valid)) {
|
|
982
|
+
return resultEnvelope({
|
|
983
|
+
status: "abstained",
|
|
984
|
+
reason: "Council produced multiple distinct stances and has no judge to reconcile them.",
|
|
985
|
+
resolution: "none",
|
|
986
|
+
votes,
|
|
987
|
+
profile,
|
|
988
|
+
usage,
|
|
989
|
+
startedAt,
|
|
990
|
+
warnings,
|
|
991
|
+
errors
|
|
992
|
+
});
|
|
993
|
+
}
|
|
902
994
|
const first = valid[0];
|
|
903
995
|
if (!first) {
|
|
904
996
|
return resultEnvelope({
|
|
@@ -935,9 +1027,30 @@ var CouncilOrchestrator = class {
|
|
|
935
1027
|
signal,
|
|
936
1028
|
usage
|
|
937
1029
|
);
|
|
1030
|
+
if (signal.aborted) {
|
|
1031
|
+
const cancelled = question.signal?.aborted === true;
|
|
1032
|
+
const reason = cancelled ? CALL_CANCELLED_REASON : OVERALL_TIMEOUT_REASON;
|
|
1033
|
+
return resultEnvelope({
|
|
1034
|
+
status: cancelled ? "cancelled" : "failed",
|
|
1035
|
+
reason,
|
|
1036
|
+
resolution: "none",
|
|
1037
|
+
votes,
|
|
1038
|
+
profile,
|
|
1039
|
+
usage,
|
|
1040
|
+
startedAt,
|
|
1041
|
+
warnings,
|
|
1042
|
+
errors: errors.some((entry) => entry.includes(reason)) ? errors : [...errors, reason],
|
|
1043
|
+
judgeUsed: true
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
938
1046
|
if (!judged.ok) {
|
|
939
1047
|
return resultEnvelope({
|
|
940
|
-
|
|
1048
|
+
// User cancel -> cancelled; overall budget expired mid-judge -> failed;
|
|
1049
|
+
// otherwise the judge simply failed -> failed (open questions cannot
|
|
1050
|
+
// abstain for a judge failure — 'abstained' is reserved for quorum
|
|
1051
|
+
// failure and stance divergence; the option path maps this same
|
|
1052
|
+
// plain-judge-failure case to 'abstained' instead).
|
|
1053
|
+
status: question.signal?.aborted ? "cancelled" : "failed",
|
|
941
1054
|
reason: judged.error,
|
|
942
1055
|
resolution: "none",
|
|
943
1056
|
votes,
|
|
@@ -976,18 +1089,28 @@ var CouncilOrchestrator = class {
|
|
|
976
1089
|
signal,
|
|
977
1090
|
usage
|
|
978
1091
|
});
|
|
979
|
-
if (result.error)
|
|
1092
|
+
if (result.error) {
|
|
1093
|
+
if (signal.aborted && !question.signal?.aborted) {
|
|
1094
|
+
return { ok: false, error: OVERALL_TIMEOUT_REASON };
|
|
1095
|
+
}
|
|
1096
|
+
if (question.signal?.aborted) {
|
|
1097
|
+
return { ok: false, error: CALL_CANCELLED_REASON };
|
|
1098
|
+
}
|
|
1099
|
+
return { ok: false, error: result.error };
|
|
1100
|
+
}
|
|
980
1101
|
return parseJudge(result.text, question, this.refusalOptionId);
|
|
981
1102
|
}
|
|
982
1103
|
/**
|
|
983
|
-
* Resolve the effective LLM caller for a call. Voter seats
|
|
984
|
-
* `seatCaller(seatIndex)` when wired
|
|
985
|
-
*
|
|
986
|
-
*
|
|
1104
|
+
* Resolve the effective LLM caller for a call. Voter seats (defined
|
|
1105
|
+
* seatIndex) use `seatCaller(seatIndex)` when wired, otherwise the shared
|
|
1106
|
+
* `caller` — a seat never falls through to the judge caller. Judge seats
|
|
1107
|
+
* (seatIndex undefined) use `judgeCaller` if set, otherwise `seatCaller(0)`
|
|
1108
|
+
* if set, otherwise the shared `caller`.
|
|
987
1109
|
*/
|
|
988
1110
|
resolveCaller(seatIndex) {
|
|
989
|
-
if (seatIndex !== void 0
|
|
990
|
-
return this.seatCaller(seatIndex);
|
|
1111
|
+
if (seatIndex !== void 0) {
|
|
1112
|
+
if (this.seatCaller) return this.seatCaller(seatIndex);
|
|
1113
|
+
return this.caller ?? this.judgeCaller;
|
|
991
1114
|
}
|
|
992
1115
|
if (this.judgeCaller) return this.judgeCaller;
|
|
993
1116
|
if (this.seatCaller) return this.seatCaller(0);
|
|
@@ -996,6 +1119,7 @@ var CouncilOrchestrator = class {
|
|
|
996
1119
|
async safeCall(input) {
|
|
997
1120
|
const effectiveCaller = this.resolveCaller(input.seatIndex);
|
|
998
1121
|
const resolvedTarget = this.resolveCouncilTarget(input.target);
|
|
1122
|
+
const startedAt = Date.now();
|
|
999
1123
|
try {
|
|
1000
1124
|
const result = await effectiveCaller.call({
|
|
1001
1125
|
system: input.system,
|
|
@@ -1012,8 +1136,17 @@ var CouncilOrchestrator = class {
|
|
|
1012
1136
|
addUsage(input.usage, result);
|
|
1013
1137
|
return result;
|
|
1014
1138
|
} catch (error) {
|
|
1015
|
-
|
|
1016
|
-
|
|
1139
|
+
const failed = {
|
|
1140
|
+
text: "",
|
|
1141
|
+
model: resolvedTarget?.model ?? "",
|
|
1142
|
+
provider: resolvedTarget?.providerId ?? "",
|
|
1143
|
+
tokens: { input: 0, output: 0, total: 0 },
|
|
1144
|
+
durationMs: Math.max(0, Date.now() - startedAt),
|
|
1145
|
+
fromFallback: false,
|
|
1146
|
+
error: errorMessage(error)
|
|
1147
|
+
};
|
|
1148
|
+
addUsage(input.usage, failed);
|
|
1149
|
+
return failed;
|
|
1017
1150
|
}
|
|
1018
1151
|
}
|
|
1019
1152
|
/**
|
|
@@ -1045,47 +1178,77 @@ var CouncilOrchestrator = class {
|
|
|
1045
1178
|
};
|
|
1046
1179
|
}
|
|
1047
1180
|
};
|
|
1048
|
-
function
|
|
1181
|
+
function parseCouncilResponse(text, question, refusalOptionId, opts) {
|
|
1182
|
+
const roleLabel = opts.role === "judge" ? "Judge" : "Voter";
|
|
1049
1183
|
const parsed = parseObject(text);
|
|
1050
1184
|
if (!parsed.ok && (!question.options || question.options.length === 0)) {
|
|
1051
1185
|
const fallback = text.trim();
|
|
1052
|
-
if (fallback) return { ok: true,
|
|
1053
|
-
return { ok: false, error:
|
|
1186
|
+
if (fallback) return { ok: true, value: { [opts.freeTextField]: fallback } };
|
|
1187
|
+
return { ok: false, error: `${roleLabel} returned an empty response.` };
|
|
1054
1188
|
}
|
|
1055
1189
|
if (!parsed.ok) return parsed;
|
|
1056
1190
|
const rationale = optionalString(parsed.value["rationale"]);
|
|
1057
1191
|
if (question.options && question.options.length > 0) {
|
|
1058
1192
|
const optionId = optionalString(parsed.value["optionId"]);
|
|
1059
|
-
const allowed = /* @__PURE__ */ new Set([
|
|
1193
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
1194
|
+
...question.options.map((option) => option.id.trim()),
|
|
1195
|
+
refusalOptionId
|
|
1196
|
+
]);
|
|
1060
1197
|
if (!optionId || !allowed.has(optionId)) {
|
|
1061
|
-
return { ok: false, error:
|
|
1198
|
+
return { ok: false, error: `${roleLabel} returned an unknown or missing optionId.` };
|
|
1062
1199
|
}
|
|
1063
|
-
return { ok: true,
|
|
1200
|
+
return { ok: true, value: { optionId, ...rationale ? { rationale } : {} } };
|
|
1064
1201
|
}
|
|
1065
|
-
const
|
|
1066
|
-
if (!
|
|
1067
|
-
|
|
1202
|
+
const freeText = optionalString(parsed.value[opts.freeTextField]);
|
|
1203
|
+
if (!freeText) {
|
|
1204
|
+
return {
|
|
1205
|
+
ok: false,
|
|
1206
|
+
error: `${roleLabel} returned an empty or missing ${opts.freeTextField}.`
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
return { ok: true, value: { [opts.freeTextField]: freeText, ...rationale ? { rationale } : {} } };
|
|
1068
1210
|
}
|
|
1069
|
-
function
|
|
1070
|
-
const
|
|
1071
|
-
|
|
1072
|
-
const
|
|
1073
|
-
if (
|
|
1074
|
-
|
|
1211
|
+
function divergentStances(valid) {
|
|
1212
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1213
|
+
for (const vote of valid) {
|
|
1214
|
+
const normalized = vote.stance.trim().replace(/^["'`]+|["'`]+$/g, "").toLowerCase().replace(/[.!?;:,]+$/g, "").replace(/\s+/g, " ").trim();
|
|
1215
|
+
if (!normalized) return true;
|
|
1216
|
+
seen.add(normalized);
|
|
1217
|
+
if (seen.size > 1) return true;
|
|
1075
1218
|
}
|
|
1219
|
+
return false;
|
|
1220
|
+
}
|
|
1221
|
+
function parseVote(text, question, refusalOptionId) {
|
|
1222
|
+
const parsed = parseCouncilResponse(text, question, refusalOptionId, {
|
|
1223
|
+
role: "voter",
|
|
1224
|
+
freeTextField: "stance"
|
|
1225
|
+
});
|
|
1076
1226
|
if (!parsed.ok) return parsed;
|
|
1077
|
-
const rationale =
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1227
|
+
const { optionId, stance, rationale } = parsed.value;
|
|
1228
|
+
return {
|
|
1229
|
+
ok: true,
|
|
1230
|
+
vote: {
|
|
1231
|
+
...optionId ? { optionId } : {},
|
|
1232
|
+
...stance ? { stance } : {},
|
|
1233
|
+
...rationale ? { rationale } : {}
|
|
1083
1234
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
function parseJudge(text, question, refusalOptionId) {
|
|
1238
|
+
const parsed = parseCouncilResponse(text, question, refusalOptionId, {
|
|
1239
|
+
role: "judge",
|
|
1240
|
+
freeTextField: "answer"
|
|
1241
|
+
});
|
|
1242
|
+
if (!parsed.ok) return parsed;
|
|
1243
|
+
const { optionId, answer, rationale } = parsed.value;
|
|
1244
|
+
return {
|
|
1245
|
+
ok: true,
|
|
1246
|
+
value: {
|
|
1247
|
+
...optionId ? { optionId } : {},
|
|
1248
|
+
...answer ? { answer } : {},
|
|
1249
|
+
...rationale ? { rationale } : {}
|
|
1250
|
+
}
|
|
1251
|
+
};
|
|
1089
1252
|
}
|
|
1090
1253
|
function parseObject(text) {
|
|
1091
1254
|
const trimmed = text.trim();
|
|
@@ -1129,7 +1292,7 @@ function callMetadata(result) {
|
|
|
1129
1292
|
};
|
|
1130
1293
|
}
|
|
1131
1294
|
function addUsage(usage, result) {
|
|
1132
|
-
usage.calls += 1;
|
|
1295
|
+
usage.calls += Math.max(1, result.attempts ?? 1);
|
|
1133
1296
|
usage.inputTokens += result.tokens.input;
|
|
1134
1297
|
usage.outputTokens += result.tokens.output;
|
|
1135
1298
|
usage.totalTokens += result.tokens.total;
|
|
@@ -1138,21 +1301,40 @@ function usageResult(usage, startedAt) {
|
|
|
1138
1301
|
return Object.freeze({ ...usage, durationMs: Math.max(0, Date.now() - startedAt) });
|
|
1139
1302
|
}
|
|
1140
1303
|
function cancelledVote(seat) {
|
|
1141
|
-
return {
|
|
1304
|
+
return {
|
|
1305
|
+
seatId: seat.id,
|
|
1306
|
+
persona: seat.persona,
|
|
1307
|
+
status: "cancelled",
|
|
1308
|
+
...seat.target?.providerId ? { provider: seat.target.providerId } : {},
|
|
1309
|
+
...seat.target?.model ? { model: seat.target.model } : {},
|
|
1310
|
+
durationMs: 0,
|
|
1311
|
+
error: CALL_CANCELLED_REASON
|
|
1312
|
+
};
|
|
1142
1313
|
}
|
|
1143
1314
|
function distinctTargetCount(votes, profile) {
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1315
|
+
return new Set(distinctTargetKeys(votes, profile)).size;
|
|
1316
|
+
}
|
|
1317
|
+
function distinctTargetKeys(votes, profile) {
|
|
1318
|
+
const keys = [];
|
|
1319
|
+
for (const vote of votes) {
|
|
1320
|
+
if (vote.status !== "valid") continue;
|
|
1321
|
+
const provider = vote.provider?.trim() ?? "";
|
|
1322
|
+
const model = vote.model?.trim() ?? "";
|
|
1323
|
+
if (profile.distinctness === "provider") {
|
|
1324
|
+
if (provider) keys.push(provider);
|
|
1325
|
+
} else if (provider || model) {
|
|
1326
|
+
keys.push(`${provider}/${model}`);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
return keys;
|
|
1148
1330
|
}
|
|
1149
1331
|
function distinctnessWarnings(votes, profile) {
|
|
1150
1332
|
if (profile.distinctness === "none") return [];
|
|
1151
|
-
const
|
|
1152
|
-
const distinct =
|
|
1153
|
-
if (
|
|
1333
|
+
const keys = distinctTargetKeys(votes, profile);
|
|
1334
|
+
const distinct = new Set(keys).size;
|
|
1335
|
+
if (keys.length > 1 && distinct < keys.length) {
|
|
1154
1336
|
return [
|
|
1155
|
-
`Council distinctness policy "${profile.distinctness}" was not met: ${distinct} distinct target(s) served ${
|
|
1337
|
+
`Council distinctness policy "${profile.distinctness}" was not met: ${distinct} distinct target(s) served ${keys.length} valid vote(s).`
|
|
1156
1338
|
];
|
|
1157
1339
|
}
|
|
1158
1340
|
return [];
|
|
@@ -1188,17 +1370,6 @@ async function mapConcurrent(items, concurrency, worker) {
|
|
|
1188
1370
|
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => run()));
|
|
1189
1371
|
return results;
|
|
1190
1372
|
}
|
|
1191
|
-
function emptyCallResult(error) {
|
|
1192
|
-
return {
|
|
1193
|
-
text: "",
|
|
1194
|
-
model: "",
|
|
1195
|
-
provider: "",
|
|
1196
|
-
tokens: { input: 0, output: 0, total: 0 },
|
|
1197
|
-
durationMs: 0,
|
|
1198
|
-
fromFallback: false,
|
|
1199
|
-
error
|
|
1200
|
-
};
|
|
1201
|
-
}
|
|
1202
1373
|
function optionalString(value) {
|
|
1203
1374
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
1204
1375
|
}
|
|
@@ -1297,14 +1468,7 @@ function validateCouncilToolInput(input, profileIds) {
|
|
|
1297
1468
|
if ((input.options?.length ?? 0) > MAX_COUNCIL_TOOL_OPTIONS) {
|
|
1298
1469
|
errors.push(`\`options\` must not contain more than ${MAX_COUNCIL_TOOL_OPTIONS} items.`);
|
|
1299
1470
|
}
|
|
1300
|
-
|
|
1301
|
-
for (const option of input.options ?? []) {
|
|
1302
|
-
const id = option.id.trim();
|
|
1303
|
-
if (!id) errors.push("Every option must have a non-empty `id`.");
|
|
1304
|
-
if (!option.label.trim()) errors.push(`Option "${id || "<empty>"}" must have a label.`);
|
|
1305
|
-
if (ids.has(id)) errors.push(`Duplicate option id "${id}".`);
|
|
1306
|
-
ids.add(id);
|
|
1307
|
-
}
|
|
1471
|
+
errors.push(...validateCouncilOptions(input.options));
|
|
1308
1472
|
return errors;
|
|
1309
1473
|
}
|
|
1310
1474
|
|
|
@@ -6199,8 +6363,18 @@ var SYSTEM_CONFIG_VIEW_SCHEMA = {
|
|
|
6199
6363
|
properties: {
|
|
6200
6364
|
section: {
|
|
6201
6365
|
type: "string",
|
|
6202
|
-
enum: [
|
|
6203
|
-
|
|
6366
|
+
enum: [
|
|
6367
|
+
"all",
|
|
6368
|
+
"providers",
|
|
6369
|
+
"models",
|
|
6370
|
+
"fallbacks",
|
|
6371
|
+
"matrix",
|
|
6372
|
+
"agents",
|
|
6373
|
+
"fleet",
|
|
6374
|
+
"refiner",
|
|
6375
|
+
"doctor"
|
|
6376
|
+
],
|
|
6377
|
+
description: "Which section to show: all (everything), providers (configured providers + keys), models (favorites + leader), fallbacks (chain + profiles + toggles), matrix (per-role assignments), agents (every catalog agent with resolved model), fleet (concurrency + lifetime spawn/token/cost budgets), refiner (goal refinement config), doctor (validate config and show issues/warnings). Default: all."
|
|
6204
6378
|
}
|
|
6205
6379
|
},
|
|
6206
6380
|
additionalProperties: false
|
|
@@ -6302,6 +6476,7 @@ ${content}`);
|
|
|
6302
6476
|
const profiles = config.fallbackProfiles ?? {};
|
|
6303
6477
|
const chain = config.fallbackModels ?? [];
|
|
6304
6478
|
const matrix = config.modelMatrix ?? {};
|
|
6479
|
+
const fleetBudget = config.fleet?.budget;
|
|
6305
6480
|
const bridge = config.fallbackBridge?.trim();
|
|
6306
6481
|
if (bridge) {
|
|
6307
6482
|
const parsed = parseModelRef(bridge);
|
|
@@ -6371,6 +6546,26 @@ ${content}`);
|
|
|
6371
6546
|
}
|
|
6372
6547
|
}
|
|
6373
6548
|
}
|
|
6549
|
+
if (typeof config.maxConcurrent === "number") {
|
|
6550
|
+
if (!Number.isFinite(config.maxConcurrent) || config.maxConcurrent < 0) {
|
|
6551
|
+
issues.push(`maxConcurrent must be a non-negative number (got ${config.maxConcurrent})`);
|
|
6552
|
+
} else if (config.maxConcurrent === 0) {
|
|
6553
|
+
warnings.push("maxConcurrent is 0 \u2014 subagent concurrency effectively disabled");
|
|
6554
|
+
} else {
|
|
6555
|
+
ok.push(`maxConcurrent ${config.maxConcurrent}`);
|
|
6556
|
+
}
|
|
6557
|
+
}
|
|
6558
|
+
if (fleetBudget && typeof fleetBudget === "object") {
|
|
6559
|
+
for (const key of ["maxSpawns", "maxTokens", "maxCostUsd"]) {
|
|
6560
|
+
const v = fleetBudget[key];
|
|
6561
|
+
if (v === void 0) continue;
|
|
6562
|
+
if (typeof v !== "number" || !Number.isFinite(v) || v < 0) {
|
|
6563
|
+
issues.push(`fleet.budget.${key} must be a non-negative number (got ${JSON.stringify(v)})`);
|
|
6564
|
+
} else {
|
|
6565
|
+
ok.push(`fleet.budget.${key} ${v}`);
|
|
6566
|
+
}
|
|
6567
|
+
}
|
|
6568
|
+
}
|
|
6374
6569
|
for (const [key, entry] of Object.entries(matrix)) {
|
|
6375
6570
|
const eProvider = entry.provider ?? config.provider;
|
|
6376
6571
|
const eModel = entry.model;
|
|
@@ -6411,6 +6606,27 @@ ${content}`);
|
|
|
6411
6606
|
}
|
|
6412
6607
|
addSection("Configuration Doctor", lines.join("\n"));
|
|
6413
6608
|
}
|
|
6609
|
+
if (section === "all" || section === "fleet") {
|
|
6610
|
+
const fleet = config.fleet;
|
|
6611
|
+
const budget = fleet?.budget;
|
|
6612
|
+
const lifecycle = fleet?.lifecycle;
|
|
6613
|
+
const fmt = (n, unit = "") => typeof n === "number" && Number.isFinite(n) ? `${n}${unit}` : "(default)";
|
|
6614
|
+
addSection(
|
|
6615
|
+
"Fleet Budgets (configured ceilings)",
|
|
6616
|
+
[
|
|
6617
|
+
` maxConcurrent: ${typeof config.maxConcurrent === "number" ? config.maxConcurrent : "(default 4)"}`,
|
|
6618
|
+
` fleet.budget.maxSpawns: ${fmt(budget?.maxSpawns)} ${typeof budget?.maxSpawns !== "number" ? "\u2192 default 64" : ""}`,
|
|
6619
|
+
` fleet.budget.maxTokens: ${fmt(budget?.maxTokens)}`,
|
|
6620
|
+
` fleet.budget.maxCostUsd: ${fmt(budget?.maxCostUsd)}`,
|
|
6621
|
+
` fleet.lifecycle.idleTimeoutMs: ${fmt(lifecycle?.idleTimeoutMs, "ms")}`,
|
|
6622
|
+
` fleet.lifecycle.retireOnTaskComplete: ${lifecycle?.retireOnTaskComplete === void 0 ? "(default true)" : String(lifecycle.retireOnTaskComplete)}`,
|
|
6623
|
+
"",
|
|
6624
|
+
" Live used/remaining spawns are on /fleet status (not static config).",
|
|
6625
|
+
" Override ceilings: --max-concurrent / WRONGSTACK_MAX_CONCURRENT,",
|
|
6626
|
+
" --max-spawns / WRONGSTACK_MAX_SPAWNS, or fleet.budget.maxSpawns in profile."
|
|
6627
|
+
].join("\n")
|
|
6628
|
+
);
|
|
6629
|
+
}
|
|
6414
6630
|
if (section === "all" || section === "refiner") {
|
|
6415
6631
|
const ref = config.autonomy;
|
|
6416
6632
|
addSection(
|
|
@@ -7732,6 +7948,7 @@ var OneShotOrchestrator = class {
|
|
|
7732
7948
|
tokens: { input: 0, output: 0, total: 0 },
|
|
7733
7949
|
durationMs: Math.round(performance.now() - startedAt),
|
|
7734
7950
|
fromFallback: false,
|
|
7951
|
+
attempts: 0,
|
|
7735
7952
|
error: "No provider or model could be resolved. Check your config."
|
|
7736
7953
|
};
|
|
7737
7954
|
}
|
|
@@ -7746,6 +7963,7 @@ var OneShotOrchestrator = class {
|
|
|
7746
7963
|
tokens: { input: 0, output: 0, total: 0 },
|
|
7747
7964
|
durationMs: Math.round(performance.now() - startedAt),
|
|
7748
7965
|
fromFallback: false,
|
|
7966
|
+
attempts: 0,
|
|
7749
7967
|
error: `Cannot build provider "${target.providerId}": ${err instanceof Error ? err.message : String(err)}`
|
|
7750
7968
|
};
|
|
7751
7969
|
}
|
|
@@ -7758,11 +7976,13 @@ var OneShotOrchestrator = class {
|
|
|
7758
7976
|
let fromFallback = false;
|
|
7759
7977
|
let lastError;
|
|
7760
7978
|
let fallbackEligible = false;
|
|
7979
|
+
let attempts = 0;
|
|
7761
7980
|
if (tracker && !tracker.isAvailable(target.providerId, target.model) || !evaluateModelCalendar(config.modelAvailabilitySchedule, target.providerId, target.model).allowed) {
|
|
7762
7981
|
this.opts.logger?.debug(
|
|
7763
7982
|
`one-shot: primary "${target.providerId}/${target.model}" is blocked \u2014 trying fallback`
|
|
7764
7983
|
);
|
|
7765
7984
|
} else {
|
|
7985
|
+
attempts += 1;
|
|
7766
7986
|
const primaryAttempt = await this.tryCall(
|
|
7767
7987
|
provider,
|
|
7768
7988
|
request,
|
|
@@ -7777,10 +7997,17 @@ var OneShotOrchestrator = class {
|
|
|
7777
7997
|
tracker?.recordSuccess(target.providerId, target.model);
|
|
7778
7998
|
servingProviderId = provider.id;
|
|
7779
7999
|
servingModel = target.model;
|
|
7780
|
-
return this.buildResult(result, servingProviderId, servingModel, false, startedAt);
|
|
8000
|
+
return this.buildResult(result, servingProviderId, servingModel, false, startedAt, attempts);
|
|
7781
8001
|
}
|
|
7782
8002
|
if (!fallbackEligible || chain.length === 0) {
|
|
7783
|
-
return this.buildErrorResult(
|
|
8003
|
+
return this.buildErrorResult(
|
|
8004
|
+
lastError,
|
|
8005
|
+
target.providerId,
|
|
8006
|
+
target.model,
|
|
8007
|
+
false,
|
|
8008
|
+
startedAt,
|
|
8009
|
+
attempts
|
|
8010
|
+
);
|
|
7784
8011
|
}
|
|
7785
8012
|
}
|
|
7786
8013
|
const estimatedTokens = estimateRequestTokens(request.messages, request.system, []).total;
|
|
@@ -7808,6 +8035,7 @@ var OneShotOrchestrator = class {
|
|
|
7808
8035
|
}
|
|
7809
8036
|
servingProviderId = fbProvider.id;
|
|
7810
8037
|
servingModel = entry.model;
|
|
8038
|
+
attempts += 1;
|
|
7811
8039
|
const attempt = await this.tryCall(
|
|
7812
8040
|
fbProvider,
|
|
7813
8041
|
this.buildRequest(input, entry.model),
|
|
@@ -7818,7 +8046,14 @@ var OneShotOrchestrator = class {
|
|
|
7818
8046
|
if (attempt.response) {
|
|
7819
8047
|
tracker?.recordSuccess(entry.providerId, entry.model);
|
|
7820
8048
|
fromFallback = true;
|
|
7821
|
-
return this.buildResult(
|
|
8049
|
+
return this.buildResult(
|
|
8050
|
+
attempt.response,
|
|
8051
|
+
servingProviderId,
|
|
8052
|
+
servingModel,
|
|
8053
|
+
true,
|
|
8054
|
+
startedAt,
|
|
8055
|
+
attempts
|
|
8056
|
+
);
|
|
7822
8057
|
}
|
|
7823
8058
|
lastError = attempt.error;
|
|
7824
8059
|
}
|
|
@@ -7827,7 +8062,8 @@ var OneShotOrchestrator = class {
|
|
|
7827
8062
|
servingProviderId,
|
|
7828
8063
|
servingModel,
|
|
7829
8064
|
fromFallback,
|
|
7830
|
-
startedAt
|
|
8065
|
+
startedAt,
|
|
8066
|
+
attempts
|
|
7831
8067
|
);
|
|
7832
8068
|
}
|
|
7833
8069
|
// ── Private helpers ─────────────────────────────────────────────
|
|
@@ -7951,7 +8187,7 @@ var OneShotOrchestrator = class {
|
|
|
7951
8187
|
}
|
|
7952
8188
|
}
|
|
7953
8189
|
/** Build a success result from a provider Response. */
|
|
7954
|
-
buildResult(response, servingProviderId, servingModel, fromFallback, startedAt) {
|
|
8190
|
+
buildResult(response, servingProviderId, servingModel, fromFallback, startedAt, attempts) {
|
|
7955
8191
|
const textBlocks = response.content.filter(isTextBlock);
|
|
7956
8192
|
const text = textBlocks.map((b) => b.text).join("\n").trim();
|
|
7957
8193
|
return {
|
|
@@ -7965,11 +8201,12 @@ var OneShotOrchestrator = class {
|
|
|
7965
8201
|
},
|
|
7966
8202
|
durationMs: Math.round(performance.now() - startedAt),
|
|
7967
8203
|
fromFallback,
|
|
8204
|
+
attempts,
|
|
7968
8205
|
stopReason: response.stopReason
|
|
7969
8206
|
};
|
|
7970
8207
|
}
|
|
7971
8208
|
/** Build a total-failure error result. */
|
|
7972
|
-
buildErrorResult(error, servingProviderId, servingModel, fromFallback, startedAt) {
|
|
8209
|
+
buildErrorResult(error, servingProviderId, servingModel, fromFallback, startedAt, attempts) {
|
|
7973
8210
|
return {
|
|
7974
8211
|
text: "",
|
|
7975
8212
|
model: servingModel,
|
|
@@ -7977,6 +8214,7 @@ var OneShotOrchestrator = class {
|
|
|
7977
8214
|
tokens: { input: 0, output: 0, total: 0 },
|
|
7978
8215
|
durationMs: Math.round(performance.now() - startedAt),
|
|
7979
8216
|
fromFallback,
|
|
8217
|
+
attempts,
|
|
7980
8218
|
error: error instanceof Error ? error.message : String(error ?? "Unknown error")
|
|
7981
8219
|
};
|
|
7982
8220
|
}
|
|
@@ -8107,6 +8345,44 @@ function createOneShotLLMTool(opts) {
|
|
|
8107
8345
|
};
|
|
8108
8346
|
}
|
|
8109
8347
|
|
|
8348
|
+
// src/plugin/config.ts
|
|
8349
|
+
function pluginEntryMatchesName(configuredName, name, aliases = []) {
|
|
8350
|
+
for (const candidate of [name, ...aliases]) {
|
|
8351
|
+
if (configuredName === candidate) return true;
|
|
8352
|
+
if (configuredName === `@wrongstack/plugins/${candidate}`) return true;
|
|
8353
|
+
}
|
|
8354
|
+
return false;
|
|
8355
|
+
}
|
|
8356
|
+
function resolvePluginEnablement(input) {
|
|
8357
|
+
if (input.config?.features?.plugins === false) {
|
|
8358
|
+
return { enabled: false, source: "feature-flag" };
|
|
8359
|
+
}
|
|
8360
|
+
const names = [.../* @__PURE__ */ new Set([input.name, ...input.aliases ?? []])];
|
|
8361
|
+
const matches = input.matches ?? ((configuredName) => pluginEntryMatchesName(configuredName, input.name, input.aliases ?? []));
|
|
8362
|
+
const plugins = input.config?.plugins;
|
|
8363
|
+
if (Array.isArray(plugins)) {
|
|
8364
|
+
for (const candidate of plugins) {
|
|
8365
|
+
if (typeof candidate === "string") {
|
|
8366
|
+
if (matches(candidate)) return { enabled: true, source: "plugin-entry" };
|
|
8367
|
+
continue;
|
|
8368
|
+
}
|
|
8369
|
+
if (!isPluginEntry(candidate) || !matches(candidate.name)) continue;
|
|
8370
|
+
return { enabled: candidate.enabled !== false, source: "plugin-entry" };
|
|
8371
|
+
}
|
|
8372
|
+
}
|
|
8373
|
+
for (const name of names) {
|
|
8374
|
+
const enabled = input.config?.extensions?.[name]?.["enabled"];
|
|
8375
|
+
if (typeof enabled === "boolean") return { enabled, source: "extension" };
|
|
8376
|
+
}
|
|
8377
|
+
return { enabled: input.defaultState === "active", source: "default" };
|
|
8378
|
+
}
|
|
8379
|
+
function isPluginEntry(value) {
|
|
8380
|
+
return isRecord2(value) && typeof value["name"] === "string";
|
|
8381
|
+
}
|
|
8382
|
+
function isRecord2(value) {
|
|
8383
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8384
|
+
}
|
|
8385
|
+
|
|
8110
8386
|
// src/utils/json-schema-validate.ts
|
|
8111
8387
|
function validateAgainstSchema(value, schema) {
|
|
8112
8388
|
const errors = [];
|
|
@@ -8230,6 +8506,12 @@ function deepEqual(a, b) {
|
|
|
8230
8506
|
|
|
8231
8507
|
// src/tools/plugin-manager.ts
|
|
8232
8508
|
var PLUGIN_MANAGER_TOOL_NAME = "plugin_manager";
|
|
8509
|
+
var PLUGIN_VIEW_STATE_SOURCE = {
|
|
8510
|
+
"feature-flag": "feature_flag",
|
|
8511
|
+
"plugin-entry": "config",
|
|
8512
|
+
extension: "extension",
|
|
8513
|
+
default: "default"
|
|
8514
|
+
};
|
|
8233
8515
|
var INPUT_SCHEMA3 = {
|
|
8234
8516
|
type: "object",
|
|
8235
8517
|
properties: {
|
|
@@ -8461,10 +8743,14 @@ function buildPluginViews(opts) {
|
|
|
8461
8743
|
return catalog.map((entry) => {
|
|
8462
8744
|
const aliases = [...entry.aliases ?? []];
|
|
8463
8745
|
const names = /* @__PURE__ */ new Set([entry.name, ...aliases]);
|
|
8464
|
-
const
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8746
|
+
const { enabled, source } = resolvePluginEnablement({
|
|
8747
|
+
name: entry.name,
|
|
8748
|
+
aliases,
|
|
8749
|
+
defaultState: entry.defaultState,
|
|
8750
|
+
config,
|
|
8751
|
+
matches: (spec) => names.has(spec)
|
|
8752
|
+
});
|
|
8753
|
+
const stateSource = PLUGIN_VIEW_STATE_SOURCE[source];
|
|
8468
8754
|
const tools = pluginTools(opts.toolRegistry, entry.name, aliases);
|
|
8469
8755
|
const managerControl = isManagerLocked(config, entry.name, aliases) ? "locked" : "allowed";
|
|
8470
8756
|
return {
|