openvibers/openvibe.space Commits
openvibe-shared v4.108.0 (was v4.107.4) (#198)
Changes
@@@ -151,5 +151,5 @@ AGPL-3.0-only. See [LICENSE](LICENSE).<!-- versions:start -->- openvibe-contracts: v0.266.0- openvibe-sdk: v0.82.0--- openvibe-shared: v4.107.4++- openvibe-shared: v4.108.0<!-- versions:end -->@@@ -8,7 +8,7 @@"domain": "openvibe.space","contracts": "openvibe-contracts v0.266.0","sdk": "openvibe-sdk v0.82.0",-- "shared": "openvibe-shared v4.107.4",++ "shared": "openvibe-shared v4.108.0","capabilities": ["space.site.manage","space.site.config",@@@ -17,7 +17,7 @@"helmet": "^8.1.0","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.266.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0","pg": "^8.23.0","quickjs-emscripten": "0.32.0"},@@@ -1166,9 +1166,9 @@}},"node_modules/openvibe-shared": {-- "version": "4.107.4",-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",-- "integrity": "sha512-tThN0m3KMncEHVcBOvE+ysHjsZTlVIDLG1P+/i2Mulmxfc/AUpebAXhpWWrut50OChZ8o+HeePxsSrPI8mUQOQ==",++ "version": "4.108.0",++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0",++ "integrity": "sha512-NPzwjxpzGIpFpIm4uw3+VwHfsxbJ2+cD9yuhRzSwolSwqv2kCmwaVtHJ0DA9gKO3K8PCBfIP3UpKzpuSbYEJ+g==","license": "MIT","dependencies": {"jsonwebtoken": "^9.0.0",@@@ -29,7 +29,7 @@"helmet": "^8.1.0","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.266.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0","pg": "^8.23.0","quickjs-emscripten": "0.32.0"},@@@ -214,7 +214,7 @@ async function createApp(opts = {}) {app.get('/robots.txt', (_req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 })).send(seo.robotsTxt({ sitemaps: [`${config.baseUrl}/sitemap.xml`], disallow: discovery.ROBOTS_DISALLOW })));app.get('/llms.txt', (_req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 }))-- .send(seo.llmsTxt({ name: SITE_NAME, summary: discovery.SUMMARY, details: discovery.SUMMARY, sections: discovery.llmsSections() })));++ .send(seo.llmsTxt({ name: SITE_NAME, markdown: true, base: config.baseUrl, summary: discovery.SUMMARY, details: discovery.SUMMARY, sections: discovery.llmsSections(), optional: discovery.llmsOptional() })));app.get('/llms-full.txt', wrap(async (_req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 })).send(seo.llmsFull({ site: SITE_NAME, summary: discovery.SUMMARY, base: config.baseUrl, sections: await discovery.llmsFullSections(), maxBytes: 512 * 1024 }))));app.get('/sitemap.xml', async (_req, res) => {@@@ -17,22 +17,29 @@ const ROBOTS_DISALLOW = ['/api/', '/auth/', '/dashboard', '/projects/', '/sites/const SUMMARY = 'OpenVibe.Space is where people make spaces: small apps on their OpenVibe account, built by OpenVibe AI from a description or started from a template and changed in a browser editor, that sign visitors in with OpenVibe, keep shared lists and private data, and talk to OpenVibe AI. It also serves tested static hosting (immutable deploys, rollback, previews, Git ingest, verified custom domains), open to OpenVibe staff until the public launch. The forum that used to live here is on OpenVibe.Community.';// ── llms.txt / llms-full.txt (llmstxt.org) ───────────────────++// AGT-5: each of Space's own pages is linked at its Markdown twin (llmsTxt's markdown: true, base: baseUrl).++// /spaces and /spaces/new have no twin yet (llms-twins-probe, 11-03), so they keep their URL and say (HTML).function llmsSections() {const u = config.baseUrl;return [{ title: 'This site', links: [{ title: 'Home', url: `${u}/`, note: 'spaces and static hosting' },-- { title: 'Spaces', url: `${u}/spaces`, note: 'the gallery of published spaces and the templates' },-- { title: 'Make a space', url: `${u}/spaces/new`, note: 'describe it to the AI builder, or start from a template (sign-in required)' },++ { title: 'Spaces', url: `${u}/spaces`, html: true, note: 'the gallery of published spaces and the templates' },++ { title: 'Make a space', url: `${u}/spaces/new`, html: true, note: 'describe it to the AI builder, or start from a template (sign-in required)' },] },{ title: 'The network', links: [{ title: 'The forum', url: `${config.communityUrl}/s`, note: 'OpenVibe.Community hosts the forum' },{ title: 'OpenVibe.Network', url: config.networkUrl, note: 'identity, accounts and sign-in' },] },-- { title: 'Machine-readable', links: [-- { title: 'Sitemap', url: `${u}/sitemap.xml` },-- { title: 'Full text for language models', url: `${u}/llms-full.txt` },-- ] },++ ];++}++++/** llmstxt.org's "## Optional": what an agent may skip when it needs a shorter context. */++function llmsOptional() {++ const u = config.baseUrl;++ return [++ { title: 'Sitemap', url: `${u}/sitemap.xml` },++ { title: 'Full text for language models', url: `${u}/llms-full.txt` },];}@@@ -57,4 +64,4 @@ async function sitemapRows(releaseLastmod, db = null) {return rows;}--module.exports = { ROBOTS_DISALLOW, SUMMARY, llmsSections, llmsFullSections, sitemapRows };++module.exports = { ROBOTS_DISALLOW, SUMMARY, llmsSections, llmsOptional, llmsFullSections, sitemapRows };@@@ -49,6 +49,8 @@ function createWebsite({ sitesDomain, publicDir }) {.send(seo.robotsTxt({ sitemaps: [`${base}/sitemap.xml`], disallow: ['/templates/'] })));router.get('/sitemap.xml', (_req, res) => res.type('application/xml').set('Cache-Control', PAGE_CACHE).send(seo.sitemapXml([{ loc: `${base}/`, changefreq: 'weekly', priority: 1 }])));++ // AGT-5: the website host's own pages, each at its Markdown twin; none of them answers as .md yet++ // (llms-twins-probe, 11-03), so they keep their URL and say (HTML). No llms-full.txt is served on this host.router.get('/llms.txt', (_req, res) => res.type('text/plain').set('Cache-Control', PAGE_CACHE).send(seo.llmsTxt({name: 'OpenVibe.Website',summary: pages.DESCRIPTION,@@@ -56,6 +58,11 @@ function createWebsite({ sitesDomain, publicDir }) {{ title: 'Start', links: [{ title: 'Website templates', url: `${base}/#templates`, html: true }, { title: 'Build on OpenVibe.Space', url: 'https://openvibe.space/spaces/new', html: true }, { title: 'Put your own computer on the web (OpenVibe Connect)', url: 'https://connect.openvibe.website/', html: true }] },{ title: 'Templates', links: templates.sites().map((t) => ({ title: t.name, url: `${base}/templates/${t.id}`, html: true, note: t.description })) },],++ // llmstxt.org's "## Optional": what an agent may skip when it needs a shorter context.++ optional: [++ { title: 'Sitemap', url: `${base}/sitemap.xml` },++ { title: 'robots.txt', url: `${base}/robots.txt` },++ ],})));router.use('/shared', require('openvibe-shared/serve').handler());@@@ -91,7 +91,13 @@ async function check(name, fn) {assert.match(await robots.text(), /Sitemap:/);const llms = await fetch(`${base}/llms.txt`);assert.strictEqual(llms.status, 200);-- assert.match(await llms.text(), /OpenVibe\.Space/);++ const text = await llms.text();++ assert.match(text, /OpenVibe\.Space/);++ // AGT-5: the home at its Markdown twin, the twin-less pages marked (HTML), Optional last.++ assert.match(text, new RegExp(`\\[Home\\]\\(http://127\\.0\\.0\\.1:${port}/index\\.md\\)`), 'the home is /index.md');++ assert.match(text, new RegExp(`\\[Spaces\\]\\(http://127\\.0\\.0\\.1:${port}/spaces\\) \\(HTML\\)`), 'a twin-less page keeps its URL');++ assert.match(text, /\n## Optional\n/);++ assert.strictEqual(text.lastIndexOf('\n## '), text.indexOf('\n## Optional'), 'Optional is the last section');const map = await fetch(`${base}/sitemap.xml`);assert.strictEqual(map.status, 200);const xml = await map.text();@@@ -80,6 +80,12 @@ assert.match(hostingSrc, /target\.kind === 'dashboard' \|\| target\.kind === 'weconst llms = (await t.get('openvibe.website', '/llms.txt')).text;assert.match(llms, /^# OpenVibe\.Website/);for (const s of templates.sites()) assert.ok(llms.includes(`https://openvibe.website/templates/${s.id}`), s.id);++ // AGT-5: none of this host's pages answers as .md yet, so each keeps its URL and says (HTML);++ // Optional is the last section.++ assert.match(llms, /\[Website templates\]\(https:\/\/openvibe\.website\/#templates\) \(HTML\)/);++ for (const s of templates.sites()) assert.ok(llms.includes(`https://openvibe.website/templates/${s.id}) (HTML)`), s.id);++ assert.match(llms, /\n## Optional\n\n[\s\S]*\[Sitemap\]\(https:\/\/openvibe\.website\/sitemap\.xml\)/);++ assert.strictEqual(llms.lastIndexOf('\n## '), llms.indexOf('\n## Optional'), 'Optional is the last section');});await check('the guest start page leads with a website template picked on the front door', async () => {
@@ -151,5 +151,5 @@ AGPL-3.0-only. See [LICENSE](LICENSE).
@@ -151,5 +151,5 @@ AGPL-3.0-only. See [LICENSE](LICENSE).
<!-- versions:start -->
<!-- versions:start -->
- openvibe-contracts: v0.266.0
- openvibe-contracts: v0.266.0
- openvibe-sdk: v0.82.0
- openvibe-sdk: v0.82.0
-- openvibe-shared: v4.107.4
+- openvibe-shared: v4.108.0
<!-- versions:end -->
<!-- versions:end -->
@@ -8,7 +8,7 @@
@@ -8,7 +8,7 @@
"domain": "openvibe.space",
"domain": "openvibe.space",
"contracts": "openvibe-contracts v0.266.0",
"contracts": "openvibe-contracts v0.266.0",
"sdk": "openvibe-sdk v0.82.0",
"sdk": "openvibe-sdk v0.82.0",
- "shared": "openvibe-shared v4.107.4",
+ "shared": "openvibe-shared v4.108.0",
"capabilities": [
"capabilities": [
"space.site.manage",
"space.site.manage",
"space.site.config",
"space.site.config",
@@ -17,7 +17,7 @@
@@ -17,7 +17,7 @@
"helmet": "^8.1.0",
"helmet": "^8.1.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.266.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.266.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0",
"pg": "^8.23.0",
"pg": "^8.23.0",
"quickjs-emscripten": "0.32.0"
"quickjs-emscripten": "0.32.0"
},
},
@@ -1166,9 +1166,9 @@
@@ -1166,9 +1166,9 @@
}
}
},
},
"node_modules/openvibe-shared": {
"node_modules/openvibe-shared": {
- "version": "4.107.4",
- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",
- "integrity": "sha512-tThN0m3KMncEHVcBOvE+ysHjsZTlVIDLG1P+/i2Mulmxfc/AUpebAXhpWWrut50OChZ8o+HeePxsSrPI8mUQOQ==",
+ "version": "4.108.0",
+ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0",
+ "integrity": "sha512-NPzwjxpzGIpFpIm4uw3+VwHfsxbJ2+cD9yuhRzSwolSwqv2kCmwaVtHJ0DA9gKO3K8PCBfIP3UpKzpuSbYEJ+g==",
"license": "MIT",
"license": "MIT",
"dependencies": {
"dependencies": {
"jsonwebtoken": "^9.0.0",
"jsonwebtoken": "^9.0.0",
@@ -29,7 +29,7 @@
@@ -29,7 +29,7 @@
"helmet": "^8.1.0",
"helmet": "^8.1.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.266.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.266.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0",
"pg": "^8.23.0",
"pg": "^8.23.0",
"quickjs-emscripten": "0.32.0"
"quickjs-emscripten": "0.32.0"
},
},
@@ -214,7 +214,7 @@ async function createApp(opts = {}) {
@@ -214,7 +214,7 @@ async function createApp(opts = {}) {
app.get('/robots.txt', (_req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 }))
app.get('/robots.txt', (_req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 }))
.send(seo.robotsTxt({ sitemaps: [`${config.baseUrl}/sitemap.xml`], disallow: discovery.ROBOTS_DISALLOW })));
.send(seo.robotsTxt({ sitemaps: [`${config.baseUrl}/sitemap.xml`], disallow: discovery.ROBOTS_DISALLOW })));
app.get('/llms.txt', (_req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 }))
app.get('/llms.txt', (_req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 }))
- .send(seo.llmsTxt({ name: SITE_NAME, summary: discovery.SUMMARY, details: discovery.SUMMARY, sections: discovery.llmsSections() })));
+ .send(seo.llmsTxt({ name: SITE_NAME, markdown: true, base: config.baseUrl, summary: discovery.SUMMARY, details: discovery.SUMMARY, sections: discovery.llmsSections(), optional: discovery.llmsOptional() })));
app.get('/llms-full.txt', wrap(async (_req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 }))
app.get('/llms-full.txt', wrap(async (_req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 }))
.send(seo.llmsFull({ site: SITE_NAME, summary: discovery.SUMMARY, base: config.baseUrl, sections: await discovery.llmsFullSections(), maxBytes: 512 * 1024 }))));
.send(seo.llmsFull({ site: SITE_NAME, summary: discovery.SUMMARY, base: config.baseUrl, sections: await discovery.llmsFullSections(), maxBytes: 512 * 1024 }))));
app.get('/sitemap.xml', async (_req, res) => {
app.get('/sitemap.xml', async (_req, res) => {
@@ -17,22 +17,29 @@ const ROBOTS_DISALLOW = ['/api/', '/auth/', '/dashboard', '/projects/', '/sites/
@@ -17,22 +17,29 @@ const ROBOTS_DISALLOW = ['/api/', '/auth/', '/dashboard', '/projects/', '/sites/
const SUMMARY = 'OpenVibe.Space is where people make spaces: small apps on their OpenVibe account, built by OpenVibe AI from a description or started from a template and changed in a browser editor, that sign visitors in with OpenVibe, keep shared lists and private data, and talk to OpenVibe AI. It also serves tested static hosting (immutable deploys, rollback, previews, Git ingest, verified custom domains), open to OpenVibe staff until the public launch. The forum that used to live here is on OpenVibe.Community.';
const SUMMARY = 'OpenVibe.Space is where people make spaces: small apps on their OpenVibe account, built by OpenVibe AI from a description or started from a template and changed in a browser editor, that sign visitors in with OpenVibe, keep shared lists and private data, and talk to OpenVibe AI. It also serves tested static hosting (immutable deploys, rollback, previews, Git ingest, verified custom domains), open to OpenVibe staff until the public launch. The forum that used to live here is on OpenVibe.Community.';
// ── llms.txt / llms-full.txt (llmstxt.org) ───────────────────
// ── llms.txt / llms-full.txt (llmstxt.org) ───────────────────
+// AGT-5: each of Space's own pages is linked at its Markdown twin (llmsTxt's markdown: true, base: baseUrl).
+// /spaces and /spaces/new have no twin yet (llms-twins-probe, 11-03), so they keep their URL and say (HTML).
function llmsSections() {
function llmsSections() {
const u = config.baseUrl;
const u = config.baseUrl;
return [
return [
{ title: 'This site', links: [
{ title: 'This site', links: [
{ title: 'Home', url: `${u}/`, note: 'spaces and static hosting' },
{ title: 'Home', url: `${u}/`, note: 'spaces and static hosting' },
- { title: 'Spaces', url: `${u}/spaces`, note: 'the gallery of published spaces and the templates' },
- { title: 'Make a space', url: `${u}/spaces/new`, note: 'describe it to the AI builder, or start from a template (sign-in required)' },
+ { title: 'Spaces', url: `${u}/spaces`, html: true, note: 'the gallery of published spaces and the templates' },
+ { title: 'Make a space', url: `${u}/spaces/new`, html: true, note: 'describe it to the AI builder, or start from a template (sign-in required)' },
] },
] },
{ title: 'The network', links: [
{ title: 'The network', links: [
{ title: 'The forum', url: `${config.communityUrl}/s`, note: 'OpenVibe.Community hosts the forum' },
{ title: 'The forum', url: `${config.communityUrl}/s`, note: 'OpenVibe.Community hosts the forum' },
{ title: 'OpenVibe.Network', url: config.networkUrl, note: 'identity, accounts and sign-in' },
{ title: 'OpenVibe.Network', url: config.networkUrl, note: 'identity, accounts and sign-in' },
] },
] },
- { title: 'Machine-readable', links: [
- { title: 'Sitemap', url: `${u}/sitemap.xml` },
- { title: 'Full text for language models', url: `${u}/llms-full.txt` },
- ] },
+ ];
+}
+
+/** llmstxt.org's "## Optional": what an agent may skip when it needs a shorter context. */
+function llmsOptional() {
+ const u = config.baseUrl;
+ return [
+ { title: 'Sitemap', url: `${u}/sitemap.xml` },
+ { title: 'Full text for language models', url: `${u}/llms-full.txt` },
];
];
}
}
@@ -57,4 +64,4 @@ async function sitemapRows(releaseLastmod, db = null) {
@@ -57,4 +64,4 @@ async function sitemapRows(releaseLastmod, db = null) {
return rows;
return rows;
}
}
-module.exports = { ROBOTS_DISALLOW, SUMMARY, llmsSections, llmsFullSections, sitemapRows };
+module.exports = { ROBOTS_DISALLOW, SUMMARY, llmsSections, llmsOptional, llmsFullSections, sitemapRows };
@@ -49,6 +49,8 @@ function createWebsite({ sitesDomain, publicDir }) {
@@ -49,6 +49,8 @@ function createWebsite({ sitesDomain, publicDir }) {
.send(seo.robotsTxt({ sitemaps: [`${base}/sitemap.xml`], disallow: ['/templates/'] })));
.send(seo.robotsTxt({ sitemaps: [`${base}/sitemap.xml`], disallow: ['/templates/'] })));
router.get('/sitemap.xml', (_req, res) => res.type('application/xml').set('Cache-Control', PAGE_CACHE)
router.get('/sitemap.xml', (_req, res) => res.type('application/xml').set('Cache-Control', PAGE_CACHE)
.send(seo.sitemapXml([{ loc: `${base}/`, changefreq: 'weekly', priority: 1 }])));
.send(seo.sitemapXml([{ loc: `${base}/`, changefreq: 'weekly', priority: 1 }])));
+ // AGT-5: the website host's own pages, each at its Markdown twin; none of them answers as .md yet
+ // (llms-twins-probe, 11-03), so they keep their URL and say (HTML). No llms-full.txt is served on this host.
router.get('/llms.txt', (_req, res) => res.type('text/plain').set('Cache-Control', PAGE_CACHE).send(seo.llmsTxt({
router.get('/llms.txt', (_req, res) => res.type('text/plain').set('Cache-Control', PAGE_CACHE).send(seo.llmsTxt({
name: 'OpenVibe.Website',
name: 'OpenVibe.Website',
summary: pages.DESCRIPTION,
summary: pages.DESCRIPTION,
@@ -56,6 +58,11 @@ function createWebsite({ sitesDomain, publicDir }) {
@@ -56,6 +58,11 @@ function createWebsite({ sitesDomain, publicDir }) {
{ title: 'Start', links: [{ title: 'Website templates', url: `${base}/#templates`, html: true }, { title: 'Build on OpenVibe.Space', url: 'https://openvibe.space/spaces/new', html: true }, { title: 'Put your own computer on the web (OpenVibe Connect)', url: 'https://connect.openvibe.website/', html: true }] },
{ title: 'Start', links: [{ title: 'Website templates', url: `${base}/#templates`, html: true }, { title: 'Build on OpenVibe.Space', url: 'https://openvibe.space/spaces/new', html: true }, { title: 'Put your own computer on the web (OpenVibe Connect)', url: 'https://connect.openvibe.website/', html: true }] },
{ title: 'Templates', links: templates.sites().map((t) => ({ title: t.name, url: `${base}/templates/${t.id}`, html: true, note: t.description })) },
{ title: 'Templates', links: templates.sites().map((t) => ({ title: t.name, url: `${base}/templates/${t.id}`, html: true, note: t.description })) },
],
],
+ // llmstxt.org's "## Optional": what an agent may skip when it needs a shorter context.
+ optional: [
+ { title: 'Sitemap', url: `${base}/sitemap.xml` },
+ { title: 'robots.txt', url: `${base}/robots.txt` },
+ ],
})));
})));
router.use('/shared', require('openvibe-shared/serve').handler());
router.use('/shared', require('openvibe-shared/serve').handler());
@@ -91,7 +91,13 @@ async function check(name, fn) {
@@ -91,7 +91,13 @@ async function check(name, fn) {
assert.match(await robots.text(), /Sitemap:/);
assert.match(await robots.text(), /Sitemap:/);
const llms = await fetch(`${base}/llms.txt`);
const llms = await fetch(`${base}/llms.txt`);
assert.strictEqual(llms.status, 200);
assert.strictEqual(llms.status, 200);
- assert.match(await llms.text(), /OpenVibe\.Space/);
+ const text = await llms.text();
+ assert.match(text, /OpenVibe\.Space/);
+ // AGT-5: the home at its Markdown twin, the twin-less pages marked (HTML), Optional last.
+ assert.match(text, new RegExp(`\\[Home\\]\\(http://127\\.0\\.0\\.1:${port}/index\\.md\\)`), 'the home is /index.md');
+ assert.match(text, new RegExp(`\\[Spaces\\]\\(http://127\\.0\\.0\\.1:${port}/spaces\\) \\(HTML\\)`), 'a twin-less page keeps its URL');
+ assert.match(text, /\n## Optional\n/);
+ assert.strictEqual(text.lastIndexOf('\n## '), text.indexOf('\n## Optional'), 'Optional is the last section');
const map = await fetch(`${base}/sitemap.xml`);
const map = await fetch(`${base}/sitemap.xml`);
assert.strictEqual(map.status, 200);
assert.strictEqual(map.status, 200);
const xml = await map.text();
const xml = await map.text();
@@ -80,6 +80,12 @@ assert.match(hostingSrc, /target\.kind === 'dashboard' \|\| target\.kind === 'we
@@ -80,6 +80,12 @@ assert.match(hostingSrc, /target\.kind === 'dashboard' \|\| target\.kind === 'we
const llms = (await t.get('openvibe.website', '/llms.txt')).text;
const llms = (await t.get('openvibe.website', '/llms.txt')).text;
assert.match(llms, /^# OpenVibe\.Website/);
assert.match(llms, /^# OpenVibe\.Website/);
for (const s of templates.sites()) assert.ok(llms.includes(`https://openvibe.website/templates/${s.id}`), s.id);
for (const s of templates.sites()) assert.ok(llms.includes(`https://openvibe.website/templates/${s.id}`), s.id);
+ // AGT-5: none of this host's pages answers as .md yet, so each keeps its URL and says (HTML);
+ // Optional is the last section.
+ assert.match(llms, /\[Website templates\]\(https:\/\/openvibe\.website\/#templates\) \(HTML\)/);
+ for (const s of templates.sites()) assert.ok(llms.includes(`https://openvibe.website/templates/${s.id}) (HTML)`), s.id);
+ assert.match(llms, /\n## Optional\n\n[\s\S]*\[Sitemap\]\(https:\/\/openvibe\.website\/sitemap\.xml\)/);
+ assert.strictEqual(llms.lastIndexOf('\n## '), llms.indexOf('\n## Optional'), 'Optional is the last section');
});
});
await check('the guest start page leads with a website template picked on the front door', async () => {
await check('the guest start page leads with a website template picked on the front door', async () => {