trae-coding-engine 0.1.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.
- package/README.md +91 -0
- package/bin/coding-engine.js +16 -0
- package/lib/cli.js +86 -0
- package/lib/index.js +6 -0
- package/lib/setup.js +290 -0
- package/package.json +32 -0
- package/templates/.agents/skills/coding-architecture/SKILL.md +347 -0
- package/templates/.agents/skills/coding-code-review/SKILL.md +95 -0
- package/templates/.agents/skills/coding-cve-remediation/SKILL.md +163 -0
- package/templates/.agents/skills/coding-db-schema/SKILL.md +273 -0
- package/templates/.agents/skills/coding-deploy-config/SKILL.md +129 -0
- package/templates/.agents/skills/coding-docs-audit/SKILL.md +285 -0
- package/templates/.agents/skills/coding-docs-audit-autofix/SKILL.md +33 -0
- package/templates/.agents/skills/coding-http-api/SKILL.md +269 -0
- package/templates/.agents/skills/coding-issue-autodev/SKILL.md +172 -0
- package/templates/.agents/skills/coding-merge-request/SKILL.md +199 -0
- package/templates/.agents/skills/coding-observability/SKILL.md +193 -0
- package/templates/.agents/skills/coding-refactor-insight/SKILL.md +89 -0
- package/templates/.agents/skills/coding-release-merge/SKILL.md +224 -0
- package/templates/.agents/skills/coding-runtime-adapter/SKILL.md +115 -0
- package/templates/.agents/skills/coding-testing/SKILL.md +169 -0
- package/templates/AGENTS.md +179 -0
- package/templates/MR-Template-Default.md +33 -0
- package/templates/Makefile +370 -0
- package/templates/REGISTRY.md +53 -0
- package/templates/scripts/check-adr.sh +283 -0
- package/templates/scripts/check-comment-i18n.py +209 -0
- package/templates/scripts/check-comment-i18n.sh +38 -0
- package/templates/scripts/check-doc-refs.sh +40 -0
- package/templates/scripts/check-docs.sh +103 -0
- package/templates/scripts/check-go-names.sh +59 -0
- package/templates/scripts/check-iam-actions.py +126 -0
- package/templates/scripts/check-migration-sql-immutability.sh +232 -0
- package/templates/scripts/check-mr-desc.sh +165 -0
- package/templates/scripts/check-mr-size.sh +128 -0
- package/templates/scripts/check-mr-title.sh +123 -0
- package/templates/scripts/check-openapi.py +221 -0
- package/templates/scripts/check-rdb-structured-queries.sh +98 -0
- package/templates/scripts/check-repository-transactions.sh +100 -0
- package/templates/scripts/check-runbooks.sh +229 -0
- package/templates/scripts/check-skill-router-sync.py +331 -0
- package/templates/scripts/check-skills.sh +243 -0
- package/templates/scripts/docs-audit-to-issues.py +373 -0
- package/templates/scripts/docs-verification-reminder.sh +63 -0
- package/templates/scripts/find-ci-failures.sh +133 -0
- package/templates/scripts/find-stale-mrs.sh +72 -0
- package/templates/scripts/gen-adr-index.sh +122 -0
- package/templates/scripts/open-mr.sh +536 -0
- package/templates/scripts/regen-agent-md.sh +149 -0
- package/templates/scripts/run-mr-hygiene.sh +140 -0
- package/templates/scripts/runbook.sh +91 -0
- package/templates/scripts/self-maintenance-digest.py +125 -0
- package/templates/scripts/send-self-maintenance-lark-card.py +116 -0
- package/templates/scripts/skill-graph.sh +114 -0
- package/templates/scripts/skill-impact.sh +134 -0
- package/templates/scripts/skill-propose.sh +302 -0
- package/templates/scripts/skill-router-hook.sh +152 -0
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# @trae/coding-engine
|
|
2
|
+
|
|
3
|
+
> Install the Trae AI-Coding best-practice guardrails (AGENTS.md, Skill Router, 31 check scripts, 15 SKILL.md) into any repo with a single command.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# One-shot (no install needed)
|
|
9
|
+
npx @trae/coding-engine setup
|
|
10
|
+
|
|
11
|
+
# Or install globally
|
|
12
|
+
npm install -g @trae/coding-engine
|
|
13
|
+
coding-engine setup
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This will assemble the following into your project:
|
|
17
|
+
|
|
18
|
+
| Destination | Content |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `AGENTS.md` (repo root) | Cross-tool source of truth — instructions for every AI coding agent (Trae, Cursor, Copilot, Claude Code, etc.) |
|
|
21
|
+
| `Makefile` (repo root) | Pre-packaged `make` targets for all 31 check scripts |
|
|
22
|
+
| `REGISTRY.md` (repo root) | Skill registry / router index |
|
|
23
|
+
| `MR-Template-Default.md` (repo root) | Merge-request template |
|
|
24
|
+
| `scripts/` (31 files) | Engineering check scripts (`.sh` + `.py`) — ADR, MR hygiene, skill sync, docs audit, self-maintenance, etc. |
|
|
25
|
+
| `.agents/skills/coding-*/SKILL.md` (15 dirs) | Skill definitions: architecture, code-review, cve-remediation, db-schema, deploy-config, docs-audit, docs-audit-autofix, http-api, issue-autodev, merge-request, observability, refactor-insight, release-merge, runtime-adapter, testing |
|
|
26
|
+
|
|
27
|
+
## Commands
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
coding-engine setup [options] # Install everything
|
|
31
|
+
coding-engine update [options] # Alias of `setup --force`
|
|
32
|
+
coding-engine list # Show every file this package would install
|
|
33
|
+
coding-engine doctor [options] # Diagnose an existing install (missing / drifted files)
|
|
34
|
+
coding-engine --help
|
|
35
|
+
coding-engine --version
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Options
|
|
39
|
+
|
|
40
|
+
| Flag | Description |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `--target <dir>` | Target repo root. Default: current working directory. |
|
|
43
|
+
| `--scripts-dir <dir>` | Where to place shell / py scripts. Default: `<target>/scripts` |
|
|
44
|
+
| `--skills-dir <dir>` | Where to place the SKILL.md tree. Default: `<target>/.agents/skills` |
|
|
45
|
+
| `--force` | Overwrite existing files (a `.bak` copy is kept for anything modified) |
|
|
46
|
+
| `--dry-run` | Print the plan without touching disk |
|
|
47
|
+
| `--no-chmod` | Skip `chmod +x` on installed shell / py scripts |
|
|
48
|
+
| `--only <group>` | Comma-separated groups to install: `agents-md,makefile,registry,mr-template,scripts,skills` |
|
|
49
|
+
| `--yes` / `-y` | Skip the confirmation prompt |
|
|
50
|
+
|
|
51
|
+
## Examples
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Install everything into the current repo
|
|
55
|
+
coding-engine setup
|
|
56
|
+
|
|
57
|
+
# Preview without writing
|
|
58
|
+
coding-engine setup --dry-run
|
|
59
|
+
|
|
60
|
+
# Install only AGENTS.md and scripts
|
|
61
|
+
coding-engine setup --only agents-md,scripts
|
|
62
|
+
|
|
63
|
+
# Force-update everything (existing files get .bak backups)
|
|
64
|
+
coding-engine update
|
|
65
|
+
|
|
66
|
+
# Check what's missing or drifted in an existing install
|
|
67
|
+
coding-engine doctor --target /path/to/repo
|
|
68
|
+
|
|
69
|
+
# Install into a specific repo
|
|
70
|
+
coding-engine setup --target ~/projects/my-app
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## How it works
|
|
74
|
+
|
|
75
|
+
1. The npm package ships a `templates/` directory containing all 51 source files.
|
|
76
|
+
2. `setup` walks `templates/` and copies each file to the corresponding destination in your repo.
|
|
77
|
+
3. Root files (`AGENTS.md`, `Makefile`, `REGISTRY.md`, `MR-Template-Default.md`) go to the repo root.
|
|
78
|
+
4. `scripts/*` go to `<target>/scripts/` (configurable via `--scripts-dir`).
|
|
79
|
+
5. `.agents/skills/**` go to `<target>/.agents/skills/` (configurable via `--skills-dir`).
|
|
80
|
+
6. `.sh` and `.py` files are `chmod +x` by default (skip with `--no-chmod`).
|
|
81
|
+
7. If a file already exists with different content, it is **skipped** by default. Use `--force` to overwrite — a `.bak` copy of the original is kept.
|
|
82
|
+
8. Re-running `setup` is idempotent: identical files are detected and no action is taken.
|
|
83
|
+
|
|
84
|
+
## Requirements
|
|
85
|
+
|
|
86
|
+
- Node.js >= 16
|
|
87
|
+
- No external dependencies (zero-dependency CLI, uses only Node.js stdlib)
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
Apache-2.0
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// coding-engine — CLI entry
|
|
3
|
+
// Zero external deps; Node >=16.
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const cli = require(path.join(__dirname, '..', 'lib', 'cli.js'));
|
|
9
|
+
|
|
10
|
+
cli.run(process.argv.slice(2)).catch((err) => {
|
|
11
|
+
process.stderr.write(`\n[coding-engine] error: ${err && err.message ? err.message : err}\n`);
|
|
12
|
+
if (process.env.CODING_ENGINE_DEBUG) {
|
|
13
|
+
process.stderr.write(String(err && err.stack) + '\n');
|
|
14
|
+
}
|
|
15
|
+
process.exit(1);
|
|
16
|
+
});
|
package/lib/cli.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const setup = require('./setup');
|
|
6
|
+
|
|
7
|
+
const HELP = `
|
|
8
|
+
coding-engine — Trae AI-Coding best-practice installer
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
coding-engine setup [options] Install AGENTS.md + scripts/ + .agents/skills/ into target repo
|
|
12
|
+
coding-engine update [options] Alias of \`setup --force\` (overwrite bundled assets, keep local edits backed up)
|
|
13
|
+
coding-engine list Show every file this package would install
|
|
14
|
+
coding-engine doctor [--target] Diagnose an existing install (missing / drifted files)
|
|
15
|
+
coding-engine --help Print this help
|
|
16
|
+
coding-engine --version Print installed package version
|
|
17
|
+
|
|
18
|
+
setup / update options:
|
|
19
|
+
--target <dir> Target repo root. Default: current working directory.
|
|
20
|
+
--scripts-dir <dir> Where to place shell / py scripts. Default: <target>/scripts
|
|
21
|
+
--skills-dir <dir> Where to place SKILL.md tree. Default: <target>/.agents/skills
|
|
22
|
+
--force Overwrite existing files (a .bak copy is kept for anything modified)
|
|
23
|
+
--dry-run Print the plan without touching disk
|
|
24
|
+
--no-chmod Skip \`chmod +x\` on installed shell/py scripts
|
|
25
|
+
--only <group> Comma-separated groups to install: agents-md, makefile, registry,
|
|
26
|
+
mr-template, scripts, skills (default: all)
|
|
27
|
+
--yes / -y Skip the confirmation prompt
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
function parseArgs(argv) {
|
|
31
|
+
const args = { _: [], flags: {} };
|
|
32
|
+
for (let i = 0; i < argv.length; i++) {
|
|
33
|
+
const a = argv[i];
|
|
34
|
+
if (a === '--help' || a === '-h') { args.flags.help = true; continue; }
|
|
35
|
+
if (a === '--version' || a === '-v') { args.flags.version = true; continue; }
|
|
36
|
+
if (a === '--force') { args.flags.force = true; continue; }
|
|
37
|
+
if (a === '--dry-run') { args.flags.dryRun = true; continue; }
|
|
38
|
+
if (a === '--no-chmod') { args.flags.noChmod = true; continue; }
|
|
39
|
+
if (a === '--yes' || a === '-y') { args.flags.yes = true; continue; }
|
|
40
|
+
if (a === '--target') { args.flags.target = argv[++i]; continue; }
|
|
41
|
+
if (a === '--scripts-dir') { args.flags.scriptsDir = argv[++i]; continue; }
|
|
42
|
+
if (a === '--skills-dir') { args.flags.skillsDir = argv[++i]; continue; }
|
|
43
|
+
if (a === '--only') { args.flags.only = argv[++i]; continue; }
|
|
44
|
+
if (a.startsWith('--')) { throw new Error(`unknown flag: ${a}`); }
|
|
45
|
+
args._.push(a);
|
|
46
|
+
}
|
|
47
|
+
return args;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function pkgVersion() {
|
|
51
|
+
try {
|
|
52
|
+
const p = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
|
53
|
+
return p.version;
|
|
54
|
+
} catch (_) { return 'unknown'; }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function run(argv) {
|
|
58
|
+
const args = parseArgs(argv);
|
|
59
|
+
|
|
60
|
+
if (args.flags.version && !args._[0]) {
|
|
61
|
+
process.stdout.write(pkgVersion() + '\n');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (args.flags.help || !args._[0]) {
|
|
65
|
+
process.stdout.write(HELP);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const cmd = args._[0];
|
|
70
|
+
switch (cmd) {
|
|
71
|
+
case 'setup':
|
|
72
|
+
return setup.run({ ...args.flags });
|
|
73
|
+
case 'update':
|
|
74
|
+
return setup.run({ ...args.flags, force: true });
|
|
75
|
+
case 'list':
|
|
76
|
+
return setup.list();
|
|
77
|
+
case 'doctor':
|
|
78
|
+
return setup.doctor({ ...args.flags });
|
|
79
|
+
case 'help':
|
|
80
|
+
process.stdout.write(HELP); return;
|
|
81
|
+
default:
|
|
82
|
+
throw new Error(`unknown command: ${cmd}. Run \`coding-engine --help\`.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = { run };
|
package/lib/index.js
ADDED
package/lib/setup.js
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
|
|
7
|
+
|
|
8
|
+
// Groups for --only filter
|
|
9
|
+
const GROUPS = ['agents-md', 'makefile', 'registry', 'mr-template', 'scripts', 'skills'];
|
|
10
|
+
|
|
11
|
+
// Map template-relative path → group
|
|
12
|
+
function groupOf(relPath) {
|
|
13
|
+
const top = relPath.split(path.sep)[0];
|
|
14
|
+
if (relPath === 'AGENTS.md') return 'agents-md';
|
|
15
|
+
if (relPath === 'Makefile') return 'makefile';
|
|
16
|
+
if (relPath === 'REGISTRY.md') return 'registry';
|
|
17
|
+
if (relPath === 'MR-Template-Default.md') return 'mr-template';
|
|
18
|
+
if (top === 'scripts') return 'scripts';
|
|
19
|
+
if (relPath.startsWith('.agents' + path.sep)) return 'skills';
|
|
20
|
+
return 'other';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Walk a directory recursively, return array of absolute file paths
|
|
24
|
+
function walkDir(dir) {
|
|
25
|
+
const out = [];
|
|
26
|
+
if (!fs.existsSync(dir)) return out;
|
|
27
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
28
|
+
const full = path.join(dir, entry.name);
|
|
29
|
+
if (entry.isDirectory()) {
|
|
30
|
+
out.push(...walkDir(full));
|
|
31
|
+
} else if (entry.isFile()) {
|
|
32
|
+
out.push(full);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Resolve destination path for a template file
|
|
39
|
+
function resolveDest(relPath, target, scriptsDir, skillsDir) {
|
|
40
|
+
const parts = relPath.split(path.sep);
|
|
41
|
+
|
|
42
|
+
// .agents/skills/... → skillsDir/...
|
|
43
|
+
if (parts[0] === '.agents' && parts[1] === 'skills') {
|
|
44
|
+
const rest = parts.slice(2).join(path.sep); // <skill-name>/SKILL.md
|
|
45
|
+
return path.join(skillsDir, rest);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// scripts/... → scriptsDir/...
|
|
49
|
+
if (parts[0] === 'scripts') {
|
|
50
|
+
return path.join(scriptsDir, parts.slice(1).join(path.sep));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// root files → target/
|
|
54
|
+
return path.join(target, relPath);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Get list of { src, dest, rel, group } for all bundled files
|
|
58
|
+
function getManifest(target, scriptsDir, skillsDir) {
|
|
59
|
+
const files = walkDir(TEMPLATES_DIR);
|
|
60
|
+
const manifest = [];
|
|
61
|
+
for (const src of files) {
|
|
62
|
+
const rel = path.relative(TEMPLATES_DIR, src);
|
|
63
|
+
const dest = resolveDest(rel, target, scriptsDir, skillsDir);
|
|
64
|
+
manifest.push({ src, dest, rel, group: groupOf(rel) });
|
|
65
|
+
}
|
|
66
|
+
// Sort: root files first, then scripts, then skills — predictable order
|
|
67
|
+
manifest.sort((a, b) => {
|
|
68
|
+
const order = { 'agents-md': 0, 'makefile': 1, 'registry': 2, 'mr-template': 3, 'scripts': 4, 'skills': 5, 'other': 6 };
|
|
69
|
+
return (order[a.group] || 6) - (order[b.group] || 6) || a.rel.localeCompare(b.rel);
|
|
70
|
+
});
|
|
71
|
+
return manifest;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function parseOnly(flag) {
|
|
75
|
+
if (!flag) return null;
|
|
76
|
+
const list = flag.split(',').map(s => s.trim()).filter(Boolean);
|
|
77
|
+
for (const g of list) {
|
|
78
|
+
if (!GROUPS.includes(g)) {
|
|
79
|
+
throw new Error(`unknown group "${g}". Valid groups: ${GROUPS.join(', ')}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return new Set(list);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function ensureDir(filePath) {
|
|
86
|
+
const dir = path.dirname(filePath);
|
|
87
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function copyFile(src, dest) {
|
|
91
|
+
ensureDir(dest);
|
|
92
|
+
fs.copyFileSync(src, dest);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function filesIdentical(a, b) {
|
|
96
|
+
try {
|
|
97
|
+
const ba = fs.readFileSync(a);
|
|
98
|
+
const bb = fs.readFileSync(b);
|
|
99
|
+
if (ba.length !== bb.length) return false;
|
|
100
|
+
return ba.equals(bb);
|
|
101
|
+
} catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isExecutable(rel) {
|
|
107
|
+
return rel.endsWith('.sh') || rel.endsWith('.py');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ─── run() ──────────────────────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
function run(flags) {
|
|
113
|
+
const target = path.resolve(flags.target || process.cwd());
|
|
114
|
+
const scriptsDir = path.resolve(target, flags.scriptsDir || 'scripts');
|
|
115
|
+
const skillsDir = path.resolve(target, flags.skillsDir || path.join('.agents', 'skills'));
|
|
116
|
+
const onlySet = parseOnly(flags.only);
|
|
117
|
+
const dryRun = !!flags.dryRun;
|
|
118
|
+
const force = !!flags.force;
|
|
119
|
+
const noChmod = !!flags.noChmod;
|
|
120
|
+
|
|
121
|
+
const manifest = getManifest(target, scriptsDir, skillsDir);
|
|
122
|
+
const filtered = onlySet ? manifest.filter(m => onlySet.has(m.group)) : manifest;
|
|
123
|
+
|
|
124
|
+
if (filtered.length === 0) {
|
|
125
|
+
process.stdout.write('\nNo files match the selected groups.\n\n');
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Plan
|
|
130
|
+
const plan = [];
|
|
131
|
+
for (const item of filtered) {
|
|
132
|
+
const destExists = fs.existsSync(item.dest);
|
|
133
|
+
let action;
|
|
134
|
+
if (!destExists) {
|
|
135
|
+
action = 'create';
|
|
136
|
+
} else if (force) {
|
|
137
|
+
action = filesIdentical(item.src, item.dest) ? 'same' : 'overwrite';
|
|
138
|
+
} else {
|
|
139
|
+
action = filesIdentical(item.src, item.dest) ? 'same' : 'skip';
|
|
140
|
+
}
|
|
141
|
+
plan.push({ ...item, action });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Print plan
|
|
145
|
+
process.stdout.write('\n');
|
|
146
|
+
process.stdout.write(` Target: ${target}\n`);
|
|
147
|
+
process.stdout.write(` Scripts dir: ${scriptsDir}\n`);
|
|
148
|
+
process.stdout.write(` Skills dir: ${skillsDir}\n`);
|
|
149
|
+
process.stdout.write(` Mode: ${dryRun ? 'DRY RUN' : force ? 'FORCE (overwrite with .bak)' : 'safe (skip existing)'}\n`);
|
|
150
|
+
if (onlySet) process.stdout.write(` Only: ${[...onlySet].join(', ')}\n`);
|
|
151
|
+
process.stdout.write(` Files: ${filtered.length}\n\n`);
|
|
152
|
+
|
|
153
|
+
let created = 0, overwritten = 0, skipped = 0, same = 0, backedUp = 0;
|
|
154
|
+
|
|
155
|
+
for (const p of plan) {
|
|
156
|
+
let symbol;
|
|
157
|
+
switch (p.action) {
|
|
158
|
+
case 'create': symbol = '+'; break;
|
|
159
|
+
case 'overwrite': symbol = '~'; break;
|
|
160
|
+
case 'skip': symbol = '!'; break;
|
|
161
|
+
case 'same': symbol = '='; break;
|
|
162
|
+
default: symbol = '?';
|
|
163
|
+
}
|
|
164
|
+
process.stdout.write(` ${symbol} ${p.rel}\n`);
|
|
165
|
+
|
|
166
|
+
if (dryRun) continue;
|
|
167
|
+
|
|
168
|
+
if (p.action === 'create') {
|
|
169
|
+
copyFile(p.src, p.dest);
|
|
170
|
+
if (isExecutable(p.rel) && !noChmod) {
|
|
171
|
+
fs.chmodSync(p.dest, 0o755);
|
|
172
|
+
}
|
|
173
|
+
created++;
|
|
174
|
+
} else if (p.action === 'overwrite') {
|
|
175
|
+
// backup
|
|
176
|
+
const bak = p.dest + '.bak';
|
|
177
|
+
if (fs.existsSync(bak)) fs.unlinkSync(bak);
|
|
178
|
+
fs.copyFileSync(p.dest, bak);
|
|
179
|
+
copyFile(p.src, p.dest);
|
|
180
|
+
if (isExecutable(p.rel) && !noChmod) {
|
|
181
|
+
fs.chmodSync(p.dest, 0o755);
|
|
182
|
+
}
|
|
183
|
+
overwritten++;
|
|
184
|
+
backedUp++;
|
|
185
|
+
} else if (p.action === 'same') {
|
|
186
|
+
same++;
|
|
187
|
+
} else {
|
|
188
|
+
skipped++;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
process.stdout.write('\n');
|
|
193
|
+
|
|
194
|
+
if (dryRun) {
|
|
195
|
+
process.stdout.write(' (dry run — no files were changed)\n\n');
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
process.stdout.write(' Summary:\n');
|
|
200
|
+
process.stdout.write(` created: ${created}\n`);
|
|
201
|
+
process.stdout.write(` overwritten: ${overwritten} (backups: ${backedUp})\n`);
|
|
202
|
+
process.stdout.write(` skipped: ${skipped}\n`);
|
|
203
|
+
process.stdout.write(` unchanged: ${same}\n\n`);
|
|
204
|
+
|
|
205
|
+
if (skipped > 0) {
|
|
206
|
+
process.stdout.write(' ⚠ Some files were skipped because they already exist with different content.\n');
|
|
207
|
+
process.stdout.write(' Run with --force to overwrite (a .bak copy will be kept for each modified file).\n\n');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (created > 0 || overwritten > 0) {
|
|
211
|
+
process.stdout.write(' ✅ Coding-Engine guardrails installed successfully.\n');
|
|
212
|
+
process.stdout.write(' Next steps:\n');
|
|
213
|
+
process.stdout.write(' 1. Review AGENTS.md at your repo root.\n');
|
|
214
|
+
process.stdout.write(' 2. Run `make help` to see available check targets.\n');
|
|
215
|
+
process.stdout.write(' 3. Commit the new files to your repo.\n\n');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ─── list() ─────────────────────────────────────────────────────────────────
|
|
220
|
+
|
|
221
|
+
function list() {
|
|
222
|
+
const manifest = walkDir(TEMPLATES_DIR).map(src => {
|
|
223
|
+
const rel = path.relative(TEMPLATES_DIR, src);
|
|
224
|
+
return { rel, group: groupOf(rel) };
|
|
225
|
+
});
|
|
226
|
+
manifest.sort((a, b) => {
|
|
227
|
+
const order = { 'agents-md': 0, 'makefile': 1, 'registry': 2, 'mr-template': 3, 'scripts': 4, 'skills': 5, 'other': 6 };
|
|
228
|
+
return (order[a.group] || 6) - (order[b.group] || 6) || a.rel.localeCompare(b.rel);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
process.stdout.write('\n Files bundled in this package:\n\n');
|
|
232
|
+
|
|
233
|
+
let currentGroup = null;
|
|
234
|
+
for (const item of manifest) {
|
|
235
|
+
if (item.group !== currentGroup) {
|
|
236
|
+
currentGroup = item.group;
|
|
237
|
+
process.stdout.write(`\n [${item.group}]\n`);
|
|
238
|
+
}
|
|
239
|
+
process.stdout.write(` ${item.rel}\n`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
process.stdout.write(`\n Total: ${manifest.length} files\n\n`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ─── doctor() ───────────────────────────────────────────────────────────────
|
|
246
|
+
|
|
247
|
+
function doctor(flags) {
|
|
248
|
+
const target = path.resolve(flags.target || process.cwd());
|
|
249
|
+
const scriptsDir = path.resolve(target, flags.scriptsDir || 'scripts');
|
|
250
|
+
const skillsDir = path.resolve(target, flags.skillsDir || path.join('.agents', 'skills'));
|
|
251
|
+
|
|
252
|
+
const manifest = getManifest(target, scriptsDir, skillsDir);
|
|
253
|
+
|
|
254
|
+
process.stdout.write('\n');
|
|
255
|
+
process.stdout.write(` Target: ${target}\n`);
|
|
256
|
+
process.stdout.write(` Scripts dir: ${scriptsDir}\n`);
|
|
257
|
+
process.stdout.write(` Skills dir: ${skillsDir}\n\n`);
|
|
258
|
+
|
|
259
|
+
let present = 0, missing = 0, drifted = 0;
|
|
260
|
+
|
|
261
|
+
for (const item of manifest) {
|
|
262
|
+
if (!fs.existsSync(item.dest)) {
|
|
263
|
+
process.stdout.write(` ✗ MISSING ${item.rel}\n`);
|
|
264
|
+
missing++;
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (!filesIdentical(item.src, item.dest)) {
|
|
268
|
+
process.stdout.write(` ~ DRIFTED ${item.rel}\n`);
|
|
269
|
+
drifted++;
|
|
270
|
+
} else {
|
|
271
|
+
process.stdout.write(` ✓ OK ${item.rel}\n`);
|
|
272
|
+
present++;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
process.stdout.write('\n');
|
|
277
|
+
process.stdout.write(' Summary:\n');
|
|
278
|
+
process.stdout.write(` OK: ${present}\n`);
|
|
279
|
+
process.stdout.write(` Missing: ${missing}\n`);
|
|
280
|
+
process.stdout.write(` Drifted: ${drifted}\n\n`);
|
|
281
|
+
|
|
282
|
+
if (missing > 0 || drifted > 0) {
|
|
283
|
+
process.stdout.write(' ⚠ Some files are missing or have drifted from the bundled version.\n');
|
|
284
|
+
process.stdout.write(' Run `coding-engine update` to restore them (existing modifications get .bak backups).\n\n');
|
|
285
|
+
} else {
|
|
286
|
+
process.stdout.write(' ✅ All files are present and up to date.\n\n');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
module.exports = { run, list, doctor };
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "trae-coding-engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Install the Trae Coding-Engine AI-Agent guardrails (AGENTS.md, Skill Router, 31 check scripts, 15 SKILL.md) into any repo with a single command.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"trae",
|
|
7
|
+
"ai-coding",
|
|
8
|
+
"agents",
|
|
9
|
+
"agents-md",
|
|
10
|
+
"skill-router",
|
|
11
|
+
"gitlab",
|
|
12
|
+
"codereview"
|
|
13
|
+
],
|
|
14
|
+
"license": "Apache-2.0",
|
|
15
|
+
"bin": {
|
|
16
|
+
"coding-engine": "bin/coding-engine.js",
|
|
17
|
+
"trae-coding-engine": "bin/coding-engine.js"
|
|
18
|
+
},
|
|
19
|
+
"main": "lib/index.js",
|
|
20
|
+
"files": [
|
|
21
|
+
"bin/",
|
|
22
|
+
"lib/",
|
|
23
|
+
"templates/",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=16"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"test": "node test/smoke.js"
|
|
31
|
+
}
|
|
32
|
+
}
|