@hgdc/agents 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/build.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // version Markdown de chaque page au build et produit les routes qui la servent sur
3
3
  // `Accept: text/markdown`. Rien ne s'exécute à la requête : tout est fichier statique et route.
4
4
  import { readdir, readFile, writeFile } from "node:fs/promises";
5
- import { htmlToMarkdown } from "./markdown.js";
5
+ import { htmlToMarkdown, pageFrontmatter } from "./markdown.js";
6
6
  const NOT_FOUND = "404.html";
7
7
  // Valeur de condition commune à Host (edge/src/router.ts) et Vercel : correspondance sur toute la valeur.
8
8
  const ACCEPTS_MARKDOWN = { type: "header", key: "accept", value: ".*text/markdown.*" };
@@ -42,7 +42,7 @@ export async function writeMarkdownPages(dir, options) {
42
42
  const html = await readFile(new URL(file, dir), "utf-8");
43
43
  const url = `${options.site}${path ?? `${base}/`}`;
44
44
  const target = notFound ? file.replace(/\.html$/, ".md") : markdownFile(path, base);
45
- await writeFile(new URL(target, dir), htmlToMarkdown(html, url) + footer);
45
+ await writeFile(new URL(target, dir), pageFrontmatter(html, url) + htmlToMarkdown(html, url) + footer);
46
46
  if (path !== null)
47
47
  pages.push({ path, file: target });
48
48
  }
package/dist/fetch.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Ce qu'une app rendue côté serveur (TanStack Start, ou tout handler `fetch`) montre aux agents : la page en
2
2
  // Markdown, ses données structurées et son adresse canonique, les pages de confiance, des erreurs d'API en JSON.
3
3
  import { canonicalLink, injectIntoHead, jsonLdScript } from "./head.js";
4
- import { htmlToMarkdown } from "./markdown.js";
4
+ import { htmlToMarkdown, pageFrontmatter } from "./markdown.js";
5
5
  import { prefersMarkdown, varyOnAccept } from "./negotiate.js";
6
6
  /** Pied de page standard : une ligne de liens, `[libellé](adresse)` séparés par « · ». */
