@fougere/cli 0.2.0-alpha.1 → 0.3.0-alpha.0

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 (74) hide show
  1. package/README.md +10 -1
  2. package/app/commands/BuildCommand.ts +39 -0
  3. package/app/commands/CallCommand.ts +4 -4
  4. package/app/commands/CheckCommand.ts +3 -2
  5. package/app/commands/ExplainCommand.ts +77 -0
  6. package/app/commands/FreezeCommand.ts +107 -0
  7. package/app/commands/GrantCommand.ts +44 -0
  8. package/app/commands/GraphCommand.ts +1 -1
  9. package/app/commands/KeysCommand.ts +56 -0
  10. package/app/commands/MigrateCommand.ts +54 -0
  11. package/app/commands/NewCommand.ts +6 -6
  12. package/app/commands/ServeCommand.ts +85 -9
  13. package/app/commands/grant-material.ts +5 -0
  14. package/dist/bin.js +54 -8
  15. package/dist/bin.js.map +1 -1
  16. package/dist/bridge.d.ts.map +1 -1
  17. package/dist/bridge.js +6 -6
  18. package/dist/bridge.js.map +1 -1
  19. package/dist/runner.d.ts.map +1 -1
  20. package/dist/runner.js +7 -7
  21. package/dist/runner.js.map +1 -1
  22. package/dist/theme.d.ts +10 -0
  23. package/dist/theme.d.ts.map +1 -0
  24. package/dist/theme.js +10 -0
  25. package/dist/theme.js.map +1 -0
  26. package/dist/ui.d.ts +74 -0
  27. package/dist/ui.d.ts.map +1 -0
  28. package/dist/ui.js +111 -0
  29. package/dist/ui.js.map +1 -0
  30. package/fronds/analysis/entities/Build.ts +7 -0
  31. package/fronds/analysis/entities/Explain.ts +8 -0
  32. package/fronds/analysis/entities/Freeze.ts +7 -0
  33. package/fronds/analysis/entities/Migrate.ts +7 -0
  34. package/fronds/analysis/handlers/BuildHandler.ts +60 -0
  35. package/fronds/analysis/handlers/CheckHandler.ts +61 -35
  36. package/fronds/analysis/handlers/ExplainHandler.ts +214 -0
  37. package/fronds/analysis/handlers/FreezeHandler.ts +172 -0
  38. package/fronds/analysis/handlers/MigrateHandler.ts +97 -0
  39. package/fronds/analysis/services/ProjectScan.ts +23 -7
  40. package/fronds/analysis/versions.ts +58 -0
  41. package/fronds/scaffold/entities/Grant.ts +6 -0
  42. package/fronds/scaffold/entities/Keys.ts +4 -0
  43. package/fronds/scaffold/entities/Serve.ts +2 -1
  44. package/fronds/scaffold/handlers/BuildFrondHandler.ts +11 -13
  45. package/fronds/scaffold/handlers/GrantHandler.ts +8 -0
  46. package/fronds/scaffold/handlers/KeysHandler.ts +8 -0
  47. package/fronds/scaffold/handlers/SyncHandler.ts +27 -24
  48. package/fronds/scaffold/services/ProjectWriter.ts +29 -10
  49. package/package.json +10 -8
  50. package/templates/admin/fronds/admin/handlers/UserHandler.ts +3 -5
  51. package/templates/admin/fronds/admin/package.json +1 -1
  52. package/templates/api/fronds/api/handlers/TaskHandler.ts +3 -5
  53. package/templates/api/fronds/api/package.json +1 -1
  54. package/templates/apps/nuxt/app/pages/index.vue +1 -1
  55. package/templates/apps/nuxt/package.json +1 -1
  56. package/templates/blog/app/pages/posts/index.vue +1 -1
  57. package/templates/blog/app/pages/posts/manage.vue +1 -1
  58. package/templates/blog/app/pages/posts/new.vue +1 -1
  59. package/templates/blog/fronds/blog/handlers/PostHandler.ts +3 -5
  60. package/templates/blog/fronds/blog/package.json +1 -1
  61. package/templates/flat/AGENTS.md +14 -0
  62. package/templates/flat/CLAUDE.md +27 -5
  63. package/templates/flat/package.json +1 -1
  64. package/templates/frond/AGENTS.md +14 -0
  65. package/templates/frond/CLAUDE.md +27 -5
  66. package/templates/frond/fronds/__name__/handlers/PostHandler.ts +3 -5
  67. package/templates/frond/fronds/__name__/package.json +1 -1
  68. package/templates/frond/package.json +1 -1
  69. package/templates/frond/serve.mjs +4 -3
  70. package/templates/fronds/blank/package.json +1 -1
  71. package/templates/fronds/blog/handlers/PostHandler.ts +2 -4
  72. package/templates/fronds/blog/package.json +1 -1
  73. package/templates/workspace/AGENTS.md +14 -0
  74. package/templates/workspace/CLAUDE.md +27 -5
