create-sl-ide 0.1.0 → 0.1.2

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.
Files changed (3) hide show
  1. package/README.md +5 -1
  2. package/index.mjs +56 -7
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,10 +5,13 @@ the IDE for building slides with Claude Code or Codex.
5
5
 
6
6
  ```sh
7
7
  pnpm create sl-ide my-deck
8
+ pnpm create sl-ide my-memo --memo # a memo on US Letter pages instead of slides
9
+ pnpm create sl-ide . # in the current (empty) folder, named after it
8
10
  # or: npm create sl-ide@latest my-deck · bun create sl-ide my-deck
9
11
  ```
10
12
 
11
- It asks a few questions, then:
13
+ It asks a few questions (slides or a memo; with no name in an empty
14
+ folder, whether to build right there; the repo; publishing), then:
12
15
 
13
16
  1. Clones the **latest** sl-ide template from GitHub, keeping its history as
14
17
  the `upstream` remote, so `git pull upstream main` brings later editor
@@ -27,6 +30,7 @@ Then `cd my-deck && pnpm dev`, open Claude Code or Codex there, and run
27
30
  ## Options
28
31
 
29
32
  ```
33
+ --format <slides|memo> 16:9 slides, or a US Letter memo (default slides; --memo for short)
30
34
  --dir <path> folder for the deck (default ./<name>)
31
35
  --github <private|public|none> the deck's repo (default private)
32
36
  --team <slug> the sl-ide cloud team that owns the deck
package/index.mjs CHANGED
@@ -7,6 +7,7 @@
7
7
  // cloud, and installs dependencies. The editor itself is never bundled here,
8
8
  // so a new deck always starts from the template's main.
9
9
  //
10
+ // pnpm create sl-ide . start the deck in this (empty) folder, named after it
10
11
  // pnpm create sl-ide login sign in to sl-ide cloud and save a team token
11
12
  // pnpm create sl-ide logout forget saved tokens
12
13
  import fs from 'node:fs';
@@ -21,10 +22,13 @@ const SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
21
22
 
22
23
  const HELP = `
23
24
  pnpm create sl-ide [name] [options]
25
+ pnpm create sl-ide . [options] in this empty folder, named after it
24
26
 
25
- Start a new deck from the latest sl-ide template.
27
+ Start a new deck (or memo) from the latest sl-ide template.
26
28
 
27
29
  Options
30
+ --format <slides|memo> 16:9 slides, or a memo on US Letter pages (default: slides)
31
+ --memo short for --format memo
28
32
  --dir <path> folder to create the deck in (default: ./<name>)
29
33
  --github <private|public|none> the deck's GitHub repo (default: private)
30
34
  --team <slug> the sl-ide cloud team that owns the deck
@@ -45,6 +49,8 @@ const HELP = `
45
49
  const { values: o, positionals } = parseArgs({
46
50
  allowPositionals: true,
47
51
  options: {
52
+ format: { type: 'string' },
53
+ memo: { type: 'boolean' },
48
54
  dir: { type: 'string' },
49
55
  github: { type: 'string' },
50
56
  team: { type: 'string' },
@@ -62,6 +68,7 @@ const { values: o, positionals } = parseArgs({
62
68
  if (o['no-publish']) o.publish = false;
63
69
  if (o['no-install']) o.install = false;
64
70
  if (o['no-open']) o.open = false;
71
+ if (o.memo) o.format = 'memo';
65
72
  if (o.help) { console.log(HELP); process.exit(0); }
66
73
 
67
74
  const interactive = process.stdin.isTTY && !o.yes;
@@ -141,7 +148,20 @@ function logout() {
141
148
  async function create() {
142
149
  p.intro('sl-ide · new deck');
143
150
 
144
- let name = positionals[0];
151
+ // `.` builds the deck in the current folder and names it after the folder.
152
+ // Asked too, when no name is given and this folder is empty.
153
+ const cwdEmpty = fs.readdirSync(process.cwd()).every((f) => f === '.DS_Store');
154
+ let here = positionals[0] === '.';
155
+ if (!positionals[0] && !o.dir && interactive && cwdEmpty) {
156
+ here = await ask(p.select({
157
+ message: 'Where should it go?',
158
+ options: [
159
+ { value: true, label: 'This folder', hint: path.basename(process.cwd()) },
160
+ { value: false, label: 'A new folder inside this one' },
161
+ ],
162
+ }));
163
+ }
164
+ let name = here ? path.basename(process.cwd()) : positionals[0];
145
165
  if (!name) {
146
166
  if (!interactive) bail('Give the deck a name: pnpm create sl-ide my-deck');
147
167
  name = await ask(p.text({
@@ -154,8 +174,27 @@ async function create() {
154
174
  const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
155
175
  if (!SLUG_RE.test(slug)) bail(`can't make a link name from "${name}"`);
