@tutorialkit-rb/cli 0.1.5 → 0.1.8

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 (185) hide show
  1. package/dist/index.js +47 -38
  2. package/package.json +1 -1
  3. package/template/.claude/skills/rails-file-management/SKILL.md +211 -0
  4. package/template/.claude/skills/rails-lesson-recipes/SKILL.md +415 -0
  5. package/template/.claude/skills/rails-wasm-author-constraints/SKILL.md +181 -0
  6. package/template/.claude/skills/tutorial-content-structure/SKILL.md +377 -0
  7. package/template/.claude/skills/tutorial-lesson-config/SKILL.md +389 -0
  8. package/template/.claude/skills/tutorial-quickstart/SKILL.md +440 -0
  9. package/template/.github/workflows/deploy.yml +85 -0
  10. package/template/.gitignore +10 -0
  11. package/template/CLAUDE.md +47 -0
  12. package/template/astro.config.ts +12 -0
  13. package/template/bin/build-pack +84 -0
  14. package/template/bin/build-ruby-base +180 -0
  15. package/template/bin/link-local +13 -0
  16. package/template/bin/unlink-local +7 -0
  17. package/template/cors-proxy/README.md +63 -0
  18. package/template/cors-proxy/package-lock.json +1504 -0
  19. package/template/cors-proxy/package.json +12 -0
  20. package/template/cors-proxy/src/index.ts +87 -0
  21. package/template/cors-proxy/wrangler.toml +7 -0
  22. package/template/netlify.toml +9 -0
  23. package/template/package.json +12 -4
  24. package/template/ruby-wasm/Gemfile +6 -0
  25. package/template/ruby-wasm/Gemfile.base +19 -0
  26. package/template/ruby-wasm/Gemfile.base.lock +50 -0
  27. package/template/ruby-wasm/Gemfile.lock +8 -0
  28. package/template/ruby-wasm/bin/pack-gems +368 -0
  29. package/template/ruby-wasm/package.json +6 -0
  30. package/template/src/components/FileManager.tsx +33 -0
  31. package/template/src/components/HeadTags.astro +6 -6
  32. package/template/src/components/HelpDropdown.tsx +1 -1
  33. package/template/src/components/RailsPathLinkHandler.tsx +2 -2
  34. package/template/src/components/ShellConfigurator.tsx +6 -1
  35. package/template/src/content/tutorial/1-getting-started/1-creating-your-first-rails-app/content.md +4 -4
  36. package/template/src/content/tutorial/1-getting-started/2-rails-console/content.md +4 -4
  37. package/template/src/content/tutorial/2-controllers/2-crud-operations/content.md +2 -2
  38. package/template/src/content/tutorial/9-outbound-http/1-making-http-requests/_files/.tk-config.json +3 -0
  39. package/template/src/content/tutorial/9-outbound-http/1-making-http-requests/_files/workspace/app/controllers/http_demo_controller.rb +65 -0
  40. package/template/src/content/tutorial/9-outbound-http/1-making-http-requests/_files/workspace/app/views/http_demo/index.html.erb +172 -0
  41. package/template/src/content/tutorial/9-outbound-http/1-making-http-requests/_files/workspace/config/routes.rb +8 -0
  42. package/template/src/content/tutorial/9-outbound-http/1-making-http-requests/content.md +97 -0
  43. package/template/src/content/tutorial/9-outbound-http/meta.md +4 -0
  44. package/template/src/content/tutorial/meta.md +5 -0
  45. package/template/src/middleware.ts +14 -0
  46. package/template/src/templates/default/lib/boot-progress.js +49 -0
  47. package/template/src/templates/default/lib/http-bridge.js +55 -0
  48. package/template/src/templates/default/lib/patches/http_bridge.rb +167 -0
  49. package/template/src/templates/default/lib/rails.js +52 -5
  50. package/template/src/templates/default/lib/server.js +33 -1
  51. package/template/src/templates/default/package.json +4 -1
  52. package/template/src/templates/default/scripts/rails.js +1 -1
  53. package/template/src/templates/default/scripts/smoke-test.js +349 -0
  54. package/template/src/templates/default/scripts/wasi-loader.mjs +10 -0
  55. package/template/src/templates/default/workspace/_debug_app/.github/dependabot.yml +12 -0
  56. package/template/src/templates/default/workspace/_debug_app/.github/workflows/ci.yml +51 -0
  57. package/template/src/templates/default/workspace/_debug_app/.ruby-version +1 -0
  58. package/template/src/templates/default/workspace/_debug_app/Gemfile +37 -0
  59. package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/views/layouts/application.html.erb +1 -2
  60. package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/views/pwa/manifest.json.erb +2 -2
  61. package/template/src/templates/default/workspace/_debug_app/bin/dev +2 -0
  62. package/template/src/templates/default/workspace/_debug_app/bin/rake +4 -0
  63. package/template/src/templates/default/workspace/_debug_app/bin/setup +34 -0
  64. package/template/src/templates/default/workspace/_debug_app/config/application.rb +30 -0
  65. package/template/src/templates/default/workspace/_debug_app/config/cable.yml +10 -0
  66. package/template/src/templates/default/workspace/_debug_app/config/credentials.yml.enc +1 -0
  67. package/template/src/templates/default/workspace/_debug_app/config/master.key +1 -0
  68. package/template/src/templates/default/workspace/_debug_app/config/routes.rb +14 -0
  69. package/template/src/templates/default/workspace/_debug_app/test/models/.keep +0 -0
  70. package/template/src/templates/default/workspace/_debug_app/test/test_helper.rb +15 -0
  71. package/template/src/templates/default/workspace/_debug_app/tmp/.keep +0 -0
  72. package/template/src/templates/default/workspace/_debug_app/tmp/pids/.keep +0 -0
  73. package/template/src/templates/default/workspace/_debug_app/tmp/storage/.keep +0 -0
  74. package/template/src/templates/default/workspace/_debug_app/vendor/.keep +0 -0
  75. package/template/src/templates/rails-app/workspace/README.md +24 -0
  76. package/template/src/templates/rails-app/workspace/Rakefile +6 -0
  77. package/template/src/templates/rails-app/workspace/app/assets/images/.keep +0 -0
  78. package/template/src/templates/rails-app/workspace/app/assets/stylesheets/application.css +534 -0
  79. package/template/src/templates/rails-app/workspace/app/controllers/application_controller.rb +2 -0
  80. package/template/src/templates/rails-app/workspace/app/helpers/application_helper.rb +2 -0
  81. package/template/src/templates/rails-app/workspace/app/jobs/application_job.rb +7 -0
  82. package/template/src/templates/rails-app/workspace/app/mailers/application_mailer.rb +4 -0
  83. package/template/src/templates/rails-app/workspace/app/models/application_record.rb +3 -0
  84. package/template/src/templates/rails-app/workspace/app/models/concerns/.keep +0 -0
  85. package/template/src/templates/rails-app/workspace/app/views/layouts/application.html.erb +38 -0
  86. package/template/src/templates/rails-app/workspace/app/views/layouts/mailer.html.erb +13 -0
  87. package/template/src/templates/rails-app/workspace/app/views/layouts/mailer.text.erb +1 -0
  88. package/template/src/templates/rails-app/workspace/bin/rails +4 -0
  89. package/template/src/templates/rails-app/workspace/{store/config → config}/application.rb +1 -1
  90. package/template/src/templates/rails-app/workspace/config/boot.rb +3 -0
  91. package/template/src/templates/rails-app/workspace/config/database.yml +32 -0
  92. package/template/src/templates/rails-app/workspace/config/environment.rb +5 -0
  93. package/template/src/templates/rails-app/workspace/config/environments/development.rb +69 -0
  94. package/template/src/templates/rails-app/workspace/config/environments/production.rb +89 -0
  95. package/template/src/templates/rails-app/workspace/config/environments/test.rb +54 -0
  96. package/template/src/templates/rails-app/workspace/config/initializers/assets.rb +7 -0
  97. package/template/src/templates/rails-app/workspace/config/initializers/content_security_policy.rb +25 -0
  98. package/template/src/templates/rails-app/workspace/config/initializers/filter_parameter_logging.rb +8 -0
  99. package/template/src/templates/rails-app/workspace/config/initializers/inflections.rb +16 -0
  100. package/template/src/templates/rails-app/workspace/config/locales/en.yml +31 -0
  101. package/template/src/templates/rails-app/workspace/config/puma.rb +41 -0
  102. package/template/src/templates/rails-app/workspace/{store/config → config}/routes.rb +1 -1
  103. package/template/src/templates/rails-app/workspace/config/storage.yml +34 -0
  104. package/template/src/templates/rails-app/workspace/config.ru +6 -0
  105. package/template/src/templates/rails-app/workspace/db/seeds.rb +9 -0
  106. package/template/src/templates/rails-app/workspace/log/.keep +0 -0
  107. package/template/src/templates/rails-app/workspace/public/400.html +114 -0
  108. package/template/src/templates/rails-app/workspace/public/404.html +114 -0
  109. package/template/src/templates/rails-app/workspace/public/406-unsupported-browser.html +114 -0
  110. package/template/src/templates/rails-app/workspace/public/422.html +114 -0
  111. package/template/src/templates/rails-app/workspace/public/500.html +114 -0
  112. package/template/src/templates/rails-app/workspace/public/icon.png +0 -0
  113. package/template/src/templates/rails-app/workspace/public/icon.svg +3 -0
  114. package/template/src/templates/rails-app/workspace/public/robots.txt +1 -0
  115. package/template/src/templates/rails-app/workspace/script/.keep +0 -0
  116. package/template/src/templates/rails-app/workspace/storage/.keep +0 -0
  117. package/template/src/templates/rails-app/workspace/test/controllers/.keep +0 -0
  118. package/template/src/templates/rails-app/workspace/test/helpers/.keep +0 -0
  119. package/template/src/templates/rails-app/workspace/test/integration/.keep +0 -0
  120. package/template/src/templates/rails-app/workspace/tmp/.keep +0 -0
  121. package/template/src/templates/rails-app/workspace/tmp/cache/.keep +0 -0
  122. package/template/src/templates/rails-app/workspace/tmp/pids/.keep +0 -0
  123. package/template/src/templates/rails-app/workspace/tmp/sockets/.keep +0 -0
  124. package/template/src/templates/rails-app/workspace/tmp/storage/.keep +0 -0
  125. package/template/src/templates/rails-app/workspace/vendor/javascripts/.keep +0 -0
  126. package/template/tsconfig.json +3 -1
  127. package/template/uno.config.ts +17 -0
  128. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/README.md +0 -0
  129. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/Rakefile +0 -0
  130. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/assets/images/.keep +0 -0
  131. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/assets/stylesheets/application.css +0 -0
  132. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/controllers/application_controller.rb +0 -0
  133. /package/template/src/templates/{rails-app/workspace/store/app/models → default/workspace/_debug_app/app/controllers}/concerns/.keep +0 -0
  134. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/helpers/application_helper.rb +0 -0
  135. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/jobs/application_job.rb +0 -0
  136. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/mailers/application_mailer.rb +0 -0
  137. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/models/application_record.rb +0 -0
  138. /package/template/src/templates/{rails-app/workspace/store/log → default/workspace/_debug_app/app/models/concerns}/.keep +0 -0
  139. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/views/layouts/mailer.html.erb +0 -0
  140. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/views/layouts/mailer.text.erb +0 -0
  141. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/views/pwa/service-worker.js +0 -0
  142. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/bin/rails +0 -0
  143. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/boot.rb +0 -0
  144. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/database.yml +0 -0
  145. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/environment.rb +0 -0
  146. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/environments/development.rb +0 -0
  147. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/environments/production.rb +0 -0
  148. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/environments/test.rb +0 -0
  149. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/initializers/assets.rb +0 -0
  150. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/initializers/content_security_policy.rb +0 -0
  151. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/initializers/filter_parameter_logging.rb +0 -0
  152. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/initializers/inflections.rb +0 -0
  153. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/locales/en.yml +0 -0
  154. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/puma.rb +0 -0
  155. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/storage.yml +0 -0
  156. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config.ru +0 -0
  157. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/db/seeds.rb +0 -0
  158. /package/template/src/templates/{rails-app/workspace/store/script → default/workspace/_debug_app/lib/tasks}/.keep +0 -0
  159. /package/template/src/templates/{rails-app/workspace/store/storage → default/workspace/_debug_app/log}/.keep +0 -0
  160. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/400.html +0 -0
  161. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/404.html +0 -0
  162. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/406-unsupported-browser.html +0 -0
  163. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/422.html +0 -0
  164. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/500.html +0 -0
  165. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/icon.png +0 -0
  166. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/icon.svg +0 -0
  167. /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/robots.txt +0 -0
  168. /package/template/src/templates/{rails-app/workspace/store/test/controllers → default/workspace/_debug_app/script}/.keep +0 -0
  169. /package/template/src/templates/{rails-app/workspace/store/test/helpers → default/workspace/_debug_app/storage}/.keep +0 -0
  170. /package/template/src/templates/{rails-app/workspace/store/test/integration → default/workspace/_debug_app/test/controllers}/.keep +0 -0
  171. /package/template/src/templates/{rails-app/workspace/store/tmp → default/workspace/_debug_app/test/fixtures/files}/.keep +0 -0
  172. /package/template/src/templates/{rails-app/workspace/store/tmp/pids → default/workspace/_debug_app/test/helpers}/.keep +0 -0
  173. /package/template/src/templates/{rails-app/workspace/store/tmp/storage → default/workspace/_debug_app/test/integration}/.keep +0 -0
  174. /package/template/src/templates/{rails-app/workspace/store/vendor/javascripts → default/workspace/_debug_app/test/mailers}/.keep +0 -0
  175. /package/template/src/templates/rails-app/workspace/{store/.ruby-version → .ruby-version} +0 -0
  176. /package/template/src/templates/rails-app/workspace/{store/Gemfile → Gemfile} +0 -0
  177. /package/template/src/templates/rails-app/workspace/{store/app → app}/javascript/application.js +0 -0
  178. /package/template/src/templates/rails-app/workspace/{store/app → app}/javascript/controllers/application.js +0 -0
  179. /package/template/src/templates/rails-app/workspace/{store/app → app}/javascript/controllers/index.js +0 -0
  180. /package/template/src/templates/rails-app/workspace/{store/bin → bin}/importmap +0 -0
  181. /package/template/src/templates/rails-app/workspace/{store/config → config}/cable.yml +0 -0
  182. /package/template/src/templates/rails-app/workspace/{store/config → config}/credentials.yml.enc +0 -0
  183. /package/template/src/templates/rails-app/workspace/{store/config → config}/importmap.rb +0 -0
  184. /package/template/src/templates/rails-app/workspace/{store/config → config}/master.key +0 -0
  185. /package/template/src/templates/rails-app/workspace/{store/test → test}/test_helper.rb +0 -0
