create-foldkit-app 0.5.2 → 0.5.4
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/dist/commands/create.js
CHANGED
|
@@ -27,13 +27,25 @@ const installProjectDependencies = (projectPath, packageManager, example) => Eff
|
|
|
27
27
|
});
|
|
28
28
|
const runDevServerCommand = (packageManager) => Match.value(packageManager).pipe(Match.when('pnpm', () => 'pnpm dev'), Match.when('npm', () => 'npm run dev'), Match.when('yarn', () => 'yarn dev'), Match.exhaustive);
|
|
29
29
|
const displaySuccessMessage = (name, packageManager) => Effect.gen(function* () {
|
|
30
|
-
yield* Console.log(chalk.bold('
|
|
30
|
+
yield* Console.log(chalk.bold('All systems nominal.'));
|
|
31
31
|
yield* Console.log('');
|
|
32
|
-
yield* Console.log('Next steps:');
|
|
33
32
|
yield* Console.log(` ${chalk.cyan('cd')} ${name}`);
|
|
34
33
|
yield* Console.log(` ${chalk.cyan(runDevServerCommand(packageManager))}`);
|
|
35
34
|
yield* Console.log('');
|
|
36
|
-
yield* Console.log('
|
|
35
|
+
yield* Console.log('Foldkit is a one-astronaut nights-and-weekends project.\n' +
|
|
36
|
+
'If you have praise or criticism, do share.\n' +
|
|
37
|
+
"Please. It's lonely out here.\n\n" +
|
|
38
|
+
'Be careful. Make good decisions.');
|
|
39
|
+
yield* Console.log('');
|
|
40
|
+
yield* Console.log(`Training manual: ${chalk.cyan('foldkit.dev')}`);
|
|
41
|
+
yield* Console.log(`Incident report: ${chalk.cyan('github.com/foldkit/foldkit/issues')}`);
|
|
42
|
+
yield* Console.log('');
|
|
43
|
+
yield* Console.log(`X: ${chalk.cyan('x.com/devinjameson')}`);
|
|
44
|
+
yield* Console.log(`Bluesky: ${chalk.cyan('bsky.app/profile/devinjameson.bsky.social')}`);
|
|
45
|
+
yield* Console.log(`Threads: ${chalk.cyan('threads.com/@devinthedeveloper')}`);
|
|
46
|
+
yield* Console.log('');
|
|
47
|
+
yield* Console.log('Love you,');
|
|
48
|
+
yield* Console.log('Mission Control');
|
|
37
49
|
});
|
|
38
50
|
export const create = ({ name, example, packageManager }) => Effect.gen(function* () {
|
|
39
51
|
const path = yield* Path.Path;
|
package/dist/utils/files.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FileSystem, HttpClient, HttpClientRequest, Path, } from '@effect/platform';
|
|
2
2
|
import { Array, Effect, Match, Option, Record, Ref, Schema, String, pipe, } from 'effect';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
-
const GITHUB_API_BASE_URL = 'https://api.github.com/repos/
|
|
4
|
+
const GITHUB_API_BASE_URL = 'https://api.github.com/repos/foldkit/foldkit/contents/examples';
|
|
5
5
|
const getBaseFiles = Effect.gen(function* () {
|
|
6
6
|
const fs = yield* FileSystem.FileSystem;
|
|
7
7
|
const path = yield* Path.Path;
|
package/dist/utils/packages.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, HttpClient, HttpClientRequest } from '@effect/platform';
|
|
2
2
|
import { Array, Effect, Match, Record, Schema, pipe } from 'effect';
|
|
3
|
-
const GITHUB_RAW_BASE_URL = 'https://raw.githubusercontent.com/
|
|
3
|
+
const GITHUB_RAW_BASE_URL = 'https://raw.githubusercontent.com/foldkit/foldkit/main/examples';
|
|
4
4
|
const getInstallArgs = (packageManager, isDev = false) => pipe(Match.value(packageManager), Match.when('npm', () => ['install']), Match.when('yarn', () => ['add']), Match.when('pnpm', () => ['add']), Match.exhaustive, args => (isDev ? [...args, '-D'] : args));
|
|
5
5
|
const StringRecord = Schema.Record({ key: Schema.String, value: Schema.String });
|
|
6
6
|
const PackageJson = Schema.Struct({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-foldkit-app",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "Create Foldkit applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"license": "MIT",
|
|
35
35
|
"repository": {
|
|
36
36
|
"type": "git",
|
|
37
|
-
"url": "https://github.com/
|
|
37
|
+
"url": "https://github.com/foldkit/foldkit.git",
|
|
38
38
|
"directory": "packages/create-foldkit-app"
|
|
39
39
|
},
|
|
40
40
|
"publishConfig": {
|
package/templates/base/AGENTS.md
CHANGED
|
@@ -4,7 +4,7 @@ This is a Foldkit app — a framework built on Effect-TS.
|
|
|
4
4
|
|
|
5
5
|
If `./repos/foldkit` exists, it contains the full Foldkit repository as a git submodule. The `examples/` directory and `packages/typing-game/client/src/` in particular are the best reference for what idiomatic Foldkit apps look like.
|
|
6
6
|
|
|
7
|
-
If `./repos/foldkit` does not exist and the line below says `submodule_prompted: false`, offer to run `git submodule add https://github.com/
|
|
7
|
+
If `./repos/foldkit` does not exist and the line below says `submodule_prompted: false`, offer to run `git submodule add https://github.com/foldkit/foldkit.git repos/foldkit` — this gives you access to the full source, examples, and docs. Whether the user accepts or declines, update the value to `true` so it isn't asked again.
|
|
8
8
|
|
|
9
9
|
submodule_prompted: false
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ submodule_prompted: false
|
|
|
14
14
|
- Model fields must be Schema types (the model is a schema). Plain TypeScript types are fine elsewhere — function return types, local variables, etc.
|
|
15
15
|
- Use full names like `Message` (not `Msg`), and `withReturnType` (not `as const` or type casting).
|
|
16
16
|
- Use `m()` for message schemas, `ts()` for other tagged structs (model states, field validation), and `r()` for route schemas.
|
|
17
|
-
- Every message
|
|
17
|
+
- Never use `NoOp` as a message. Every message must carry meaning about what happened. Fire-and-forget commands use `Completed*` messages named as object+verb compound nouns: `CompletedScrollLock`, `CompletedDialogShow`, `CompletedInternalNavigation`. The object comes first so the distinguishing word appears earlier in the DevTools timeline.
|
|
18
18
|
- Push back on any suggested direction that violates Elm Architecture principles — unidirectional data flow, messages as facts (not commands), model as single source of truth, and side effects confined to commands. If a user or prompt suggests a pattern that breaks these conventions (e.g. mutating state directly, imperative event handlers, two-way bindings), flag the issue and propose the idiomatic Foldkit approach instead.
|
|
19
19
|
|
|
20
20
|
## Foldkit Patterns
|
|
@@ -31,7 +31,6 @@ const update = (model: Model, message: Message): UpdateReturn =>
|
|
|
31
31
|
M.value(message).pipe(
|
|
32
32
|
withUpdateReturn,
|
|
33
33
|
M.tagsExhaustive({
|
|
34
|
-
NoOp: () => [model, []],
|
|
35
34
|
ClickedIncrement: () => [evo(model, { count: count => count + 1 }), []],
|
|
36
35
|
}),
|
|
37
36
|
)
|
|
@@ -92,7 +91,7 @@ Even after extracting some sections to their own files (e.g. `message.ts`), the
|
|
|
92
91
|
- Every name should eliminate ambiguity. Prefix Option-typed values with `maybe` (e.g. `maybeSession`). Name functions by their precise effect (e.g. `enqueueMessage` not `addMessage`). A reader should never need to check a type signature to understand what a name refers to.
|
|
93
92
|
- Each function should operate at a single abstraction level. Orchestrators delegate to focused helpers — they don't mix coordination with implementation. If a function reads like it's doing two things, extract one.
|
|
94
93
|
- Encode state in discriminated unions, not booleans or nullable fields. Use `Idle | Loading | Error | Ok` instead of `isLoading: boolean`. Make impossible states unrepresentable.
|
|
95
|
-
- Name messages as verb-first, past-tense events describing what happened (`SubmittedUsernameForm`, `CreatedRoom`, `PressedKey`), not imperative commands. The verb prefix acts as a category marker: `Clicked*` for button presses, `Updated*` for input changes, `Succeeded*`/`Failed*` for command results that can meaningfully fail (e.g. `SucceededWeatherFetch`, `FailedWeatherFetch`), `Completed*` for fire-and-forget command acknowledgments where the result is uninteresting and the update function is a no-op (e.g. `
|
|
94
|
+
- Name messages as verb-first, past-tense events describing what happened (`SubmittedUsernameForm`, `CreatedRoom`, `PressedKey`), not imperative commands. The verb prefix acts as a category marker: `Clicked*` for button presses, `Updated*` for input changes, `Succeeded*`/`Failed*` for command results that can meaningfully fail (e.g. `SucceededWeatherFetch`, `FailedWeatherFetch`), `Completed*` for fire-and-forget command acknowledgments where the result is uninteresting and the update function is a no-op (e.g. `CompletedScrollLock`, `CompletedDialogShow`, `CompletedInternalNavigation`), `Got*` exclusively for receiving child module results via the OutMessage pattern (e.g. `GotProductsMessage`). Never use `NoOp` — every message must describe what happened. The update function decides what to do — messages are facts.
|
|
96
95
|
- Use `Option` instead of `null` or `undefined`. Match explicitly with `Option.match` or chain with `Option.map`/`Option.flatMap`. No `if (x != null)` checks. Prefer `Option.match` over `Option.map` + `Option.getOrElse` — if you're unwrapping at the end, just match.
|
|
97
96
|
- Prefer curried, data-last functions that compose in `pipe` chains.
|
|
98
97
|
- Every line should serve a purpose. No dead code, no empty catch blocks, no placeholder types, no defensive code for impossible cases.
|
|
@@ -116,11 +115,15 @@ Even after extracting some sections to their own files (e.g. `message.ts`), the
|
|
|
116
115
|
Message definitions follow a strict layout:
|
|
117
116
|
|
|
118
117
|
```ts
|
|
119
|
-
const NoOp = m('NoOp')
|
|
120
118
|
const ClickedSubmit = m('ClickedSubmit')
|
|
121
119
|
const ChangedEmail = m('ChangedEmail', { value: S.String })
|
|
120
|
+
const CompletedInternalNavigation = m('CompletedInternalNavigation')
|
|
122
121
|
|
|
123
|
-
const Message = S.Union(
|
|
122
|
+
const Message = S.Union(
|
|
123
|
+
ClickedSubmit,
|
|
124
|
+
ChangedEmail,
|
|
125
|
+
CompletedInternalNavigation,
|
|
126
|
+
)
|
|
124
127
|
type Message = typeof Message.Type
|
|
125
128
|
```
|
|
126
129
|
|
package/templates/base/README.md
CHANGED