156
176
 
157
- const dest = path.resolve(o.dir ?? name);
158
- if (fs.existsSync(dest) && fs.readdirSync(dest).length) bail(`${dest} already exists and isn't empty`);
177
+ // Slides or a memo. A memo is the same template with the memo starter
178
+ // swapped in by its own script (scripts/use-format.mjs).
179
+ let format = o.format;
180
+ if (!format) {
181
+ format = interactive ? await ask(p.select({
182
+ message: 'What are you making?',
183
+ options: [
184
+ { value: 'slides', label: 'Slides', hint: '16:9 pages' },
185
+ { value: 'memo', label: 'A memo', hint: 'US Letter pages, text flows from page to page' },
186
+ ],
187
+ })) : 'slides';
188
+ }
189
+ if (!['slides', 'memo'].includes(format)) bail('--format is slides or memo');
190
+
191
+ const dest = path.resolve(o.dir ?? (here ? '.' : name));
192
+ if (fs.existsSync(dest)) {
193
+ // Finder leaves .DS_Store in folders it opens; it would stop git clone.
194
+ const left = fs.readdirSync(dest).filter((f) => f !== '.DS_Store');
195
+ if (left.length) bail(`${dest} already exists and isn't empty`);
196
+ fs.rmSync(path.join(dest, '.DS_Store'), { force: true });
197
+ }
159
198
 
160
199
  for (const tool of ['git', 'pnpm']) {
161
200
  if (!has(tool)) bail(tool === 'pnpm' ? 'pnpm is needed: corepack enable pnpm' : 'git is needed');
@@ -221,6 +260,16 @@ async function create() {
221
260
  const head = await run('git', ['log', '-1', '--format=%h %s'], { cwd: dest });
222
261
  s.stop(`Cloned sl-ide (${head.split(' ')[0]})`);
223
262
 
263
+ if (format !== 'slides') {
264
+ if (!fs.existsSync(path.join(dest, 'scripts', 'use-format.mjs'))) {
265
+ throw new Error(`this sl-ide template has no ${format} format yet`);
266
+ }
267
+ await run('node', ['scripts/use-format.mjs', format], { cwd: dest });
268
+ await run('git', ['add', '-A'], { cwd: dest });
269
+ await run('git', ['-c', 'core.hooksPath=/dev/null', 'commit', '-q', '-m', `Start from the ${format} starter`], { cwd: dest });
270
+ p.log.success(`Set up as a ${format}`);
271
+ }
272
+
224
273
  if (pub) {
225
274
  const config = { slug, team: pub.team, visibility: share };
226
275
  fs.writeFileSync(path.join(dest, 'sl-ide.config.json'), `${JSON.stringify(config, null, 2)}\n`);
@@ -249,12 +298,12 @@ async function create() {
249
298
 
250
299
  const rel = path.relative(process.cwd(), dest) || '.';
251
300
  const lines = [
252
- `cd ${rel}`,
301
+ ...(rel === '.' ? [] : [`cd ${rel}`]),
253
302
  ...(o.install ? [] : ['pnpm install']),
254
303
  'pnpm dev',
255
304
  '',
256
305
  'Then open Claude Code or Codex in that folder and run /new-deck',
257
- '(Codex: $new-deck) to learn your style and outline the story.',
306
+ `(Codex: $new-deck) to learn your style and outline the ${format === 'memo' ? 'memo' : 'story'}.`,
258
307
  ];
259
308
  p.note(lines.join('\n'), 'Next');
260
309
  if (pub) {
@@ -262,7 +311,7 @@ async function create() {
262
311
  } else {
263
312
  p.log.info('Not publishing. To publish later, add sl-ide.config.json (see the deck\'s README).');
264
313
  }
265
- p.outro('Deck ready.');
314
+ p.outro(format === 'memo' ? 'Memo ready.' : 'Deck ready.');
266
315
  }
267
316
 
268
317
  const cmd = positionals[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sl-ide",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Start a slide deck with sl-ide: pnpm create sl-ide",
5
5
  "type": "module",
6
6
  "bin": {