7
7
  export function linksFooter(links) {
@@ -40,7 +40,13 @@ export function withMarkdown(handler, options = {}) {
40
40
  const redirected = response.status >= 300 && response.status < 400;
41
41
  if (!markdown || response.status < 200 || redirected)
42
42
  return withHeaders(response, request.method === "HEAD" ? null : enrichHead(response, url, options), varyOnAccept);
43
- const text = htmlToMarkdown(await response.text(), request.url) + (options.footer ? `\n---\n\n${options.footer}\n` : "");
43
+ const html = await response.text();
44
+ // Métadonnées en tête ; l'adresse canonique seulement si l'origine publique est connue (une console
45
+ // relayée voit l'adresse de son relais, pas celle du visiteur).
46
+ const canonical = options.canonicalOrigin ? `${options.canonicalOrigin}${url.pathname}` : undefined;
47
+ const text = pageFrontmatter(html, canonical) +
48
+ htmlToMarkdown(html, request.url) +
49
+ (options.footer ? `\n---\n\n${options.footer}\n` : "");
44
50
  return withHeaders(response, request.method === "HEAD" ? null : text, (out) => {
45
51
  for (const name of BODY_HEADERS)
46
52
  out.delete(name);
package/dist/hgdc.d.ts CHANGED
@@ -3,6 +3,12 @@
3
3
  * de l'entreprise, sur hgdc.ch. Pour l'option `redirects` de `withMarkdown`.
4
4
  */
5
5
  export declare const HGDC_TRUST_PAGES: Readonly<Record<string, string>>;
6
+ /**
7
+ * Fichiers de découverte que les agents cherchent à la racine de chaque hôte : ceux de l'entreprise, sur
8
+ * hgdc.ch (catalogue ARD, index Agent Skills). Pour l'option `redirects` de `withMarkdown`, avec
9
+ * `HGDC_TRUST_PAGES`.
10
+ */
11
+ export declare const HGDC_DISCOVERY_FILES: Readonly<Record<string, string>>;
6
12
  /** Nœud schema.org de l'entreprise, même `@id` que sur hgdc.ch. */
7
13
  export declare const HGDC_ORGANIZATION: {
8
14
  readonly "@type": "Organization";
@@ -10,6 +16,7 @@ export declare const HGDC_ORGANIZATION: {
10
16
  readonly name: "Hugo Gebel Développement Conseil";
11
17
  readonly alternateName: "HGDC";
12
18
  readonly url: "https://hgdc.ch";
19
+ readonly sameAs: readonly ["https://www.linkedin.com/company/smartflowsa", "https://www.instagram.com/smartflowsa.ch"];
13
20
  readonly description: "Entreprise individuelle suisse : agence web, accompagnement IA, outils en ligne de la H Collection et logiciel Stratta, pour les entreprises en Suisse.";
14
21
  readonly email: "contact@hgdc.ch";
15
22
  readonly contactPoint: {
@@ -29,7 +36,7 @@ export declare const HGDC_ORGANIZATION: {
29
36
  readonly addressCountry: "CH";
30
37
  };
31
38
  };
32
- /** Graphe JSON-LD d'un produit : l'entreprise et le site du produit, qu'elle publie. */
39
+ /** Graphe JSON-LD d'un produit : l'entreprise, le produit (logiciel en ligne) et son site, qu'elle publie. */
33
40
  export declare function productJsonLd(product: {
34
41
  name: string;
35
42
  url: string;
package/dist/hgdc.js CHANGED
@@ -9,6 +9,15 @@ export const HGDC_TRUST_PAGES = {
9
9
  "/contact": "https://hgdc.ch/contact",
10
10
  "/privacy": "https://hgdc.ch/confidentialite",
11
11
  };
12
+ /**
13
+ * Fichiers de découverte que les agents cherchent à la racine de chaque hôte : ceux de l'entreprise, sur
14
+ * hgdc.ch (catalogue ARD, index Agent Skills). Pour l'option `redirects` de `withMarkdown`, avec
15
+ * `HGDC_TRUST_PAGES`.
16
+ */
17
+ export const HGDC_DISCOVERY_FILES = {
18
+ "/.well-known/ard.json": "https://hgdc.ch/.well-known/ard.json",
19
+ "/.well-known/agent-skills/index.json": "https://hgdc.ch/.well-known/agent-skills/index.json",
20
+ };
12
21
  /** Nœud schema.org de l'entreprise, même `@id` que sur hgdc.ch. */
13
22
  export const HGDC_ORGANIZATION = {
14
23
  "@type": "Organization",
@@ -16,6 +25,8 @@ export const HGDC_ORGANIZATION = {
16
25
  name: "Hugo Gebel Développement Conseil",
17
26
  alternateName: "HGDC",
18
27
  url: "https://hgdc.ch",
28
+ // Profils publics de l'entreprise (ceux de l'Agence, ex-SmartFlow, renommés sans changer d'adresse).
29
+ sameAs: ["https://www.linkedin.com/company/smartflowsa", "https://www.instagram.com/smartflowsa.ch"],
19
30
  description: "Entreprise individuelle suisse : agence web, accompagnement IA, outils en ligne de la H Collection et logiciel Stratta, pour les entreprises en Suisse.",
20
31
  email: "contact@hgdc.ch",
21
32
  contactPoint: {
@@ -35,7 +46,7 @@ export const HGDC_ORGANIZATION = {
35
46
  addressCountry: "CH",
36
47
  },
37
48
  };
38
- /** Graphe JSON-LD d'un produit : l'entreprise et le site du produit, qu'elle publie. */
49
+ /** Graphe JSON-LD d'un produit : l'entreprise, le produit (logiciel en ligne) et son site, qu'elle publie. */
39
50
  export function productJsonLd(product) {
40
51
  return {
41
52
  "@context": "https://schema.org",
@@ -50,6 +61,17 @@ export function productJsonLd(product) {
50
61
  inLanguage: "fr-CH",
51
62
  publisher: { "@id": HGDC_ORGANIZATION["@id"] },
52
63
  },
64
+ {
65
+ "@type": "SoftwareApplication",
66
+ "@id": `${product.url}/#software`,
67
+ name: product.name,
68
+ url: product.url,
69
+ description: product.description,
70
+ applicationCategory: "BusinessApplication",
71
+ operatingSystem: "Web",
72
+ inLanguage: "fr-CH",
73
+ publisher: { "@id": HGDC_ORGANIZATION["@id"] },
74
+ },
53
75
  ],
54
76
  };
55
77
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { htmlToMarkdown, pageTitle } from "./markdown.js";
1
+ export { htmlToMarkdown, pageFrontmatter, pageTitle } from "./markdown.js";
2
2
  export { prefersMarkdown, varyOnAccept } from "./negotiate.js";
3
3
  export { linksFooter, withMarkdown, type MarkdownOptions } from "./fetch.js";
4
4
  export { canonicalLink, injectIntoHead, jsonLdScript } from "./head.js";
5
- export { HGDC_ORGANIZATION, HGDC_TRUST_PAGES, productJsonLd } from "./hgdc.js";
5
+ export { HGDC_DISCOVERY_FILES, HGDC_ORGANIZATION, HGDC_TRUST_PAGES, productJsonLd } from "./hgdc.js";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { htmlToMarkdown, pageTitle } from "./markdown.js";
1
+ export { htmlToMarkdown, pageFrontmatter, pageTitle } from "./markdown.js";
2
2
  export { prefersMarkdown, varyOnAccept } from "./negotiate.js";
3
3
  export { linksFooter, withMarkdown } from "./fetch.js";
4
4
  export { canonicalLink, injectIntoHead, jsonLdScript } from "./head.js";
5
- export { HGDC_ORGANIZATION, HGDC_TRUST_PAGES, productJsonLd } from "./hgdc.js";
5
+ export { HGDC_DISCOVERY_FILES, HGDC_ORGANIZATION, HGDC_TRUST_PAGES, productJsonLd } from "./hgdc.js";
@@ -1,7 +1,9 @@
1
1
  /** Titre de la page (`<title>`), pour une page dont le contenu n'a pas de titre de niveau 1. */
2
2
  export declare function pageTitle(html: string): string | null;
3
3
  /**
4
- * Markdown du contenu d'une page HTML.
5
- * @param base adresse de la page, pour rendre les liens absolus
4
+ * Bloc de métadonnées YAML qui ouvre le Markdown d'une page : titre, description et adresse canonique, lus
5
+ * dans le `<head>` (`url` à défaut de `<link rel="canonical">`, sinon pas d'adresse). Les valeurs sont des
6
+ * chaînes JSON, du YAML valide quel que soit leur contenu.
6
7
  */
8
+ export declare function pageFrontmatter(html: string, url?: string | URL): string;
7
9
  export declare function htmlToMarkdown(html: string, base: string | URL): string;
package/dist/markdown.js CHANGED
@@ -243,6 +243,35 @@ export function pageTitle(html) {
243
243
  * Markdown du contenu d'une page HTML.
244
244
  * @param base adresse de la page, pour rendre les liens absolus
245
245
  */
246
+ const attribute = (tag, name) => new RegExp(`\\s${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`, "i")
247
+ .exec(tag)
248
+ ?.slice(1)
249
+ .find((v) => v !== undefined);
250
+ /** Première balise `<tag …>` du document dont un attribut vaut `value`, avec son attribut `read`. */
251
+ function headValue(html, tag, key, value, read) {
252
+ for (const m of html.matchAll(new RegExp(`<${tag}\\b[^>]*>`, "gi"))) {
253
+ if (attribute(m[0], key)?.toLowerCase() === value) {
254
+ const found = attribute(m[0], read);
255
+ if (found)
256
+ return collapse(decode(found)).trim();
257
+ }
258
+ }
259
+ return null;
260
+ }
261
+ /**
262
+ * Bloc de métadonnées YAML qui ouvre le Markdown d'une page : titre, description et adresse canonique, lus
263
+ * dans le `<head>` (`url` à défaut de `<link rel="canonical">`, sinon pas d'adresse). Les valeurs sont des
264
+ * chaînes JSON, du YAML valide quel que soit leur contenu.
265
+ */
266
+ export function pageFrontmatter(html, url) {
267
+ const fields = [
268
+ ["title", pageTitle(html)],
269
+ ["description", headValue(html, "meta", "name", "description", "content")],
270
+ ["canonical", headValue(html, "link", "rel", "canonical", "href") ?? (url ? new URL(url).href : null)],
271
+ ];
272
+ const lines = fields.filter(([, v]) => v).map(([k, v]) => `${k}: ${JSON.stringify(v)}`);
273
+ return lines.length ? `---\n${lines.join("\n")}\n---\n\n` : "";
274
+ }
246
275
  export function htmlToMarkdown(html, base) {
247
276
  const page = new URL(base);
248
277
  const link = (href) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hgdc/agents",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Sites lisibles par les agents IA : version Markdown des pages (Accept: text/markdown), 404 en Markdown, routes Build Output API pour les sites prérendus.",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://github.com/hugogebel-boop/hgdc-kit/tree/main/packages/agents#readme",