Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions .github/scripts/manifests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Demo Manifests

Builds one searchable **Demo Manifest** per demo, so the JointJS MCP
demo search ranks catalog entries (title, summary, keywords, packages)
instead of raw source chunks. Each manifest carries a section per
**Variant**. Vocabulary (Manifest, Variant, Demo Snapshot, Edition)
follows `CONTEXT.md` in the
[joint-mcp](https://github.com/clientIO/joint-mcp) repo; the spec is
joint-mcp issue #27 (v3 layout: #39).

## Usage

```bash
# from the repo root
npm run manifests:build -- --version 4.3 # write .manifests/
npm run manifests:test # golden-fixture + unit tests
```

`--version` is required: this repo is unversioned, so the value labels the
Demo Snapshot the manifests describe (the JointJS version the demos target).
Manifests exist from snapshot 4.3 forward.

## Output

```
.manifests/
manifests/
version-4.3/
<demo>.md # one Manifest per demo, YAML frontmatter + per-variant sections
manifests-index/
version-4.3.json # slim runtime index: bare array of { demo, variant_dir, variant }
```

One Manifest per demo, flat under `manifests/version-X.Y/`. Frontmatter is
`demo`, `version`, `edition`, `title`. A shared header (title + summary,
**Edition**, curated **Keywords**) precedes one `## Variant: <dir>` section
per variant, each carrying a `demo_id` / `**Packages:**` / `**Uses:**` block
followed by its `### Source files`. `demo_id`
(`version-X.Y/<demo>/<variant_dir>`) matches the R2 `versioned_demos/`
layout, so `get_demo_code` resolves it unchanged.

The `manifests-index/version-X.Y.json` is a bare array of
`{ demo, variant_dir, variant }` (canonical `variant`: `react-ts` →
`react`, `vue-ts` → `vue`) in generation order — the worker's framework
pre-filter source. It is deliberately kept **outside** the `manifests/`
prefix so the AutoRAG index never chunks it as searchable noise.

Rules of thumb:

- **Title & summary** come from the **demo-root `README.md` only**; variant
READMEs are no longer parsed (they still appear under Source files). A demo
with no root README is skipped entirely (`:: Skipping <demo> (no root
README.md)`) — no manifest, no index entries.
- **Keywords** come solely from `demo-keywords.json` at the repo root, keyed
by demo name (shared across variants). Authoring rule: keywords are the
*synonym/expansion channel* — terms an agent might search for that the
title and summary do **not** already contain. Prefer the established
jointjs.com/demos vocabulary (application categories such as
"Project management", "Data modeling"; feature tags such as "Drag & Drop",
"Automatic layout"); free terms (diagram-type synonyms like "swimlane",
"ERD") are allowed. Casing and order are preserved as authored. A demo
missing from the overlay gets a build warning and no Keywords line; a
keyword containing a comma is warned about and skipped (the body line is
comma-joined).
- **Uses** lists collapsed runtime Joint API surfaces extracted from imports
of Joint packages: named imports directly (`GraphProvider`), namespace
bindings resolved through member access and collapsed after the first
capitalized segment (`ui.Stencil`, `shapes.standard.Rectangle`,
`dia.Paper.Options` → `dia.Paper`). Aliased imports are recorded under
their original names, star imports without their local prefix;
imported-but-unused bindings and the `jsx`/`env` tooling bindings are
dropped.
- **Source files** is a curated view for orientation, not the full
inventory (`get_demo_code` lists the real files live): lockfiles
(`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`) and binary assets
(png, jpg, jpeg, gif, ico, woff, woff2, ttf, eot, mp3, mp4) are excluded;
`.svg` and config files are kept deliberately.
- **Packages** come from the variant's `package.json` `dependencies`
(`@joint/*`, `jointjs`, `rappid`, `@clientio/rappid`). **Edition** is
shared across the demo: `commercial` when any variant depends on
`@joint/plus` or `@joint/react-plus` (or `rappid`/`@clientio/rappid`);
demos with no joint dependency (CDN-loaded) fall back to a `JointJS+`
title check.
- **Imperative-react advisory.** A `react` variant whose packages include no
`@joint/react*` package gets a single advisory line after its
`**Packages:**` line, steering agents to `get_started(framework="react")`
and `@joint/react` (or `@joint/react-plus` under a JointJS+ license).
- Every variant directory with a `package.json` gets a section —
`demos.config.json` `skip` flags are build-only and not honored here.

## R2 destination

Manifests are uploaded (by the sync step, joint-mcp#30) to the demos bucket
under two top-level prefixes, siblings of the demo source:

```
versioned_demos/version-4.3/<demo>/<variant>/… # demo source (existing)
manifests/version-4.3/<demo>.md # search documents (this script)
manifests-index/version-4.3.json # framework pre-filter index (this script)
```

The upload is scripted: `npm run sync -- --version X.Y` (dev bucket) /
`npm run sync:prod -- --version X.Y` (prod) syncs all three prefixes —
see `.github/scripts/sync.mjs`. It is sync-only and fails preflight
unless this script's build output for that version exists.

The AutoRAG demos index points at `manifests/` only; the slim
`manifests-index/` sits outside it and `get_demo_code` keeps reading full
source from `versioned_demos/`.
43 changes: 43 additions & 0 deletions .github/scripts/manifests/build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env node

// Builds Demo Manifests into .manifests/: one markdown Manifest per demo at
// manifests/version-X.Y/{demo}.md plus a slim index at
// manifests-index/version-X.Y.json, ready to upload to the demos R2 bucket
// under the matching prefixes — see README.md here.
//
// Usage: npm run manifests:build -- --version 4.3

import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
import { dirname, join, resolve } from 'node:path';
import { parseArgs } from 'node:util';
import { generateManifests } from './generate.mjs';

const USAGE = 'Usage: npm run manifests:build -- --version X.Y (e.g. 4.3)';

let values = {};
try {
({ values } = parseArgs({ options: { version: { type: 'string' } } }));
} catch {
console.warn(USAGE);
process.exit(1);
}
if (!values.version || !/^\d+\.\d+$/.test(values.version)) {
console.warn(USAGE);
process.exit(1);
}

const ROOT = resolve(import.meta.dirname, '..', '..', '..');
const OUT_DIR = join(ROOT, '.manifests');

rmSync(OUT_DIR, { recursive: true, force: true });
const outputs = generateManifests(ROOT, values.version);
for (const [relPath, content] of outputs) {
const destination = join(OUT_DIR, relPath);
mkdirSync(dirname(destination), { recursive: true });
writeFileSync(destination, content);
}
const demoCount = [...outputs.keys()].filter((key) => key.startsWith('manifests/version-')).length;
const variantCount = JSON.parse(outputs.get(`manifests-index/version-${values.version}.json`)).length;
console.log(
`Wrote ${outputs.size} files to .manifests/ (${demoCount} demos, ${variantCount} variants, Demo Snapshot version ${values.version})`,
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[
{
"demo": "flow-tool",
"variant_dir": "ts",
"variant": "ts"
},
{
"demo": "flow-tool",
"variant_dir": "vue-ts",
"variant": "vue"
},
{
"demo": "legacy-embed",
"variant_dir": "js",
"variant": "js"
},
{
"demo": "widget-board",
"variant_dir": "js",
"variant": "js"
},
{
"demo": "widget-board",
"variant_dir": "react-js",
"variant": "react"
},
{
"demo": "widget-board",
"variant_dir": "react-ts",
"variant": "react"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
demo: "flow-tool"
version: "9.9"
edition: "open-source"
title: "Flow Tool"
---

# Flow Tool

Flow Tool is an open-source JointJS demo showing a minimal process editor.

**Edition:** open-source

**Keywords:** Process modeling, Automatic layout, swimlane

## Variant: ts

**demo_id:** version-9.9/flow-tool/ts
**Packages:** @joint/core
**Uses:** dia.Paper, shapes.standard.Rectangle

### Source files

- README.md
- package.json
- src/main.ts

## Variant: vue-ts

**demo_id:** version-9.9/flow-tool/vue-ts
**Packages:** @joint/core
**Uses:** dia.Graph, shapes.standard.Rectangle

### Source files

- README.md
- package.json
- src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
demo: "legacy-embed"
version: "9.9"
edition: "commercial"
title: "JointJS+: Legacy Embed"
---

# JointJS+: Legacy Embed

Legacy Embed loads JointJS+ from a CDN bundle, so its package.json declares no Joint dependency.

**Edition:** commercial

## Variant: js

**demo_id:** version-9.9/legacy-embed/js
**Packages:** none
**Uses:** none

### Source files

- index.html
- package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
demo: "widget-board"
version: "9.9"
edition: "commercial"
title: "JointJS+: Widget Board"
---

# JointJS+: Widget Board

The Widget Board demo lets users arrange dashboard widgets on a grid and connect them with links.

**Edition:** commercial

**Keywords:** Dashboard, Drag & Drop, widget grid

## Variant: js

**demo_id:** version-9.9/widget-board/js
**Packages:** @joint/plus
**Uses:** dia.Graph, dia.Paper, highlighters.addClass, ui.Stencil

### Source files

- index.html
- package.json
- src/index.js

## Variant: react-js

**demo_id:** version-9.9/widget-board/react-js
**Packages:** @joint/plus
⚠ **API note:** this variant uses the imperative `@joint/plus` API inside React, not the declarative React package. For new React apps call `get_started(framework="react")` and prefer `@joint/react` — or `@joint/react-plus` if the project has a JointJS+ license (this demo relies on JointJS+ features). Adapt this demo's ideas, not its integration pattern.
**Uses:** dia.Paper

### Source files

- package.json
- src/App.jsx

## Variant: react-ts

**demo_id:** version-9.9/widget-board/react-ts
**Packages:** @joint/react-plus
**Uses:** GraphProvider, Paper

### Source files

- package.json
- src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"flow-tool": ["Process modeling", "Automatic layout", "flowchart, diagram", "swimlane"],
"widget-board": ["Dashboard", "Drag & Drop", "widget grid"]
}
17 changes: 17 additions & 0 deletions .github/scripts/manifests/fixtures/sample-repo/flow-tool/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Flow Tool

Flow Tool is an open-source JointJS demo showing a minimal process editor.

<a href="https://stackblitz.com/github/clientio/joint-demos/tree/main/flow-tool/ts">
<img
alt="Open in StackBlitz"
src="https://developer.stackblitz.com/img/open_in_stackblitz.svg"
/>
</a>

This demo is also available online at [jointjs.com](https://jointjs.com/demos/flow-tool).

## Available Versions

- [TypeScript](./ts/)
- [Vue](./vue-ts/)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Flow Tool (TypeScript)

Flow Tool is an open-source JointJS demo showing a minimal process editor.

<a href="https://stackblitz.com/github/clientio/joint-demos/tree/main/flow-tool/ts">
<img
alt="Open in StackBlitz"
src="https://developer.stackblitz.com/img/open_in_stackblitz.svg"
/>
</a>

## What this demo shows

- **Custom shapes** — rectangles with ports
- **Link routing** — orthogonal links between ports
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "flow-tool-ts",
"private": true,
"dependencies": {
"@joint/core": "4.3.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as joint from '@joint/core';

const options: joint.dia.Paper.Options = { gridSize: 10 };
const paper = new joint.dia.Paper(options);
const rect = new joint.shapes.standard.Rectangle();
paper.model.addCell(rect);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Flow Tool (Vue)

Flow Tool is an open-source JointJS demo showing a minimal process editor, built with Vue.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "flow-tool-vue",
"private": true,
"dependencies": {
"@joint/core": "4.3.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { dia, shapes as defaultShapes } from '@joint/core';

const graph = new dia.Graph();
const rect = new defaultShapes.standard.Rectangle();
graph.addCell(rect);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# JointJS+: Legacy Embed

Legacy Embed loads JointJS+ from a CDN bundle, so its package.json declares no Joint dependency.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<!DOCTYPE html>
<html><body><div id="paper"></div></body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "legacy-embed-js",
"private": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# JointJS+: Widget Board <a href="https://www.jointjs.com/jointjs-plus"><img src="../jointjs-plus-badge.svg" alt="JointJS+" width="123" align="right" /></a>

The Widget Board demo lets users arrange dashboard widgets on a grid and connect them with links.

This demo is also available online at [jointjs.com](https://jointjs.com/demos/widget-board).

## Available Versions

- [JavaScript](./js/)
- [React](./react-ts/)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<!DOCTYPE html>
<html><body><div id="paper"></div></body></html>
Loading