Lines 110-150javascript
110 const md = readFileSync(join(specsDir, file), 'utf8');
111 specs[capability] = {
112 hash: contentHashOf(md),
113 requirements: Object.fromEntries(parseRequirements(md).map((r) => [r.id || r.name, contentHashOf(JSON.stringify(r))])),
119export function livingSpecCapabilities(vaultBase) {
120 return Object.keys(readLivingSpecs(vaultBase));
123export function adoptSpecsState(vaultBase) {
124 const state = { version: 1, generatedAt: new Date().toISOString(), specs: readLivingSpecs(vaultBase) };
125 ensureDir(join(vaultBase, '.brain'));
126 writeFileSync(join(vaultBase, SPECS_STATE_FILE), `${JSON.stringify(state, null, 2)}\n`, 'utf8');
130export function readSpecsState(vaultBase) {
131 try { return JSON.parse(readFileSync(join(vaultBase, SPECS_STATE_FILE), 'utf8')); } catch { return null; }
132}
LowWeak Crypto
Package source references weak cryptographic algorithms.
hooks/spec-core.mjsView on unpkg · L130 134export function checkSpecsState(vaultBase) {
135 const recorded = readSpecsState(vaultBase);
136 if (!recorded) return { ok: false, missing: true, changed: [] };
137 const current = readLivingSpecs(vaultBase);
138 const names = new Set([...Object.keys(recorded.specs || {}), ...Object.keys(current)]);
139 const changed = [...names].filter((name) => recorded.specs?.[name]?.hash !== current[name]?.hash);
140 return { ok: changed.length === 0, missing: false, changed, current, recorded };
143function recordPromotedSpecs(vaultBase, capabilities) {
144 const existing = readSpecsState(vaultBase);
145 if (!existing) return adoptSpecsState(vaultBase);
146 const current = readLivingSpecs(vaultBase);
147 const specs = { ...(existing.specs || {}) };
148 for (const capability of capabilities) {
149 if (current[capability]) specs[capability] = current[capability];
150 else delete specs[capability];