amxx-builder 1.7.0 → 1.7.1

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/AGENTS.md CHANGED
@@ -68,6 +68,7 @@ The opencode bridge plugin (`.opencode/plugin/amxb-skills.js`, generated by `amx
68
68
  - Plugin rules (`plugins.rules:`) apply **only to local** `.sma` files, not repo plugins; `plugins.defaults` and `repos[].plugins` apply to all plugins. An effective non-`false` `ini` enables INI generation.
69
69
  - Local `amxmodx/` always wins over repo files (intentional override layer, no conflict warning).
70
70
  - `.sma` files ARE copied during collect (like any other file) and are also compiled; exclude them per-repo via `exclude_files` if sources should not ship.
71
+ - `amxmodx.exclude_files` (array of glob patterns, default `[]`, relative to the local `amxmodx.dir`) keeps matching files from the project's own local `amxmodx/` out of `build/amxmodx/` and the archive. It does not touch `repos:` files (those use per-repo `exclude_files`) and does not stop compilation of local `.sma` (use `plugins.rules[].enabled: false` for that); watch ignores excluded local files. Distinct from `deploy.exclude`, which protects server files from being overwritten during deploy/watch.
71
72
  - `repos:`/`deps:` entries can be satisfied by a **local directory** instead of GitHub: `source: local` + `path` (relative to the manifest dir, or absolute; optional `name` gives the synthetic id `local/<name>`, defaulting to the path basename). A local repo is collected + its `.sma` compiled and may still set `amxmodx_dir` / `plugins` / `exclude` / `exclude_files` / `deps_override` (`repo`/`ref` forbidden; the deprecated `plugins_ini_postfix` is still accepted with a build warning); a local dep contributes `.inc` to `build/_includes/` (`repo`/`ref`/`id`/`url`/`asset` forbidden; object form only, the `owner/repo@ref[:include_path]` string stays git-only). Local sources are unpinned (the working tree is read as-is) so builds are not reproducible, and watch does not follow dirs outside the manifest's `amxmodx/`/`assets/`.
72
73
 
73
74
  ## GitHub Action release flow
package/README.md CHANGED
@@ -155,6 +155,22 @@ my-server/
155
155
  weapon.wav
156
156
  ```
157
157
 
158
+ ### Исключение локальных файлов
159
+
160
+ Поле `amxmodx.exclude_files` задаёт массив glob-паттернов. Файлы локальной папки `amxmodx/`, попавшие под паттерн, не копируются в `build/amxmodx/` и не попадают в архив. По умолчанию значение пустое (`[]`), то есть копируется всё. Паттерны считаются от `amxmodx.dir` (по умолчанию `amxmodx`):
161
+
162
+ ```yaml
163
+ amxmodx:
164
+ exclude_files:
165
+ - configs/*.cfg
166
+ - "**/*.ini"
167
+ - scripting/dev.sma
168
+ ```
169
+
170
+ Поле действует только на собственную локальную папку `amxmodx/` рядом с манифестом. Файлов из `repos:` оно не касается. Для них исключение задаётся на самом репо через `repos[].exclude_files`. Компиляцию локальных `.sma` поле не отменяет. Чтобы полностью пропустить локальный плагин, используйте `plugins.rules[].enabled: false` (см. раздел про плагины). В watch-режиме изменения исключённых локальных файлов игнорируются, поэтому они не деплоятся.
171
+
172
+ Не путайте с `deploy.exclude`. Это поле не даёт `amxb deploy` и `amxb watch` перезаписывать файлы сервера (например, существующие конфиги). А `amxmodx.exclude_files` просто не кладёт файлы в пакет.
173
+
158
174
  ## Управление плагинами и INI
159
175
 
160
176
  Секция `plugins:` описывает, какие плагины попадают в INI-файлы, как эти файлы называются и добавлять ли к строке плагина ` debug`. Она состоит из двух частей:
@@ -7,6 +7,7 @@ version: "1.0.0"
7
7
  amxmodx:
8
8
  dir: amxmodx
9
9
  defines: []
10
+ exclude_files: []
10
11
 
11
12
  github:
12
13
  token_env: GITHUB_TOKEN
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amxx-builder",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "author": {
5
5
  "name": "ArKaNeMaN"
6
6
  },
@@ -48,6 +48,7 @@
48
48
  "enquirer": "^2.4.1",
49
49
  "fast-glob": "^3.3.2",
50
50
  "js-yaml": "^4.3.1",
51
+ "micromatch": "^4.0.8",
51
52
  "simple-git": "^3.22.0"
52
53
  },
