generator-folklore 3.0.60 → 3.0.61

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.
@@ -5,9 +5,57 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _chalk = _interopRequireDefault(require("chalk"));
8
+ var _child_process = require("child_process");
8
9
  var _generator = _interopRequireDefault(require("../../lib/generator"));
9
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ const launchArgs = {
12
+ laravel: ['run', 'server', '--', '--no-open'],
13
+ html: ['run', 'server', '--', '--server', 'http', '--no-open']
14
+ };
15
+ const defaultUrls = {
16
+ laravel: 'https://localhost:8080',
17
+ html: 'http://localhost:8080'
18
+ };
10
19
  class AgentsGenerator extends _generator.default {
20
+ constructor(...args) {
21
+ super(...args);
22
+ this.option('git-host', {
23
+ type: String,
24
+ desc: 'Git host of the repository: github or gitlab (defaults to the host of the origin remote, or github)'
25
+ });
26
+ this.option('claude', {
27
+ type: Boolean,
28
+ desc: 'Write the Claude Code files: CLAUDE.md, .claude/settings.json and .claude/launch.json (--no-claude to skip them)',
29
+ defaults: true
30
+ });
31
+ this.option('type', {
32
+ type: String,
33
+ desc: 'Project type for the Claude Code browser preview: laravel (served through its .test domain) or html (served on localhost). Defaults to laravel when composer.json exists'
34
+ });
35
+ this.option('url', {
36
+ type: String,
37
+ desc: 'Url opened by the Claude Code browser preview (defaults to the dev server url)'
38
+ });
39
+ }
40
+ getGitHost() {
41
+ const {
42
+ 'git-host': gitHost = null
43
+ } = this.options;
44
+ if (gitHost !== null) {
45
+ return gitHost === 'gitlab' ? 'gitlab' : 'github';
46
+ }
47
+ try {
48
+ const remoteUrl = (0, _child_process.execFileSync)('git', ['remote', 'get-url', 'origin'], {
49
+ cwd: this.destinationRoot(),
50
+ encoding: 'utf8',
51
+ stdio: ['ignore', 'pipe', 'ignore']
52
+ });
53
+ return remoteUrl.includes('gitlab') ? 'gitlab' : 'github';
54
+ } catch {
55
+ // No git repository or no origin remote yet
56
+ return 'github';
57
+ }
58
+ }
11
59
  prompting() {
12
60
  if (this.options.quiet) {
13
61
  return;
@@ -16,15 +64,51 @@ class AgentsGenerator extends _generator.default {
16
64
  console.log('AGENTS.md Generator');
17
65
  console.log(_chalk.default.yellow('----------------------\n'));
18
66
  }
19
- writing() {
20
- const destPath = this.destinationPath('AGENTS.md');
21
- const hasComposerJson = this.fs.exists(this.destinationPath('composer.json'));
22
- const hasPackageJson = this.fs.exists(this.destinationPath('package.json'));
23
- const existingContent = this.fs.exists(destPath) ? this.fs.read(destPath) : '';
24
- const separator = '\n\n---\n\n';
25
- const parts = [this.fs.read(this.templatePath('general.md')), this.fs.read(this.templatePath('workflow.md')), hasComposerJson ? this.fs.read(this.templatePath('laravel.md')) : null, hasPackageJson ? this.fs.read(this.templatePath('frontend.md')) : null, hasComposerJson ? this.fs.read(this.templatePath('serve-laravel.md')) : null, !hasComposerJson && hasPackageJson ? this.fs.read(this.templatePath('serve-html.md')) : null, this.fs.read(this.templatePath('after.md'))].filter(it => it !== null).join(separator);
26
- const newContent = existingContent.length > 0 ? `${existingContent}${separator}${parts}` : parts;
27
- this.fs.write(destPath, newContent);
67
+ get writing() {
68
+ return {
69
+ agents() {
70
+ const destPath = this.destinationPath('AGENTS.md');
71
+ const hasComposerJson = this.fs.exists(this.destinationPath('composer.json'));
72
+ const hasPackageJson = this.fs.exists(this.destinationPath('package.json'));
73
+ const existingContent = this.fs.exists(destPath) ? this.fs.read(destPath) : '';
74
+ const separator = '\n\n---\n\n';
75
+ const parts = [this.fs.read(this.templatePath('general.md')), this.fs.read(this.templatePath(`workflow-${this.getGitHost()}.md`)), hasComposerJson ? this.fs.read(this.templatePath('laravel.md')) : null, hasPackageJson ? this.fs.read(this.templatePath('frontend.md')) : null, hasComposerJson ? this.fs.read(this.templatePath('serve-laravel.md')) : null, !hasComposerJson && hasPackageJson ? this.fs.read(this.templatePath('serve-html.md')) : null, this.fs.read(this.templatePath('after.md'))].filter(it => it !== null).join(separator);
76
+ const newContent = existingContent.length > 0 ? `${existingContent}${separator}${parts}` : parts;
77
+ this.fs.write(destPath, newContent);
78
+ },
79
+ claude() {
80
+ if (!this.options.claude) {
81
+ return;
82
+ }
83
+
84
+ // Claude Code reads CLAUDE.md, not AGENTS.md: import AGENTS.md from it
85
+ const claudePath = this.destinationPath('CLAUDE.md');
86
+ const claudeImport = '@AGENTS.md';
87
+ const existingClaudeContent = this.fs.exists(claudePath) ? this.fs.read(claudePath) : '';
88
+ const hasClaudeImport = existingClaudeContent.split('\n').some(line => line.trim() === claudeImport);
89
+ if (!hasClaudeImport) {
90
+ this.fs.write(claudePath, existingClaudeContent.length > 0 ? `${claudeImport}\n\n${existingClaudeContent}` : `${claudeImport}\n`);
91
+ }
92
+ const {
93
+ type: typeOption = null,
94
+ url: urlOption = null
95
+ } = this.options;
96
+ const detectedType = this.fs.exists(this.destinationPath('composer.json')) ? 'laravel' : 'html';
97
+ const type = (typeOption || detectedType) === 'laravel' ? 'laravel' : 'html';
98
+ const url = (urlOption || defaultUrls[type]).replace(/\/$/, '');
99
+ this.fs.writeJSON(this.destinationPath('.claude/launch.json'), {
100
+ version: '0.0.1',
101
+ configurations: [{
102
+ name: 'dev',
103
+ runtimeExecutable: 'npm',
104
+ runtimeArgs: launchArgs[type],
105
+ port: 8080,
106
+ url
107
+ }]
108
+ }, null, 4);
109
+ this.fs.copy(this.templatePath(`settings-${type}.json`), this.destinationPath('.claude/settings.json'));
110
+ }
111
+ };
28
112
  }
29
113
  }
30
114
  exports.default = AgentsGenerator;
@@ -8,7 +8,7 @@ This file defines how coding agents should work in this repository.
8
8
 
9
9
  ## Language Rules
10
10
 
11
- - Everything written for people is in French: conversations, GitHub issues and their comments, pull request titles, bodies and review comments.
11
+ - Everything written for people is in French: conversations, issues and their comments, pull or merge request titles, descriptions and review comments.
12
12
  - Code is always in English: identifiers, comments, file names, and commit messages.
13
13
 
14
14
  ## Editing Guidelines
@@ -8,7 +8,7 @@ On GitHub, `develop` is the default branch (so PRs target it and `Closes #<numbe
8
8
 
9
9
  - Small changes asked for directly in conversation: fixes, style or copy tweaks, translations, content.
10
10
  - Documentation, comments and config with no runtime effect.
11
- - Run the checks , then stop and leave the changes uncommitted: the maintainer reviews them before they land. Commit only when explicitly asked to. Never push unless asked.
11
+ - Run the checks, then stop and leave the changes uncommitted: the maintainer reviews them before they land. Commit only when explicitly asked to. Never push unless asked.
12
12
 
13
13
  ### Use an issue and a PR
14
14
 
@@ -0,0 +1,43 @@
1
+ ## Development Workflow
2
+
3
+ Branching follows Gitflow, kept light. `develop` is where development happens: every commit and every merge lands there first. `main` is production: it only receives `develop` when deploying to prod. The backlog is the repository's GitLab issues; merge requests are where reviewed work lands. Most day-to-day work skips both: the issue/MR flow exists to run work in parallel and to review what deserves it, not to slow down small changes.
4
+
5
+ Use `glab` for every GitLab operation (read `.agents/skills/glab/SKILL.md` first when it exists). On GitLab, `develop` is the default branch (so MRs target it and `Closes #<iid>` closes issues on merge), and the `bug`, `feature` and `in-progress` labels exist.
6
+
7
+ ### Work straight on `develop` (default)
8
+
9
+ - Small changes asked for directly in conversation: fixes, style or copy tweaks, translations, content.
10
+ - Documentation, comments and config with no runtime effect.
11
+ - Run the checks, then stop and leave the changes uncommitted: the maintainer reviews them before they land. Commit only when explicitly asked to. Never push unless asked.
12
+
13
+ ### Use an issue and an MR
14
+
15
+ - A feature or a chunk of work that spans several sessions, or needs a written plan.
16
+ - Work meant to run in parallel with other sessions.
17
+ - Risky or broad changes: migrations, refactors, dependencies, routing, or any diff the maintainer would want to read.
18
+ - Anything started from an existing issue.
19
+
20
+ What decides the flow is where the request came from and what it touches, not the size of the diff. When unsure, ask.
21
+
22
+ ### Working an issue
23
+
24
+ 1. Read the issue and its comments first; they may change the plan.
25
+ 2. Assign yourself and add the `in-progress` label before starting: it stops a second session from picking the same issue. Remove it if the work is abandoned.
26
+ 3. For a `feature`, write a short plan in the issue description before coding. `bug` issues skip the plan.
27
+ 4. One branch per issue, prefixed by its type: `feature/<iid>-<slug>` for a `feature`, `bug/<iid>-<slug>` for a `bug` (other types follow the same pattern, e.g. `docs/`, `refactor/`). Branch from an up-to-date `develop`, in its own worktree under `.claude/worktrees/<iid>-<slug>` so parallel sessions don't share a checkout.
28
+ 5. Commit on the issue branch as the work progresses, without asking: the MR is where the review happens. Run the checks, push and open the MR against `develop` with `Closes #<iid>` in its description, without asking. If the change couldn't be verified in the session, list the test scenario as a checkbox list in the MR description.
29
+ 6. The issue closes when the MR merges into `develop`, never just because code was pushed. Remove the worktree (`git worktree remove`) once merged.
30
+
31
+ Something out of scope noticed along the way becomes a new issue (title, context, files involved) rather than growing the current change. Every issue carries a type label: `bug` or `feature`.
32
+
33
+ ### Releasing to production
34
+
35
+ When deploying, merge `develop` into `main` (only when asked). An urgent fix for prod goes on a `hotfix/<slug>` branch from `main`, merged into `main` and then into `develop` so the two don't diverge.
36
+
37
+ ### Checks
38
+
39
+ Run the project's lint, format, typecheck and test scripts (see `package.json` and `composer.json`) on what changed. When the codebase has pre-existing errors, a check passes when it reports nothing new in the files touched.
40
+
41
+ ### Rules live in this file
42
+
43
+ Rules that always apply to this project (workflow, conventions, setup) are written here, not in an agent's private memory, so every session and every teammate shares them.
@@ -152,9 +152,6 @@ class HTMLProjectGenerator extends _generator.default {
152
152
  }
153
153
  this.composeWith('folklore:agents', {
154
154
  'src-path': srcPath,
155
- quiet: true
156
- });
157
- this.composeWith('folklore:claude', {
158
155
  type: 'html',
159
156
  quiet: true
160
157
  });
@@ -249,14 +249,6 @@ class LaravelProjectGenerator extends _generator.default {
249
249
  quiet: true,
250
250
  'skip-install': true
251
251
  });
252
- this.composeWith('folklore:claude', {
253
- type: 'laravel',
254
- url: _lodashEs.default.template(_lodashEs.default.get(this.options, 'local-url'))({
255
- project_host: this.options['project-host'],
256
- project_name: this.options['project-name']
257
- }),
258
- quiet: true
259
- });
260
252
  if (this.options.mediatheque) {
261
253
  this.composeWith('folklore:laravel-mediatheque', {
262
254
  'project-name': this.options['project-name'],
@@ -274,6 +266,11 @@ class LaravelProjectGenerator extends _generator.default {
274
266
 
275
267
  // Composed last so its writing runs once composer.json and package.json exist
276
268
  this.composeWith('folklore:agents', {
269
+ type: 'laravel',
270
+ url: _lodashEs.default.template(_lodashEs.default.get(this.options, 'local-url'))({
271
+ project_host: this.options['project-host'],
272
+ project_name: this.options['project-name']
273
+ }),
277
274
  quiet: true
278
275
  });
279
276
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "generator-folklore",
3
- "version": "3.0.60",
3
+ "version": "3.0.61",
4
4
  "description": "Yeoman generator for projects at Folklore",
5
5
  "keywords": [
6
6
  "yeoman-generator"
@@ -40,5 +40,5 @@
40
40
  "yeoman-generator": "5.9.0",
41
41
  "yeoman-remote": "^1.0.1"
42
42
  },
43
- "gitHead": "c54cd91bc3627c29fa1c97ff240e7a70d22e7bf3"
43
+ "gitHead": "34d318239aff6543bdac6e2ec9c9d5f39fdd6e6e"
44
44
  }
@@ -1,55 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _chalk = _interopRequireDefault(require("chalk"));
8
- var _generator = _interopRequireDefault(require("../../lib/generator"));
9
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
- const launchArgs = {
11
- laravel: ['run', 'server', '--', '--no-open'],
12
- html: ['run', 'server', '--', '--server', 'http', '--no-open']
13
- };
14
- const defaultUrls = {
15
- laravel: 'https://localhost:8080',
16
- html: 'http://localhost:8080'
17
- };
18
- class ClaudeGenerator extends _generator.default {
19
- constructor(...args) {
20
- super(...args);
21
- this.option('type', {
22
- type: String,
23
- desc: 'Project type: laravel (served through its .test domain) or html (served on localhost)',
24
- defaults: 'html'
25
- });
26
- this.option('url', {
27
- type: String,
28
- desc: 'Url opened by the browser preview (defaults to the dev server url)'
29
- });
30
- }
31
- prompting() {
32
- if (this.options.quiet) {
33
- return;
34
- }
35
- console.log(_chalk.default.yellow('\n----------------------'));
36
- console.log('Claude Code Generator');
37
- console.log(_chalk.default.yellow('----------------------\n'));
38
- }
39
- writing() {
40
- const type = this.options.type === 'laravel' ? 'laravel' : 'html';
41
- const url = (this.options.url || defaultUrls[type]).replace(/\/$/, '');
42
- this.fs.writeJSON(this.destinationPath('.claude/launch.json'), {
43
- version: '0.0.1',
44
- configurations: [{
45
- name: 'dev',
46
- runtimeExecutable: 'npm',
47
- runtimeArgs: launchArgs[type],
48
- port: 8080,
49
- url
50
- }]
51
- }, null, 4);
52
- this.fs.copy(this.templatePath(`settings-${type}.json`), this.destinationPath('.claude/settings.json'));
53
- }
54
- }
55
- exports.default = ClaudeGenerator;