@@ -0,0 +1,389 @@
1
+ ---
2
+ name: tutorial-lesson-config
3
+ description: |
4
+ Use this skill whenever configuring lesson frontmatter or checking inheritance rules.
5
+ Trigger on: 'frontmatter', 'prepareCommands', 'mainCommand', 'editor config', 'terminal
6
+ config', 'preview config', 'configuration inheritance', 'focus file', 'i18n', 'allowEdits',
7
+ 'previews', 'autoReload', 'scope', 'defaults', 'what inherits', 'does X inherit',
8
+ 'invalid combination', 'constraint', or any YAML frontmatter question — even without
9
+ mentioning configuration. Authoritative reference for all frontmatter options, inheritance
10
+ rules, defaults, and invalid-combination constraints with Rails-specific patterns. Do NOT
11
+ guess frontmatter without this skill. Do NOT use for content hierarchy
12
+ (use tutorial-content-structure) or file organization (use rails-file-management).
13
+ ---
14
+
15
+ # Tutorial Lesson Configuration
16
+
17
+ Complete reference for configuring lessons, with Rails-specific defaults and patterns.
18
+
19
+ ## Configuration Cascade
20
+
21
+ Configuration **inherits downward**: Tutorial > Part > Chapter > Lesson. Set shared defaults at the tutorial level; override per-lesson as needed.
22
+
23
+ ```
24
+ meta.md (type: tutorial) ← base defaults for all lessons
25
+ meta.md (type: part) ← overrides for this part's lessons
26
+ meta.md (type: chapter) ← overrides for this chapter's lessons
27
+ content.md (type: lesson) ← final per-lesson overrides
28
+ ```
29
+
30
+ **Rails convention:** Set these once in the tutorial root `meta.md`:
31
+
32
+ ```yaml
33
+ prepareCommands:
34
+ - ['npm install', 'Preparing Ruby runtime']
35
+ terminalBlockingPrepareCommandsCount: 1
36
+ previews: false
37
+ filesystem:
38
+ watch: ['/*.json', '/workspace/**/*']
39
+ terminal:
40
+ open: true
41
+ panels:
42
+ - type: terminal
43
+ id: 'cmds'
44
+ title: 'Command Line'
45
+ allowRedirects: true
46
+ - ['output', 'Setup Logs']
47
+ ```
48
+
49
+ Then override only what changes per-lesson (e.g., enable `previews: [3000]` for lessons with a running server).
50
+
51
+ ## Inheritance Rules
52
+
53
+ ### Properties That Inherit (via cascade)
54
+
55
+ These properties are resolved through the cascade (Tutorial → Part → Chapter → Lesson). The **most specific** (lesson-level) value wins. For plain objects, child and parent are deep-merged; for arrays and primitives, the child **replaces** the parent entirely.
56
+
57
+ | Property | Merge behavior |
58
+ |----------|---------------|
59
+ | `mainCommand` | Replace |
60
+ | `prepareCommands` | **Replace** (not merge — if a lesson sets this, it completely overrides the parent) |
61
+ | `terminalBlockingPrepareCommandsCount` | Replace |
62
+ | `previews` | Replace |
63
+ | `autoReload` | Replace |
64
+ | `template` | Replace |
65
+ | `terminal` | Deep-merge if both are objects; replace if either is a primitive (`true`/`false`) |
66
+ | `editor` | Deep-merge if both are objects; replace if either is a primitive |
67
+ | `focus` | Replace |
68
+ | `i18n` | Deep-merge (lesson keys override parent keys; unset keys fall through) |
69
+ | `meta` | Deep-merge |
70
+ | `editPageLink` | Replace |
71
+ | `openInStackBlitz` | Replace |
72
+ | `downloadAsZip` | Replace |
73
+ | `filesystem` | Deep-merge |
74
+
75
+ ### Properties That Do NOT Inherit
76
+
77
+ These are **per-lesson only** and must be set on each lesson that needs them:
78
+
79
+ | Property | Why no inheritance |
80
+ |----------|-------------------|
81
+ | `custom` (including `custom.shell.workdir`) | Not in the cascade — set it on every lesson |
82
+ | `scope` | Lesson-specific file tree filter |
83
+ | `hideRoot` | Lesson-specific file tree option |
84
+
85
+ **Critical:** `custom.shell.workdir` must be set on **every lesson** that needs a custom terminal working directory. It will NOT be inherited from a part or tutorial `meta.md`.
86
+
87
+ **Critical:** When a lesson overrides `prepareCommands`, it **replaces** the entire array from the parent. If the tutorial root sets `prepareCommands: [['npm install', 'Preparing Ruby runtime']]` and a lesson needs to add `db:prepare`, the lesson must include **both** commands:
88
+
89
+ ```yaml
90
+ # WRONG — npm install is lost
91
+ prepareCommands:
92
+ - ['node scripts/rails.js db:prepare', 'Prepare database']
93
+
94
+ # CORRECT — include all commands
95
+ prepareCommands:
96
+ - ['npm install', 'Preparing Ruby runtime']
97
+ - ['node scripts/rails.js db:prepare', 'Prepare database']
98
+ ```
99
+
100
+ ## Editor Configuration
101
+
102
+ ### Show/Hide Editor
103
+
104
+ ```yaml
105
+ editor: false # Hide editor entirely (terminal-only lessons)
106
+ editor: true # Show editor (default)
107
+ ```
108
+
109
+ ### File Tree Options
110
+
111
+ ```yaml
112
+ editor:
113
+ fileTree: false # Hide file tree, show only editor tabs
114
+ fileTree:
115
+ allowEdits: true # Allow creating files/folders anywhere
116
+ allowEdits: "/workspace/**" # Allow edits matching glob
117
+ allowEdits: # Multiple glob patterns
118
+ - "/workspace/app/**"
119
+ - "/workspace/config/**"
120
+ ```
121
+
122
+ ### Focus File
123
+
124
+ Auto-open a specific file in the editor when the lesson loads:
125
+
126
+ ```yaml
127
+ focus: /workspace/app/controllers/products_controller.rb
128
+ ```
129
+
130
+ **Path must be absolute** from the WebContainer root. For Rails apps, this is typically `/workspace/<app-name>/...`.
131
+
132
+ ### File Tree Scope and Root
133
+
134
+ ```yaml
135
+ scope: /workspace # Only show files under this path in the tree
136
+ hideRoot: true # Hide the "/" root node (default: true)
137
+ ```
138
+
139
+ `scope` is useful to avoid exposing infrastructure files (`bin/`, `lib/`, `scripts/`) to tutorial users.
140
+
141
+ ## Terminal Configuration
142
+
143
+ ### Basic
144
+
145
+ ```yaml
146
+ terminal: false # Hide terminal entirely
147
+ terminal: true # Show with defaults
148
+ ```
149
+
150
+ ### Panel Configuration
151
+
152
+ ```yaml
153
+ terminal:
154
+ open: true # Open terminal panel by default
155
+ activePanel: 0 # Which tab is active (0-indexed)
156
+ panels:
157
+ - type: terminal # Interactive terminal
158
+ id: 'cmds' # Persistent session ID (survives lesson navigation)
159
+ title: 'Command Line'
160
+ allowRedirects: true
161
+ allowCommands: # Restrict allowed commands (optional)
162
+ - rails
163
+ - ruby
164
+ - node
165
+ - type: output # Read-only output panel (max 1 per lesson)
166
+ title: 'Setup Logs'
167
+ ```
168
+
169
+ **Shorthand panel syntax:**
170
+
171
+ ```yaml
172
+ panels:
173
+ - terminal # Interactive terminal, default title
174
+ - output # Read-only output, default title
175
+ - [terminal, "Rails Console"] # Interactive with custom title
176
+ - ['output', 'Setup Logs'] # Read-only with custom title
177
+ ```
178
+
179
+ **Persistent sessions:** Use `id` to keep terminal state across lesson navigation. The user's terminal history and running processes persist when they switch between lessons that share the same `id`.
180
+
181
+ ### Output Panel
182
+
183
+ Only **one** `output` panel is allowed per lesson. It captures output from `prepareCommands` and `mainCommand`.
184
+
185
+ ## Preview Configuration
186
+
187
+ ### Basic
188
+
189
+ ```yaml
190
+ previews: false # No preview panel
191
+ previews: true # Auto-detect preview
192
+ previews: [3000] # Show preview for port 3000
193
+ ```
194
+
195
+ ### Advanced
196
+
197
+ ```yaml
198
+ previews:
199
+ - 3000 # Port only
200
+ - "3000/products" # Port with pathname
201
+ - [3000, "Rails App"] # Port with title
202
+ - [3000, "Rails App", "/products"] # Port, title, pathname
203
+ - { port: 3000, title: "App", pathname: "/products" } # Object form
204
+ ```
205
+
206
+ ### Auto-Reload
207
+
208
+ ```yaml
209
+ autoReload: true # Force preview reload when navigating to this lesson
210
+ ```
211
+
212
+ Useful for lessons where the preview state may be stale from a previous lesson.
213
+
214
+ ## Commands
215
+
216
+ ### prepareCommands
217
+
218
+ Commands that run **before** the lesson is interactive. Shown as progress steps to the user:
219
+
220
+ ```yaml
221
+ prepareCommands:
222
+ - 'npm install' # String form
223
+ - ['npm install', 'Preparing Ruby runtime'] # [command, label]
224
+ - { command: 'node scripts/rails.js db:prepare', title: 'Preparing database' } # Object form
225
+ ```
226
+
227
+ **Rails patterns:**
228
+
229
+ ```yaml
230
+ # Basic — just install WASM runtime (set at tutorial level)
231
+ prepareCommands:
232
+ - ['npm install', 'Preparing Ruby runtime']
233
+
234
+ # With database — for lessons that need migrations/seeds
235
+ prepareCommands:
236
+ - ['npm install', 'Preparing Ruby runtime']
237
+ - ['node scripts/rails.js db:prepare', 'Prepare development database']
238
+ ```
239
+
240
+ ### terminalBlockingPrepareCommandsCount
241
+
242
+ How many `prepareCommands` must finish before the terminal becomes interactive:
243
+
244
+ ```yaml
245
+ terminalBlockingPrepareCommandsCount: 1 # Block until npm install finishes
246
+ ```
247
+
248
+ ### mainCommand
249
+
250
+ The primary long-running process (usually the dev server). Runs after all `prepareCommands` complete:
251
+
252
+ ```yaml
253
+ mainCommand: ['node scripts/rails.js server', 'Starting Rails server']
254
+ ```
255
+
256
+ **Important:** Use `node scripts/rails.js server` — not `rails server` — because the Rails CLI dispatches through Node.js wrapper scripts in this WASM environment.
257
+
258
+ ## Filesystem Watching
259
+
260
+ ```yaml
261
+ filesystem:
262
+ watch: true # Watch all files
263
+ watch: ['/*.json', '/workspace/**/*'] # Watch specific patterns
264
+ ```
265
+
266
+ For Rails tutorials, watch `/workspace/**/*` so the preview reflects file changes in the Rails app.
267
+
268
+ ## Defaults
269
+
270
+ When a property is not set at any level in the cascade, these defaults apply:
271
+
272
+ | Property | Default | Effect |
273
+ |----------|---------|--------|
274
+ | `template` | `'default'` | Uses the base Rails WASM runtime template |
275
+ | `editor` | (unset) | Editor is shown with default file tree |
276
+ | `terminal` | (unset) | One read-only "Output" panel, initially closed |
277
+ | `previews` | `true` | Auto-detect: shows preview for the first port that opens |
278
+ | `autoReload` | (unset) | Preview is not force-reloaded on navigation |
279
+ | `focus` | (unset) | No file auto-opened in editor |
280
+ | `openInStackBlitz` | `true` | "Open in StackBlitz" button shown |
281
+ | `downloadAsZip` | `false` | Download button hidden |
282
+ | `mainCommand` | (unset) | No long-running process started |
283
+ | `prepareCommands` | (unset) | No preparation steps |
284
+ | `filesystem.watch` | (unset) | No file watching |
285
+ | `scope` | (unset) | All files visible in tree |
286
+ | `hideRoot` | `true` | Root "/" node hidden in file tree |
287
+ | `custom` | (unset) | No custom fields |
288
+
289
+ ## Constraints
290
+
291
+ Invalid or problematic frontmatter combinations that cause silent failures:
292
+
293
+ | Combination | Problem | Fix |
294
+ |-------------|---------|-----|
295
+ | `focus: /path/...` with `editor: false` | Focus is silently ignored — no editor to open the file in | Remove `focus` or set `editor: true` |
296
+ | `previews: [3000]` without `mainCommand` | Nothing starts a server on port 3000 — preview stays blank | Add `mainCommand: ['node scripts/rails.js server', 'Starting Rails server']` |
297
+ | `mainCommand: 'rails server'` | Bare `rails` won't work — commands must go through the Node.js wrapper | Use `mainCommand: ['node scripts/rails.js server', 'Starting Rails server']` |
298
+ | Lesson `prepareCommands` without `npm install` | WASM runtime never loads — everything else fails | Always include `['npm install', 'Preparing Ruby runtime']` as the first prepare command |
299
+ | `previews` without `prepareCommands` including `npm install` | Runtime not loaded, server can't start | Add `prepareCommands` with `npm install` (or inherit from tutorial root) |
300
+ | `terminal: false` with `mainCommand` set | Terminal hidden but `mainCommand` still runs — output is invisible | Either show terminal or remove `mainCommand` |
301
+ | `custom.shell.workdir` set only in `meta.md` | `custom` doesn't inherit — terminal won't cd in lessons | Set `custom.shell.workdir` on each lesson's `content.md` |
302
+
303
+ ## Other Options
304
+
305
+ ### Custom Shell Working Directory
306
+
307
+ ```yaml
308
+ custom:
309
+ shell:
310
+ workdir: "/workspace"
311
+ ```
312
+
313
+ Sets the terminal's working directory by sending `cd /home/tutorial<workdir> && clear` to the first terminal panel on lesson load. The path is constructed by prepending `/home/tutorial` to the `workdir` value, so `workdir: "/workspace"` sends `cd /home/tutorial/workspace && clear`. This is a **Rails-tutorial-specific** feature (implemented via `ShellConfigurator` in this template, not upstream TutorialKit). Essential for Rails tutorials where the app lives at `/workspace`.
314
+
315
+ **Does not inherit.** Must be set on every lesson that needs it (see Inheritance Rules above).
316
+
317
+ ### Template Selection
318
+
319
+ ```yaml
320
+ template: default # Use the default (base Rails) template
321
+ template: rails-app # Use a template with pre-generated Rails app
322
+ ```
323
+
324
+ Templates live in `src/templates/`. Each lesson can also override via `_files/.tk-config.json`.
325
+
326
+ ### Download and StackBlitz
327
+
328
+ ```yaml
329
+ openInStackBlitz: false # Hide "Open in StackBlitz" button (default: true)
330
+ openInStackBlitz: # Object form with project customization
331
+ projectTitle: "My Rails Tutorial"
332
+ projectDescription: "A Rails CRUD app"
333
+ projectTemplate: "node" # html | node | angular-cli | create-react-app | javascript | polymer | typescript | vue
334
+ downloadAsZip: true # Allow downloading lesson code (default: false)
335
+ downloadAsZip:
336
+ filename: "rails-crud-app" # Custom zip filename
337
+ ```
338
+
339
+ ### Edit Page Link
340
+
341
+ ```yaml
342
+ editPageLink: "https://github.com/your-org/your-tutorial/edit/main/src/content/tutorial/${path}"
343
+ ```
344
+
345
+ ### Meta Tags
346
+
347
+ ```yaml
348
+ meta:
349
+ title: "Learn Rails CRUD Operations"
350
+ description: "Build a product catalog with full CRUD in Ruby on Rails"
351
+ image: "/og-image.png"
352
+ ```
353
+
354
+ ## i18n — Customize UI Text
355
+
356
+ Override any UI label at any level in the cascade:
357
+
358
+ ```yaml
359
+ i18n:
360
+ solveButtonText: "Show Answer"
361
+ resetButtonText: "Start Over"
362
+ prepareEnvironmentTitleText: "Setting Up Rails"
363
+ toggleTerminalButtonText: "Terminal"
364
+ defaultPreviewTitleText: "Rails App"
365
+ startWebContainerText: "Launch Tutorial"
366
+ ```
367
+
368
+ All available keys:
369
+
370
+ | Key | Default |
371
+ |-----|---------|
372
+ | `partTemplate` | `"Part ${index}: ${title}"` |
373
+ | `editPageText` | `"Edit this page"` |
374
+ | `webcontainerLinkText` | `"Powered by WebContainers"` |
375
+ | `startWebContainerText` | `"Run this tutorial"` |
376
+ | `noPreviewNorStepsText` | `"No preview to run nor steps to show"` |
377
+ | `filesTitleText` | `"Files"` |
378
+ | `fileTreeCreateFileText` | `"Create file"` |
379
+ | `fileTreeCreateFolderText` | `"Create folder"` |
380
+ | `fileTreeActionNotAllowedText` | `"This action is not allowed"` |
381
+ | `fileTreeFileExistsAlreadyText` | `"File exists on filesystem already"` |
382
+ | `fileTreeAllowedPatternsText` | `"Created files and folders must match following patterns:"` |
383
+ | `confirmationText` | `"OK"` |
384
+ | `prepareEnvironmentTitleText` | `"Preparing Environment"` |
385
+ | `defaultPreviewTitleText` | `"Preview"` |
386
+ | `reloadPreviewTitle` | `"Reload Preview"` |
387
+ | `toggleTerminalButtonText` | `"Toggle Terminal"` |
388
+ | `solveButtonText` | `"Solve"` |
389
+ | `resetButtonText` | `"Reset"` |