@@ -0,0 +1,14 @@
1
+ # Working in this application
2
+
3
+ This project is built with **Fougere**. Read `CLAUDE.md` for the model and architecture guidance
4
+ that applies to every coding agent.
5
+
6
+ ## Required verification workflow
7
+
8
+ After every change to handlers, entities, Fronds, configuration, or topology:
9
+
10
+ 1. Run `fougere check`.
11
+ 2. Fix every deterministic error it reports before continuing.
12
+ 3. Run the relevant tests, then run `npx tsc -p fronds --noEmit`.
13
+
14
+ `fougere check` is the Fougere model barrier; tests and TypeScript come after it passes.
@@ -35,8 +35,8 @@ Before adding a surface, reach for its **projection**:
35
35
 
36
36
  | surface | the call |
37
37
  |---|---|
38
- | REST | `generateRoutes(app)` then `registerRoutes(router, routes)` — `@fougere/schema-rest` |
39
- | GraphQL | `registerAll(builder, app)` then `registerGraphQL(router, builder.toSchema())` — `@fougere/schema-graphql` |
38
+ | REST | `generateRoutes(app)` then `registerRoutes(router, routes)` — `@fougere/adapter-rest` |
39
+ | GraphQL | `registerAll(builder, app)` then `registerGraphQL(router, builder.toSchema())` — `@fougere/adapter-graphql` |
40
40
 
41
41
  Hand-writing the types (`buildSchema`, raw SDL, one Pothos resolver per field) rebuilds what the
42
42
  projection already derives, and drops the judge on the way. `registerType` / `registerOperations`
@@ -44,7 +44,18 @@ exist to add what a projection cannot derive — never to replace it.
44
44
 
45
45
  ## Reading data
46
46
 
47
- `EntityOrm`, injected by type, is the only data access:
47
+ Storage is reached through a repository. Never inject `EntityOrm` directly into a handler,
48
+ presenter or collector — the boot refuses it. With no repository file, ask for the default shape:
49
+
50
+ ```ts
51
+ import type { RepositoryOf } from '@fougere/core';
52
+ import Product from '../entities/Product.js';
53
+
54
+ constructor(private products: RepositoryOf<Product>) {}
55
+ ```
56
+
57
+ If the handler extends `Crud(Product)`, its inherited `this.orm` is already backed by that
58
+ repository; do not add a constructor. The repository forwards the guarded storage gestures:
48
59
 
49
60
  ```
50
61
  list(options?) every row — `options.where` filters, plus paging and sorting
@@ -56,10 +67,21 @@ create / update / delete
56
67
 
57
68
  Read a relation with `findAllBy`. Never read a whole table to filter it in memory.
58
69
 
70
+ When a query deserves a domain name, add `repositories/ProductRepository.ts` with
71
+ `class ProductRepository extends Repository(Product)`, put the query there, and inject
72
+ `ProductRepository`. A repository is registered as a provider and remains the only route to storage.
73
+
59
74
  ## Checking your work
60
75
 
76
+ After every change to handlers, entities, Fronds, configuration, or topology:
77
+
78
+ 1. Run `fougere check`.
79
+ 2. Fix every deterministic error it reports before continuing.
80
+ 3. Run the relevant tests, then run the project typecheck.
81
+
61
82
  ```bash
