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.
- package/lib/generators/agents/index.js +93 -9
- package/lib/generators/agents/templates/general.md +1 -1
- 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 → agents}/templates/settings-html.json +0 -0
- /package/lib/generators/{claude → agents}/templates/settings-laravel.json +0 -0
|
@@ -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;
|
|
@@ -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;
|
|
File without changes
|
|
File without changes
|