@hutusi/amytis 1.14.0 → 1.16.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/.github/workflows/ci.yml +1 -1
- package/.github/workflows/publish.yml +2 -2
- package/CHANGELOG.md +42 -0
- package/CLAUDE.md +90 -219
- package/README.md +33 -1
- package/README.zh.md +33 -1
- package/TODO.md +10 -0
- package/bun.lock +205 -539
- package/content/books/sample-book/index.mdx +3 -0
- package/content/posts/code-block-features-showcase.mdx +223 -0
- package/content/series/rst-legacy/deeper-notes/images/test.svg +4 -0
- package/content/series/rst-legacy/deeper-notes/index.rst +15 -0
- package/content/series/rst-legacy/getting-started.rst +24 -0
- package/content/series/rst-legacy/index.rst +9 -0
- package/content/series/rst-readme/README.rst +9 -0
- package/content/series/rst-readme/readme-index-post.rst +10 -0
- package/content/series/rst-toctree/first-post.rst +6 -0
- package/content/series/rst-toctree/index.rst +10 -0
- package/content/series/rst-toctree/second-post.rst +6 -0
- package/content/series/rst-toctree-precedence/first-post.rst +6 -0
- package/content/series/rst-toctree-precedence/index.rst +12 -0
- package/content/series/rst-toctree-precedence/second-post.rst +6 -0
- package/docs/ALERTS.md +112 -0
- package/docs/ARCHITECTURE.md +239 -8
- package/docs/CODE-BLOCKS.md +238 -0
- package/docs/CONTRIBUTING.md +36 -0
- package/docs/guides/README.md +11 -0
- package/docs/guides/importing-vuepress-books.md +178 -0
- package/eslint.config.mjs +20 -6
- package/next.config.ts +2 -2
- package/package.json +52 -24
- package/packages/create-amytis/package.json +1 -1
- package/packages/create-amytis/src/index.test.ts +43 -1
- package/packages/create-amytis/src/index.ts +64 -8
- package/public/next-image-export-optimizer-hashes.json +14 -73
- package/scripts/build-pagefind.ts +172 -0
- package/scripts/copy-assets.ts +246 -56
- package/scripts/generate-code-group-icons.ts +79 -0
- package/scripts/generate-knowledge-graph.ts +2 -1
- package/scripts/render-rst.py +923 -0
- package/scripts/run-with-rst-python.ts +42 -0
- package/scripts/sync-vuepress-book.ts +499 -0
- package/src/app/[slug]/[postSlug]/page.tsx +20 -10
- package/src/app/[slug]/page/[page]/page.tsx +15 -0
- package/src/app/books/[slug]/{[chapter] → [...chapter]}/page.tsx +32 -10
- package/src/app/books/[slug]/page.tsx +67 -32
- package/src/app/globals.css +639 -94
- package/src/app/page.tsx +1 -1
- package/src/app/series/[slug]/page/[page]/page.tsx +74 -6
- package/src/app/series/[slug]/page.tsx +11 -13
- package/src/app/series/page.tsx +3 -3
- package/src/app/sitemap.ts +3 -3
- package/src/components/ArticleCopyCleaner.tsx +64 -0
- package/src/components/AuthorCard.tsx +25 -16
- package/src/components/BookMobileNav.tsx +44 -50
- package/src/components/BookSidebar.tsx +0 -0
- package/src/components/CodeBlock.test.tsx +93 -8
- package/src/components/CodeBlock.tsx +39 -101
- package/src/components/CodeBlockToolbar.tsx +88 -0
- package/src/components/CodeGroup.tsx +81 -0
- package/src/components/CoverImage.tsx +6 -2
- package/src/components/ExternalLinkIcon.tsx +15 -0
- package/src/components/FeaturedStoriesSection.tsx +3 -3
- package/src/components/GithubAlert.tsx +97 -0
- package/src/components/MarkdownRenderer.test.tsx +30 -4
- package/src/components/MarkdownRenderer.tsx +148 -24
- package/src/components/Mermaid.tsx +32 -1
- package/src/components/PostList.tsx +1 -1
- package/src/components/PostNavigation.tsx +13 -2
- package/src/components/PostSidebar.tsx +13 -2
- package/src/components/RstRenderer.test.tsx +93 -0
- package/src/components/RstRenderer.tsx +157 -0
- package/src/components/Search.tsx +18 -4
- package/src/components/SeriesCatalog.tsx +1 -1
- package/src/components/ShareBar.tsx +5 -0
- package/src/components/TocPanel.tsx +10 -2
- package/src/i18n/translations.ts +2 -0
- package/src/layouts/BookLayout.tsx +35 -4
- package/src/layouts/PostLayout.tsx +10 -2
- package/src/layouts/SimpleLayout.tsx +10 -3
- package/src/lib/code-group-icons.test.ts +78 -0
- package/src/lib/code-group-icons.ts +148 -0
- package/src/lib/image-utils.test.ts +19 -0
- package/src/lib/image-utils.ts +11 -0
- package/src/lib/markdown.test.ts +195 -14
- package/src/lib/markdown.ts +928 -254
- package/src/lib/normalize-vuepress-math.ts +118 -0
- package/src/lib/rehype-fence-meta.ts +22 -0
- package/src/lib/rehype-image-metadata.ts +2 -2
- package/src/lib/remark-book-chapter-links.ts +106 -0
- package/src/lib/remark-code-group.ts +54 -0
- package/src/lib/remark-github-alerts.test.ts +83 -0
- package/src/lib/remark-github-alerts.ts +65 -0
- package/src/lib/remark-vuepress-containers.ts +130 -0
- package/src/lib/rst-renderer.test.ts +355 -0
- package/src/lib/rst-renderer.ts +629 -0
- package/src/lib/rst.test.ts +350 -0
- package/src/lib/rst.ts +674 -0
- package/src/lib/series-redirects.ts +42 -0
- package/src/lib/shiki-rst.ts +185 -0
- package/src/lib/shiki.test.ts +153 -0
- package/src/lib/shiki.ts +292 -0
- package/src/lib/urls.ts +57 -0
- package/src/test-utils/render.ts +23 -0
- package/tests/fixtures/sync-vuepress-book/docs/.vuepress/config.js +43 -0
- package/tests/fixtures/sync-vuepress-book/docs/intro/welcome.md +7 -0
- package/tests/fixtures/sync-vuepress-book/docs/maths/linear/assets/diagram.png +1 -0
- package/tests/fixtures/sync-vuepress-book/docs/maths/linear/matrices.md +7 -0
- package/tests/fixtures/sync-vuepress-book/docs/maths/linear/vectors.md +9 -0
- package/tests/helpers/env.ts +19 -0
- package/tests/integration/book-chapter-links.test.ts +107 -0
- package/tests/integration/books-nested-toc.test.ts +176 -0
- package/tests/integration/books.test.ts +3 -2
- package/tests/integration/code-block-features.test.ts +188 -0
- package/tests/integration/code-group.test.ts +183 -0
- package/tests/integration/code-notation.test.ts +97 -0
- package/tests/integration/feed-utils.test.ts +13 -0
- package/tests/integration/github-alerts.test.ts +82 -0
- package/tests/integration/markdown-external-links.test.ts +103 -0
- package/tests/integration/normalize-vuepress-math.test.ts +149 -0
- package/tests/integration/reading-time-headings.test.ts +12 -14
- package/tests/integration/series-draft.test.ts +12 -5
- package/tests/integration/series.test.ts +93 -0
- package/tests/integration/sync-vuepress-book.test.ts +240 -0
- package/tests/integration/vuepress-containers.test.ts +107 -0
- package/tests/tooling/build-pagefind.test.ts +66 -0
- package/tests/tooling/new-post.test.ts +1 -1
- package/tests/unit/static-params.test.ts +166 -13
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Importing a VuePress 2 book
|
|
2
|
+
|
|
3
|
+
Amytis can host a VuePress 2 book natively. `bun run sync-vuepress-book`
|
|
4
|
+
copies the upstream `docs/` tree into a slug under `content/books/`, derives
|
|
5
|
+
Amytis's nested-section book TOC from the VuePress sidebar config, and
|
|
6
|
+
preserves any user-controlled fields you've added to the book's `index.mdx`.
|
|
7
|
+
|
|
8
|
+
The importer is idempotent — re-running mirrors the current state of the
|
|
9
|
+
source (including upstream deletions). You should *not* edit chapter
|
|
10
|
+
markdown files in the dest: they get overwritten on every sync. Customize
|
|
11
|
+
the book's metadata in `index.mdx` (preserved) or extend the source repo.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- The source must be a VuePress 2 project where the docs root contains a
|
|
18
|
+
`.vuepress/` directory with a `config.js` or `config.mjs`.
|
|
19
|
+
- `config.ts` is **not supported** — acorn (used to AST-extract the sidebar)
|
|
20
|
+
parses JS only. Compile to JS first (`tsc`, `bun build --no-bundle`, …) or
|
|
21
|
+
rename to `.mjs` if the config is pure ESM.
|
|
22
|
+
- The destination directory under `content/books/<slug>/` may already exist
|
|
23
|
+
with a partial `index.mdx`; user-controlled frontmatter is preserved.
|
|
24
|
+
|
|
25
|
+
## Quick start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bun run sync-vuepress-book \
|
|
29
|
+
--source /path/to/your-book/docs \
|
|
30
|
+
--dest content/books/your-book
|
|
31
|
+
|
|
32
|
+
# Positional shorthand:
|
|
33
|
+
bun run sync-vuepress-book /path/to/your-book/docs content/books/your-book
|
|
34
|
+
|
|
35
|
+
# Then rebuild + preview locally:
|
|
36
|
+
bun run build:dev
|
|
37
|
+
bun dev
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The script prints a one-line summary on completion:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
[sync-vuepress-book] Done. 74 markdown files, 104 asset files copied, 61 chapters mapped.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
It will also warn about anomalies it noticed in the sidebar — empty section
|
|
47
|
+
placeholders, sections with their own page-link header, dropped meta-nav
|
|
48
|
+
leaves (see [Conventions](#conventions) below), etc.
|
|
49
|
+
|
|
50
|
+
## What the script does
|
|
51
|
+
|
|
52
|
+
1. Locates `.vuepress/config.{js,mjs}` under `<source>`.
|
|
53
|
+
2. AST-parses the file with acorn, walks the tree for the `sidebar:` array
|
|
54
|
+
wherever it lives (theme wrapper, plain export, etc.), and converts its
|
|
55
|
+
literals to a plain JS structure. Unsupported AST shapes throw — silent
|
|
56
|
+
drops would produce a half-correct TOC.
|
|
57
|
+
3. Maps every VuePress sidebar item to one of:
|
|
58
|
+
- `{ title, id }` for a leaf (`{ text, link }` in VuePress).
|
|
59
|
+
- `{ section, items, collapsible? }` for a group (`{ text, children }`),
|
|
60
|
+
recursive — VuePress's two layers of nesting map 1:1.
|
|
61
|
+
- Mixed/unknown shapes are warned and skipped.
|
|
62
|
+
4. Validates that every leaf's resolved chapter id has a real source file at
|
|
63
|
+
one of `<id>.md`, `<id>.mdx`, `<id>/README.md(x)`, or `<id>/index.md(x)`.
|
|
64
|
+
Throws and lists the missing files if any.
|
|
65
|
+
5. **Mirrors** the source tree into `<dest>` (`fs.copyFileSync`):
|
|
66
|
+
- Copies every file except `.vuepress/`, `node_modules`, `.git`, and
|
|
67
|
+
dotfiles.
|
|
68
|
+
- Prunes any importer-managed dest file/dir whose path is no longer in
|
|
69
|
+
the source — re-running after an upstream rename or deletion is clean.
|
|
70
|
+
- Preserves `index.mdx` (regenerated separately, not mirrored) and any
|
|
71
|
+
dest dotfiles you added (`.gitkeep`, etc.).
|
|
72
|
+
6. Rewrites `<dest>/index.mdx` with the new `chapters:` TOC, merging into
|
|
73
|
+
any existing frontmatter rather than replacing it. See
|
|
74
|
+
[User-controlled fields](#user-controlled-fields-in-indexmdx) below.
|
|
75
|
+
|
|
76
|
+
## Conventions
|
|
77
|
+
|
|
78
|
+
- The sidebar leaf with id `contents` is dropped from the generated TOC —
|
|
79
|
+
it's a VuePress convention for a hand-written table-of-contents page, and
|
|
80
|
+
Amytis's book landing page already renders one. The `contents.md` file
|
|
81
|
+
itself is still copied so the dest layout matches upstream; it just
|
|
82
|
+
isn't reachable from the TOC.
|
|
83
|
+
- Sections with `collapsible: false` on the VuePress side keep that hint —
|
|
84
|
+
the Amytis sidebar honors it (forces the section open).
|
|
85
|
+
- A group whose VuePress entry has both `link` and `children` is treated as
|
|
86
|
+
a pure group; the group's own page link is dropped (warned).
|
|
87
|
+
|
|
88
|
+
## User-controlled fields in `index.mdx`
|
|
89
|
+
|
|
90
|
+
The script forces `chapters:` to whatever the current sidebar produces, but
|
|
91
|
+
leaves the rest of the frontmatter alone if it's already populated:
|
|
92
|
+
|
|
93
|
+
| Field | Behavior |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `title` | Preserved if set; else derived from the VuePress config's `title` |
|
|
96
|
+
| `excerpt` | Preserved |
|
|
97
|
+
| `date` | Preserved if set; else today |
|
|
98
|
+
| `coverImage` | Preserved |
|
|
99
|
+
| `featured` | Preserved (defaults to `false` on first sync) |
|
|
100
|
+
| `draft` | Preserved (defaults to `false` on first sync) |
|
|
101
|
+
| `authors` | Preserved |
|
|
102
|
+
| `latex` | Preserved — set to `true` for math-heavy books to enable KaTeX globally for the book |
|
|
103
|
+
| `showChapterExcerpt` | Preserved (defaults to `false`). Set to `true` if you want the chapter's `excerpt` rendered as a subtitle under the chapter title. The default suppresses it because most chapters open with their own lede paragraph that duplicates the excerpt. |
|
|
104
|
+
| `chapters` | **Always rewritten** from the sidebar |
|
|
105
|
+
|
|
106
|
+
The prose body below the frontmatter is also preserved, so you can write a
|
|
107
|
+
custom landing-page introduction and re-running the script won't blow it
|
|
108
|
+
away.
|
|
109
|
+
|
|
110
|
+
## What about VuePress-specific content?
|
|
111
|
+
|
|
112
|
+
`MarkdownRenderer` quietly handles the syntax shapes the VuePress ecosystem
|
|
113
|
+
uses, so you don't have to rewrite chapters by hand:
|
|
114
|
+
|
|
115
|
+
- **`:::note` / `:::tip` / `:::warning` / `:::danger` / `:::info`** —
|
|
116
|
+
rewritten to Amytis's existing `<GithubAlert>` component. Custom titles
|
|
117
|
+
(e.g. `:::tip 智慧的疆界`) are preserved via `data-alert-title`.
|
|
118
|
+
- **Mermaid fences** — `` ```mermaid `` blocks render via the existing
|
|
119
|
+
`<Mermaid>` client component. The `compact` modifier dmla uses is harmless
|
|
120
|
+
(it lives in fence meta, not the language tag).
|
|
121
|
+
- **Inline `$$ ... $$` block math** — VuePress allows
|
|
122
|
+
`$$ \mathbf{A} = \begin{bmatrix}` openers and `\end{bmatrix} $$` closers
|
|
123
|
+
on the same line as the math body; `remark-math` requires `$$` to be on
|
|
124
|
+
its own line. A pre-processor (`normalizeVuepressBlockMath`) splits them
|
|
125
|
+
before parsing, preserving any list-item indent.
|
|
126
|
+
- **Inter-chapter `[X](other.md)` links** — `remark-book-chapter-links`
|
|
127
|
+
rewrites these to canonical `/books/<slug>/<chapter-id>` URLs. Targets
|
|
128
|
+
outside the book throw; targets not in the TOC (work-in-progress chapters
|
|
129
|
+
the author commented out of the sidebar) warn and pass through unrewritten.
|
|
130
|
+
- **CJK in math** — KaTeX's `unicodeTextInMathMode` warning is silenced via
|
|
131
|
+
`strict: 'ignore'`. Chinese-language math like `$输入$` or `$h_{隐藏状态}$`
|
|
132
|
+
renders without flooding the dev console.
|
|
133
|
+
- **Custom Vue components** — `<Swiper>` / `<Slide>` / `<ClientOnly>` /
|
|
134
|
+
`<GlobalTOC>` / `<HomeHero>` / `<ChatDemo>` get passive overrides so
|
|
135
|
+
React doesn't warn about unknown HTML tags. Children pass through where
|
|
136
|
+
reasonable (slides stack vertically); UI-component nulls render nothing.
|
|
137
|
+
- **Inline-styled `<img>` tags** — author-supplied `style` attributes
|
|
138
|
+
(typical for small social-media icons in author bios) are respected and
|
|
139
|
+
the image isn't pushed through `next/image` optimization.
|
|
140
|
+
|
|
141
|
+
## Re-running
|
|
142
|
+
|
|
143
|
+
Running the sync again against the same source/dest is the common case:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
bun run sync-vuepress-book --source ... --dest ...
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
It is **safe** and **idempotent** so long as you haven't hand-edited the
|
|
150
|
+
synced chapter `.md` files. The script:
|
|
151
|
+
|
|
152
|
+
- Overwrites every chapter file from source.
|
|
153
|
+
- Prunes importer-managed dest files whose path is not in the current source.
|
|
154
|
+
- Re-derives `chapters:` from the current sidebar.
|
|
155
|
+
- Preserves user-controlled `index.mdx` fields + body.
|
|
156
|
+
|
|
157
|
+
After re-running, run `bun run build:dev` to regenerate the image-optimization
|
|
158
|
+
output under `public/books/<slug>/` and the Pagefind search index.
|
|
159
|
+
|
|
160
|
+
## Troubleshooting
|
|
161
|
+
|
|
162
|
+
| Symptom | Likely cause | Fix |
|
|
163
|
+
| --- | --- | --- |
|
|
164
|
+
| `[amytis] No VuePress config found …` | Source isn't a VuePress 2 docs root | Pass the parent of `.vuepress/`, e.g. `<repo>/docs`, not the repo root. |
|
|
165
|
+
| `[amytis] Found config.ts …` error | TS config not supported | Compile to JS first, or rename to `.mjs` if pure ESM. |
|
|
166
|
+
| `[amytis] N sidebar leaf chapters point to source files that do not exist` | Sidebar entry has no matching `.md` | Fix the sidebar in the VuePress config or write the missing file. |
|
|
167
|
+
| `Could not locate a sidebar: [...] property` | Sidebar uses an unsupported shape | The walker only handles plain literal arrays/objects; a sidebar built by a function call won't work. Extract to a literal array. |
|
|
168
|
+
| Chapter page 404s after sync | Chapter file moved/renamed upstream, but the dest dir still has the old file | This shouldn't happen now (mirror prunes deletions); if it does, rerun the sync and clear `.next` / `public/books/<slug>`. |
|
|
169
|
+
| Stale image after upstream rename | Pagefind / Next image cache | `bun run clean && bun run build:dev`. |
|
|
170
|
+
|
|
171
|
+
## Related
|
|
172
|
+
|
|
173
|
+
- `scripts/sync-vuepress-book.ts` — the implementation.
|
|
174
|
+
- `docs/ARCHITECTURE.md` — book schema, route map, and the markdown
|
|
175
|
+
pipeline plugins listed above.
|
|
176
|
+
- `tests/integration/sync-vuepress-book.test.ts` — covers AST extraction,
|
|
177
|
+
mirror semantics, folder-index links, TS-config rejection, dotfile
|
|
178
|
+
preservation, and the `contents` skip.
|
package/eslint.config.mjs
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { defineConfig, globalIgnores } from "eslint/config";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import nextPlugin from "@next/eslint-plugin-next";
|
|
3
|
+
import reactHooksPlugin from "eslint-plugin-react-hooks";
|
|
4
|
+
import tseslint from "typescript-eslint";
|
|
4
5
|
|
|
5
6
|
const eslintConfig = defineConfig([
|
|
6
|
-
...nextVitals,
|
|
7
|
-
...nextTs,
|
|
8
|
-
// Override default ignores of eslint-config-next.
|
|
9
7
|
globalIgnores([
|
|
10
|
-
// Default ignores of eslint-config-next:
|
|
11
8
|
".next/**",
|
|
12
9
|
"out/**",
|
|
13
10
|
"build/**",
|
|
@@ -16,7 +13,24 @@ const eslintConfig = defineConfig([
|
|
|
16
13
|
"public/pagefind/**",
|
|
17
14
|
// Package compiled output — not authored code
|
|
18
15
|
"packages/*/dist/**",
|
|
16
|
+
// Local Python renderer virtualenv
|
|
17
|
+
".venv-rst/**",
|
|
19
18
|
]),
|
|
19
|
+
|
|
20
|
+
...tseslint.configs.recommended,
|
|
21
|
+
|
|
22
|
+
{
|
|
23
|
+
files: ["**/*.{js,jsx,mjs,ts,tsx,mts,cts}"],
|
|
24
|
+
plugins: {
|
|
25
|
+
"@next/next": nextPlugin,
|
|
26
|
+
"react-hooks": reactHooksPlugin,
|
|
27
|
+
},
|
|
28
|
+
rules: {
|
|
29
|
+
...nextPlugin.configs.recommended.rules,
|
|
30
|
+
...nextPlugin.configs["core-web-vitals"].rules,
|
|
31
|
+
...reactHooksPlugin.configs.recommended.rules,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
20
34
|
]);
|
|
21
35
|
|
|
22
36
|
export default eslintConfig;
|
package/next.config.ts
CHANGED
|
@@ -15,8 +15,8 @@ const nextConfig: NextConfig = {
|
|
|
15
15
|
output: "export",
|
|
16
16
|
images: {
|
|
17
17
|
loader: "custom",
|
|
18
|
-
imageSizes: [
|
|
19
|
-
deviceSizes: [640,
|
|
18
|
+
imageSizes: [64, 128, 256],
|
|
19
|
+
deviceSizes: [640, 1200, 1920],
|
|
20
20
|
},
|
|
21
21
|
transpilePackages: ["next-image-export-optimizer"],
|
|
22
22
|
env: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hutusi/amytis",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"description": "A high-performance digital garden and blog engine with Next.js 16 and Tailwind CSS v4",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,14 +11,18 @@
|
|
|
11
11
|
},
|
|
12
12
|
"homepage": "https://github.com/hutusi/amytis#readme",
|
|
13
13
|
"private": false,
|
|
14
|
-
"packageManager": "bun@1.3.
|
|
14
|
+
"packageManager": "bun@1.3.11",
|
|
15
15
|
"scripts": {
|
|
16
|
-
"dev": "next dev",
|
|
17
|
-
"build": "bun scripts/copy-assets.ts && bun run build:graph && next build && next-image-export-optimizer &&
|
|
18
|
-
"build:dev": "bun scripts/copy-assets.ts && bun run build:graph && next build &&
|
|
16
|
+
"dev": "bun scripts/run-with-rst-python.ts next dev",
|
|
17
|
+
"build": "bun scripts/copy-assets.ts && bun run build:graph && bun scripts/run-with-rst-python.ts next build && next-image-export-optimizer && bun run build:search",
|
|
18
|
+
"build:dev": "bun scripts/copy-assets.ts && bun run build:graph && bun scripts/run-with-rst-python.ts next build && bun run build:search:dev",
|
|
19
19
|
"build:graph": "NODE_ENV=production bun scripts/generate-knowledge-graph.ts",
|
|
20
|
+
"build:search": "bun scripts/build-pagefind.ts --site out --output-path out/pagefind",
|
|
21
|
+
"build:search:dev": "bun scripts/build-pagefind.ts --site out --output-path public/pagefind",
|
|
22
|
+
"build:search:cli": "pagefind --site out",
|
|
23
|
+
"build:search:cli:dev": "pagefind --site out --output-path public/pagefind",
|
|
20
24
|
"validate": "bun run lint && bun run test && bun run build:dev",
|
|
21
|
-
"clean": "rm -rf .next out public/posts public/books public/flows",
|
|
25
|
+
"clean": "rm -rf .next out public/posts public/books public/flows public/images/nextImageExportOptimizer",
|
|
22
26
|
"new": "bun scripts/new-post.ts",
|
|
23
27
|
"new-weekly": "bun scripts/new-post.ts --series ai-nexus-weekly --md --folder --prefix weekly",
|
|
24
28
|
"new-series": "bun scripts/new-series.ts",
|
|
@@ -30,6 +34,7 @@
|
|
|
30
34
|
"import-obsidian": "bun scripts/import-obsidian.ts",
|
|
31
35
|
"import-book": "bun scripts/import-book.ts",
|
|
32
36
|
"sync-book": "bun scripts/sync-book-chapters.ts",
|
|
37
|
+
"sync-vuepress-book": "bun scripts/sync-vuepress-book.ts",
|
|
33
38
|
"series-draft": "bun scripts/series-draft.ts",
|
|
34
39
|
"add-series-redirects": "bun scripts/add-series-redirects.ts",
|
|
35
40
|
"deploy": "bun scripts/deploy.ts",
|
|
@@ -43,52 +48,75 @@
|
|
|
43
48
|
},
|
|
44
49
|
"dependencies": {
|
|
45
50
|
"@giscus/react": "^3.1.0",
|
|
51
|
+
"@shikijs/transformers": "^4.1.0",
|
|
46
52
|
"@tailwindcss/typography": "^0.5.19",
|
|
47
53
|
"d3": "^7.9.0",
|
|
48
54
|
"github-slugger": "^2.0.0",
|
|
49
55
|
"gray-matter": "^4.0.3",
|
|
56
|
+
"hast-util-to-html": "^9.0.5",
|
|
50
57
|
"image-size": "^2.0.2",
|
|
51
|
-
"katex": "^0.16.
|
|
52
|
-
"mermaid": "^11.
|
|
53
|
-
"next": "16.2.
|
|
58
|
+
"katex": "^0.16.47",
|
|
59
|
+
"mermaid": "^11.15.0",
|
|
60
|
+
"next": "16.2.6",
|
|
54
61
|
"next-image-export-optimizer": "^1.20.1",
|
|
55
62
|
"next-themes": "^0.4.6",
|
|
56
|
-
"react": "19.2.
|
|
57
|
-
"react-dom": "19.2.
|
|
63
|
+
"react": "19.2.6",
|
|
64
|
+
"react-dom": "19.2.6",
|
|
58
65
|
"react-icons": "^5.6.0",
|
|
59
66
|
"react-markdown": "^10.1.0",
|
|
60
|
-
"react-syntax-highlighter": "^16.1.1",
|
|
61
67
|
"rehype-katex": "^7.0.1",
|
|
68
|
+
"rehype-parse": "^9.0.1",
|
|
62
69
|
"rehype-raw": "^7.0.0",
|
|
63
70
|
"rehype-slug": "^6.0.0",
|
|
64
71
|
"rehype-stringify": "^10.0.1",
|
|
72
|
+
"remark-directive": "^4.0.0",
|
|
65
73
|
"remark-gfm": "^4.0.1",
|
|
66
74
|
"remark-math": "^6.0.0",
|
|
67
75
|
"remark-parse": "^11.0.0",
|
|
68
76
|
"remark-rehype": "^11.1.2",
|
|
77
|
+
"sanitize-html": "^2.17.4",
|
|
78
|
+
"shiki": "^4.1.0",
|
|
69
79
|
"unified": "^11.0.5",
|
|
70
80
|
"unist-util-visit": "^5.1.0",
|
|
71
|
-
"zod": "^4.3
|
|
81
|
+
"zod": "^4.4.3"
|
|
72
82
|
},
|
|
73
83
|
"devDependencies": {
|
|
74
|
-
"@
|
|
75
|
-
"@
|
|
76
|
-
"@
|
|
84
|
+
"@iconify-json/logos": "^1.2.11",
|
|
85
|
+
"@iconify-json/vscode-icons": "^1.2.52",
|
|
86
|
+
"@next/eslint-plugin-next": "^16.2.6",
|
|
87
|
+
"@playwright/test": "^1.60.0",
|
|
88
|
+
"@tailwindcss/postcss": "^4.3.0",
|
|
89
|
+
"@types/bun": "^1.3.14",
|
|
77
90
|
"@types/d3": "^7.4.3",
|
|
78
91
|
"@types/hast": "^3.0.4",
|
|
79
92
|
"@types/image-size": "^0.8.0",
|
|
80
93
|
"@types/mdast": "^4.0.4",
|
|
81
|
-
"@types/node": "^
|
|
94
|
+
"@types/node": "^25.8.0",
|
|
82
95
|
"@types/react": "^19.2.14",
|
|
83
96
|
"@types/react-dom": "^19.2.3",
|
|
84
|
-
"@types/
|
|
97
|
+
"@types/sanitize-html": "^2.16.1",
|
|
98
|
+
"acorn": "^8.16.0",
|
|
85
99
|
"babel-plugin-react-compiler": "1.0.0",
|
|
86
|
-
"eslint": "^
|
|
87
|
-
"eslint-
|
|
88
|
-
"pagefind": "^1.
|
|
89
|
-
"pdf-to-img": "^
|
|
90
|
-
"tailwindcss": "^4.
|
|
91
|
-
"typescript": "^
|
|
100
|
+
"eslint": "^10.4.0",
|
|
101
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
102
|
+
"pagefind": "^1.5.2",
|
|
103
|
+
"pdf-to-img": "^6.1.0",
|
|
104
|
+
"tailwindcss": "^4.3.0",
|
|
105
|
+
"typescript": "^6.0.3",
|
|
106
|
+
"typescript-eslint": "^8.59.3"
|
|
107
|
+
},
|
|
108
|
+
"overrides": {
|
|
109
|
+
"@typescript-eslint/eslint-plugin": "^8.59.3",
|
|
110
|
+
"@typescript-eslint/parser": "^8.59.3",
|
|
111
|
+
"@typescript-eslint/project-service": "^8.59.3",
|
|
112
|
+
"@typescript-eslint/scope-manager": "^8.59.3",
|
|
113
|
+
"@typescript-eslint/tsconfig-utils": "^8.59.3",
|
|
114
|
+
"@typescript-eslint/type-utils": "^8.59.3",
|
|
115
|
+
"@typescript-eslint/types": "^8.59.3",
|
|
116
|
+
"@typescript-eslint/typescript-estree": "^8.59.3",
|
|
117
|
+
"@typescript-eslint/utils": "^8.59.3",
|
|
118
|
+
"@typescript-eslint/visitor-keys": "^8.59.3",
|
|
119
|
+
"typescript-eslint": "^8.59.3"
|
|
92
120
|
},
|
|
93
121
|
"ignoreScripts": [
|
|
94
122
|
"sharp",
|
|
@@ -2,7 +2,7 @@ import { describe, test, expect, afterAll } from "bun:test";
|
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as os from "os";
|
|
4
4
|
import * as path from "path";
|
|
5
|
-
import { patchSiteConfig, patchPackageJson } from "./index";
|
|
5
|
+
import { buildExtractCommand, getArchiveMetadata, patchSiteConfig, patchPackageJson } from "./index";
|
|
6
6
|
|
|
7
7
|
// Minimal site.config.ts that mirrors the real file's patchable fields.
|
|
8
8
|
// Inner backticks and `${` are escaped so they appear literally in the string.
|
|
@@ -185,3 +185,45 @@ describe("patchPackageJson", () => {
|
|
|
185
185
|
expect(() => patchPackageJson(dir, "my-garden")).not.toThrow();
|
|
186
186
|
});
|
|
187
187
|
});
|
|
188
|
+
|
|
189
|
+
describe("getArchiveMetadata", () => {
|
|
190
|
+
test("uses zip archives on Windows", () => {
|
|
191
|
+
const archive = getArchiveMetadata("v1.13.0", "win32");
|
|
192
|
+
expect(archive.kind).toBe("zip");
|
|
193
|
+
expect(archive.filename).toBe("amytis-v1.13.0.zip");
|
|
194
|
+
expect(archive.url).toBe("https://github.com/hutusi/amytis/archive/refs/tags/v1.13.0.zip");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("uses tar.gz archives on non-Windows platforms", () => {
|
|
198
|
+
const archive = getArchiveMetadata("v1.13.0", "darwin");
|
|
199
|
+
expect(archive.kind).toBe("tar.gz");
|
|
200
|
+
expect(archive.filename).toBe("amytis-v1.13.0.tar.gz");
|
|
201
|
+
expect(archive.url).toBe("https://github.com/hutusi/amytis/archive/refs/tags/v1.13.0.tar.gz");
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe("buildExtractCommand", () => {
|
|
206
|
+
test("builds the PowerShell Expand-Archive command on Windows", () => {
|
|
207
|
+
const command = buildExtractCommand("C:\\tmp\\amytis-v1.13.0.zip", "C:\\tmp\\my-garden.__tmp__", "zip", "win32");
|
|
208
|
+
expect(command.command).toBe("powershell.exe");
|
|
209
|
+
expect(command.args).toEqual([
|
|
210
|
+
"-NoProfile",
|
|
211
|
+
"-NonInteractive",
|
|
212
|
+
"-ExecutionPolicy",
|
|
213
|
+
"Bypass",
|
|
214
|
+
"-Command",
|
|
215
|
+
"Expand-Archive",
|
|
216
|
+
"-LiteralPath",
|
|
217
|
+
"C:\\tmp\\amytis-v1.13.0.zip",
|
|
218
|
+
"-DestinationPath",
|
|
219
|
+
"C:\\tmp\\my-garden.__tmp__",
|
|
220
|
+
"-Force",
|
|
221
|
+
]);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("builds the tar extraction command on non-Windows platforms", () => {
|
|
225
|
+
const command = buildExtractCommand("/tmp/amytis-v1.13.0.tar.gz", "/tmp/my-garden.__tmp__", "tar.gz", "darwin");
|
|
226
|
+
expect(command.command).toBe("tar");
|
|
227
|
+
expect(command.args).toEqual(["xzf", "/tmp/amytis-v1.13.0.tar.gz", "-C", "/tmp/my-garden.__tmp__"]);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
@@ -4,7 +4,7 @@ import * as fs from "fs";
|
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
import * as https from "https";
|
|
6
6
|
import * as readline from "readline";
|
|
7
|
-
import { execSync } from "child_process";
|
|
7
|
+
import { execFileSync, execSync } from "child_process";
|
|
8
8
|
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
10
|
// Helpers
|
|
@@ -77,11 +77,67 @@ function downloadFile(url: string, dest: string): Promise<void> {
|
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
function
|
|
80
|
+
export function getArchiveMetadata(tag: string, platform: NodeJS.Platform = process.platform): {
|
|
81
|
+
url: string;
|
|
82
|
+
filename: string;
|
|
83
|
+
kind: "zip" | "tar.gz";
|
|
84
|
+
} {
|
|
85
|
+
if (platform === "win32") {
|
|
86
|
+
return {
|
|
87
|
+
url: `https://github.com/hutusi/amytis/archive/refs/tags/${tag}.zip`,
|
|
88
|
+
filename: `amytis-${tag}.zip`,
|
|
89
|
+
kind: "zip",
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
url: `https://github.com/hutusi/amytis/archive/refs/tags/${tag}.tar.gz`,
|
|
95
|
+
filename: `amytis-${tag}.tar.gz`,
|
|
96
|
+
kind: "tar.gz",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function buildExtractCommand(
|
|
101
|
+
archivePath: string,
|
|
102
|
+
tmpDir: string,
|
|
103
|
+
kind: "zip" | "tar.gz",
|
|
104
|
+
platform: NodeJS.Platform = process.platform,
|
|
105
|
+
): { command: string; args: string[] } {
|
|
106
|
+
if (kind === "zip") {
|
|
107
|
+
if (platform !== "win32") {
|
|
108
|
+
throw new Error("ZIP extraction is only supported on Windows in create-amytis");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
command: "powershell.exe",
|
|
113
|
+
args: [
|
|
114
|
+
"-NoProfile",
|
|
115
|
+
"-NonInteractive",
|
|
116
|
+
"-ExecutionPolicy",
|
|
117
|
+
"Bypass",
|
|
118
|
+
"-Command",
|
|
119
|
+
"Expand-Archive",
|
|
120
|
+
"-LiteralPath",
|
|
121
|
+
archivePath,
|
|
122
|
+
"-DestinationPath",
|
|
123
|
+
tmpDir,
|
|
124
|
+
"-Force",
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
command: "tar",
|
|
131
|
+
args: ["xzf", archivePath, "-C", tmpDir],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function extractArchive(archivePath: string, outDir: string, kind: "zip" | "tar.gz", platform: NodeJS.Platform = process.platform): void {
|
|
81
136
|
// Extract into a temp dir, then move the inner folder out
|
|
82
137
|
const tmpDir = `${outDir}.__tmp__`;
|
|
83
138
|
fs.mkdirSync(tmpDir, { recursive: true });
|
|
84
|
-
|
|
139
|
+
const { command, args } = buildExtractCommand(archivePath, tmpDir, kind, platform);
|
|
140
|
+
execFileSync(command, args, { stdio: "inherit" });
|
|
85
141
|
|
|
86
142
|
// The tarball unpacks to a single top-level dir like "amytis-1.2.0/"
|
|
87
143
|
const entries = fs.readdirSync(tmpDir);
|
|
@@ -91,7 +147,7 @@ function extractTarball(tarPath: string, outDir: string): void {
|
|
|
91
147
|
const innerDir = path.join(tmpDir, entries[0]);
|
|
92
148
|
fs.renameSync(innerDir, outDir);
|
|
93
149
|
fs.rmdirSync(tmpDir);
|
|
94
|
-
fs.unlinkSync(
|
|
150
|
+
fs.unlinkSync(archivePath);
|
|
95
151
|
}
|
|
96
152
|
|
|
97
153
|
// ---------------------------------------------------------------------------
|
|
@@ -180,14 +236,14 @@ async function main(): Promise<void> {
|
|
|
180
236
|
console.log(` Found: ${tag}`);
|
|
181
237
|
|
|
182
238
|
// 3. Download tarball
|
|
183
|
-
const
|
|
184
|
-
const
|
|
239
|
+
const archive = getArchiveMetadata(tag);
|
|
240
|
+
const archiveDest = path.join(process.cwd(), archive.filename);
|
|
185
241
|
console.log("Downloading tarball...");
|
|
186
|
-
await downloadFile(
|
|
242
|
+
await downloadFile(archive.url, archiveDest);
|
|
187
243
|
|
|
188
244
|
// 4. Extract
|
|
189
245
|
console.log("Extracting...");
|
|
190
|
-
|
|
246
|
+
extractArchive(archiveDest, targetDir, archive.kind);
|
|
191
247
|
console.log(` Scaffolded: ${targetDir}`);
|
|
192
248
|
|
|
193
249
|
// 5-6. Prompt for site metadata
|
|
@@ -1,75 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"books/agentic-design-patterns/images/chapter-12/image1.png": "4e4AD2MJFSB3GByGxGVr4VCQ4H+eYkR3oq39KuZhzw8=",
|
|
17
|
-
"books/agentic-design-patterns/images/chapter-12/image2.png": "1MyjXYovLBeKJmUGnUnx38T-UgkhRfV5opzOcP+OEdw=",
|
|
18
|
-
"books/agentic-design-patterns/images/chapter-13/image1.png": "PB3msIGhOmq1Oyrv6ubGJZJCvO+dD7XNxZiw5Ck-834=",
|
|
19
|
-
"books/agentic-design-patterns/images/chapter-14/image1.png": "p-06-D2Vp2x7HMXwmkTNLneS9sjsfSvmTsLTlVUjY5k=",
|
|
20
|
-
"books/agentic-design-patterns/images/chapter-14/image2.png": "XvXKYbuijYChfq4+MlZYXLBpxTg11ddJ0AFnzvntLPw=",
|
|
21
|
-
"books/agentic-design-patterns/images/chapter-14/image3.png": "YhmOWyJo3pDKVbKW7RMgTbNrbmsE89RkmaJ2z76vhos=",
|
|
22
|
-
"books/agentic-design-patterns/images/chapter-14/image4.png": "QBNe+Wt65qdLfkC5MJqaiNBJGMa-DbCm3gCOqfB7ehk=",
|
|
23
|
-
"books/agentic-design-patterns/images/chapter-15/image1.png": "I90CSqCb8g-h1F0a3sDusDC+LmHdjJTBBk6iFw4ZnJY=",
|
|
24
|
-
"books/agentic-design-patterns/images/chapter-15/image2.png": "HaxOSZ1f67BhEPa3KXtYAlK0cNm3G4H24dnLXpcgyA0=",
|
|
25
|
-
"books/agentic-design-patterns/images/chapter-16/image1.png": "Blc0vDhlie6PM3f6QSUX3argbfezTNDOLYhmT9uuS6E=",
|
|
26
|
-
"books/agentic-design-patterns/images/chapter-16/image2.png": "9-KZ0VOekDwFVL1dEzB9aleyCYF+WU6bx1h3aVNoOAM=",
|
|
27
|
-
"books/agentic-design-patterns/images/chapter-17/image1.png": "jjGM2Ll5bdszl9xFThVxxJzcq76iYDM1zz8qq2MVVYE=",
|
|
28
|
-
"books/agentic-design-patterns/images/chapter-17/image2.png": "O1KLKrodQew2Pdd7k3vBZhE4dCiK9u6JLvXSXy7h1do=",
|
|
29
|
-
"books/agentic-design-patterns/images/chapter-17/image3.png": "Sd9qFn-U5g8dhinNPJEk5LaeaN8DFH2FCus1Wcm6oSg=",
|
|
30
|
-
"books/agentic-design-patterns/images/chapter-17/image4.png": "eV38Dg78Y2Qo-0sqlsvcK8-p19fgRJqwx42sBKTzC+s=",
|
|
31
|
-
"books/agentic-design-patterns/images/chapter-17/image5.png": "bgKPC1TSVlvfkCG5vILT-4j9gJU7LyeGFkXO+8OFdXE=",
|
|
32
|
-
"books/agentic-design-patterns/images/chapter-17/image6.png": "qMku-C8gxZEFQEl8Qq8Y1ld5zUntH1Q-2izcb4QxLA0=",
|
|
33
|
-
"books/agentic-design-patterns/images/chapter-17/image7.png": "20wopLVN59okB+C-F+U5vi79Lg0uH+5P6wIj72gV7wU=",
|
|
34
|
-
"books/agentic-design-patterns/images/chapter-18/image1.png": "kjCIoNU60icXMOHmYNXWNMjdi5nIdJZYDSp0WFnG2Es=",
|
|
35
|
-
"books/agentic-design-patterns/images/chapter-19/image1.png": "XrQVFAWWsMcwKHgcqx8jGLy4q+6RbiGZ5CuKpRlk4Y0=",
|
|
36
|
-
"books/agentic-design-patterns/images/chapter-19/image2.png": "URHY+cH5AR4KvA6HPnXPhZd5fwwGdlwvFvxgCdTkWjg=",
|
|
37
|
-
"books/agentic-design-patterns/images/chapter-19/image3.png": "VLp1qFNcaj126-RuATV6ikSsow8lrXsn3EuZotvR5N4=",
|
|
38
|
-
"books/agentic-design-patterns/images/chapter-19/image4.png": "CnyNMtPiFSdzqrewwLgPu2X1CKdgMqCl8T8+d7lw2Fw=",
|
|
39
|
-
"books/agentic-design-patterns/images/chapter-2/image1.png": "C6odPDB9zhN28YxfU909JAoQWe0mRm3lUsyG8NzHBWk=",
|
|
40
|
-
"books/agentic-design-patterns/images/chapter-20/image1.png": "qkzjKCUjVFD8IWyoZQXuBuZ4zFJ0Y0CQfKepVcrnEN0=",
|
|
41
|
-
"books/agentic-design-patterns/images/chapter-21/image1.png": "3KpW6uLQDru7DFDdgi6ntD5WhuGS383aYwlQLWoVX+w=",
|
|
42
|
-
"books/agentic-design-patterns/images/chapter-21/image2.png": "wSXMrRuAnhQcEM5fg-sJ5ZikM3olj0vz6FDKWKIUyW8=",
|
|
43
|
-
"books/agentic-design-patterns/images/chapter-3/image1.png": "iHnUE2kckwzB0xiIySSe4O34c6bIs3VlO7pUQBmV8iI=",
|
|
44
|
-
"books/agentic-design-patterns/images/chapter-3/image2.png": "9-G6F+aBymQVTnDQy4zwsXDZMkLaYKBe4xw26tC24R8=",
|
|
45
|
-
"books/agentic-design-patterns/images/chapter-4/image1.png": "8h0PBlqt+JFo7Y803cA9MgfTe8TZeZd6te9l+WEsIss=",
|
|
46
|
-
"books/agentic-design-patterns/images/chapter-4/image2.png": "p-arzpUPFdnKmzTOKaDQys5Eml0jHA7VuUV0FyLYpqM=",
|
|
47
|
-
"books/agentic-design-patterns/images/chapter-5/image1.png": "XE5qhAklrW-7eVf7T9x9vo4xQX3WesZjZ9IjuyeSUkc=",
|
|
48
|
-
"books/agentic-design-patterns/images/chapter-5/image2.png": "MqUdsG5aXQECft+lsCRTeMIJP-YzxWFHC8HdNzio6aw=",
|
|
49
|
-
"books/agentic-design-patterns/images/chapter-6/image1.png": "t6mFrbVSNJYF73t+Q+YydXdwRQr1c4yIUkySvCelw1I=",
|
|
50
|
-
"books/agentic-design-patterns/images/chapter-6/image2.png": "zvwqWis6Ad7Iv1-wgYtTgz2ItXsno2PetcHRHon0-wY=",
|
|
51
|
-
"books/agentic-design-patterns/images/chapter-6/image3.png": "al-H2S7UznxQzP3KT3N0lCTNd83B45bqbPppuhSphy0=",
|
|
52
|
-
"books/agentic-design-patterns/images/chapter-6/image4.png": "u2k2jHjTOABLTlJ3OsxkGyCoOR-fwHeDmTXMACbtQ+4=",
|
|
53
|
-
"books/agentic-design-patterns/images/chapter-7/image1.png": "izX9YjrJ+gHGOiR9RHbuMIupCE2zyB01w-gwJAJr4Is=",
|
|
54
|
-
"books/agentic-design-patterns/images/chapter-7/image2.png": "-0zrZR8CNZqtuyaBRwUbZSfthKwuqrBu4fLar9L4Clg=",
|
|
55
|
-
"books/agentic-design-patterns/images/chapter-7/image3.png": "dKr7VICWOTc-ZRhm4Aaokz+xPZ8IXS0SiDOJeF1Y03c=",
|
|
56
|
-
"books/agentic-design-patterns/images/chapter-8/image1.png": "GWG47Om+9GwRvl8x-X269Sa-Mv3rqkW2xkx1WIB-I-E=",
|
|
57
|
-
"books/agentic-design-patterns/images/chapter-9/image1.png": "fIZ4QE7EIQSAv0K2GmU99OmTBAkpvnYUsFFScCv6VPI=",
|
|
58
|
-
"books/agentic-design-patterns/images/chapter-9/image2.png": "6y-8OjY7oEedk5ZhUUU2YIU3tjMxIzpnxcDxIRWPGpI=",
|
|
59
|
-
"books/agentic-design-patterns/images/chapter-9/image3.png": "69nSkOOPfX9FkIJGhKIrhSuCOZt29L5UAukVXfMXN2E=",
|
|
60
|
-
"books/agentic-design-patterns/images/chapter-9/image4.png": "GQCpjBMz5DRxsHIA8-73IMsxeBPc5ZTMaIsx2iihMME=",
|
|
61
|
-
"books/agentic-design-patterns/images/cover.png": "R47dqw-ws79m6VBfzhWuLi9ihoCaU7JcezquBAB1-bQ=",
|
|
62
|
-
"images/amytis-screenshot.jpg": "t9tzciqJPsNz1hlixAFLrrvD4Fsaih2Kbd1Jd2C-fqs=",
|
|
63
|
-
"images/antelope-canyon.jpg": "xuP3HlbwqA4z1Hsq7s1u2u61yN3SHzIMUd6Wl5yqgK8=",
|
|
64
|
-
"images/avatar.jpg": "SUGxOhDUD96YiVxZJkVJ6ou4W5MdCJ9hTBQMSQanZOM=",
|
|
65
|
-
"images/cappadocia.jpg": "EE2Mt8d9ERKd40SfwyhjFsejZLhFx1SfSAQmlu+TQOo=",
|
|
66
|
-
"images/flowers.jpg": "Lq9dhpZvAIgkYnijDsFIzrKiv8trdM-cUnl-5Y86PuM=",
|
|
67
|
-
"images/galaxy.jpg": "-3YwMkU3PGsm4P2yNsA2S02XRL1j0KbBh6nWKwy0hYc=",
|
|
68
|
-
"images/lake.jpg": "imAORQhxpmoU3jzKBMNFJuFSa0UgiSf2Dmea5Rj8-8M=",
|
|
69
|
-
"images/mountains.jpg": "FsrkZws9EKMqHCk1Hc6i6nEIcTRcrMBa4ddgqR6oRaI=",
|
|
70
|
-
"images/screenshot.png": "FAqbAgLRbWbYq9yJ4iggq2aKxRD8hdeDICc3DI14yhg=",
|
|
71
|
-
"images/vibrant-waves.jpg": "vdBm72ev5ETPM5H2CDK6tqph5t8N5nTCSApBJp2lW6U=",
|
|
72
|
-
"images/wechat-qr.jpg": "DNIzz0Wcl8WP0h-jHHgZ9LEvf3ZKOXHgxlvpw3gK2ME=",
|
|
73
|
-
"posts/02-routing-mastery/assets/m-p-model.png": "fDmvlEkZnE-UCvPK4gmDkJD7SU8coOTl4iw5hpsmcWI=",
|
|
74
|
-
"posts/images/vibrant-waves.jpg": "YogfFJOm4PQV1g3iMRpCL1pKtjPXpMeJDFf6NTILcBQ="
|
|
2
|
+
"images/amytis-screenshot.jpg": "rWj-Nh3prlVpvj8efQnsSHJTSOOVzgz9PGnQRj98jXc=",
|
|
3
|
+
"images/antelope-canyon.jpg": "sub7CbOTPj1Vred2Ow9yJKMqjbP9+0nkjmmaaa5Di2k=",
|
|
4
|
+
"images/avatar.jpg": "4c7EI6nQ6UHOj9drx0D42heSmiYWTt0Gd3Nsri3BQeo=",
|
|
5
|
+
"images/cappadocia.jpg": "eDzJe+p3qkAP83ATa7x0m0od4LxwkZltWsVQ2s9rgDI=",
|
|
6
|
+
"images/flowers.jpg": "oxwbVQa8o5AcEu-vRbHj9o64BTZwCFxPOSA7D53n7tI=",
|
|
7
|
+
"images/galaxy.jpg": "yDGttkksBSUhLDWlVL2BFGg1al1+GHy3BXcEVp07bys=",
|
|
8
|
+
"images/lake.jpg": "NEaTNMMXdrgHLMU7CDEWEVwguVdv1E4y5FN8CMHqTvg=",
|
|
9
|
+
"images/mountains.jpg": "0YIE1wGkreZ1MzM8zGnXCQ9I-IcmA+zO52-dtfL4X94=",
|
|
10
|
+
"images/screenshot.png": "zuBVQ-P-dCmcM9tYPdDvixwAHo7rGTZQE1y+X4o2pJ4=",
|
|
11
|
+
"images/vibrant-waves.jpg": "uWywQzN1RbusnZFato8mb7pqvCUkAr4us50HU6rFYUg=",
|
|
12
|
+
"images/wechat-qr.jpg": "Vhxz8S8TDfXZUjB3M5o5jvis3hu2n8xJEdW3bPjtd+A=",
|
|
13
|
+
"posts/02-routing-mastery/assets/m-p-model.png": "LZQHFy9SfWdBHatT9DwrARlD1sRqLT2blB573YyTv-U=",
|
|
14
|
+
"posts/images/vibrant-waves.jpg": "J+C7EolOmfP3fHl-22UoIx-h0hImPk9iEhL+66I60P4=",
|
|
15
|
+
"posts/welcome-to-amytis/images/vibrant-waves.jpg": "gAUaQXipxs2k7jJ6OoyIJ1+hj9HjM5QeuUuWTQoByps="
|
|
75
16
|
}
|