claude-harness/dsh/bundle/lib/selfcheck.js

57 lines
1.8 KiB
JavaScript

/**
* 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`,
}
})
}