@uniqbit/mate-core 0.18.4 → 0.18.5

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.
Files changed (44) hide show
  1. package/opencode-plugin/src/add-dir.ts +76 -10
  2. package/opencode-plugin/src/companion.ts +1 -8
  3. package/opencode-plugin/src/server.ts +2 -15
  4. package/package.json +1 -1
  5. package/src/cli/commands/artifact/finish/openspec.ts +40 -8
  6. package/src/cli/commands/doctor.ts +92 -86
  7. package/src/cli/commands/install.ts +0 -8
  8. package/src/cli/commands/studio/terminal-launch.ts +7 -16
  9. package/src/cli/commands/wrap.ts +4 -29
  10. package/src/cli/usage.ts +1 -2
  11. package/src/hooks/session-guidance.ts +2 -20
  12. package/src/lib/orchestrator/adapters/claude.ts +20 -130
  13. package/src/lib/orchestrator/adapters/opencode.ts +7 -24
  14. package/src/lib/orchestrator/config-store.ts +2 -70
  15. package/src/lib/orchestrator/projection-claude-skills.ts +35 -88
  16. package/src/lib/orchestrator/projection-entries.ts +0 -1
  17. package/src/lib/orchestrator/projection-types.ts +0 -2
  18. package/src/lib/orchestrator/session-prepare.ts +4 -82
  19. package/src/lib/orchestrator/wrap-pass.ts +1 -88
  20. package/src/runtime/guidance.ts +0 -17
  21. package/src/runtime/policy.ts +1 -14
  22. package/src/runtime/runtime-document-manifest.ts +0 -17
  23. package/src/runtime/wrap-state.ts +0 -4
  24. package/src/tools/setup/capabilities/openspec.ts +140 -18
  25. package/src/tools/setup/dynamic-plugins/audiences.ts +7 -39
  26. package/src/tools/setup/dynamic-plugins/declarations.ts +1 -1
  27. package/src/tools/setup/dynamic-plugins/hydrate.ts +4 -7
  28. package/src/tools/setup/engine.ts +10 -141
  29. package/src/tools/setup/plugin.ts +4 -19
  30. package/src/tools/setup/plugins/gitignore.ts +1 -7
  31. package/src/tools/setup/providers/claude.ts +2 -27
  32. package/src/tools/setup/providers/opencode.ts +0 -10
  33. package/src/tools/setup/registry.ts +2 -24
  34. package/src/tools/setup/surface-target.ts +4 -13
  35. package/src/tools/setup.ts +6 -9
  36. package/opencode-plugin/src/audience-layer.ts +0 -91
  37. package/src/runtime/audience-layer.ts +0 -84
  38. package/src/runtime/opencode-audience-layer.ts +0 -176
  39. package/src/tools/setup/audience-isolation.fixture.ts +0 -325
  40. package/src/tools/setup/audience-layer.ts +0 -207
  41. package/src/tools/setup/audience-registrations.ts +0 -52
  42. package/src/tools/setup/contribution-ledger.ts +0 -207
  43. package/src/tools/setup/isolation-diagnostics.ts +0 -139
  44. package/src/tools/setup/upgrade-sweep.ts +0 -153
