Compare commits
19 Commits
chore/fix-
...
chore/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e1b704aa6 | |||
| 0b4a31a432 | |||
| c617dc3979 | |||
| 1b95161de0 | |||
| ebd976bd46 | |||
| f8d57d8fe0 | |||
| 09a4d2c472 | |||
| 1f6dc874d0 | |||
| 4dd63945ee | |||
| ba64b0694b | |||
| 58e5ceda59 | |||
| 08f826ee01 | |||
| 3358d280ec | |||
| 9cb0d5e416 | |||
| a46f058917 | |||
| 604b2199da | |||
| d153f71be6 | |||
| 8f64e4b098 | |||
| 0c46b0d19b |
@@ -47,86 +47,152 @@ jobs:
|
||||
|
||||
node --input-type=module <<'NODE'
|
||||
import fs from "node:fs";
|
||||
|
||||
const ev = JSON.parse(fs.readFileSync(process.env.EVENT_JSON, "utf8"));
|
||||
const repoObj = ev?.repository || {};
|
||||
|
||||
const cloneUrl =
|
||||
repoObj?.clone_url ||
|
||||
(repoObj?.html_url ? (repoObj.html_url.replace(/\/$/,"") + ".git") : "");
|
||||
if (!cloneUrl) throw new Error("No repository clone_url/html_url in event.json");
|
||||
|
||||
const defaultBranch = repoObj?.default_branch || "main";
|
||||
const sha =
|
||||
|
||||
// Push-range (most reliable for change detection)
|
||||
const before = String(ev?.before || "").trim();
|
||||
const after =
|
||||
(process.env.GITHUB_SHA && String(process.env.GITHUB_SHA).trim()) ||
|
||||
ev?.after ||
|
||||
ev?.sha ||
|
||||
ev?.head_commit?.id ||
|
||||
ev?.pull_request?.head?.sha ||
|
||||
"";
|
||||
String(ev?.after || ev?.sha || ev?.head_commit?.id || ev?.pull_request?.head?.sha || "").trim();
|
||||
|
||||
const shq = (s) => "'" + String(s).replace(/'/g, "'\\''") + "'";
|
||||
|
||||
fs.writeFileSync("/tmp/deploy.env", [
|
||||
`REPO_URL=${shq(cloneUrl)}`,
|
||||
`DEFAULT_BRANCH=${shq(defaultBranch)}`,
|
||||
`SHA=${shq(sha)}`
|
||||
`BEFORE=${shq(before)}`,
|
||||
`AFTER=${shq(after)}`
|
||||
].join("\n") + "\n");
|
||||
NODE
|
||||
|
||||
source /tmp/deploy.env
|
||||
echo "Repo URL: $REPO_URL"
|
||||
echo "Default branch: $DEFAULT_BRANCH"
|
||||
echo "SHA: ${SHA:-<empty>}"
|
||||
echo "BEFORE: ${BEFORE:-<empty>}"
|
||||
echo "AFTER: ${AFTER:-<empty>}"
|
||||
|
||||
rm -rf .git
|
||||
git init -q
|
||||
git remote add origin "$REPO_URL"
|
||||
|
||||
if [[ -n "${SHA:-}" ]]; then
|
||||
git fetch --depth 1 origin "$SHA"
|
||||
# Checkout AFTER (or default branch if missing)
|
||||
if [[ -n "${AFTER:-}" ]]; then
|
||||
git fetch --depth 50 origin "$AFTER"
|
||||
git -c advice.detachedHead=false checkout -q FETCH_HEAD
|
||||
else
|
||||
git fetch --depth 1 origin "$DEFAULT_BRANCH"
|
||||
git fetch --depth 50 origin "$DEFAULT_BRANCH"
|
||||
git -c advice.detachedHead=false checkout -q "origin/$DEFAULT_BRANCH"
|
||||
SHA="$(git rev-parse HEAD)"
|
||||
echo "SHA='$SHA'" >> /tmp/deploy.env
|
||||
echo "Resolved SHA: $SHA"
|
||||
AFTER="$(git rev-parse HEAD)"
|
||||
echo "AFTER='$AFTER'" >> /tmp/deploy.env
|
||||
echo "Resolved AFTER: $AFTER"
|
||||
fi
|
||||
|
||||
git log -1 --oneline
|
||||
|
||||
- name: Gate — decide HOTPATCH vs FULL rebuild
|
||||
- name: Gate — decide SKIP vs HOTPATCH vs FULL rebuild
|
||||
env:
|
||||
INPUT_FORCE: ${{ inputs.force }}
|
||||
EVENT_JSON: /var/run/act/workflow/event.json
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source /tmp/deploy.env
|
||||
|
||||
FORCE="${INPUT_FORCE:-0}"
|
||||
|
||||
# liste fichiers touchés (utile pour copier les médias)
|
||||
CHANGED="$(git show --name-only --pretty="" "$SHA" | sed '/^$/d' || true)"
|
||||
printf "%s\n" "$CHANGED" > /tmp/changed.txt
|
||||
# Lire before/after du push depuis event.json (merge-proof)
|
||||
node --input-type=module <<'NODE'
|
||||
import fs from "node:fs";
|
||||
const ev = JSON.parse(fs.readFileSync(process.env.EVENT_JSON, "utf8"));
|
||||
const before = ev?.before || "";
|
||||
const after = ev?.after || ev?.sha || "";
|
||||
const shq = (s) => "'" + String(s).replace(/'/g, "'\\''") + "'";
|
||||
fs.writeFileSync("/tmp/gate.env", [
|
||||
`EV_BEFORE=${shq(before)}`,
|
||||
`EV_AFTER=${shq(after)}`
|
||||
].join("\n") + "\n");
|
||||
NODE
|
||||
|
||||
echo "== changed files =="
|
||||
echo "$CHANGED" | sed -n '1,260p'
|
||||
source /tmp/gate.env
|
||||
|
||||
if [[ "$FORCE" == "1" ]]; then
|
||||
echo "GO=1" >> /tmp/deploy.env
|
||||
echo "MODE='full'" >> /tmp/deploy.env
|
||||
echo "✅ force=1 -> MODE=full (rebuild+restart)"
|
||||
exit 0
|
||||
BEFORE="${EV_BEFORE:-}"
|
||||
AFTER="${EV_AFTER:-}"
|
||||
if [[ -z "${AFTER:-}" ]]; then
|
||||
AFTER="${SHA:-}"
|
||||
fi
|
||||
|
||||
# Auto mode: uniquement annotations/media => hotpatch only
|
||||
if echo "$CHANGED" | grep -qE '^(src/annotations/|public/media/)'; then
|
||||
echo "GO=1" >> /tmp/deploy.env
|
||||
echo "MODE='hotpatch'" >> /tmp/deploy.env
|
||||
echo "Gate ctx: BEFORE=${BEFORE:-<empty>} AFTER=${AFTER:-<empty>} FORCE=${FORCE}"
|
||||
|
||||
# Produire une liste CHANGED fiable :
|
||||
# - si BEFORE/AFTER valides -> git diff before..after
|
||||
# - sinon fallback -> diff parent1..after ou show after
|
||||
CHANGED=""
|
||||
Z40="0000000000000000000000000000000000000000"
|
||||
|
||||
if [[ -n "${BEFORE:-}" && "${BEFORE}" != "${Z40}" ]] \
|
||||
&& git cat-file -e "${BEFORE}^{commit}" 2>/dev/null \
|
||||
&& git cat-file -e "${AFTER}^{commit}" 2>/dev/null; then
|
||||
CHANGED="$(git diff --name-only "${BEFORE}" "${AFTER}" || true)"
|
||||
else
|
||||
P1="$(git rev-parse "${AFTER}^" 2>/dev/null || true)"
|
||||
if [[ -n "${P1:-}" ]] && git cat-file -e "${P1}^{commit}" 2>/dev/null; then
|
||||
CHANGED="$(git diff --name-only "${P1}" "${AFTER}" || true)"
|
||||
else
|
||||
CHANGED="$(git show --name-only --pretty="" "${AFTER}" | sed '/^$/d' || true)"
|
||||
fi
|
||||
fi
|
||||
|
||||
printf "%s\n" "${CHANGED}" > /tmp/changed.txt
|
||||
|
||||
echo "== changed files (first 200) =="
|
||||
sed -n '1,200p' /tmp/changed.txt || true
|
||||
|
||||
# Flags
|
||||
HAS_FULL=0
|
||||
HAS_HOTPATCH=0
|
||||
|
||||
# FULL si build-impacting (ce que tu veux : content/anchors/pages/scripts)
|
||||
if grep -qE '^(src/content/|src/anchors/|src/pages/|scripts/)' /tmp/changed.txt; then
|
||||
HAS_FULL=1
|
||||
fi
|
||||
|
||||
# HOTPATCH si annotations/media touchés
|
||||
if grep -qE '^(src/annotations/|public/media/)' /tmp/changed.txt; then
|
||||
HAS_HOTPATCH=1
|
||||
fi
|
||||
|
||||
echo "Gate flags: HAS_FULL=${HAS_FULL} HAS_HOTPATCH=${HAS_HOTPATCH}"
|
||||
|
||||
# Décision
|
||||
if [[ "${FORCE}" == "1" ]]; then
|
||||
GO=1
|
||||
MODE="full"
|
||||
echo "✅ force=1 -> MODE=full (rebuild+restart)"
|
||||
elif [[ "${HAS_FULL}" == "1" ]]; then
|
||||
GO=1
|
||||
MODE="full"
|
||||
echo "✅ build-impacting change -> MODE=full (rebuild+restart)"
|
||||
elif [[ "${HAS_HOTPATCH}" == "1" ]]; then
|
||||
GO=1
|
||||
MODE="hotpatch"
|
||||
echo "✅ annotations/media change -> MODE=hotpatch"
|
||||
else
|
||||
echo "GO=0" >> /tmp/deploy.env
|
||||
echo "MODE='skip'" >> /tmp/deploy.env
|
||||
echo "ℹ️ no annotations/media change -> skip deploy"
|
||||
GO=0
|
||||
MODE="skip"
|
||||
echo "ℹ️ no relevant change -> skip deploy"
|
||||
fi
|
||||
|
||||
echo "GO=${GO}" >> /tmp/deploy.env
|
||||
echo "MODE='${MODE}'" >> /tmp/deploy.env
|
||||
|
||||
- name: Toolchain sanity + resolve COMPOSE_PROJECT_NAME
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -108,22 +108,6 @@ jobs:
|
||||
echo "✅ context:"
|
||||
sed -n '1,120p' /tmp/proposer.env
|
||||
|
||||
- name: Detect app dir (repo-root vs ./site)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source /tmp/proposer.env
|
||||
|
||||
APP_DIR="."
|
||||
if [[ -d "site" && -f "site/package.json" ]]; then
|
||||
APP_DIR="site"
|
||||
fi
|
||||
|
||||
echo "APP_DIR=$APP_DIR" >> /tmp/proposer.env
|
||||
echo "✅ APP_DIR=$APP_DIR"
|
||||
ls -la "$APP_DIR" | sed -n '1,80p'
|
||||
test -f "$APP_DIR/package.json" || { echo "❌ package.json missing in APP_DIR=$APP_DIR"; exit 1; }
|
||||
test -d "$APP_DIR/scripts" || { echo "❌ scripts/ missing in APP_DIR=$APP_DIR"; exit 1; }
|
||||
|
||||
- name: Gate on label state/approved
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -233,6 +217,25 @@ jobs:
|
||||
git fetch --depth 1 origin "$DEFAULT_BRANCH"
|
||||
git -c advice.detachedHead=false checkout -q FETCH_HEAD
|
||||
git log -1 --oneline
|
||||
echo "✅ workspace:"
|
||||
ls -la | sed -n '1,120p'
|
||||
|
||||
- name: Detect app dir (repo-root vs ./site)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source /tmp/proposer.env
|
||||
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
||||
|
||||
APP_DIR="."
|
||||
if [[ -d "site" && -f "site/package.json" ]]; then
|
||||
APP_DIR="site"
|
||||
fi
|
||||
|
||||
echo "APP_DIR=$APP_DIR" >> /tmp/proposer.env
|
||||
echo "✅ APP_DIR=$APP_DIR"
|
||||
ls -la "$APP_DIR" | sed -n '1,120p'
|
||||
test -f "$APP_DIR/package.json" || { echo "❌ package.json missing in APP_DIR=$APP_DIR"; exit 1; }
|
||||
test -d "$APP_DIR/scripts" || { echo "❌ scripts/ missing in APP_DIR=$APP_DIR"; exit 1; }
|
||||
|
||||
- name: NPM harden (reduce flakiness)
|
||||
run: |
|
||||
@@ -284,7 +287,7 @@ jobs:
|
||||
|
||||
export GITEA_OWNER="$OWNER"
|
||||
export GITEA_REPO="$REPO"
|
||||
export FORGE_BASE="$API_BASE" # fallback utile pour apply-ticket si FORGE_API absent
|
||||
export FORGE_BASE="$API_BASE"
|
||||
|
||||
LOG="/tmp/proposer-apply.log"
|
||||
set +e
|
||||
@@ -310,32 +313,6 @@ jobs:
|
||||
echo "END_SHA=$END_SHA" >> /tmp/proposer.env
|
||||
fi
|
||||
|
||||
- name: Comment issue on failure
|
||||
if: ${{ always() }}
|
||||
env:
|
||||
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source /tmp/proposer.env || true
|
||||
[[ "${SKIP:-0}" != "1" ]] || exit 0
|
||||
|
||||
RC="${APPLY_RC:-0}"
|
||||
if [[ "$RC" == "0" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
BODY="(no log)"
|
||||
[[ -f /tmp/proposer-apply.log ]] && BODY="$(tail -n 160 /tmp/proposer-apply.log | sed 's/\r$//')"
|
||||
|
||||
MSG="❌ Proposer Apply échoué (rc=${RC}).\n\n\`\`\`\n${BODY}\n\`\`\`\n"
|
||||
PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.argv[1]||""}))' "$MSG")"
|
||||
|
||||
curl -fsS -X POST \
|
||||
-H "Authorization: token $FORGE_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER/comments" \
|
||||
--data-binary "$PAYLOAD"
|
||||
|
||||
- name: Push bot branch
|
||||
if: ${{ always() }}
|
||||
env:
|
||||
|
||||
@@ -114,7 +114,6 @@ async function runMammoth(docxPath, assetsOutDirWebRoot) {
|
||||
);
|
||||
|
||||
let html = result.value || "";
|
||||
|
||||
// Mammoth gives relative src="image-xx.png" ; we will prefix later
|
||||
return html;
|
||||
}
|
||||
@@ -182,6 +181,25 @@ async function exists(p) {
|
||||
try { await fs.access(p); return true; } catch { return false; }
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ compat:
|
||||
* - ancien : collection="archicratie" + slug="archicrat-ia/chapitre-3"
|
||||
* - nouveau : collection="archicrat-ia" + slug="chapitre-3"
|
||||
*
|
||||
* But : toujours écrire dans src/content/archicrat-ia/<slugSansPrefix>.mdx
|
||||
*/
|
||||
function normalizeDest(collection, slug) {
|
||||
let outCollection = String(collection || "").trim();
|
||||
let outSlug = String(slug || "").trim().replace(/^\/+|\/+$/g, "");
|
||||
|
||||
if (outCollection === "archicratie" && outSlug.startsWith("archicrat-ia/")) {
|
||||
outCollection = "archicrat-ia";
|
||||
outSlug = outSlug.replace(/^archicrat-ia\//, "");
|
||||
}
|
||||
|
||||
return { outCollection, outSlug };
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const args = parseArgs(process.argv);
|
||||
const manifestPath = path.resolve(args.manifest);
|
||||
@@ -203,11 +221,14 @@ async function main() {
|
||||
|
||||
for (const it of selected) {
|
||||
const docxPath = path.resolve(it.source);
|
||||
const outFile = path.resolve("src/content", it.collection, `${it.slug}.mdx`);
|
||||
|
||||
const { outCollection, outSlug } = normalizeDest(it.collection, it.slug);
|
||||
|
||||
const outFile = path.resolve("src/content", outCollection, `${outSlug}.mdx`);
|
||||
const outDir = path.dirname(outFile);
|
||||
|
||||
const assetsPublicDir = path.posix.join("/imported", it.collection, it.slug);
|
||||
const assetsDiskDir = path.resolve("public", "imported", it.collection, it.slug);
|
||||
const assetsPublicDir = path.posix.join("/imported", outCollection, outSlug);
|
||||
const assetsDiskDir = path.resolve("public", "imported", outCollection, outSlug);
|
||||
|
||||
if (!(await exists(docxPath))) {
|
||||
throw new Error(`Missing source docx: ${docxPath}`);
|
||||
@@ -241,18 +262,20 @@ async function main() {
|
||||
html = rewriteLocalImageLinks(html, assetsPublicDir);
|
||||
body = html.trim() ? html : "<p>(Import vide)</p>";
|
||||
}
|
||||
|
||||
|
||||
const defaultVersion = process.env.PUBLIC_RELEASE || "0.1.0";
|
||||
|
||||
// ✅ IMPORTANT: archicrat-ia partage edition/status avec archicratie (pas de migration frontmatter)
|
||||
const schemaDefaultsByCollection = {
|
||||
archicratie: { edition: "archicratie", status: "modele_sociopolitique", level: 1 },
|
||||
ia: { edition: "ia", status: "cas_pratique", level: 1 },
|
||||
traite: { edition: "traite", status: "ontodynamique", level: 1 },
|
||||
glossaire: { edition: "glossaire", status: "lexique", level: 1 },
|
||||
atlas: { edition: "atlas", status: "atlas", level: 1 },
|
||||
archicratie: { edition: "archicratie", status: "modele_sociopolitique", level: 1 },
|
||||
"archicrat-ia": { edition: "archicrat-ia", status: "essai_these", level: 1 },
|
||||
ia: { edition: "ia", status: "cas_pratique", level: 1 },
|
||||
traite: { edition: "traite", status: "ontodynamique", level: 1 },
|
||||
glossaire: { edition: "glossaire", status: "lexique", level: 1 },
|
||||
atlas: { edition: "atlas", status: "atlas", level: 1 },
|
||||
};
|
||||
|
||||
const defaults = schemaDefaultsByCollection[it.collection] || { edition: it.collection, status: "draft", level: 1 };
|
||||
const defaults = schemaDefaultsByCollection[outCollection] || { edition: outCollection, status: "draft", level: 1 };
|
||||
|
||||
const fm = [
|
||||
"---",
|
||||
@@ -282,4 +305,4 @@ async function main() {
|
||||
main().catch((e) => {
|
||||
console.error("\nERROR:", e?.message || e);
|
||||
process.exit(1);
|
||||
});
|
||||
});
|
||||
@@ -1,2 +1,5 @@
|
||||
{}
|
||||
|
||||
{
|
||||
"/archicrat-ia/chapitre-3/": {
|
||||
"p-1-60c7ea48": "p-1-a21087b0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,3 +8,4 @@ paras:
|
||||
kind: (livre / article / vidéo / site / autre) Site
|
||||
ts: 2026-03-02T20:01:55.858Z
|
||||
fromIssue: 172
|
||||
# testB: hotpatch-auto gate proof
|
||||
|
||||
@@ -3,14 +3,11 @@ import { getCollection } from "astro:content";
|
||||
|
||||
const { currentSlug } = Astro.props;
|
||||
|
||||
const entries = (await getCollection("archicratie"))
|
||||
.filter((e) => e.slug.startsWith("archicrat-ia/"))
|
||||
// ✅ Après migration : TOC = collection "archicrat-ia"
|
||||
const entries = (await getCollection("archicrat-ia"))
|
||||
.sort((a, b) => (a.data.order ?? 0) - (b.data.order ?? 0));
|
||||
|
||||
// ✅ On route l’Essai-thèse sur /archicrat-ia/<slug-sans-prefix>/
|
||||
// (Astro trailingSlash = always → on garde le "/" final)
|
||||
const strip = (s) => String(s || "").replace(/^archicrat-ia\//, "");
|
||||
const href = (slug) => `/archicrat-ia/${strip(slug)}/`;
|
||||
const href = (slug) => `/archicrat-ia/${slug}/`;
|
||||
---
|
||||
|
||||
<nav class="toc-global" aria-label="Table des matières — ArchiCraT-IA">
|
||||
@@ -163,4 +160,4 @@ const href = (slug) => `/archicrat-ia/${strip(slug)}/`;
|
||||
const active = document.querySelector(".toc-global .toc-item.is-active");
|
||||
if (active) active.scrollIntoView({ block: "nearest" });
|
||||
})();
|
||||
</script>
|
||||
</script>
|
||||
@@ -14,7 +14,7 @@ source:
|
||||
---
|
||||
Ce chapitre se tient à un point nodal de notre essai-thèse : il ouvre un espace d’exploration systématique des formes conceptuelles et philosophiques à travers lesquelles le pouvoir se configure comme régime de régulation. Il ne s’agit pas ici de revenir une nouvelle fois sur les fondements de l’autorité, ni d’interroger la légitimité politique au sens classique du terme, ni même d’enquêter sur la genèse des institutions. L’ambition est autre, structurelle, transversale, morphologique, elle tentera d’arpenter, à même les dispositifs, les pensées, les théorisations et les expériences, les modalités différentiées par lesquelles s’instaurent, s’éprouvent et se disputent les formes de régulation du vivre-ensemble.
|
||||
|
||||
Dès lors, ce chapitre ne postule aucun fondement, ne cherche aucun point d’origine, ne prétend restituer aucune ontologie stable du politique. Ce qu’il donne à lire, c’est une cartographie dynamique des régimes de régulation, traversée par des formes irréductibles, non homogènes, souvent conflictuelles, parfois incompatibles, mais toutes pensées comme des configurations singulières.
|
||||
Dès lors, ce chapitre ne postule aucun fondement, ne cherche aucun point d’origine, ne prétend restituer aucune ontologie stable du politique. Ce qu’il donne à lire, c’est une cartographie dynamique des régimes de régulation, traversée par des formes irréductibles, non homogènes, souvent conflictuelles, parfois incompatibles, mais toutes pensées comme des configurations singulières, et souvent complémentaires.
|
||||
|
||||
Ainsi, loin d’être une galerie illustrative de théories politiques juxtaposées, le chapitre s’agence comme une topologie critique, une plongée stratigraphique dans les scènes où s’articule la régulation — entendue ici non comme stabilisation externe ou ajustement technico-fonctionnel, mais comme dispositif instituant, tension structurante, scène traversée de conflictualité et d’exigence normative. Car à nos yeux, la régulation n’est pas ce qui vient après le pouvoir, elle en est la forme même constitutive — son architecture, son rythme, son épaisseur. Elle est ce par quoi le pouvoir ne se contente pas d’être exercé, mais s’institue, se justifie, se dispute, se recompose.
|
||||
|
||||
@@ -2,7 +2,7 @@ import { defineCollection, z } from "astro:content";
|
||||
|
||||
const linkSchema = z.object({
|
||||
type: z.enum(["definition", "appui", "transposition"]),
|
||||
target: z.string().min(1), // URL interne (ex: /glossaire/archicratie/) ou slug
|
||||
target: z.string().min(1),
|
||||
note: z.string().optional()
|
||||
});
|
||||
|
||||
@@ -12,7 +12,6 @@ const baseTextSchema = z.object({
|
||||
version: z.string().min(1),
|
||||
concepts: z.array(z.string().min(1)).default([]),
|
||||
links: z.array(linkSchema).default([]),
|
||||
// optionnels mais utiles dès maintenant
|
||||
order: z.number().int().nonnegative().optional(),
|
||||
summary: z.string().optional()
|
||||
});
|
||||
@@ -50,20 +49,31 @@ const atlas = defineCollection({
|
||||
})
|
||||
});
|
||||
|
||||
// ✅ NOUVELLE collection : archicrat-ia (Essai-thèse)
|
||||
// NOTE : on accepte temporairement edition/status "archicratie/modele_sociopolitique"
|
||||
// si tes MDX n’ont pas encore été normalisés.
|
||||
// Quand tu voudras "strict", on passera à edition="archicrat-ia" status="essai_these"
|
||||
// + update frontmatter des 7 fichiers.
|
||||
const archicratIa = defineCollection({
|
||||
type: "content",
|
||||
schema: baseTextSchema.extend({
|
||||
edition: z.union([z.literal("archicrat-ia"), z.literal("archicratie")]),
|
||||
status: z.union([z.literal("essai_these"), z.literal("modele_sociopolitique")])
|
||||
})
|
||||
});
|
||||
|
||||
// Glossaire (référentiel terminologique)
|
||||
const glossaire = defineCollection({
|
||||
type: "content",
|
||||
schema: z.object({
|
||||
title: z.string().min(1), // Titre public (souvent identique au terme)
|
||||
term: z.string().min(1), // Terme canonique
|
||||
title: z.string().min(1),
|
||||
term: z.string().min(1),
|
||||
aliases: z.array(z.string().min(1)).default([]),
|
||||
edition: z.literal("glossaire"),
|
||||
status: z.literal("referentiel"),
|
||||
version: z.string().min(1),
|
||||
// Micro-définition affichable en popover (courte, stable)
|
||||
definitionShort: z.string().min(1),
|
||||
concepts: z.array(z.string().min(1)).default([]),
|
||||
// Liens typés (vers ouvrages ou autres termes)
|
||||
links: z.array(linkSchema).default([])
|
||||
})
|
||||
});
|
||||
@@ -73,5 +83,8 @@ export const collections = {
|
||||
archicratie,
|
||||
ia,
|
||||
glossaire,
|
||||
atlas
|
||||
};
|
||||
atlas,
|
||||
|
||||
// ⚠️ clé avec tiret => doit être quotée
|
||||
"archicrat-ia": archicratIa
|
||||
};
|
||||
@@ -5,12 +5,11 @@ import EditionToc from "../../components/EditionToc.astro";
|
||||
import LocalToc from "../../components/LocalToc.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const entries = (await getCollection("archicratie"))
|
||||
.filter((e) => e.slug.startsWith("archicrat-ia/"));
|
||||
// ✅ Après migration : plus de filtre par prefix, on prend toute la collection
|
||||
const entries = await getCollection("archicrat-ia");
|
||||
|
||||
return entries.map((entry) => ({
|
||||
// ✅ inline : jamais de helper externe (évite "stripPrefix is not defined")
|
||||
params: { slug: entry.slug.replace(/^archicrat-ia\//, "") },
|
||||
params: { slug: entry.slug },
|
||||
props: { entry },
|
||||
}));
|
||||
}
|
||||
@@ -35,4 +34,4 @@ const { Content, headings } = await entry.render();
|
||||
|
||||
<h1>{entry.data.title}</h1>
|
||||
<Content />
|
||||
</EditionLayout>
|
||||
</EditionLayout>
|
||||
@@ -2,13 +2,12 @@
|
||||
import SiteLayout from "../../layouts/SiteLayout.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
const entries = (await getCollection("archicratie"))
|
||||
.filter((e) => e.slug.startsWith("archicrat-ia/"));
|
||||
// ✅ Après migration physique : collection = "archicrat-ia", slug = "chapitre-3" (sans prefix)
|
||||
const entries = await getCollection("archicrat-ia");
|
||||
|
||||
entries.sort((a, b) => (a.data.order ?? 9999) - (b.data.order ?? 9999));
|
||||
|
||||
const strip = (slug) => slug.replace(/^archicrat-ia\//, "");
|
||||
const href = (slug) => `/archicrat-ia/${strip(slug)}/`;
|
||||
const href = (slug) => `/archicrat-ia/${slug}/`;
|
||||
---
|
||||
|
||||
<SiteLayout title="Essai-thèse — ArchiCraT-IA">
|
||||
@@ -19,4 +18,4 @@ const href = (slug) => `/archicrat-ia/${strip(slug)}/`;
|
||||
<li><a href={href(e.slug)}>{e.data.title}</a></li>
|
||||
))}
|
||||
</ul>
|
||||
</SiteLayout>
|
||||
</SiteLayout>
|
||||
Reference in New Issue
Block a user