@surph_ai/cli 0.0.36 → 0.0.37
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/board/deploy.js +7 -2
- package/board/server.js +14 -17
- package/package.json +1 -1
- package/scaffold/board/AGENTS.md +18 -2
- package/scaffold/board/README.md +27 -12
- package/scaffold/board/board.json +1 -1
- package/scaffold/board/site/index.html +1 -1
- package/scaffold/index.js +9 -1
package/board/deploy.js
CHANGED
|
@@ -26,7 +26,9 @@ const ZIP_NAME = 'site.zip';
|
|
|
26
26
|
const RPC_URL = 'https://rpc.surph.ai';
|
|
27
27
|
// Unzips an uploaded archive in place on S3 (the `sync` action).
|
|
28
28
|
const SYNC_URL = 'https://e3lunom2hka3u6iiotrlzrcez40uwdnk.lambda-url.us-east-1.on.aws/';
|
|
29
|
-
|
|
29
|
+
// Also the board's host name (<slug>.surph-boards.com), so at most 63 characters.
|
|
30
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9-]{0,62}$/;
|
|
31
|
+
const PLACEHOLDER_SLUG = 'my-board';
|
|
30
32
|
|
|
31
33
|
// The board's site: site/ in its folder (boards/<slug>/site/ when live).
|
|
32
34
|
const SITE = path.join(ROOT, 'site');
|
|
@@ -139,7 +141,10 @@ const boardSlug = () => {
|
|
|
139
141
|
fail(`board.json isn't valid JSON: ${error.message}`);
|
|
140
142
|
}
|
|
141
143
|
const slug = typeof board?.slug === 'string' ? board.slug.trim() : '';
|
|
142
|
-
if (!SLUG_RE.test(slug)) fail('board.json needs a "slug": lowercase letters, digits and dashes (e.g. "
|
|
144
|
+
if (!SLUG_RE.test(slug)) fail('board.json needs a "slug": lowercase letters, digits and dashes, at most 63 characters (e.g. "breakledger").');
|
|
145
|
+
// The template's placeholder: publishing under it would overwrite whatever
|
|
146
|
+
// else was published as "my-board".
|
|
147
|
+
if (slug === PLACEHOLDER_SLUG) fail(`board.json's "slug" is still the placeholder "${PLACEHOLDER_SLUG}". Set it to this board's own slug (from its name, e.g. "breakledger"), then deploy.`);
|
|
143
148
|
return slug;
|
|
144
149
|
};
|
|
145
150
|
|
package/board/server.js
CHANGED
|
@@ -4,15 +4,17 @@
|
|
|
4
4
|
// http://localhost:4180 for Surph's dev mode (Settings → Developer → Run
|
|
5
5
|
// Surph as a local board). Node's built-ins only; needs Node.js 20 or later.
|
|
6
6
|
//
|
|
7
|
-
// The folder
|
|
8
|
-
//
|
|
9
|
-
//
|
|
7
|
+
// The folder holds board.json at the top and the board's pages and assets in
|
|
8
|
+
// site/. site/ is the server's base: http://localhost:4180/ is
|
|
9
|
+
// site/index.html. Only site/ and board.json are served — the project's own
|
|
10
|
+
// files (README.md, AGENTS.md, package.json…) aren't.
|
|
10
11
|
//
|
|
11
|
-
// GET /board.json The board
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// GET
|
|
15
|
-
//
|
|
12
|
+
// GET /board.json The board (board.json at the folder's top), with
|
|
13
|
+
// CORS so Surph (another address) can read it.
|
|
14
|
+
// Never cached, like everything here.
|
|
15
|
+
// GET /<file> The board's pages and assets, from site/ (/ is
|
|
16
|
+
// site/index.html).
|
|
17
|
+
// GET /__surph/assets The image files in site/assets/ (the icon picker).
|
|
16
18
|
// PUT /board.json Surph's Local board panel saving the board. Only
|
|
17
19
|
// from Surph's own addresses, only this one file,
|
|
18
20
|
// only a JSON object with a config.pages list.
|
|
@@ -76,16 +78,15 @@ const cors = (req) => {
|
|
|
76
78
|
return headers;
|
|
77
79
|
};
|
|
78
80
|
|
|
79
|
-
// The board's site: site/ in this folder (
|
|
81
|
+
// The board's site: site/ in this folder, served as the base (it becomes
|
|
82
|
+
// boards/<slug>/site/ when live).
|
|
80
83
|
const SITE = path.join(ROOT, 'site');
|
|
81
84
|
|
|
82
|
-
// A
|
|
83
|
-
//
|
|
85
|
+
// A path → its file inside site/, or null (no way out of it, no dot-files,
|
|
86
|
+
// no node_modules).
|
|
84
87
|
const inside = (urlPath) => {
|
|
85
88
|
let rel;
|
|
86
89
|
try { rel = decodeURIComponent(urlPath.split('?')[0]); } catch { return null; }
|
|
87
|
-
if (rel !== '/site' && !rel.startsWith('/site/')) return null;
|
|
88
|
-
rel = rel.slice('/site'.length) || '/';
|
|
89
90
|
if (rel.endsWith('/')) rel += 'index.html';
|
|
90
91
|
const full = path.normalize(path.join(SITE, rel));
|
|
91
92
|
if (!full.startsWith(SITE + path.sep)) return null;
|
|
@@ -151,10 +152,6 @@ const handle = async (req, res) => {
|
|
|
151
152
|
return;
|
|
152
153
|
}
|
|
153
154
|
const pathname = urlPath.split('?')[0];
|
|
154
|
-
if (pathname === '/') {
|
|
155
|
-
send(res, 302, '', { ...headers, Location: '/site/' });
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
155
|
if (pathname === '/board.json') {
|
|
159
156
|
const file = path.join(ROOT, 'board.json');
|
|
160
157
|
if (!fs.existsSync(file)) {
|
package/package.json
CHANGED
package/scaffold/board/AGENTS.md
CHANGED
|
@@ -16,17 +16,33 @@ Previewing and publishing the board need **Node.js 20 or later**. The pages them
|
|
|
16
16
|
3. A fresh install may not be visible in the current terminal. If `node -v` still fails afterwards, open a new terminal session (or load the shell profile) and check again.
|
|
17
17
|
4. If an install isn't possible (declined, or blocked on a work computer), point them to the installer at https://nodejs.org and wait for them.
|
|
18
18
|
|
|
19
|
+
## The board's name and slug
|
|
20
|
+
|
|
21
|
+
`board.json` has two identifiers, and they do different jobs:
|
|
22
|
+
|
|
23
|
+
- **`name`** is the label people see (Surph's header, `board.get`). Change it whenever the person asks.
|
|
24
|
+
- **`slug`** is the board's identity in Surph: it names where the board is published (`boards/<slug>/`) and its live address (`https://<slug>.surph-boards.com`), and it's shared across everyone on Surph, so it must be unique. Lowercase letters, digits and dashes only, at most 63 characters.
|
|
25
|
+
|
|
26
|
+
Keep them in step on a board that hasn't been published yet. The person won't think about the slug, so you do:
|
|
27
|
+
|
|
28
|
+
1. **Whenever you set or change the board's name on an unpublished board, set `slug` from it in the same edit:** lowercase, spaces and punctuation turned into single dashes (BreakLedger → `breakledger`, "DC Tech Events" → `dc-tech-events`). Tell the person the slug you chose, in a word: it's the board's address (`https://<slug>.surph-boards.com`).
|
|
29
|
+
2. **A new board's slug starts from its folder name** (`surph board break-ledger` → `break-ledger`). Older boards may still have the placeholder `my-board`: replace it as soon as the board has a name. `npm run deploy` refuses to publish with `my-board`.
|
|
30
|
+
3. **Check the slug is free before you settle on it:** `curl -s -o /dev/null -w "%{http_code}" https://surph.s3.us-east-1.amazonaws.com/boards/<slug>/board.json`. `200` means a board with that slug already exists. If this folder never published it, it's someone else's: pick another (add a short suffix, e.g. `breakledger-dk`) and say so. Anything else (403 or 404) means it's free.
|
|
31
|
+
4. **Is this board published?** Treat it as published if the person says so, or if you ran `npm run deploy` for it. If unsure, ask.
|
|
32
|
+
5. **Once the board is published, don't change `slug`** unless the person asks for a new address. A new slug publishes a second, separate board; the old one stays live under the old slug. Renaming a published board only changes `name`.
|
|
33
|
+
|
|
19
34
|
## The working loop
|
|
20
35
|
|
|
21
|
-
1. **Preview:** run `npm run dev` from this folder and leave it running. It serves the board at `http://localhost:4180`:
|
|
36
|
+
1. **Preview:** run `npm run dev` from this folder and leave it running. It serves the board at `http://localhost:4180`: the pages in `site/` as its base (`/` is `site/index.html`), plus `/board.json` (nothing to install; it uses the Surph CLI through `npx`).
|
|
22
37
|
2. **See it in Surph:** ask the person to open Surph, go to **Settings → Developer**, turn on **Run Surph as a local board**, and keep the address `http://localhost:4180`. Surph reloads as this board.
|
|
23
38
|
3. **Configure the board** (name, contexts, tools, instructions): the person can click the **DEV** label in Surph's canvas header to open the Local board panel, which saves `board.json` for you. You can also edit `board.json` directly; the README describes every field.
|
|
24
39
|
4. **Change pages:** the pages and their assets live in `site/` (`site/index.html`, `site/assets/…`). Edit them there and keep `board.json`'s `config.pages` in step (every page listed, `shows` written as plain facts, `ops` matching the page's `host.rpc` calls). The person reloads Surph to see the change.
|
|
25
|
-
5. **Publish:** `npm run deploy`. **Only when the person asks you to in this conversation.** It replaces the live board for everyone who uses it. Check the board in dev mode first.
|
|
40
|
+
5. **Publish:** `npm run deploy`. **Only when the person asks you to in this conversation.** It replaces the live board for everyone who uses it. Check the board in dev mode first, and check `slug` first (see above): not `my-board`, and either free or this board's own. Once deployed, the site is live at `https://<slug>.surph-boards.com/`.
|
|
26
41
|
|
|
27
42
|
## What to keep in mind
|
|
28
43
|
|
|
29
44
|
- Pages talk to Surph only through the Surph SDK (`host.rpc(…)`) and only with the operations the README lists. Don't invent operations or fields; if a page needs data Surph doesn't offer, say so.
|
|
30
45
|
- Write data from Surph with `textContent`, never `innerHTML`.
|
|
46
|
+
- `site/` is served at the root of the board's address, locally (`http://localhost:4180/`) and live (`https://<slug>.surph-boards.com/`), so paths like `/assets/…` and app routes work the same in both. It's static: there's no server for `/api/…` calls. The README's "Where the site is served" has the details.
|
|
31
47
|
- Everything in `site/` (except dot-files) gets published by `npm run deploy`, and nothing outside it except `board.json`. Keep drafts, notes and secrets out of `site/`.
|
|
32
48
|
- Before handing off, go through the README's "Checklist before handing off a change".
|
package/scaffold/board/README.md
CHANGED
|
@@ -31,9 +31,24 @@ AGENTS.md, CLAUDE.md Notes for coding agents
|
|
|
31
31
|
The folder mirrors the live board in Surph's storage: `board.json` at the top, the pages and assets in `site/`.
|
|
32
32
|
|
|
33
33
|
- **Pages sit at the top of `site/`.** A page's registry entry names its file without a folder, so a page can't live in a subfolder of `site/`.
|
|
34
|
-
- **Everything else a page loads, apart from the SDK, goes under `site/assets
|
|
34
|
+
- **Everything else a page loads, apart from the SDK, goes under `site/assets/`** (`assets/css/site.css`, `assets/js/…`).
|
|
35
35
|
- **Only `site/` is published.** Keep notes, drafts and anything else outside it.
|
|
36
36
|
|
|
37
|
+
### Where the site is served
|
|
38
|
+
|
|
39
|
+
`site/` is always served at the root of the board's own address, so `/` is `site/index.html`:
|
|
40
|
+
|
|
41
|
+
| | Address |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| Developing (`npm run dev`) | `http://localhost:4180/` |
|
|
44
|
+
| Live, once deployed | `https://<slug>.surph-boards.com/` (for example `https://breakledger.surph-boards.com/`) |
|
|
45
|
+
|
|
46
|
+
Surph's canvas loads the pages from that address too, and the live address also works on its own in a browser tab. What follows from it:
|
|
47
|
+
|
|
48
|
+
- **Root paths and relative paths both work** (`/assets/css/site.css` or `assets/css/site.css`), the same locally and live.
|
|
49
|
+
- **App routes work.** A page load at an address with no file extension (`/account`, a reload, a shared link) gets `index.html`, so a single-page app with its own router (React Router, Vite's default build) works as it does locally.
|
|
50
|
+
- **The site is static: there's no server behind it.** A script's call to the site's own address that isn't a file (`fetch('/api/…')`) fails. Data comes from Surph through the SDK; a page that needs another server calls it by its full `https://` address, and that server has to allow it (CORS).
|
|
51
|
+
|
|
37
52
|
### Shared styles: `assets/css/site.css`
|
|
38
53
|
|
|
39
54
|
Every page links it in `<head>`, before its own `<style>`:
|
|
@@ -58,11 +73,11 @@ Surph only shows pages that are registered with the board. The board itself is d
|
|
|
58
73
|
"slug": "my-board",
|
|
59
74
|
"name": "My Board",
|
|
60
75
|
"description": "What the board is about.",
|
|
61
|
-
"logo": "logo.png",
|
|
62
76
|
"contexts": ["<context slug>"],
|
|
63
77
|
"defaultContext": "<context slug>",
|
|
64
78
|
"tools": [],
|
|
65
79
|
"config": {
|
|
80
|
+
"icon": "assets/img/icon.png",
|
|
66
81
|
"instructions": "How the board's chat should behave: its tone, what it helps with.",
|
|
67
82
|
"pages": [
|
|
68
83
|
{ "name": "home", "file": "index.html", "shows": "…", "start": "always", "ops": ["board.get"] }
|
|
@@ -73,15 +88,15 @@ Surph only shows pages that are registered with the board. The board itself is d
|
|
|
73
88
|
|
|
74
89
|
| Field | Meaning |
|
|
75
90
|
| --- | --- |
|
|
76
|
-
| `slug` | The board's
|
|
91
|
+
| `slug` | The board's identity in Surph: where it's published (`boards/<slug>/`) and its live address (`https://<slug>.surph-boards.com`). Unique across Surph; lowercase letters, digits and dashes. A new board's slug starts from its folder name; when the board gets its real name, set the slug from that before publishing (BreakLedger → `breakledger`), and don't change it after (a new slug publishes a separate board). The deploy refuses the old placeholder `my-board`. See `AGENTS.md`, "The board's name and slug". |
|
|
77
92
|
| `name` | The board's name, shown in Surph's header and returned by `board.get`. |
|
|
78
|
-
| `description` |
|
|
79
|
-
| `logo` | An image file in `site/assets/` (just its name, e.g. `logo.png`), shown in Surph's header. |
|
|
93
|
+
| `description` | The board's opening line in the chat: what a visitor sees first on the board's home, shown as written. Write it to the visitor ("Track every Whatnot break: ask me about spend, sales and ROI."). Without one, the chat greets from the board's contexts, or says "Welcome to <name>!" when it has none. |
|
|
80
94
|
| `contexts` | Slugs of the Surph contexts the board draws on. Their items are what `board.get` and the chat's lookups return. They're live Surph contexts; find a context's slug in its address (`/c/<slug>`). |
|
|
81
95
|
| `defaultContext` | The context the chat starts with; else the first in `contexts`. |
|
|
82
96
|
| `tools` | Slugs of Surph tools the board's chat can use. Optional. |
|
|
83
97
|
| `config.instructions` | Instructions from the board's owner for the board's chat: tone, behavior, what it helps with. On a board they take the place of each context's own instructions. |
|
|
84
98
|
| `config.pages` | The board's pages, one registry entry each (below). |
|
|
99
|
+
| `config.icon` | Optional. The board's icon: a file in `site/`, by its path there (`apple-touch-icon.png`, `assets/img/icon.png`). Surph shows it beside the board's name: on each of the chat's replies ("@BreakLedger") and in the header. A small square image works best. |
|
|
85
100
|
|
|
86
101
|
A registry entry:
|
|
87
102
|
|
|
@@ -405,11 +420,11 @@ A field marked "omitted" is missing from the object, not `null`. Every URL is `h
|
|
|
405
420
|
|
|
406
421
|
## Developing locally
|
|
407
422
|
|
|
408
|
-
1. Run `npm run dev` (nothing to install). It starts the board dev server from the Surph CLI (`npx @surph_ai/cli board-server`), which serves the board at `http://localhost:4180` (
|
|
423
|
+
1. Run `npm run dev` (nothing to install). It starts the board dev server from the Surph CLI (`npx @surph_ai/cli board-server`), which serves the board at `http://localhost:4180` (the pages in `site/` as its base, plus `/board.json`) with caching off, lets Surph read it from another address, and lets Surph's Local board panel save `board.json`. It only listens on your own machine.
|
|
409
424
|
2. Keep it running while you work; the terminal shows a line each time Surph saves `board.json`.
|
|
410
|
-
3. Open `http://localhost:4180
|
|
411
|
-
4. **Run Surph as your board with dev mode.** Keep `npm run dev` running. In Surph, open **Settings → Developer**, turn on **Run Surph as a local board**, and keep the address `http://localhost:4180`. Surph reloads as the board `board.json` describes: its name and
|
|
412
|
-
5. **Configure the board from Surph.** Click the **DEV** label to open the **Local board** panel: set the board's name, slug, description and
|
|
425
|
+
3. Open `http://localhost:4180/` (your `site/index.html`) to check a page loads without console errors. It shows its empty layout there (`hosted` is false); real data only appears inside the Surph canvas.
|
|
426
|
+
4. **Run Surph as your board with dev mode.** Keep `npm run dev` running. In Surph, open **Settings → Developer**, turn on **Run Surph as a local board**, and keep the address `http://localhost:4180`. Surph reloads as the board `board.json` describes: its name and icon in the header, its contexts and instructions in the chat, and its pages in the canvas (it opens on your start page, the Pages menu lists your pages, and the chat's model sees their `shows` lines). The status under the address says what loaded, or why it couldn't read `board.json`; until it loads, Surph runs as usual. A **DEV** label in the canvas header shows your board is loaded. While it's on, anything the chat saves goes to your own space in Surph, not to a board's shared space.
|
|
427
|
+
5. **Configure the board from Surph.** Click the **DEV** label to open the **Local board** panel: set the board's name, slug, description and icon (an image in `site/`), pick its contexts (yours, or public ones by search) and which one the chat starts with, pick its tools, and write its instructions. The panel also lists the pages and flags a missing `shows` line or an operation the host doesn't answer. **Save and reload** writes `board.json` through the dev server and reloads Surph as the updated board. Pages and any other fields are kept as they are in the file; edit pages in `board.json` itself.
|
|
413
428
|
6. Dev mode affects only your browser. Turn it off in the same place to get Surph's own pages back.
|
|
414
429
|
7. In Surph, keep your browser's DevTools open with **Network → Disable cache** checked, or the canvas may keep showing an older copy of a page after you change it. After editing `board.json` by hand, reload Surph so it reads the file again.
|
|
415
430
|
|
|
@@ -417,13 +432,13 @@ A field marked "omitted" is missing from the object, not `null`. Every URL is `h
|
|
|
417
432
|
|
|
418
433
|
`npm run deploy` (`npx @surph_ai/cli board-deploy`, from the Surph CLI) publishes the board to Surph. Run it from the board's folder. It needs Node.js 20 or later and nothing else installed. In order, it:
|
|
419
434
|
|
|
420
|
-
1. **Reads the board's `slug`** from `board.json` (lowercase letters, digits and dashes). The slug names the board's place in Surph; without a valid one it stops before doing anything.
|
|
435
|
+
1. **Reads the board's `slug`** from `board.json` (lowercase letters, digits and dashes). The slug names the board's place in Surph, so it must be this board's own, not the placeholder `my-board` and not another board's (see the `slug` field above); without a valid one it stops before doing anything.
|
|
421
436
|
2. **Zips the site** into `site.zip`: every file in `site/`, except dot-files (`.env`, `.DS_Store`) and `node_modules`. Nothing outside `site/` is included (`board.json` goes up on its own in step 5). It lists the files it zipped.
|
|
422
437
|
3. **Uploads `site.zip`** to the board's `site/` folder in Surph's storage, then deletes the local `site.zip`. If the upload fails, the zip is kept to look at.
|
|
423
438
|
4. **Unzips it there**, so the board's `site/` folder in Surph's storage holds the same files as your `site/`, where each page's `file` is found.
|
|
424
439
|
5. **Uploads `board.json`**, last, so the live board's definition only changes once its pages are up. If an earlier step fails, `board.json` isn't uploaded and the live board keeps its previous version.
|
|
425
440
|
|
|
426
|
-
Each step prints what it did; a failure prints why and stops. After a deploy, Surph picks up the new `board.json` within about a minute.
|
|
441
|
+
Each step prints what it did; a failure prints why and stops. After a deploy, the site is live at `https://<slug>.surph-boards.com/`, and Surph picks up the new `board.json` within about a minute. A changed file can take a few minutes to replace the old copy there; reload to check.
|
|
427
442
|
|
|
428
443
|
**For coding agents:**
|
|
429
444
|
- **Deploying publishes the board to everyone who uses it.** Don't run `npm run deploy` unless the person asks you to in this conversation. Check the board with dev mode first (see [Developing locally](#developing-locally)).
|
|
@@ -439,6 +454,6 @@ Each step prints what it did; a failure prints why and stops. After a deploy, Su
|
|
|
439
454
|
- [ ] The SDK `<script>` tag is the v1 URL above, unchanged.
|
|
440
455
|
- [ ] Every page (in `site/`) links `assets/css/site.css?v=<n>`; if `site.css` changed, `<n>` is bumped in every page.
|
|
441
456
|
- [ ] `board.json`'s `config.pages` lists every page: `name`, `file` (or `url`), `shows` written as facts, `ops` matching the file's `rpc` calls, and one `start` page.
|
|
442
|
-
- [ ] Opened at `http://localhost:4180
|
|
457
|
+
- [ ] Opened at `http://localhost:4180/<page>`, every page loads without console errors.
|
|
443
458
|
- [ ] Checked in Surph with dev mode on: the canvas opens on the start page and each page paints with real data.
|
|
444
459
|
- [ ] Not deployed unless the person asked for it; if deployed, `npm run deploy` finished without errors and its file list holds only the board's site.
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
<h2>Next steps</h2>
|
|
91
91
|
<ol class="steps">
|
|
92
92
|
<li><strong>Read <code>README.md</code>.</strong> It lists every operation the host answers, the item shape, and the rules a page follows. Point your coding agent at it.</li>
|
|
93
|
-
<li><strong>Run it locally:</strong> <code>npm run dev</code> serves the board at <code>http://localhost:4180</code> (this page is
|
|
93
|
+
<li><strong>Run it locally:</strong> <code>npm run dev</code> serves the board at <code>http://localhost:4180</code> (this page is its home) with caching off.</li>
|
|
94
94
|
<li><strong>Add pages</strong> in <code>site/</code>, next to this one (<code>items.html</code>, <code>events.html</code>…), and list each in <code>board.json</code> with its <code>name</code>, <code>file</code>, <code>shows</code> and the <code>ops</code> it calls. Shared styles go in <code>site/assets/css/site.css</code>.</li>
|
|
95
95
|
<li><strong>See them in Surph:</strong> open <strong>Settings → Developer</strong> and turn on dev mode for <code>http://localhost:4180</code>. The canvas then shows the board's pages, with real data.</li>
|
|
96
96
|
</ol>
|
package/scaffold/index.js
CHANGED
|
@@ -272,7 +272,15 @@ const scaffoldBoard = async (name) => {
|
|
|
272
272
|
shell.cp('-R', path.join(__dirname, `board/README.md`), 'README.md')
|
|
273
273
|
shell.cp('-R', path.join(__dirname, `board/AGENTS.md`), 'AGENTS.md')
|
|
274
274
|
shell.cp('-R', path.join(__dirname, `board/CLAUDE.md`), 'CLAUDE.md')
|
|
275
|
-
|
|
275
|
+
// board.json gets the board's own slug and name from <name> (the folder
|
|
276
|
+
// it was created in), so a new board never carries the template's
|
|
277
|
+
// placeholder slug. The slug is where the board publishes in Surph.
|
|
278
|
+
const boardJson = JSON.parse(utils.readFile(path.join(__dirname, 'board/board.json')))
|
|
279
|
+
const folderName = path.basename(name)
|
|
280
|
+
const boardSlug = slugify(folderName, 0)
|
|
281
|
+
if (/^[a-z0-9][a-z0-9-]*$/.test(boardSlug)) boardJson.slug = boardSlug
|
|
282
|
+
boardJson.name = folderName
|
|
283
|
+
utils.write('board.json', JSON.stringify(boardJson, null, 2) + '\n')
|
|
276
284
|
|
|
277
285
|
// The board's pages and assets go in site/ (boards/<slug>/site/ when live).
|
|
278
286
|
shell.mkdir('-p', 'site/assets/css')
|