generator-folklore 3.0.59 → 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.
- package/lib/generators/agents/index.js +93 -9
- package/lib/generators/agents/templates/frontend.md +8 -0
- package/lib/generators/agents/templates/general.md +1 -1
- package/lib/generators/agents/templates/settings-html.json +4 -0
- package/lib/generators/agents/templates/settings-laravel.json +4 -0
- package/lib/generators/agents/templates/{workflow.md → workflow-github.md} +1 -1
- package/lib/generators/agents/templates/workflow-gitlab.md +43 -0
- package/lib/generators/html-project/index.js +0 -3
- package/lib/generators/laravel-project/index.js +5 -8
- package/package.json +2 -2
- package/lib/generators/claude/index.js +0 -55
- package/lib/generators/claude/templates/settings-html.json +0 -33
- package/lib/generators/claude/templates/settings-laravel.json +0 -38
|
@@ -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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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;
|
|
@@ -20,3 +20,11 @@
|
|
|
20
20
|
- Add className props for style composition and when needed add className props for inner elements
|
|
21
21
|
- Don't write string, use i18n components from react-intl
|
|
22
22
|
- Always add a `description` to i18n message and don't define `id`
|
|
23
|
+
|
|
24
|
+
### CSS
|
|
25
|
+
- Use CSS modules with PostCSS
|
|
26
|
+
- Use CSS nesting (via postcss preset env)
|
|
27
|
+
- Make use of the theme folder (if present) and global css variables to standardize codebase.
|
|
28
|
+
- Avoid too recent CSS features to emphasize compatibility.
|
|
29
|
+
- In components *.modules.css files, follow the pattern of scoping classes under a .container.
|
|
30
|
+
- A component never positions itself: its placement (position, offsets, margins, z-index, size in the layout) belongs to the parent using it, through a class passed with `className`. The component's own stylesheet only styles what is inside it.
|
|
@@ -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,
|
|
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
|
|
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.
|
|
@@ -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.
|
|
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": "
|
|
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;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(npm run lint*)",
|
|
5
|
-
"Bash(npm run format*)",
|
|
6
|
-
"Bash(npm run typecheck)",
|
|
7
|
-
"Bash(npm run test*)",
|
|
8
|
-
"Bash(npm test*)",
|
|
9
|
-
"Bash(npm run server*)",
|
|
10
|
-
"Bash(npx prettier *)",
|
|
11
|
-
"Bash(npx eslint *)",
|
|
12
|
-
"Bash(npx stylelint *)",
|
|
13
|
-
"Bash(npx tsc --noEmit*)",
|
|
14
|
-
"Bash(gh issue view *)",
|
|
15
|
-
"Bash(gh issue list*)",
|
|
16
|
-
"Bash(gh issue create *)",
|
|
17
|
-
"Bash(gh issue edit *)",
|
|
18
|
-
"Bash(gh issue comment *)",
|
|
19
|
-
"Bash(gh pr view*)",
|
|
20
|
-
"Bash(gh pr list*)",
|
|
21
|
-
"Bash(gh pr diff*)",
|
|
22
|
-
"Bash(gh pr checks*)",
|
|
23
|
-
"Bash(gh pr create *)",
|
|
24
|
-
"Bash(gh pr edit *)",
|
|
25
|
-
"Bash(gh pr comment *)",
|
|
26
|
-
"mcp__Claude_Browser",
|
|
27
|
-
"mcp__Claude_Code_iOS_Simulator"
|
|
28
|
-
],
|
|
29
|
-
"ask": [
|
|
30
|
-
"Bash(git push*)"
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(npm run lint*)",
|
|
5
|
-
"Bash(npm run format*)",
|
|
6
|
-
"Bash(npm run typecheck)",
|
|
7
|
-
"Bash(npm run test*)",
|
|
8
|
-
"Bash(npm test*)",
|
|
9
|
-
"Bash(npm run server*)",
|
|
10
|
-
"Bash(npx prettier *)",
|
|
11
|
-
"Bash(npx eslint *)",
|
|
12
|
-
"Bash(npx stylelint *)",
|
|
13
|
-
"Bash(npx tsc --noEmit*)",
|
|
14
|
-
"Bash(php artisan test*)",
|
|
15
|
-
"Bash(npx flklr certificates*)",
|
|
16
|
-
"Bash(npx flklr certs*)",
|
|
17
|
-
"Bash(gh issue view *)",
|
|
18
|
-
"Bash(gh issue list*)",
|
|
19
|
-
"Bash(gh issue create *)",
|
|
20
|
-
"Bash(gh issue edit *)",
|
|
21
|
-
"Bash(gh issue comment *)",
|
|
22
|
-
"Bash(gh pr view*)",
|
|
23
|
-
"Bash(gh pr list*)",
|
|
24
|
-
"Bash(gh pr diff*)",
|
|
25
|
-
"Bash(gh pr checks*)",
|
|
26
|
-
"Bash(gh pr create *)",
|
|
27
|
-
"Bash(gh pr edit *)",
|
|
28
|
-
"Bash(gh pr comment *)",
|
|
29
|
-
"mcp__Claude_Browser",
|
|
30
|
-
"mcp__Claude_Code_iOS_Simulator"
|
|
31
|
-
],
|
|
32
|
-
"ask": [
|
|
33
|
-
"Bash(npx flklr certificates*--fix*)",
|
|
34
|
-
"Bash(npx flklr certs*--fix*)",
|
|
35
|
-
"Bash(git push*)"
|
|
36
|
-
]
|
|
37
|
-
}
|
|
38
|
-
}
|