@heretek-ai/epistemic-swarm 0.7.21 → 0.7.23
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/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/bin/cli.js +3 -2
- package/extensions/pi/index.js +3 -2
- package/package.json +5 -1
- package/plugins/antigravity/plugin.json +1 -1
- package/plugins/factory/skills/factory/SKILL.md +1 -1
- package/plugins/opencode/analysis-bridge.js +566 -0
- package/plugins/opencode/config-io.js +598 -31
- package/plugins/opencode/dep-health.js +1039 -0
- package/plugins/opencode/hook-bus.js +434 -0
- package/plugins/opencode/index.js +252 -19
- package/plugins/opencode/tui.js +230 -17
- package/plugins/opencode/weight-baseline.json +16 -0
- package/plugins/opencode/weight-signals.js +769 -0
- package/plugins/research-cache/skills/research_cache/hasher.py +33 -8
- package/runner/__pycache__/__init__.cpython-311.pyc +0 -0
- package/runner/__pycache__/auctioneer.cpython-311.pyc +0 -0
- package/runner/__pycache__/auditor_engine.cpython-311.pyc +0 -0
- package/runner/__pycache__/claim_store.cpython-311.pyc +0 -0
- package/runner/__pycache__/claim_witness.cpython-311.pyc +0 -0
- package/runner/__pycache__/darkharvest_claims.cpython-311.pyc +0 -0
- package/runner/__pycache__/errors.cpython-311.pyc +0 -0
- package/runner/__pycache__/living_dossiers.cpython-311.pyc +0 -0
- package/runner/__pycache__/mcp_protocol.cpython-311.pyc +0 -0
- package/runner/__pycache__/mcp_server.cpython-311.pyc +0 -0
- package/runner/__pycache__/path_safety.cpython-311.pyc +0 -0
- package/runner/__pycache__/pcrb.cpython-311.pyc +0 -0
- package/runner/__pycache__/pcrb_verify.cpython-311.pyc +0 -0
- package/runner/__pycache__/preflight.cpython-311.pyc +0 -0
- package/runner/__pycache__/refinement.cpython-311.pyc +0 -0
- package/runner/__pycache__/research_swarm.cpython-311.pyc +0 -0
- package/runner/__pycache__/retrieval_log.cpython-311.pyc +0 -0
- package/runner/__pycache__/schema_validate.cpython-311.pyc +0 -0
- package/runner/__pycache__/schemas.cpython-311.pyc +0 -0
- package/runner/__pycache__/state_machine.cpython-311.pyc +0 -0
- package/runner/mcp_server.py +249 -81
- package/runner/refinement.py +5 -0
- package/runner/schema_validate.py +63 -1
- package/runner/schemas.py +9 -4
- package/runner/tests/__pycache__/test_analysis_bridge.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_antigravity_plugin.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_auction_order.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_backends.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_bet1_spike.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_claim_store.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_claim_witness.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_claude_plugin.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_config_schema.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_contract_tooling.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_darkharvest_audit.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_dep_health.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_domain_packs.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_dossier_contract.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_factory.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_fleet_seam.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_frontier_concurrency.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_frontier_mirror_standalone.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_grounding.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_hardening_contract.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_hook_bus.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_living_dossiers.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_manifest_concurrency.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_mcp_server.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_opencode_ux.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_opencode_v2_registrars.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_pcrb.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_phase08_waiver_reopens.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_refinement.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_search_anomaly.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_search_provider.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_search_provider_plugin.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_swarm.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_swarm_config.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_sweep_regressions.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_webcache.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_weight_signals.cpython-311.pyc +0 -0
- package/runner/tests/fixtures/config_validation_cases.json +60 -0
- package/runner/tests/test_analysis_bridge.py +356 -0
- package/runner/tests/test_config_schema.py +119 -15
- package/runner/tests/test_dep_health.py +484 -0
- package/runner/tests/test_hardening_contract.py +391 -0
- package/runner/tests/test_hook_bus.py +802 -0
- package/runner/tests/test_opencode_ux.py +232 -0
- package/runner/tests/test_opencode_v2_registrars.py +548 -16
- package/runner/tests/test_phase08_waiver_reopens.py +539 -0
- package/runner/tests/test_weight_signals.py +361 -0
- package/schemas/config.schema.json +4 -3
- package/scripts/__pycache__/bet1_advisory_spike.cpython-311.pyc +0 -0
- package/scripts/__pycache__/build_adapters.cpython-311.pyc +0 -0
- package/scripts/__pycache__/check_docs.cpython-311.pyc +0 -0
- package/scripts/__pycache__/divergence_experiment.cpython-311.pyc +0 -0
- package/scripts/__pycache__/gen_schemas.cpython-311.pyc +0 -0
- package/skills/epistemic_search/scripts/__pycache__/search.cpython-311.pyc +0 -0
- package/skills/factory/SKILL.md +1 -1
- package/skills/grilling/__pycache__/__init__.cpython-311.pyc +0 -0
- package/skills/grilling/__pycache__/socratic_tree.cpython-311.pyc +0 -0
- package/skills/research_cache/__pycache__/__init__.cpython-311.pyc +0 -0
- package/skills/research_cache/__pycache__/hasher.cpython-311.pyc +0 -0
- package/skills/research_cache/hasher.py +33 -8
- package/skills/swarm_config/SKILL.md +6 -1
- package/skills/swarm_config/__pycache__/__init__.cpython-311.pyc +0 -0
- package/skills/swarm_config/__pycache__/configure.cpython-311.pyc +0 -0
- package/skills/swarm_config/configure.py +254 -17
package/plugins/opencode/tui.js
CHANGED
|
@@ -26,7 +26,8 @@ import {
|
|
|
26
26
|
saveConfig,
|
|
27
27
|
validateConfig,
|
|
28
28
|
} from './config-io.js';
|
|
29
|
-
import {
|
|
29
|
+
import { gatePreCommit } from './hook-bus.js';
|
|
30
|
+
import { OPENCODE_COMMANDS, SettingsRpc, hookBus as sharedHookBus } from './index.js';
|
|
30
31
|
|
|
31
32
|
const PLUGIN_ID = 'heretek.iumbtems.epistemic-swarm.tui';
|
|
32
33
|
const REFRESH_MS = 5000;
|
|
@@ -100,6 +101,70 @@ export function subscribeSettingsChanged(api, onChanged) {
|
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Phase 01-hook-bus-spec fix round (QA-B FAIL 1): `pre-commit` gate for the
|
|
106
|
+
* TUI direct-fs fallback leg (`saveConfig(draft, baseDir, guard)` in
|
|
107
|
+
* `openSettingsWizard`). The RPC leg already gates in
|
|
108
|
+
* `createSettingsHandlers().set`; without this the fallback wrote with zero
|
|
109
|
+
* `pre-commit` emit and zero audit entry.
|
|
110
|
+
*
|
|
111
|
+
* Emits `pre-commit` through the bus and maps the verdict per the tier table
|
|
112
|
+
* (deny blocks, bus faults fail open). The stale-write guard is NOT replaced
|
|
113
|
+
* — the caller still passes `guard` to `saveConfig`, which enforces
|
|
114
|
+
* `CONFIG_STALE` downstream. On RPC-null hosts the bus remains the
|
|
115
|
+
* enforcement point: pass `opts.hookBus` (or a host carrying the adopted
|
|
116
|
+
* `host.iumbtemsHookBus`); a null bus fails open with `{ allowed: true }`.
|
|
117
|
+
* The emit itself audit-logs the decision, so a denied fallback write always
|
|
118
|
+
* leaves an audit entry. Never throws.
|
|
119
|
+
*
|
|
120
|
+
* Narrow fix round (qa-b bypass): the shipped TUI path previously called
|
|
121
|
+
* `openSettingsWizard(api, root)` with no opts on an api that carried no
|
|
122
|
+
* `iumbtemsHookBus`, so the fallback gate resolved null and failed open past
|
|
123
|
+
* a denying pre-commit handler. `resolveHookBus` closes that wiring gap: the
|
|
124
|
+
* shared bus (`hookBus` from `index.js`, same instance the settings-RPC leg
|
|
125
|
+
* gates on [VERIFIED: sha256:52ac5b4d26062cfc6093440faa415ab152f8acd0d18c4496eb0087ed18a27d76])
|
|
126
|
+
* is the final fallback, so the shipped configuration never resolves a null
|
|
127
|
+
* bus. Fail-open remains only for genuine bus faults (null/non-emit bus
|
|
128
|
+
* passed EXPLICITLY to `gateDirectFsPreCommit`), not for missing wiring.
|
|
129
|
+
*/
|
|
130
|
+
export async function gateDirectFsPreCommit(bus, { draft, baseDir, guard } = {}) {
|
|
131
|
+
try {
|
|
132
|
+
if (!bus || typeof bus.emit !== 'function') return { allowed: true };
|
|
133
|
+
const expected = guard?.expected_hash ?? guard?.expectedHash ?? null;
|
|
134
|
+
return await gatePreCommit(bus, {
|
|
135
|
+
updates: draft ?? {},
|
|
136
|
+
root: baseDir ?? null,
|
|
137
|
+
...(expected !== null && expected !== undefined ? { expected_hash: expected } : {}),
|
|
138
|
+
});
|
|
139
|
+
} catch {
|
|
140
|
+
return { allowed: true };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Resolve the pre-commit bus for the wizard fallback leg. Precedence:
|
|
146
|
+
* explicit `opts.hookBus` > adopted `host.iumbtemsHookBus` > shared bus.
|
|
147
|
+
* The shared-bus fallback is what keeps the shipped TUI path (slash command
|
|
148
|
+
* + palette, both RPC-null) from resolving a null bus. Never throws.
|
|
149
|
+
*/
|
|
150
|
+
export function resolveHookBus(host, opts) {
|
|
151
|
+
try {
|
|
152
|
+
const explicit = opts && opts.hookBus;
|
|
153
|
+
if (explicit && typeof explicit.emit === 'function') return explicit;
|
|
154
|
+
const adopted = host && host.iumbtemsHookBus;
|
|
155
|
+
if (adopted && typeof adopted.emit === 'function') return adopted;
|
|
156
|
+
if (sharedHookBus && typeof sharedHookBus.emit === 'function') return sharedHookBus;
|
|
157
|
+
return null;
|
|
158
|
+
} catch {
|
|
159
|
+
try {
|
|
160
|
+
if (sharedHookBus && typeof sharedHookBus.emit === 'function') return sharedHookBus;
|
|
161
|
+
} catch {
|
|
162
|
+
/* fall through */
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
103
168
|
/** Read UI-only prefs ({} when the host has no TUI storage). Never throws. */
|
|
104
169
|
export function readUiPrefs(api) {
|
|
105
170
|
try {
|
|
@@ -426,7 +491,7 @@ function SwarmKeymapLayer(api) {
|
|
|
426
491
|
'Edit IUMBTEMS settings in a dialog wizard (validates input, writes atomically)',
|
|
427
492
|
group: 'IUMBTEMS',
|
|
428
493
|
palette: true,
|
|
429
|
-
run: () => openSettingsWizard(api, resolveRoot(api)),
|
|
494
|
+
run: () => openSettingsWizard(api, resolveRoot(api), { hookBus: resolveHookBus(api, null) }),
|
|
430
495
|
},
|
|
431
496
|
{
|
|
432
497
|
id: SETTINGS_PANEL_COMMAND_ID,
|
|
@@ -504,9 +569,98 @@ const WIZARD_KEEP_VALUE = '__iumbtems_keep__';
|
|
|
504
569
|
|
|
505
570
|
function wizardToast(host, title, message) {
|
|
506
571
|
try {
|
|
507
|
-
host?.ui?.toast
|
|
572
|
+
const toast = host?.ui?.toast;
|
|
573
|
+
const show = toast?.show;
|
|
574
|
+
if (typeof show !== 'function') return false;
|
|
575
|
+
show.call(toast, { title, message, variant: 'info', duration: 6000 });
|
|
576
|
+
return true;
|
|
577
|
+
} catch {
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// ---------------------------------------------------------------------------
|
|
583
|
+
// Phase 07 (H8): keyed advisory dedup window for the repeating R4 advisories.
|
|
584
|
+
//
|
|
585
|
+
// Editing an env-shadowed or deprecated row fires its advisory on EVERY edit,
|
|
586
|
+
// so a multi-edit wizard session spams one toast per row visit. `warnOnce`
|
|
587
|
+
// collapses repeats of the SAME advisory key inside a TTL window: the first
|
|
588
|
+
// shows, repeats within the window are suppressed (counted), expiry re-shows
|
|
589
|
+
// (annotated with the suppressed count), and distinct keys stay independent.
|
|
590
|
+
//
|
|
591
|
+
// SAFETY: only the two repeating R4 advisories route here. Degraded-path,
|
|
592
|
+
// malformed-config, validation-error, stale, and save-failure toasts call
|
|
593
|
+
// `wizardToast` directly and are NEVER deduped (missed-action safety).
|
|
594
|
+
// Durations are preserved: wizard advisories stay 6000ms via `wizardToast`
|
|
595
|
+
// (the 4000ms keymap usage toast is untouched).
|
|
596
|
+
// ---------------------------------------------------------------------------
|
|
597
|
+
|
|
598
|
+
/** Dedup window for repeating R4 advisories, in ms. Exported for tests. */
|
|
599
|
+
export const ADVISORY_DEDUP_MS = 30000;
|
|
600
|
+
|
|
601
|
+
/** key -> { ts, suppressed }: last show time + repeats collapsed since. */
|
|
602
|
+
const advisorySeen = new Map();
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Show a keyed advisory toast at most once per `ttlMs` window.
|
|
606
|
+
* Returns true when a toast was actually delivered, false when collapsed
|
|
607
|
+
* or when delivery failed (failed deliveries never arm the window).
|
|
608
|
+
* `opts.now` injects the clock (tests); `opts.ttlMs` overrides the window.
|
|
609
|
+
* Session scope: each `openSettingsWizard` call resets the window (fresh
|
|
610
|
+
* wizard session always warns at least once); repeats within one session
|
|
611
|
+
* still collapse. Never throws.
|
|
612
|
+
*/
|
|
613
|
+
export function warnOnce(host, key, title, message, opts = {}) {
|
|
614
|
+
try {
|
|
615
|
+
const ttl =
|
|
616
|
+
opts && opts.ttlMs !== undefined && opts.ttlMs !== null
|
|
617
|
+
? Number(opts.ttlMs)
|
|
618
|
+
: ADVISORY_DEDUP_MS;
|
|
619
|
+
const now =
|
|
620
|
+
opts && opts.now !== undefined && opts.now !== null
|
|
621
|
+
? Number(opts.now)
|
|
622
|
+
: Date.now();
|
|
623
|
+
const entry = advisorySeen.get(key);
|
|
624
|
+
if (entry && Number.isFinite(ttl) && ttl > 0) {
|
|
625
|
+
const dt = now - entry.ts;
|
|
626
|
+
if (Number.isFinite(dt) && dt >= 0 && dt < ttl) {
|
|
627
|
+
entry.suppressed += 1;
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
// dt < 0 (clock moved backwards) or dt >= ttl (expiry) fall through
|
|
631
|
+
// to reshow — a backwards clock must never suppress indefinitely.
|
|
632
|
+
}
|
|
633
|
+
let text = message;
|
|
634
|
+
if (entry && entry.suppressed > 0) {
|
|
635
|
+
text += ` (repeated ${entry.suppressed + 1}× since last notice)`;
|
|
636
|
+
}
|
|
637
|
+
// Arm the window ONLY on actual delivery: a failed toast (missing/broken
|
|
638
|
+
// host) leaves state untouched so the next real warning still delivers.
|
|
639
|
+
const delivered = wizardToast(host, title, text);
|
|
640
|
+
if (!delivered) return false;
|
|
641
|
+
advisorySeen.set(key, { ts: now, suppressed: 0 });
|
|
642
|
+
return true;
|
|
643
|
+
} catch {
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/** Test hook: forget all dedup state. Never throws. */
|
|
649
|
+
export function _resetAdvisoryDedup() {
|
|
650
|
+
try {
|
|
651
|
+
advisorySeen.clear();
|
|
652
|
+
} catch {
|
|
653
|
+
/* never throw */
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/** Test hook: suppressed-repeat count pending for `key`. Never throws. */
|
|
658
|
+
export function _advisorySuppressed(key) {
|
|
659
|
+
try {
|
|
660
|
+
const entry = advisorySeen.get(key);
|
|
661
|
+
return entry ? entry.suppressed : 0;
|
|
508
662
|
} catch {
|
|
509
|
-
|
|
663
|
+
return 0;
|
|
510
664
|
}
|
|
511
665
|
}
|
|
512
666
|
|
|
@@ -715,23 +869,29 @@ async function editRow(dialog, host, draft, row) {
|
|
|
715
869
|
try {
|
|
716
870
|
const sub = row.schema || {};
|
|
717
871
|
// R4 advisories (never block the edit; the write still proceeds):
|
|
718
|
-
// an env-shadowed value
|
|
719
|
-
//
|
|
872
|
+
// an env-shadowed value is not effective while the override is set, and
|
|
873
|
+
// a deprecated key is ignored at runtime. Both route through the keyed
|
|
874
|
+
// dedup window (per-key repeats collapse); every other toast stays
|
|
875
|
+
// un-deduped so no error or degraded-path notice is ever swallowed.
|
|
720
876
|
if (row.source === 'env-override') {
|
|
721
|
-
|
|
877
|
+
warnOnce(
|
|
722
878
|
host,
|
|
879
|
+
`env:${row.key}`,
|
|
723
880
|
'Environment override',
|
|
724
|
-
`The environment shadows '${row.key}' —
|
|
725
|
-
'
|
|
726
|
-
'
|
|
881
|
+
`The environment shadows '${row.key}' — the file value is not ` +
|
|
882
|
+
'effective while the override is set and has no runtime effect ' +
|
|
883
|
+
'until the override is unset. The edited value is still stored ' +
|
|
884
|
+
'on save (cancel writes nothing).'
|
|
727
885
|
);
|
|
728
886
|
}
|
|
729
887
|
if (row.deprecated) {
|
|
730
|
-
|
|
888
|
+
warnOnce(
|
|
731
889
|
host,
|
|
890
|
+
`deprecated:${row.key}`,
|
|
732
891
|
'Deprecated field',
|
|
733
|
-
`'${row.key}' is deprecated and
|
|
734
|
-
'
|
|
892
|
+
`'${row.key}' is deprecated and ignored — it has no runtime ` +
|
|
893
|
+
'effect. The edited value is still stored on save for reference, ' +
|
|
894
|
+
'but changes nothing (cancel writes nothing).'
|
|
735
895
|
);
|
|
736
896
|
}
|
|
737
897
|
const types = Array.isArray(sub.type) ? sub.type : [sub.type];
|
|
@@ -999,6 +1159,15 @@ async function editAgentsRow(dialog, host, draft, row) {
|
|
|
999
1159
|
*/
|
|
1000
1160
|
export async function openSettingsWizard(host, root, opts = {}) {
|
|
1001
1161
|
try {
|
|
1162
|
+
// R1 session scope: a fresh wizard session always warns at least once.
|
|
1163
|
+
// The keyed R4 window collapses repeats WITHIN one session only; reset
|
|
1164
|
+
// the boundary here so a prior session (same key, <30s ago) never leaks
|
|
1165
|
+
// into the new session. Never throws.
|
|
1166
|
+
try {
|
|
1167
|
+
advisorySeen.clear();
|
|
1168
|
+
} catch {
|
|
1169
|
+
/* dedup reset is best-effort */
|
|
1170
|
+
}
|
|
1002
1171
|
const dialog = dialogOf(host);
|
|
1003
1172
|
const baseDir = researchDirOf(host, root);
|
|
1004
1173
|
const env = (opts && opts.env) || process.env;
|
|
@@ -1164,6 +1333,32 @@ export async function openSettingsWizard(host, root, opts = {}) {
|
|
|
1164
1333
|
opts && (opts.expected_hash !== undefined || opts.expectedHash !== undefined)
|
|
1165
1334
|
? { expected_hash: opts.expected_hash, expectedHash: opts.expectedHash }
|
|
1166
1335
|
: { expectedHash: startHash };
|
|
1336
|
+
// Phase 01-hook-bus-spec fix round (QA-B FAIL 1): the direct-fs
|
|
1337
|
+
// fallback is gated by `pre-commit` too — a tier-table deny blocks
|
|
1338
|
+
// the write (toast + `{ ok: false, reason: 'pre-commit-denied' }`,
|
|
1339
|
+
// nothing written, decision audit-logged on the bus). Bus faults
|
|
1340
|
+
// fail open; the stale-write guard below (`saveConfig` raising
|
|
1341
|
+
// `CONFIG_STALE`) is preserved unchanged.
|
|
1342
|
+
try {
|
|
1343
|
+
// Narrow fix round (qa-b bypass): resolve via the shared-bus
|
|
1344
|
+
// fallback so the shipped RPC-null path never gates on null.
|
|
1345
|
+
const fsBus = resolveHookBus(host, opts);
|
|
1346
|
+
const fsGate = await gateDirectFsPreCommit(fsBus, {
|
|
1347
|
+
draft,
|
|
1348
|
+
baseDir,
|
|
1349
|
+
guard,
|
|
1350
|
+
});
|
|
1351
|
+
if (fsGate && fsGate.allowed === false) {
|
|
1352
|
+
wizardToast(
|
|
1353
|
+
host,
|
|
1354
|
+
'IUMBTEMS settings',
|
|
1355
|
+
'Save denied by pre-commit hook — nothing was written.'
|
|
1356
|
+
);
|
|
1357
|
+
return { ok: false, reason: 'pre-commit-denied', written: false };
|
|
1358
|
+
}
|
|
1359
|
+
} catch {
|
|
1360
|
+
/* gate faults fail open; the write below still runs */
|
|
1361
|
+
}
|
|
1167
1362
|
try {
|
|
1168
1363
|
const res = saveConfig(draft, baseDir, guard);
|
|
1169
1364
|
wizardToast(
|
|
@@ -1248,7 +1443,7 @@ export async function openSettingsPanel(host, root, opts = {}) {
|
|
|
1248
1443
|
* without `command.transform` there is nothing to register (the palette
|
|
1249
1444
|
* entries from the keymap layer still work). Never throws.
|
|
1250
1445
|
*/
|
|
1251
|
-
export async function registerWizardSlashCommand(api) {
|
|
1446
|
+
export async function registerWizardSlashCommand(api, opts = {}) {
|
|
1252
1447
|
try {
|
|
1253
1448
|
if (typeof api?.command?.transform !== 'function') return null;
|
|
1254
1449
|
let existing = new Set();
|
|
@@ -1270,7 +1465,13 @@ export async function registerWizardSlashCommand(api) {
|
|
|
1270
1465
|
'Inspect or update Epistemic Swarm parameters in a dialog wizard (validates + writes atomically)',
|
|
1271
1466
|
execute: async () => {
|
|
1272
1467
|
try {
|
|
1273
|
-
|
|
1468
|
+
// Narrow fix round (qa-b bypass): thread the bus on the shipped
|
|
1469
|
+
// path — explicit opt > adopted host bus > shared bus — so the
|
|
1470
|
+
// fallback gate never resolves null here.
|
|
1471
|
+
await openSettingsWizard(api, resolveRoot(api), {
|
|
1472
|
+
...(opts || {}),
|
|
1473
|
+
hookBus: resolveHookBus(api, opts),
|
|
1474
|
+
});
|
|
1274
1475
|
} catch {
|
|
1275
1476
|
/* the wizard never throws into the host */
|
|
1276
1477
|
}
|
|
@@ -1292,8 +1493,20 @@ export async function registerWizardSlashCommand(api) {
|
|
|
1292
1493
|
}
|
|
1293
1494
|
|
|
1294
1495
|
/** TUI setup: sidebar slot + palette command. Never throws. */
|
|
1295
|
-
export function setupTui(api) {
|
|
1496
|
+
export function setupTui(api, opts = {}) {
|
|
1296
1497
|
try {
|
|
1498
|
+
// Narrow fix round (qa-b bypass): adopt the shared bus onto the TUI api
|
|
1499
|
+
// so `opts.hookBus || host.iumbtemsHookBus` never resolves null on the
|
|
1500
|
+
// shipped path. Best-effort; never throws. The shared instance is the
|
|
1501
|
+
// same one the settings-RPC leg gates on.
|
|
1502
|
+
try {
|
|
1503
|
+
if (api && typeof api === 'object' && !(api.iumbtemsHookBus && typeof api.iumbtemsHookBus.emit === 'function')) {
|
|
1504
|
+
const bus = (opts && opts.hookBus) || sharedHookBus || null;
|
|
1505
|
+
if (bus && typeof bus.emit === 'function') api.iumbtemsHookBus = bus;
|
|
1506
|
+
}
|
|
1507
|
+
} catch {
|
|
1508
|
+
/* host attach is best-effort */
|
|
1509
|
+
}
|
|
1297
1510
|
const root = resolveRoot(api);
|
|
1298
1511
|
const offSidebar = registerSlot(api, 'sidebar.content', () =>
|
|
1299
1512
|
SwarmSidebar(api, root)
|
|
@@ -1304,7 +1517,7 @@ export function setupTui(api) {
|
|
|
1304
1517
|
// setup stays synchronous; the handle lands when the host resolves it.
|
|
1305
1518
|
let slashRegistration = null;
|
|
1306
1519
|
try {
|
|
1307
|
-
Promise.resolve(registerWizardSlashCommand(api))
|
|
1520
|
+
Promise.resolve(registerWizardSlashCommand(api, opts))
|
|
1308
1521
|
.then((reg) => {
|
|
1309
1522
|
slashRegistration = reg;
|
|
1310
1523
|
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Phase 04-coverage-treeshake-signals bundle baseline: measured once at build (esbuild metafile:true, write:false — measure, never emit) over the plugin host surface. Deltas compute against `bytes`. Refresh is an explicit user-confirmed step — NEVER automatic (a stale baseline annotates `stale-baseline` and still allows).",
|
|
3
|
+
"entry": "plugins/opencode/index.js",
|
|
4
|
+
"bytes": 182262,
|
|
5
|
+
"files": 6,
|
|
6
|
+
"topHeaviest": [
|
|
7
|
+
{ "file": "plugins/opencode/index.js", "bytes": 119966 },
|
|
8
|
+
{ "file": "plugins/opencode/config-io.js", "bytes": 60042 },
|
|
9
|
+
{ "file": "plugins/opencode/dep-health.js", "bytes": 40199 },
|
|
10
|
+
{ "file": "plugins/opencode/weight-signals.js", "bytes": 29350 },
|
|
11
|
+
{ "file": "plugins/opencode/analysis-bridge.js", "bytes": 20953 }
|
|
12
|
+
],
|
|
13
|
+
"measuredAt": "2026-10-03T00:00:00.000Z",
|
|
14
|
+
"measuredBy": "esbuild 0.28.2 (pinned devDep; bundle:true, metafile:true, write:false, platform:node, format:esm, external:[esbuild])",
|
|
15
|
+
"phase": "04-coverage-treeshake-signals"
|
|
16
|
+
}
|