openvibers/openvibe.sites Commits

Record openvibe.services plannedRepo and let it supersede noRepo on sync

OP OpenVibers committed 4 Oct 2026 · da0d4abcfe · 3 files, +34 −13

Asked: T13 READY NOW groundwork (dossier /home/workstation/openvibe/agents/ds/prep/T13.md, READY NOW section). Start from origin/main. In sites.json, on the entry whose domain is openvibe.services, replace the noRepo true field with a plannedRepo field set to OpenVibe.Services, so the catalog records the …
Harness job sites-t13-ready-now-groundwork-dossier-190029.

Changes

ddiff --git a/scripts/sync-catalog.js b/scripts/sync-catalog.js
iindex f5fd823..5ed70f0 100644
---- a/scripts/sync-catalog.js
++++ b/scripts/sync-catalog.js
@@@ -13,6 +13,9 @@
* the value sites.json has today (frozen, never dropped): the `network` block, LOCAL fields, and for
* a service-home row SERVICE_LOCAL (a service manifest's site name/icon/tagline/legalProfile are the
* console card's, not the page's). A sites.json domain missing from the catalog is kept and reported.
++ *
++ * plannedRepo is noRepo with the repository named (an entry without a live repository yet): when
++ * sites.json names one, Contracts' noRepo does not come back (a row never carries both).
*/
const fs = require('fs');
const path = require('path');
@@@ -43,6 +46,12 @@ function fromContracts(row, field) {
return SHAPE[field] ? SHAPE[field](v) : v;
}
++/** plannedRepo is noRepo with the repository named; a row must never carry both. */
++function dropNoRepo(out) {
++ if (out.plannedRepo !== undefined) delete out.noRepo;
++ return out;
++}
++
function sync(current) {
const rows = new Map(catalog().map(r => [r.domain, r]));
const kept = [];
@@@ -56,24 +65,28 @@ function sync(current) {
if (v !== undefined) out[k] = v;
else if (site[k] !== undefined) out[k] = site[k];
}
-- return out;
++ return dropNoRepo(out);
});
for (const row of rows.values()) {
const out = {};
for (const k of FIELDS) { const v = fromContracts(row, k); if (v !== undefined) out[k] = v; }
-- sites.push(out);
++ sites.push(dropNoRepo(out));
}
return { json: { ...current, sites }, kept };
}
--const before = fs.readFileSync(FILE, 'utf8');
--const { json, kept } = sync(JSON.parse(before));
--const after = JSON.stringify(json, null, 2) + '\n';
--for (const d of kept) console.error(`sync-catalog: ${d} is not in the Contracts catalog; kept as it is`);
--if (process.argv.includes('--check')) {
-- if (after !== before) { console.error('sync-catalog: sites.json differs from the Contracts catalog; run node scripts/sync-catalog.js'); process.exit(1); }
-- console.log(`sync-catalog: sites.json matches the Contracts catalog (${json.sites.length} sites)`);
--} else {
-- fs.writeFileSync(FILE, after);
-- console.log(`sync-catalog: wrote ${json.sites.length} sites to sites.json`);
++if (require.main === module) {
++ const before = fs.readFileSync(FILE, 'utf8');
++ const { json, kept } = sync(JSON.parse(before));
++ const after = JSON.stringify(json, null, 2) + '\n';
++ for (const d of kept) console.error(`sync-catalog: ${d} is not in the Contracts catalog; kept as it is`);
++ if (process.argv.includes('--check')) {
++ if (after !== before) { console.error('sync-catalog: sites.json differs from the Contracts catalog; run node scripts/sync-catalog.js'); process.exit(1); }
++ console.log(`sync-catalog: sites.json matches the Contracts catalog (${json.sites.length} sites)`);
++ } else {
++ fs.writeFileSync(FILE, after);
++ console.log(`sync-catalog: wrote ${json.sites.length} sites to sites.json`);
++ }
}
++
++module.exports = { sync, dropNoRepo };
ddiff --git a/sites.json b/sites.json
iindex 0e0dbac..76cd47c 100644
---- a/sites.json
++++ b/sites.json
@@@ -1039,7 +1039,7 @@
"name": "OpenVibe.Services",
"icon": "fa-server",
"accent": "#38bdf8",
-- "noRepo": true,
++ "plannedRepo": "OpenVibe.Services",
"tagline": "Build with the whole network.",
"description": "OpenVibe.Services will be the way into everything programmable on OpenVibe. Start from what you want to build (monitor a page and summarise changes, run an AI agent, process uploads, control a robot, add support to a site) and it assembles the services, keys, permissions and working code for you. Then operate it all in one place: projects, grants, usage, quotas, runs, events, deploys and health, with each service keeping its own data.",
"pillars": [
ddiff --git a/test/sync-catalog.test.js b/test/sync-catalog.test.js
iindex 846f7bc..39fb782 100644
---- a/test/sync-catalog.test.js
++++ b/test/sync-catalog.test.js
@@@ -22,4 +22,12 @@ for (const conf of fs.readdirSync(path.join(ROOT, 'deploy', 'nginx'))) {
assert.ok(sites.some(s => s.domain === d), `${d}: has a vhost, so sites.json keeps it`);
assert.ok(domains.has(d) || AWAITING_CONTRACTS.includes(d), `${d}: has a home in the Contracts catalog`);
}
++// plannedRepo (a planned but not yet live repository) supersedes noRepo: Contracts still marks
++// openvibe.services noRepo, and sync must not put it back beside the planned repository (T13).
++const { dropNoRepo } = require('../scripts/sync-catalog.js');
++assert.deepStrictEqual(dropNoRepo({ plannedRepo: 'OpenVibe.Services', noRepo: true }), { plannedRepo: 'OpenVibe.Services' });
++assert.deepStrictEqual(dropNoRepo({ noRepo: true }), { noRepo: true });
++const services = sites.find(s => s.domain === 'openvibe.services');
++assert.strictEqual(services && services.plannedRepo, 'OpenVibe.Services', 'openvibe.services records its planned repository');
++assert.ok(services && !('noRepo' in services), 'openvibe.services must not also carry noRepo');
console.log(`sync-catalog: ${sites.length} sites, all in the Contracts catalog but ${AWAITING_CONTRACTS.join(', ')}`);