/** * Activation-time self-check of the DSH contract the bundle depends on. * * Pure shape inspection: no ctx service is invoked, only checked for presence. * A DSH upgrade may rename or remove a service; the check turns that into a * visible `not-ok` line (activation log plus the `dsh-harness-check` command) * instead of a TypeError at first use. */ const CONTRACT = [ { feature: 'guards', label: 'tools.guard', available: (ctx) => typeof ctx?.tools?.guard === 'function', }, { feature: 'bootstrap', label: 'ctx.on (agent/pre-step)', available: (ctx) => typeof ctx?.on === 'function', }, { feature: 'commands', label: 'ctx.inject', available: (ctx) => typeof ctx?.inject === 'function', }, { feature: 'workingDirectory', label: 'workingDirectory.get', available: (ctx) => typeof ctx?.workingDirectory?.get === 'function', }, ] /** * Inspect a ctx-like object without calling anything on it. * @param {object} [config] - bundle config; a feature whose config switch is * false is skipped entirely (workingDirectory is always checked, and * `commands` is checked while either `roleCommand` or `checkCommand` is on). * @returns {{feature: 'guards'|'bootstrap'|'commands'|'workingDirectory', * ok: boolean, detail: string}[]} */ export function collectSelfCheck(ctxLike, config = {}) { const disabled = { guards: config?.guards === false, bootstrap: config?.bootstrap === false, commands: config?.roleCommand === false && config?.checkCommand === false, } return CONTRACT.filter(({ feature }) => feature === 'workingDirectory' || !disabled[feature]) .map(({ feature, label, available }) => { const ok = available(ctxLike) return { feature, ok, detail: ok ? `${label}: available` : `${label}: missing or not a function`, } }) }