@@ -1,207 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
-
4
- import { FRAMEWORK_NAME } from "../../framework";
5
- import { writeAtomic } from "../../runtime/write-atomic";
6
- import { instructionBlockKey } from "./context-services";
7
- import type { CapabilityContributionInput, RuntimeContributions } from "./plugin";
8
-
9
- /**
10
- * Contribution Ledger: which plugin owns each contribution a persisted pass
11
- * applied to the companion, per Agent Runtime. Committed with the companion,
12
- * because it describes committed files: a clone that never loaded a plugin
13
- * must still be able to remove what another clone committed. It records
14
- * identities only (names, block keys, markers, entries), never a value, so it
15
- * carries no secret.
16
- */
17
-
18
- export const CONTRIBUTION_LEDGER_VERSION = 1;
19
-
20
- /** The identities one owner applied on one runtime. Absent kinds are none. */
21
- export interface LedgerIdentities {
22
- mcpServers?: string[];
23
- guidanceKeys?: string[];
24
- skillTrees?: string[];
25
- agentDefinitions?: string[];
26
- hookMarkers?: string[];
27
- permissionEntries?: string[];
28
- pluginReferences?: string[];
29
- }
30
-
31
- export interface ContributionLedger {
32
- version: number;
33
- /** Runtime id → owning plugin id → identities. */
34
- runtimes: Record<string, Record<string, LedgerIdentities>>;
35
- /** Audience plugin packages the upgrade sweep could not load; retried by every pass. */
36
- unswept?: string[];
37
- }
38
-
39
- export function contributionLedgerPath(companionPath: string): string {
40
- return path.join(companionPath, `.${FRAMEWORK_NAME}`, "config", "contribution-ledger.json");
41
- }
42
-
43
- function isRecord(value: unknown): value is Record<string, unknown> {
44
- return typeof value === "object" && value !== null && !Array.isArray(value);
45
- }
46
-
47
- function stringList(value: unknown): string[] {
48
- return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
49
- }
50
-
51
- const IDENTITY_KINDS = [
52
- "agentDefinitions",
53
- "guidanceKeys",
54
- "hookMarkers",
55
- "mcpServers",
56
- "permissionEntries",
57
- "pluginReferences",
58
- "skillTrees",
59
- ] as const satisfies readonly (keyof LedgerIdentities)[];
60
-
61
- function sortedUnique(values: Iterable<string>): string[] {
62
- return [...new Set(values)].toSorted();
63
- }
64
-
65
- /** Sorted kinds and values, empty kinds dropped; `null` when nothing is left. */
66
- function normalizeIdentities(identities: LedgerIdentities): LedgerIdentities | null {
67
- const normalized: LedgerIdentities = {};
68
- for (const kind of IDENTITY_KINDS) {
69
- const values = sortedUnique(identities[kind] ?? []);
70
- if (values.length > 0) normalized[kind] = values;
71
- }
72
- return Object.keys(normalized).length > 0 ? normalized : null;
73
- }
74
-
75
- /** Sorted runtimes and owners; empty owners and runtimes dropped. */
76
- function normalizeLedger(ledger: ContributionLedger): ContributionLedger {
77
- const runtimes: ContributionLedger["runtimes"] = {};
78
- for (const runtimeId of Object.keys(ledger.runtimes).toSorted()) {
79
- const owners: Record<string, LedgerIdentities> = {};
80
- for (const owner of Object.keys(ledger.runtimes[runtimeId] ?? {}).toSorted()) {
81
- const identities = normalizeIdentities(ledger.runtimes[runtimeId]![owner]!);
82
- if (identities) owners[owner] = identities;
83
- }
84
- if (Object.keys(owners).length > 0) runtimes[runtimeId] = owners;
85
- }
86
- const unswept = sortedUnique(ledger.unswept ?? []);
87
- return {
88
- version: CONTRIBUTION_LEDGER_VERSION,
89
- runtimes,
90
- ...(unswept.length > 0 ? { unswept } : {}),
91
- };
92
- }
93
-
94
- /** The companion's ledger; `null` when absent or unreadable, which a pass treats as never recorded. */
95
- export async function readContributionLedger(
96
- companionPath: string,
97
- ): Promise<ContributionLedger | null> {
98
- let parsed: unknown;
99
- try {
100
- parsed = JSON.parse(await fs.readFile(contributionLedgerPath(companionPath), "utf8"));
101
- } catch {
102
- return null;
103
- }
104
- if (!isRecord(parsed) || !isRecord(parsed.runtimes)) return null;
105
- const runtimes: ContributionLedger["runtimes"] = {};
106
- for (const [runtimeId, owners] of Object.entries(parsed.runtimes)) {
107
- if (!isRecord(owners)) continue;
108
- runtimes[runtimeId] = {};
109
- for (const [owner, identities] of Object.entries(owners)) {
110
- if (!isRecord(identities)) continue;
111
- const read: LedgerIdentities = {};
112
- for (const kind of IDENTITY_KINDS) read[kind] = stringList(identities[kind]);
113
- runtimes[runtimeId][owner] = read;
114
- }
115
- }
116
- return normalizeLedger({
117
- version: CONTRIBUTION_LEDGER_VERSION,
118
- runtimes,
119
- unswept: stringList(parsed.unswept),
120
- });
121
- }
122
-
123
- /** Writes the ledger in its stable form; an unchanged ledger leaves the file untouched. */
124
- export async function writeContributionLedger(
125
- companionPath: string,
126
- ledger: ContributionLedger,
127
- ): Promise<void> {
128
- const target = contributionLedgerPath(companionPath);
129
- const text = `${JSON.stringify(normalizeLedger(ledger), null, 2)}\n`;
130
- const existing = await fs.readFile(target, "utf8").catch(() => null);
131
- if (existing === text) return;
132
- await fs.mkdir(path.dirname(target), { recursive: true });
133
- await writeAtomic(target, text);
134
- }
135
-
136
- /** The identities a contribution set applies for `pluginId`. */
137
- export function identitiesOf(
138
- pluginId: string,
139
- contributions: RuntimeContributions,
140
- ): LedgerIdentities {
141
- return {
142
- mcpServers: (contributions.mcpServers ?? []).map((server) => server.name),
143
- guidanceKeys: (contributions.guidanceSections ?? []).map((section) =>
144
- instructionBlockKey(pluginId, section.content),
145
- ),
146
- skillTrees: (contributions.skillTrees ?? []).map((tree) => tree.name),
147
- agentDefinitions: (contributions.agentDefinitions ?? []).map((agent) => agent.name),
148
- hookMarkers: (contributions.hookGroups ?? []).map((hook) => hook.marker),
149
- permissionEntries: [...(contributions.permissionEntries ?? [])],
150
- pluginReferences: (contributions.pluginReferences ?? []).map((entry) => entry.reference),
151
- };
152
- }
153
-
154
- /** The ledger a pass leaves: what its enabled inputs applied, per runtime and owner. */
155
- export function ledgerFromInputs(
156
- inputsByRuntime: ReadonlyMap<string, readonly CapabilityContributionInput[]>,
157
- unswept: readonly string[] = [],
158
- ): ContributionLedger {
159
- const runtimes: ContributionLedger["runtimes"] = {};
160
- for (const [runtimeId, inputs] of inputsByRuntime) {
161
- const owners: Record<string, LedgerIdentities> = {};
162
- for (const input of inputs) {
163
- if (!input.enabled) continue;
164
- const identities = identitiesOf(input.pluginId, input.contributions);
165
- const merged = owners[input.pluginId] ?? {};
166
- for (const kind of IDENTITY_KINDS) {
167
- merged[kind] = [...(merged[kind] ?? []), ...(identities[kind] ?? [])];
168
- }
169
- owners[input.pluginId] = merged;
170
- }
171
- runtimes[runtimeId] = owners;
172
- }
173
- return normalizeLedger({ version: CONTRIBUTION_LEDGER_VERSION, runtimes, unswept: [...unswept] });
174
- }
175
-
176
- /**
177
- * A disabled input naming every recorded identity of `owner`, so each Runtime
178
- * Surface removes them through its existing disabled-input path. Removal keys
179
- * on identity only, so no value is needed: guidance is stripped by owner, a
180
- * hook group by its marker, a plugin reference by its exact entry.
181
- */
182
- export function ledgerTeardownInput(
183
- owner: string,
184
- identities: LedgerIdentities,
185
- ): CapabilityContributionInput {
186
- return {
187
- pluginId: owner,
188
- enabled: false,
189
- capabilityEnabled: false,
190
- contributions: {
191
- mcpServers: (identities.mcpServers ?? []).map((name) => ({ name })),
192
- guidanceSections: (identities.guidanceKeys ?? []).length > 0 ? [{ content: "" }] : [],
193
- skillTrees: (identities.skillTrees ?? []).map((name) => ({ name, sourceDir: "" })),
194
- agentDefinitions: (identities.agentDefinitions ?? []).map((name) => ({ name, content: "" })),
195
- hookGroups: (identities.hookMarkers ?? []).map((marker) => ({
196
- event: "",
197
- marker,
198
- group: {},
199
- })),
200
- permissionEntries: [...(identities.permissionEntries ?? [])],
201
- pluginReferences: (identities.pluginReferences ?? []).map((reference) => ({
202
- reference,
203
- isManagedReference: (entry: unknown) => entry === reference,
204
- })),
205
- },
206
- };
207
- }
@@ -1,139 +0,0 @@
1
- // oxlint-disable no-await-in-loop
2
- import path from "node:path";
3
-
4
- import type { FrameworkConfig } from "../../lib/orchestrator/types";
5
- import {
6
- readContributionLedger,
7
- type ContributionLedger,
8
- type LedgerIdentities,
9
- } from "./contribution-ledger";
10
- import type { CapabilityPlugin, SetupContext } from "./plugin";
11
- import type { PluginRegistry } from "./registry";
12
- import { managedGuidanceOwners } from "./upgrade-sweep";
13
-
14
- /**
15
- * What `mate doctor` reports about audience isolation: contributions on the
16
- * companion's persisted surfaces that no base plugin owns, audience plugins
17
- * the upgrade sweep could not load, and the active audience's plugins whose
18
- * imperative parts a launch layer cannot deliver.
19
- */
20
-
21
- export interface LeakedContribution {
22
- /** Companion-relative file or directory. */
23
- surface: string;
24
- kind: string;
25
- /** The entry's name; absent where the surface entry is the owner's block. */
26
- identity?: string;
27
- owner: string;
28
- }
29
-
30
- export interface UndeliveredAudiencePlugin {
31
- pluginId: string;
32
- /** `apply`, `teardown`, `forProvider` or `pluginReferences`. */
33
- parts: string[];
34
- }
35
-
36
- export interface AudienceIsolationReport {
37
- leaked: LeakedContribution[];
38
- unswept: string[];
39
- undelivered: UndeliveredAudiencePlugin[];
40
- }
41
-
42
- /** Ledger kinds by where each runtime keeps them; guidance is read from the files themselves. */
43
- const LEDGER_SURFACES: Record<string, Partial<Record<keyof LedgerIdentities, string>>> = {
44
- claude: {
45
- mcpServers: ".mcp.json",
46
- skillTrees: path.join(".claude", "skills"),
47
- agentDefinitions: path.join(".claude", "agents"),
48
- hookMarkers: path.join(".claude", "settings.local.json"),
49
- permissionEntries: path.join(".claude", "settings.local.json"),
50
- },
51
- opencode: {
52
- mcpServers: path.join(".opencode", "opencode.json"),
53
- pluginReferences: path.join(".opencode", "opencode.json"),
54
- skillTrees: path.join(".agents", "skills"),
55
- agentDefinitions: path.join(".opencode", "agents"),
56
- },
57
- };
58
-
59
- function leakedLedgerContributions(
60
- ledger: ContributionLedger | null,
61
- baseIds: ReadonlySet<string>,
62
- ): LeakedContribution[] {
63
- const leaked: LeakedContribution[] = [];
64
- for (const [runtimeId, owners] of Object.entries(ledger?.runtimes ?? {})) {
65
- for (const [owner, identities] of Object.entries(owners)) {
66
- if (baseIds.has(owner)) continue;
67
- for (const [kind, surface] of Object.entries(LEDGER_SURFACES[runtimeId] ?? {})) {
68
- for (const identity of identities[kind as keyof LedgerIdentities] ?? []) {
69
- leaked.push({ surface: surface!, kind, identity, owner });
70
- }
71
- }
72
- }
73
- }
74
- return leaked;
75
- }
76
-
77
- /**
78
- * Whether a lifecycle hook does anything. `apply` and `teardown` are required
79
- * members, so a declarative plugin carries empty ones; only a body counts.
80
- */
81
- function hasBody(hook: unknown): boolean {
82
- if (typeof hook !== "function") return false;
83
- const source = Function.prototype.toString.call(hook);
84
- const open = source.indexOf("{");
85
- const close = source.lastIndexOf("}");
86
- if (open === -1 || close <= open) return true;
87
- const body = source
88
- .slice(open + 1, close)
89
- .replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*/g, "")
90
- .trim();
91
- return body.length > 0;
92
- }
93
-
94
- async function undeliveredParts(plugin: CapabilityPlugin, ctx: SetupContext): Promise<string[]> {
95
- const parts: string[] = [];
96
- if (hasBody(plugin.apply)) parts.push("apply");
97
- if (hasBody(plugin.teardown)) parts.push("teardown");
98
- if (plugin.forProvider && Object.keys(plugin.forProvider).length > 0) parts.push("forProvider");
99
- try {
100
- const byRuntime = (await plugin.getRuntimeContributions?.(ctx)) ?? {};
101
- if (Object.values(byRuntime).some((runtime) => (runtime?.pluginReferences ?? []).length > 0)) {
102
- parts.push("pluginReferences");
103
- }
104
- } catch {
105
- /** A plugin whose declarations fail is the plugin checks' finding, not this one. */
106
- }
107
- return parts;
108
- }
109
-
110
- export async function inspectAudienceIsolation(
111
- companionPath: string,
112
- config: FrameworkConfig,
113
- registry: PluginRegistry,
114
- activeAudience: string | null,
115
- ): Promise<AudienceIsolationReport> {
116
- const baseIds = new Set(registry.baseRegistrations().map((entry) => entry.plugin.id));
117
- const leaked: LeakedContribution[] = [];
118
-
119
- for (const [surface, owners] of await managedGuidanceOwners(companionPath)) {
120
- for (const owner of owners) {
121
- if (!baseIds.has(owner)) leaked.push({ surface, kind: "guidance", owner });
122
- }
123
- }
124
-
125
- const ledger = await readContributionLedger(companionPath);
126
- leaked.push(...leakedLedgerContributions(ledger, baseIds));
127
-
128
- const undelivered: UndeliveredAudiencePlugin[] = [];
129
- if (activeAudience) {
130
- const ctx: SetupContext = { companionPath, config, mode: "sync", activeProviders: [] };
131
- for (const { plugin } of registry.audienceRegistrations(activeAudience)) {
132
- if (plugin.kind !== "capability") continue;
133
- const parts = await undeliveredParts(plugin as CapabilityPlugin, ctx);
134
- if (parts.length > 0) undelivered.push({ pluginId: plugin.id, parts });
135
- }
136
- }
137
-
138
- return { leaked, unswept: ledger?.unswept ?? [], undelivered };
139
- }
@@ -1,153 +0,0 @@
1
- // oxlint-disable no-await-in-loop
2
- import fs from "node:fs/promises";
3
- import path from "node:path";
4
-
5
- import { FRAMEWORK_NAME } from "../../framework";
6
- import { removeManagedBlocksForPlugin } from "./context-services";
7
- import {
8
- audiencePluginDeclarations,
9
- declaredAudiences,
10
- effectivePluginDeclarations,
11
- readFrameworkRaw,
12
- } from "./dynamic-plugins/audiences";
13
- import { validateDeclaration } from "./dynamic-plugins/declarations";
14
- import { loadDynamicPlugin, type DynamicPluginLoadDeps } from "./dynamic-plugins/loader";
15
- import type { CapabilityContributionInput, CapabilityPlugin, Plugin, SetupContext } from "./plugin";
16
- import type { NormalizedRegistration } from "./registry";
17
-
18
- /**
19
- * Upgrade Sweep: removes what audience plugins leaked into a companion before
20
- * the contribution ledger existed. Runs once, when a persisted pass finds no
21
- * ledger, and again only for the packages it could not load then.
22
- */
23
-
24
- /** The companion files Mate's managed guidance blocks live in. */
25
- const GUIDANCE_FILES = ["CLAUDE.md", "AGENTS.md", path.join(".opencode", "AGENTS.md")];
26
-
27
- const MANAGED_BLOCK_START = new RegExp(
28
- `<!-- ${FRAMEWORK_NAME}:managed:([^\\n]+):[0-9a-f]+ start -->`,
29
- "g",
30
- );
31
-
32
- /** Plugin ids owning a managed guidance block in `text`. */
33
- export function managedBlockOwners(text: string): string[] {
34
- return [...new Set([...text.matchAll(MANAGED_BLOCK_START)].map((match) => match[1]!))];
35
- }
36
-
37
- /** `relative path → owners` for every managed guidance block under `root`. */
38
- export async function managedGuidanceOwners(root: string): Promise<Map<string, string[]>> {
39
- const owners = new Map<string, string[]>();
40
- for (const file of GUIDANCE_FILES) {
41
- const text = await fs.readFile(path.join(root, file), "utf8").catch(() => null);
42
- if (text === null) continue;
43
- const found = managedBlockOwners(text);
44
- if (found.length > 0) owners.set(file, found);
45
- }
46
- return owners;
47
- }
48
-
49
- /**
50
- * Guidance blocks name their owner, so this needs no plugin loaded: every
51
- * block whose owner is not a base registration goes.
52
- */
53
- export async function removeForeignGuidanceBlocks(
54
- root: string,
55
- baseIds: ReadonlySet<string>,
56
- ): Promise<void> {
57
- for (const [file, owners] of await managedGuidanceOwners(root)) {
58
- for (const owner of owners) {
59
- if (baseIds.has(owner)) continue;
60
- await removeManagedBlocksForPlugin(path.join(root, file), FRAMEWORK_NAME, owner);
61
- }
62
- }
63
- }
64
-
65
- export interface AudienceSweep {
66
- /** Disabled inputs for every swept plugin, per runtime. */
67
- teardown: Map<string, CapabilityContributionInput[]>;
68
- /** Packages that could not be loaded; their non-guidance entries stay until a retry. */
69
- unswept: string[];
70
- warnings: string[];
71
- }
72
-
73
- export interface AudienceSweepOptions {
74
- /** Every registration of the process; an audience plugin already loaded is reused, not reloaded. */
75
- registrations: readonly NormalizedRegistration[];
76
- /** Restrict the sweep to these packages; every audience declaration when absent. */
77
- packages?: ReadonlySet<string>;
78
- deps?: DynamicPluginLoadDeps;
79
- }
80
-
81
- /** One distinct package per audience declaration, base packages excluded. */
82
- function audiencePackages(raw: unknown): Map<string, ReturnType<typeof validateDeclaration>> {
83
- const basePackages = new Set(
84
- effectivePluginDeclarations(raw, null).flatMap((entry) => {
85
- const { declaration } = validateDeclaration(entry);
86
- return declaration ? [declaration.package] : [];
87
- }),
88
- );
89
- const found = new Map<string, ReturnType<typeof validateDeclaration>>();
90
- for (const audience of declaredAudiences(raw)) {
91
- for (const entry of audiencePluginDeclarations(raw, audience)) {
92
- const validated = validateDeclaration(entry);
93
- const name = validated.declaration?.package;
94
- if (!name || basePackages.has(name) || found.has(name)) continue;
95
- found.set(name, validated);
96
- }
97
- }
98
- return found;
99
- }
100
-
101
- /**
102
- * Collects the declarations of every audience plugin as disabled inputs:
103
- * loaded for its declarations only — never activated, no lifecycle hook run.
104
- * An unloadable plugin is reported, never fatal.
105
- */
106
- export async function sweepAudienceDeclarations(
107
- ctx: SetupContext,
108
- options: AudienceSweepOptions,
109
- ): Promise<AudienceSweep> {
110
- const sweep: AudienceSweep = { teardown: new Map(), unswept: [], warnings: [] };
111
- const raw = await readFrameworkRaw(ctx.companionPath);
112
-
113
- for (const [name, { declaration }] of audiencePackages(raw)) {
114
- if (options.packages && !options.packages.has(name)) continue;
115
- let plugin: Plugin | undefined = options.registrations.find(
116
- (entry) => entry.packageName === name,
117
- )?.plugin;
118
- if (!plugin) {
119
- const loaded = await loadDynamicPlugin(ctx.companionPath, declaration!, options.deps);
120
- if (!loaded.ok) {
121
- sweep.unswept.push(name);
122
- sweep.warnings.push(
123
- `audience plugin "${name}" was not swept from the companion: ${loaded.warning} Its entries stay until a pass can load it.`,
124
- );
125
- continue;
126
- }
127
- plugin = loaded.plugin;
128
- }
129
-
130
- const capability = plugin as CapabilityPlugin;
131
- if (plugin.kind !== "capability" || !capability.getRuntimeContributions) continue;
132
- try {
133
- const byRuntime = await capability.getRuntimeContributions(ctx);
134
- for (const [runtimeId, contributions] of Object.entries(byRuntime)) {
135
- if (!contributions) continue;
136
- const inputs = sweep.teardown.get(runtimeId) ?? [];
137
- inputs.push({
138
- pluginId: plugin.id,
139
- enabled: false,
140
- capabilityEnabled: false,
141
- contributions,
142
- });
143
- sweep.teardown.set(runtimeId, inputs);
144
- }
145
- } catch (error) {
146
- sweep.unswept.push(name);
147
- sweep.warnings.push(
148
- `audience plugin "${name}" was not swept from the companion: ${error instanceof Error ? error.message : String(error)}`,
149
- );
150
- }
151
- }
152
- return sweep;
153
- }