62
- npx tsc -p fronds --noEmit # the compiler — free, immediate, and it catches most of it
83
+ fougere check
84
+ npx tsc -p fronds --noEmit
63
85
  ```
64
86
 
65
- Run it. It is the first judge, and the cheapest.
87
+ `fougere check` is the Fougere model barrier; tests and TypeScript come after it passes.
@@ -10,7 +10,7 @@ export default class PostHandler extends Crud(Post) {
10
10
  if (!post) {
11
11
  throw new FougereError({ code: ErrorCode.NOT_FOUND, message: `Post '${id}' not found`, entity: 'post', operation: 'publish' });
12
12
  }
13
- if ((post as { status?: string }).status === 'published') {
13
+ if (post.status === 'published') {
14
14
  throw new FougereError({ code: ErrorCode.CONFLICT, message: 'Already published', entity: 'post', operation: 'publish' });
15
15
  }
16
16
  return this.orm.update(id, { status: 'published' });
@@ -18,9 +18,7 @@ export default class PostHandler extends Crud(Post) {
18
18
 
19
19
  /** Only published posts, projected to the card. */
20
20
  async published(): Promise<PostCard[]> {
21
- const all = await this.orm.list();
22
- return all
23
- .filter((p) => (p as { status?: string }).status === 'published')
24
- .map((p) => ({ id: String(p.id), title: String(p.title), status: 'published' })) as PostCard[];
21
+ const posts = await this.orm.list({ where: { status: 'published' } });
22
+ return posts.map(({ id, title, status }) => ({ id, title, status }));
25
23
  }
26
24
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "@frond/__name__",
2
+ "name": "@fronds/__name__",
3
3
  "version": "0.0.1",
4
4
  "type": "module",
5
5
  "exports": {
@@ -8,7 +8,7 @@
8
8
  "dependencies": {
9
9
  "@fougere/core": "latest",
10
10
  "@fougere/schema": "latest",
11
- "@fougere/runtime": "latest",
11
+ "@fougere/defaults": "latest",
12
12
  "@fougere/transport-http": "latest",
13
13
  "better-sqlite3": "^13.0.3",
14
14
  "kysely": "^0.28.17",
@@ -8,11 +8,12 @@
8
8
  * Nothing in the frond changes — only where it runs.
9
9
  */
10
10
  import { createJiti } from 'jiti';
11
- import { createLocalRunner, setModuleLoader, frondAliases, Logger } from '@fougere/core';
12
- import { bootAppFromConfig } from '@fougere/runtime';
11
+ import { createLocalRunner, Logger } from '@fougere/core';
12
+ import { setModuleLoader, frondAliases } from '@fougere/core/node';
13
+ import { bootAppFromConfig } from '@fougere/defaults';
13
14
  import { serve } from '@fougere/transport-http';
14
15
 
15
- // `frondAliases` is what makes `@frond/<neighbour>/entities/X.js` resolve — the
16
+ // `frondAliases` is what makes `@fronds/<neighbour>/entities/X.js` resolve — the
16
17
  // named form a frond uses for its neighbour. A bare jiti loads frond sources but
17
18
  // not that convention, so a collector or handler importing across fronds dies here
18
19
  // while the same code works in-process.
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "@frond/__name__",
2
+ "name": "@fronds/__name__",
3
3
  "version": "0.0.1",
4
4
  "type": "module",
5
5
  "exports": {
@@ -30,9 +30,7 @@ export default class PostHandler extends Crud(Post) {
30
30
 
31
31
  /** Only published posts, projected to the card. */
32
32
  async published(): Promise<PostCard[]> {
33
- const all = await this.orm.list();
34
- return all
35
- .filter((p) => p.status === 'published')
36
- .map(({ id, title, status }) => ({ id, title, status }));
33
+ const posts = await this.orm.list({ where: { status: 'published' } });
34
+ return posts.map(({ id, title, status }) => ({ id, title, status }));
37
35
  }
38
36
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "@frond/__name__",
2
+ "name": "@fronds/__name__",
3
3
  "version": "0.0.1",
4
4
  "type": "module",
5
5
  "exports": {
@@ -0,0 +1,14 @@
1
+ # Working in this application
2
+
3
+ This project is built with **Fougere**. Read `CLAUDE.md` for the model and architecture guidance
4
+ that applies to every coding agent.
5
+
6
+ ## Required verification workflow
7
+
8
+ After every change to handlers, entities, Fronds, configuration, or topology:
9
+
10
+ 1. Run `fougere check`.
11
+ 2. Fix every deterministic error it reports before continuing.
12
+ 3. Run the relevant tests, then run `pnpm typecheck`.
13
+
14
+ `fougere check` is the Fougere model barrier; tests and TypeScript come after it passes.
@@ -35,8 +35,8 @@ Before adding a surface, reach for its **projection**:
35
35
 
36
36
  | surface | the call |
37
37
  |---|---|
38
- | REST | `generateRoutes(app)` then `registerRoutes(router, routes)` — `@fougere/schema-rest` |
39
- | GraphQL | `registerAll(builder, app)` then `registerGraphQL(router, builder.toSchema())` — `@fougere/schema-graphql` |
38
+ | REST | `generateRoutes(app)` then `registerRoutes(router, routes)` — `@fougere/adapter-rest` |
39
+ | GraphQL | `registerAll(builder, app)` then `registerGraphQL(router, builder.toSchema())` — `@fougere/adapter-graphql` |
40
40
 
41
41
  Hand-writing the types (`buildSchema`, raw SDL, one Pothos resolver per field) rebuilds what the
42
42
  projection already derives, and drops the judge on the way. `registerType` / `registerOperations`
@@ -44,7 +44,18 @@ exist to add what a projection cannot derive — never to replace it.
44
44
 
45
45
  ## Reading data
46
46
 
47
- `EntityOrm`, injected by type, is the only data access:
47
+ Storage is reached through a repository. Never inject `EntityOrm` directly into a handler,
48
+ presenter or collector — the boot refuses it. With no repository file, ask for the default shape:
49
+
50
+ ```ts
51
+ import type { RepositoryOf } from '@fougere/core';
52
+ import Product from '../entities/Product.js';
53
+
54
+ constructor(private products: RepositoryOf<Product>) {}
55
+ ```
56
+
57
+ If the handler extends `Crud(Product)`, its inherited `this.orm` is already backed by that
58
+ repository; do not add a constructor. The repository forwards the guarded storage gestures:
48
59
 
49
60
  ```
50
61
  list(options?) every row — `options.where` filters, plus paging and sorting
@@ -56,10 +67,21 @@ create / update / delete
56
67
 
57
68
  Read a relation with `findAllBy`. Never read a whole table to filter it in memory.
58
69
 
70
+ When a query deserves a domain name, add `repositories/ProductRepository.ts` with
71
+ `class ProductRepository extends Repository(Product)`, put the query there, and inject
72
+ `ProductRepository`. A repository is registered as a provider and remains the only route to storage.
73
+
59
74
  ## Checking your work
60
75
 
76
+ After every change to handlers, entities, Fronds, configuration, or topology:
77
+
78
+ 1. Run `fougere check`.
79
+ 2. Fix every deterministic error it reports before continuing.
80
+ 3. Run the relevant tests, then run the project typecheck.
81
+
61
82
  ```bash
62
- pnpm typecheck # the compiler — free, immediate, and it catches most of it
83
+ fougere check
84
+ pnpm typecheck
63
85
  ```
64
86
 
65
- Run it. It is the first judge, and the cheapest.
87
+ `fougere check` is the Fougere model barrier; tests and TypeScript come after it passes.