53
54
  "files": [
@@ -435,8 +435,10 @@ AMXB_LOCAL_SOURCES='Org/Repo=../Repo' amxb build
435
435
  - локальная папка `amxmodx/` всегда выигрывает у файлов из репо
436
436
  (намеренный слой переопределения, предупреждений нет);
437
437
  - `.sma`-файлы **и копируются** в пакет (как любые файлы), **и
438
- компилируются**; если исходники не должны попадать в архив — исключить
439
- их (для репо — `exclude:`/`exclude_files:` в правиле репозитория);
438
+ компилируются**; если исходники не должны попадать в архив, их можно
439
+ исключить: для репо через `exclude:`/`exclude_files:` в правиле
440
+ репозитория, для локальной `amxmodx/` через `amxmodx.exclude_files`
441
+ (glob-паттерны относительно `amxmodx.dir`);
440
442
  - README.md попадает в архив только при `output.readme: true` (дефолт);
441
443
  - агент-доки и скиллы проекта можно объявить верхнеуровневыми `docs:`
442
444
  (файлы) и `skills:` (одиночный файл либо папка с `SKILL.md` +
package/src/collector.js CHANGED
@@ -82,7 +82,7 @@ async function collectAll(manifest, repoLocalDirs, buildDir) {
82
82
  const files = await glob('**/*', {
83
83
  cwd: localAmxmodxDir,
84
84
  onlyFiles: true,
85
- ignore: [],
85
+ ignore: manifest.amxmodx.exclude_files || [],
86
86
  });
87
87
  for (const f of files) {
88
88
  const dest = path.join(amxmodxBuildDir, f);
package/src/manifest.js CHANGED
@@ -71,6 +71,9 @@ function parseManifest(manifestPath) {
71
71
  defines: (raw.amxmodx && Array.isArray(raw.amxmodx.defines))
72
72
  ? raw.amxmodx.defines.map(String)
73
73
  : [],
74
+ exclude_files: (raw.amxmodx && Array.isArray(raw.amxmodx.exclude_files))
75
+ ? raw.amxmodx.exclude_files.map(String)
76
+ : [],
74
77
  },
75
78
  github: { token_env: tokenEnv, tokens, token, ssh },
76
79
  globalDeps,
package/src/watcher.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const crypto = require('crypto');
6
+ const micromatch = require('micromatch');
6
7
  const logger = require('./logger');
7
8
 
8
9
  const fileHashes = new Map();
@@ -16,6 +17,22 @@ function contentChanged(filePath) {
16
17
  return true;
17
18
  }
18
19
 
20
+ /**
21
+ * True when a path under the project's local `amxmodx/` dir matches one of the
22
+ * `amxmodx.exclude_files` patterns. `relPath` is relative to `amxmodx.dir`;
23
+ * patterns follow the same forward-slash convention as `repos[].exclude_files`.
24
+ * Missing/empty patterns → false (default behavior: nothing excluded).
25
+ *
26
+ * @param {string} relPath
27
+ * @param {string[]} [patterns]
28
+ * @returns {boolean}
29
+ */
30
+ function isExcludedLocalAmxmodx(relPath, patterns) {
31
+ if (!Array.isArray(patterns) || patterns.length === 0) return false;
32
+ const normalized = String(relPath).split(path.sep).join('/');
33
+ return micromatch.isMatch(normalized, patterns, { dot: true });
34
+ }
35
+
19
36
  /**
20
37
  * Starts watching local project files for changes.
21
38
  *
@@ -83,6 +100,10 @@ function startWatch(manifest, manifestPath, handlers) {
83
100
  const section = inAmxmodx ? 'amxmodx' : 'assets';
84
101
  const baseDir = inAmxmodx ? localAmxmodxDir : localAssetsDir;
85
102
  let relToBase = path.relative(baseDir, absPath);
103
+ if (inAmxmodx && isExcludedLocalAmxmodx(relToBase, manifest.amxmodx.exclude_files || [])) {
104
+ logger.dim(` skip (excluded): ${rel}`);
105
+ return;
106
+ }
86
107
  if (inAmxmodx && caseNorm(relToBase).endsWith('.inc')) return; // includes are never deployed
87
108
  if (inAmxmodx && caseNorm(relToBase).endsWith('.sma')) {
88
109
  // A deleted .sma should remove its compiled output, not the source copy.
@@ -111,6 +132,11 @@ function startWatch(manifest, manifestPath, handlers) {
111
132
  const baseDir = inAmxmodx ? localAmxmodxDir : localAssetsDir;
112
133
  const relToBase = path.relative(baseDir, absPath);
113
134
 
135
+ if (inAmxmodx && isExcludedLocalAmxmodx(relToBase, manifest.amxmodx.exclude_files || [])) {
136
+ logger.dim(` skip (excluded): ${rel}`);
137
+ return;
138
+ }
139
+
114
140
  if (inAmxmodx && caseNorm(filePath).endsWith('.sma')) {
115
141
  logger.step(`Changed: ${rel}`);
116
142
  safeCall(() => handlers.onSmaChange(absPath));
@@ -132,4 +158,4 @@ function startWatch(manifest, manifestPath, handlers) {
132
158
  return watcher;
133
159
  }
134
160
 
135
- module.exports = { startWatch };
161
+ module.exports = { startWatch, isExcludedLocalAmxmodx };