@retailcrm/embed-ui 0.9.22-alpha.3 → 0.9.22-alpha.5
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/CHANGELOG.md +13 -0
- package/README.md +10 -4
- package/bin/embed-ui.mjs +371 -49
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## [0.9.22-alpha.5](https://github.com/retailcrm/embed-ui/compare/v0.9.22-alpha.4...v0.9.22-alpha.5) (2026-05-19)
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* Embed UI init flow improved ([50357d6](https://github.com/retailcrm/embed-ui/commit/50357d647d5288c9794e46ef91a36d2da6620101))
|
|
9
|
+
* Embed UI init MCP setup completed ([749c87a](https://github.com/retailcrm/embed-ui/commit/749c87a64bab67b6ed72aed7391ccf24403943ff))
|
|
10
|
+
## [0.9.22-alpha.4](https://github.com/retailcrm/embed-ui/compare/v0.9.22-alpha.3...v0.9.22-alpha.4) (2026-05-19)
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* Deprecated deep equality dependency removed ([32abfbc](https://github.com/retailcrm/embed-ui/commit/32abfbc540609b4b3e611ca7dd5331d92be56d83))
|
|
15
|
+
* Embed UI init output noise reduced ([d8d8c7b](https://github.com/retailcrm/embed-ui/commit/d8d8c7b99e1e0201fc4a4a8753931c799fdc005a))
|
|
16
|
+
* Release job hang prevented ([17ca586](https://github.com/retailcrm/embed-ui/commit/17ca5861c2227936bf8ea2b24e2670a17a1e7295))
|
|
4
17
|
## [0.9.22-alpha.3](https://github.com/retailcrm/embed-ui/compare/v0.9.22-alpha.2...v0.9.22-alpha.3) (2026-05-18)
|
|
5
18
|
|
|
6
19
|
### Features
|
package/README.md
CHANGED
|
@@ -38,9 +38,11 @@ npx @retailcrm/embed-ui --help
|
|
|
38
38
|
- добавляет `package.json`, если его еще нет;
|
|
39
39
|
- добавляет зависимости `@retailcrm/embed-ui*`, `vue`, `pinia`, `vue-i18n` и dev-зависимости для Vite, TypeScript и ESLint;
|
|
40
40
|
- создает `tsconfig.json`, `vite.config.ts`, `eslint.config.js`, `env.d.ts`;
|
|
41
|
+
- создает или дополняет `.gitignore` типовыми правилами для `node_modules`, `dist`, `coverage`, `.env` и логов;
|
|
41
42
|
- создает стартовые файлы во frontend-каталоге: endpoint worker, страницу настроек, виджет заказа, i18n JSON-сообщения;
|
|
42
43
|
- добавляет `extensionrc.json` и `scripts/publish-extension.mjs`;
|
|
43
|
-
- добавляет `AGENTS.md` и MCP-настройки пакетов, если они не отключены
|
|
44
|
+
- добавляет `AGENTS.md` и MCP-настройки пакетов, если они не отключены флагами;
|
|
45
|
+
- может инициализировать Git-репозиторий, если включить `--git` или выбрать это действие в интерактивном режиме.
|
|
44
46
|
|
|
45
47
|
```bash
|
|
46
48
|
npx @retailcrm/embed-ui init ./web --package-manager yarn
|
|
@@ -52,13 +54,15 @@ npx @retailcrm/embed-ui init ./web --package-manager yarn
|
|
|
52
54
|
- frontend-каталог — позиционный аргумент команды, а если его нет, то `./src` для нового проекта или `./web`, если `./src` уже существует;
|
|
53
55
|
- версия пакетов — версия запущенного CLI;
|
|
54
56
|
- package manager — определяется по единственному lock-файлу в корне проекта, в интерактивном терминале запрашивается у пользователя, в неинтерактивном режиме используется `npm`;
|
|
57
|
+
- интерактивный выбор package manager показывает только найденные в `PATH` варианты, а явно выбранный недоступный manager останавливает `init` до записи файлов;
|
|
55
58
|
- пакеты — `@retailcrm/embed-ui`, `v1-components`, `v1-contexts`, `v1-types` и `v1-endpoint`;
|
|
56
59
|
- установка зависимостей — запускается автоматически после изменения `package.json`;
|
|
57
60
|
- шаблон — создается стартовая конфигурация для страницы настроек и виджета `order/card:common.after`;
|
|
58
61
|
- каталоги — создаются `endpoint`, `pages`, `widgets`, `shared`, `i18n` и `i18n/locales` внутри frontend-каталога;
|
|
59
62
|
- `AGENTS.md` — создается или дополняется инструкциями корневого пакета и выбранных пакетов;
|
|
60
63
|
- MCP — добавляется `.mcp.json` для `v1-endpoint`;
|
|
61
|
-
- client configs для Cursor, Junie и VS Code — не создаются без `--mcp-client-configs`;
|
|
64
|
+
- client configs для Codex CLI, Cursor, Junie и VS Code — не создаются без `--mcp-client-configs`;
|
|
65
|
+
- Git — в неинтерактивном режиме не инициализируется без `--git`, а в интерактивном режиме предлагается, если корень проекта не является Git-репозиторием;
|
|
62
66
|
- существующие файлы не перезаписываются, а зависимости с потенциальным конфликтом не заменяются без явных force-флагов.
|
|
63
67
|
|
|
64
68
|
По умолчанию команда использует текущий рабочий каталог как корень проекта. Его можно задать явно:
|
|
@@ -74,6 +78,7 @@ npx @retailcrm/embed-ui init ./web --cwd ./my-project --package-manager npm
|
|
|
74
78
|
|
|
75
79
|
- `--no-install` — не запускать установку зависимостей после изменения `package.json`.
|
|
76
80
|
- `--interactive` — задать основные параметры через TTY-интерфейс со списками выбора, сохранив флаги как явные ограничения.
|
|
81
|
+
- `--verbose` — вывести подробный список изменений после `init`; без него CLI печатает краткую сводку.
|
|
77
82
|
- `--version 0.9.21` — использовать указанную версию пакетов вместо версии запущенного CLI.
|
|
78
83
|
- `--exact` — записывать точные версии вместо диапазонов.
|
|
79
84
|
- `--packages embed-ui,components,contexts,types,endpoint` — явно выбрать пакеты для установки и настройки.
|
|
@@ -84,7 +89,8 @@ npx @retailcrm/embed-ui init ./web --cwd ./my-project --package-manager npm
|
|
|
84
89
|
- `--no-template` — не создавать стартовые Vue-файлы и `extensionrc.json`.
|
|
85
90
|
- `--no-agents` — не создавать и не дополнять `AGENTS.md`.
|
|
86
91
|
- `--no-mcp` — не добавлять MCP-настройки пакетов.
|
|
87
|
-
- `--mcp-client-configs cursor,junie,vscode` — дополнительно создать
|
|
92
|
+
- `--mcp-client-configs codex,cursor,junie,vscode` — дополнительно подключить или создать конфиги поддерживаемых AI-клиентов.
|
|
93
|
+
- `--git` — выполнить `git init` в корне проекта, если каталог еще не является Git-репозиторием.
|
|
88
94
|
|
|
89
95
|
`--force` включает силовой режим для управляемых частей, но учитывает флаги `--no-*`. Например, можно обновить только
|
|
90
96
|
агентские инструкции и MCP-настройки без перегенерации стартовых файлов:
|
|
@@ -110,7 +116,7 @@ npx @retailcrm/embed-ui init ./web --force --no-install --no-template
|
|
|
110
116
|
Чтобы добавить только поддерживаемые project-level конфиги, укажите:
|
|
111
117
|
|
|
112
118
|
```bash
|
|
113
|
-
npx @retailcrm/embed-ui init ./web --no-install --mcp-client-configs cursor,junie,vscode
|
|
119
|
+
npx @retailcrm/embed-ui init ./web --no-install --mcp-client-configs codex,cursor,junie,vscode
|
|
114
120
|
```
|
|
115
121
|
|
|
116
122
|
Повторный запуск без `--force` не дублирует управляемые секции и записи MCP. При `--force` обновляются только записи
|
package/bin/embed-ui.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createInterface } from "node:readline/promises";
|
|
3
|
-
import { execFileSync } from "node:child_process";
|
|
3
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
@@ -27,13 +27,15 @@ Options:
|
|
|
27
27
|
--cwd <path> Project working directory for init
|
|
28
28
|
--package-manager Package manager for init installs
|
|
29
29
|
--interactive Ask init questions with TTY selection prompts
|
|
30
|
+
--verbose Print detailed init change lists
|
|
30
31
|
--no-install Do not run package manager install in init mode
|
|
31
32
|
--no-configs Do not create root TypeScript, Vite, ESLint and env config files
|
|
32
33
|
--force-deps Replace incompatible existing init dependencies
|
|
33
34
|
--fix-sections Move init dependencies to expected package.json sections
|
|
34
35
|
--no-agents Do not create or update AGENTS.md in init mode
|
|
35
36
|
--no-mcp Do not add package MCP instructions in init mode
|
|
36
|
-
--mcp-client-configs Comma-separated MCP client configs to create (cursor,junie,vscode)
|
|
37
|
+
--mcp-client-configs Comma-separated MCP client configs to create (codex,cursor,junie,vscode)
|
|
38
|
+
--git Initialize Git repository in init mode when cwd is not a Git work tree
|
|
37
39
|
-h, --help Show this help
|
|
38
40
|
|
|
39
41
|
Examples:
|
|
@@ -109,10 +111,14 @@ const parseInitArgs = (argv) => {
|
|
|
109
111
|
type: "string",
|
|
110
112
|
default: "order/card:common.after",
|
|
111
113
|
describe: "Starter widget target"
|
|
112
|
-
}).option("dry-run", { type: "boolean", default: false }).option("exact", { type: "boolean", default: false }).option("interactive", { type: "boolean", default: false }).option("install", { type: "boolean", default: true }).option("force", { type: "boolean", default: false }).option("force-deps", { type: "boolean", default: false }).option("fix-sections", { type: "boolean", default: false }).option("force-files", { type: "boolean", default: false }).option("configs", { type: "boolean", default: true }).option("dirs-enabled", { type: "boolean", default: true }).option("template-enabled", { type: "boolean", default: true }).option("agents", { type: "boolean", default: true }).option("force-agents", { type: "boolean", default: false }).option("agents-only", { type: "boolean", default: false }).option("mcp", { type: "boolean", default: true }).option("force-mcp", { type: "boolean", default: false }).option("mcp-client-configs", {
|
|
114
|
+
}).option("dry-run", { type: "boolean", default: false }).option("exact", { type: "boolean", default: false }).option("interactive", { type: "boolean", default: false }).option("verbose", { type: "boolean", default: false }).option("install", { type: "boolean", default: true }).option("force", { type: "boolean", default: false }).option("force-deps", { type: "boolean", default: false }).option("fix-sections", { type: "boolean", default: false }).option("force-files", { type: "boolean", default: false }).option("configs", { type: "boolean", default: true }).option("dirs-enabled", { type: "boolean", default: true }).option("template-enabled", { type: "boolean", default: true }).option("agents", { type: "boolean", default: true }).option("force-agents", { type: "boolean", default: false }).option("agents-only", { type: "boolean", default: false }).option("mcp", { type: "boolean", default: true }).option("force-mcp", { type: "boolean", default: false }).option("mcp-client-configs", {
|
|
113
115
|
type: "string",
|
|
114
116
|
coerce: parsePackageList,
|
|
115
117
|
describe: "Comma-separated MCP client config ids"
|
|
118
|
+
}).option("git", {
|
|
119
|
+
type: "boolean",
|
|
120
|
+
default: false,
|
|
121
|
+
describe: "Initialize Git repository when cwd is not a Git work tree"
|
|
116
122
|
}).parseSync();
|
|
117
123
|
if (parsed.help || parsed.h) {
|
|
118
124
|
console.log(HELP_TEXT);
|
|
@@ -136,6 +142,7 @@ const parseInitArgs = (argv) => {
|
|
|
136
142
|
with: parsed.with ?? null,
|
|
137
143
|
packageManager: parsed.packageManager ?? null,
|
|
138
144
|
interactive: parsed.interactive,
|
|
145
|
+
verbose: parsed.verbose,
|
|
139
146
|
noInstall: !parsed.install,
|
|
140
147
|
force: parsed.force,
|
|
141
148
|
forceDeps: parsed.forceDeps,
|
|
@@ -154,7 +161,8 @@ const parseInitArgs = (argv) => {
|
|
|
154
161
|
agentsOnly: parsed.agentsOnly,
|
|
155
162
|
noMcp: !parsed.mcp,
|
|
156
163
|
forceMcp: parsed.forceMcp,
|
|
157
|
-
mcpClientConfigs: parsed.mcpClientConfigs ?? null
|
|
164
|
+
mcpClientConfigs: parsed.mcpClientConfigs ?? null,
|
|
165
|
+
initGit: parsed.git
|
|
158
166
|
};
|
|
159
167
|
};
|
|
160
168
|
const parseArgs = (argv) => {
|
|
@@ -455,12 +463,13 @@ const INIT_RUNTIME_DEPENDENCIES = [
|
|
|
455
463
|
{ name: "@remote-ui/rpc", range: "^1.4.7" },
|
|
456
464
|
{ name: "pinia", range: "^2.2" },
|
|
457
465
|
{ name: "vue", range: "^3.5" },
|
|
458
|
-
{ name: "vue-i18n", range: "^11" }
|
|
466
|
+
{ name: "vue-i18n", range: "^11" },
|
|
467
|
+
{ name: "zod", range: "^4.4" }
|
|
459
468
|
];
|
|
460
469
|
const INIT_DEV_DEPENDENCIES = [
|
|
461
470
|
{ name: "@eslint/js", range: "^9.39" },
|
|
462
|
-
{ name: "@intlify/eslint-plugin-vue-i18n", range: "
|
|
463
|
-
{ name: "@intlify/unplugin-vue-i18n", range: "^11.
|
|
471
|
+
{ name: "@intlify/eslint-plugin-vue-i18n", range: "^4.4" },
|
|
472
|
+
{ name: "@intlify/unplugin-vue-i18n", range: "^11.2" },
|
|
464
473
|
{ name: "@omnicajs/eslint-plugin-dependencies", range: "^0.0.2" },
|
|
465
474
|
{ name: "@types/node", range: "^22.19" },
|
|
466
475
|
{ name: "@vitejs/plugin-vue", range: "^6.0" },
|
|
@@ -607,13 +616,7 @@ const setDependency = (packageJson, section, name, range, changes, options = {})
|
|
|
607
616
|
nextRange
|
|
608
617
|
});
|
|
609
618
|
};
|
|
610
|
-
const
|
|
611
|
-
const binPath = path.join(cwd, "node_modules", ".bin", process.platform === "win32" ? `${binName}.cmd` : binName);
|
|
612
|
-
return fs.existsSync(binPath) ? binPath : null;
|
|
613
|
-
};
|
|
614
|
-
const hasLocalPackage = (cwd, packageName) => fs.existsSync(path.join(cwd, "node_modules", packageName, "package.json"));
|
|
615
|
-
const createPackageSpec = (packageName, version) => version && version !== "not used" ? `${packageName}@${version}` : packageName;
|
|
616
|
-
const resolvePackageManagerVersion$1 = (packageManager) => {
|
|
619
|
+
const resolvePackageManagerVersion = (packageManager) => {
|
|
617
620
|
try {
|
|
618
621
|
return execFileSync(packageManager, ["--version"], {
|
|
619
622
|
encoding: "utf8",
|
|
@@ -623,6 +626,90 @@ const resolvePackageManagerVersion$1 = (packageManager) => {
|
|
|
623
626
|
return null;
|
|
624
627
|
}
|
|
625
628
|
};
|
|
629
|
+
const isPackageManagerAvailable = (packageManager) => resolvePackageManagerVersion(packageManager) !== null;
|
|
630
|
+
const assertPackageManagerAvailable = (packageManager) => {
|
|
631
|
+
if (!isPackageManagerAvailable(packageManager)) {
|
|
632
|
+
throw new Error(
|
|
633
|
+
`Package manager "${packageManager}" was selected, but its binary was not found in PATH. Install ${packageManager} or choose another package manager.`
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
const SPINNER_FRAMES = ["-", "\\", "|", "/"];
|
|
638
|
+
class CommandError extends Error {
|
|
639
|
+
stdout;
|
|
640
|
+
stderr;
|
|
641
|
+
constructor(command, exitCode, stdout, stderr) {
|
|
642
|
+
super(`Command failed${exitCode === null ? "" : ` with exit code ${exitCode}`}: ${command}`);
|
|
643
|
+
this.stdout = stdout;
|
|
644
|
+
this.stderr = stderr;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
const createSpinner = (message) => {
|
|
648
|
+
if (!process.stderr.isTTY) {
|
|
649
|
+
return () => void 0;
|
|
650
|
+
}
|
|
651
|
+
let frameIndex = 0;
|
|
652
|
+
process.stderr.write(`${SPINNER_FRAMES[frameIndex]} ${message}`);
|
|
653
|
+
const timer = setInterval(() => {
|
|
654
|
+
frameIndex = (frameIndex + 1) % SPINNER_FRAMES.length;
|
|
655
|
+
process.stderr.write(`\r${SPINNER_FRAMES[frameIndex]} ${message}`);
|
|
656
|
+
}, 100);
|
|
657
|
+
return () => {
|
|
658
|
+
clearInterval(timer);
|
|
659
|
+
};
|
|
660
|
+
};
|
|
661
|
+
const finishSpinner = (message, status) => {
|
|
662
|
+
if (process.stderr.isTTY) {
|
|
663
|
+
process.stderr.write(`\r${status} ${message}
|
|
664
|
+
`);
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
const runCommandWithTerminalStatus = async (command, args, options, message) => {
|
|
668
|
+
const stopSpinner = createSpinner(message);
|
|
669
|
+
const displayCommand = [command, ...args].join(" ");
|
|
670
|
+
let stdoutResult = "";
|
|
671
|
+
let stderrResult = "";
|
|
672
|
+
try {
|
|
673
|
+
await new Promise((resolve, reject) => {
|
|
674
|
+
const child = spawn(command, args, {
|
|
675
|
+
...options,
|
|
676
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
677
|
+
});
|
|
678
|
+
const stdout = [];
|
|
679
|
+
const stderr = [];
|
|
680
|
+
child.stdout.on("data", (chunk) => stdout.push(chunk));
|
|
681
|
+
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
682
|
+
child.on("error", reject);
|
|
683
|
+
child.on("close", (exitCode) => {
|
|
684
|
+
const stdoutBuffer = Buffer.concat(stdout);
|
|
685
|
+
const stderrBuffer = Buffer.concat(stderr);
|
|
686
|
+
stdoutResult = stdoutBuffer.toString("utf8");
|
|
687
|
+
stderrResult = stderrBuffer.toString("utf8");
|
|
688
|
+
if (exitCode === 0) {
|
|
689
|
+
resolve();
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
reject(new CommandError(displayCommand, exitCode, stdoutBuffer, stderrBuffer));
|
|
693
|
+
});
|
|
694
|
+
});
|
|
695
|
+
finishSpinner(message, "OK");
|
|
696
|
+
return {
|
|
697
|
+
stdout: stdoutResult,
|
|
698
|
+
stderr: stderrResult
|
|
699
|
+
};
|
|
700
|
+
} catch (error) {
|
|
701
|
+
finishSpinner(message, "FAIL");
|
|
702
|
+
throw error;
|
|
703
|
+
} finally {
|
|
704
|
+
stopSpinner();
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
const resolveLocalBinPath = (cwd, binName) => {
|
|
708
|
+
const binPath = path.join(cwd, "node_modules", ".bin", process.platform === "win32" ? `${binName}.cmd` : binName);
|
|
709
|
+
return fs.existsSync(binPath) ? binPath : null;
|
|
710
|
+
};
|
|
711
|
+
const hasLocalPackage = (cwd, packageName) => fs.existsSync(path.join(cwd, "node_modules", packageName, "package.json"));
|
|
712
|
+
const createPackageSpec = (packageName, version) => version && version !== "not used" ? `${packageName}@${version}` : packageName;
|
|
626
713
|
const resolveMajorVersion = (version) => {
|
|
627
714
|
const major = version?.match(/^\d+/u)?.[0];
|
|
628
715
|
return major ? Number(major) : null;
|
|
@@ -640,7 +727,7 @@ const resolveDownloadCommand = (packageName, binName, packageManager, args, pack
|
|
|
640
727
|
source: "transient"
|
|
641
728
|
};
|
|
642
729
|
}
|
|
643
|
-
const commandArgs2 = ["-y", "-p", packageSpec, binName, ...args];
|
|
730
|
+
const commandArgs2 = ["-y", "--loglevel=error", "-p", packageSpec, binName, ...args];
|
|
644
731
|
return {
|
|
645
732
|
command: "npx",
|
|
646
733
|
args: commandArgs2,
|
|
@@ -666,7 +753,7 @@ const resolveDownloadCommand = (packageName, binName, packageManager, args, pack
|
|
|
666
753
|
source: "transient"
|
|
667
754
|
};
|
|
668
755
|
}
|
|
669
|
-
const commandArgs = ["exec", "--yes", "--package", packageSpec, "--", binName, ...args];
|
|
756
|
+
const commandArgs = ["exec", "--yes", "--loglevel=error", "--package", packageSpec, "--", binName, ...args];
|
|
670
757
|
return {
|
|
671
758
|
command: "npm",
|
|
672
759
|
args: commandArgs,
|
|
@@ -674,7 +761,7 @@ const resolveDownloadCommand = (packageName, binName, packageManager, args, pack
|
|
|
674
761
|
source: "transient"
|
|
675
762
|
};
|
|
676
763
|
};
|
|
677
|
-
const resolvePackageHookCommand = (cwd, packageName, binName, packageManager, args, packageVersion = null, versionResolver = resolvePackageManagerVersion
|
|
764
|
+
const resolvePackageHookCommand = (cwd, packageName, binName, packageManager, args, packageVersion = null, versionResolver = resolvePackageManagerVersion) => {
|
|
678
765
|
const localBinPath = resolveLocalBinPath(cwd, binName);
|
|
679
766
|
if (localBinPath) {
|
|
680
767
|
return {
|
|
@@ -692,12 +779,29 @@ const resolvePackageHookCommand = (cwd, packageName, binName, packageManager, ar
|
|
|
692
779
|
return resolveDownloadCommand(packageName, binName, packageManager, args, packageVersion, versionResolver);
|
|
693
780
|
};
|
|
694
781
|
const getExecErrorMessage = (error) => {
|
|
782
|
+
if (error && typeof error === "object") {
|
|
783
|
+
const output = [
|
|
784
|
+
"stderr" in error ? error.stderr : null,
|
|
785
|
+
"stdout" in error ? error.stdout : null
|
|
786
|
+
].map((value) => value instanceof Buffer ? value.toString("utf8") : value).filter((value) => typeof value === "string" && value.trim().length > 0).map((value) => value.trim()).join("\n");
|
|
787
|
+
if (output) {
|
|
788
|
+
return output;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
695
791
|
if (error instanceof Error && error.message) {
|
|
696
792
|
return error.message;
|
|
697
793
|
}
|
|
698
794
|
return String(error);
|
|
699
795
|
};
|
|
700
|
-
const
|
|
796
|
+
const appendMcpHookNotices = (output, changes) => {
|
|
797
|
+
for (const line of output.split(/\r?\n/u)) {
|
|
798
|
+
const trimmedLine = line.trim();
|
|
799
|
+
if (trimmedLine.startsWith("MCP: ")) {
|
|
800
|
+
changes.mcp.push(trimmedLine.slice("MCP: ".length));
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
const runPackageHookCommand = async (cwd, packageName, binName, packageManager, args, failureMode, options, changes) => {
|
|
701
805
|
const command = resolvePackageHookCommand(
|
|
702
806
|
cwd,
|
|
703
807
|
packageName,
|
|
@@ -711,10 +815,13 @@ const runPackageHookCommand = (cwd, packageName, binName, packageManager, args,
|
|
|
711
815
|
return;
|
|
712
816
|
}
|
|
713
817
|
try {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
818
|
+
const result = await runCommandWithTerminalStatus(
|
|
819
|
+
command.command,
|
|
820
|
+
command.args,
|
|
821
|
+
{ cwd },
|
|
822
|
+
`Running ${packageName} ${args[0]}`
|
|
823
|
+
);
|
|
824
|
+
appendMcpHookNotices(result.stdout, changes);
|
|
718
825
|
} catch (error) {
|
|
719
826
|
if (command.source === "transient" && failureMode === "advisory") {
|
|
720
827
|
changes.warnings.push(`Package hook ${command.display} was skipped: ${getExecErrorMessage(error)}`);
|
|
@@ -759,12 +866,12 @@ const updateRootAgents = (cwd, options, changes) => {
|
|
|
759
866
|
}
|
|
760
867
|
changes.agents.push(`update ${agentsPath}`);
|
|
761
868
|
};
|
|
762
|
-
const runInitAgentsHook = (packageName, binName, cwd, packageManager, failureMode, options, changes) => {
|
|
869
|
+
const runInitAgentsHook = async (packageName, binName, cwd, packageManager, failureMode, options, changes) => {
|
|
763
870
|
const args = ["init-agents", cwd];
|
|
764
871
|
if (options.force || options.forceAgents) {
|
|
765
872
|
args.push("--force");
|
|
766
873
|
}
|
|
767
|
-
runPackageHookCommand(
|
|
874
|
+
await runPackageHookCommand(
|
|
768
875
|
cwd,
|
|
769
876
|
packageName,
|
|
770
877
|
binName,
|
|
@@ -775,7 +882,7 @@ const runInitAgentsHook = (packageName, binName, cwd, packageManager, failureMod
|
|
|
775
882
|
changes
|
|
776
883
|
);
|
|
777
884
|
};
|
|
778
|
-
const applyInitAgents = (cwd, selectedPackages, packageManager, options, changes) => {
|
|
885
|
+
const applyInitAgents = async (cwd, selectedPackages, packageManager, options, changes) => {
|
|
779
886
|
if (options.noAgents) {
|
|
780
887
|
return;
|
|
781
888
|
}
|
|
@@ -789,7 +896,7 @@ const applyInitAgents = (cwd, selectedPackages, packageManager, options, changes
|
|
|
789
896
|
changes.warnings.push(`Skipping ${selectedPackage.id} ${hook.command} because it currently includes MCP instructions`);
|
|
790
897
|
continue;
|
|
791
898
|
}
|
|
792
|
-
runInitAgentsHook(
|
|
899
|
+
await runInitAgentsHook(
|
|
793
900
|
selectedPackage.name,
|
|
794
901
|
hook.binName,
|
|
795
902
|
cwd,
|
|
@@ -801,7 +908,7 @@ const applyInitAgents = (cwd, selectedPackages, packageManager, options, changes
|
|
|
801
908
|
}
|
|
802
909
|
}
|
|
803
910
|
};
|
|
804
|
-
const applyInitPackageConfigHooks = (cwd, selectedPackages, packageManager, options, changes) => {
|
|
911
|
+
const applyInitPackageConfigHooks = async (cwd, selectedPackages, packageManager, options, changes) => {
|
|
805
912
|
for (const selectedPackage of selectedPackages) {
|
|
806
913
|
for (const hook of selectedPackage.hooks ?? []) {
|
|
807
914
|
if (hook.type !== "config") {
|
|
@@ -817,7 +924,7 @@ const applyInitPackageConfigHooks = (cwd, selectedPackages, packageManager, opti
|
|
|
817
924
|
if (hook.requiresMcp && options.mcpClientConfigs?.length) {
|
|
818
925
|
args.push("--mcp-client-configs", options.mcpClientConfigs.join(","));
|
|
819
926
|
}
|
|
820
|
-
runPackageHookCommand(
|
|
927
|
+
await runPackageHookCommand(
|
|
821
928
|
cwd,
|
|
822
929
|
selectedPackage.name,
|
|
823
930
|
hook.binName,
|
|
@@ -900,6 +1007,35 @@ const describePathState = (cwd, relativePath) => {
|
|
|
900
1007
|
}
|
|
901
1008
|
return `${relativePath}: found`;
|
|
902
1009
|
};
|
|
1010
|
+
const isGitWorkTree$2 = (cwd) => {
|
|
1011
|
+
try {
|
|
1012
|
+
execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
1013
|
+
cwd,
|
|
1014
|
+
encoding: "utf8",
|
|
1015
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1016
|
+
});
|
|
1017
|
+
return true;
|
|
1018
|
+
} catch {
|
|
1019
|
+
return false;
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
const analyzeGitDirectory = (cwd, options, changes) => {
|
|
1023
|
+
const gitPath = path.join(cwd, ".git");
|
|
1024
|
+
if (!fs.existsSync(gitPath)) {
|
|
1025
|
+
if (options.initGit) {
|
|
1026
|
+
changes.preflight.push("git: missing; git init enabled");
|
|
1027
|
+
}
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
if (isGitWorkTree$2(cwd)) {
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
if (options.initGit) {
|
|
1034
|
+
changes.preflight.push("git: invalid .git metadata; git init enabled");
|
|
1035
|
+
} else {
|
|
1036
|
+
changes.warnings.push(".git exists, but Git does not recognize this directory as a repository; initialize or repair Git metadata before relying on git context");
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
903
1039
|
const readExistingPackageJson = (packageJsonPath, changes) => {
|
|
904
1040
|
if (!fs.existsSync(packageJsonPath)) {
|
|
905
1041
|
changes.preflight.push("package.json: missing; it will be created");
|
|
@@ -1070,6 +1206,7 @@ const applyInitPreflight = (cwd, sourceRoot, packageManager, selectedPackages, v
|
|
|
1070
1206
|
if (!options.target && !options.srcDir && fs.existsSync(path.join(cwd, "src")) && path.basename(sourceRoot) === "web") {
|
|
1071
1207
|
changes.warnings.push("src/ already exists; generated frontend source root resolved to web/");
|
|
1072
1208
|
}
|
|
1209
|
+
analyzeGitDirectory(cwd, options, changes);
|
|
1073
1210
|
changes.preflight.push(describePathState(cwd, "src"));
|
|
1074
1211
|
changes.preflight.push(describePathState(cwd, "web"));
|
|
1075
1212
|
if (options.noConfigs) {
|
|
@@ -2190,6 +2327,7 @@ const createInitChanges = () => ({
|
|
|
2190
2327
|
files: [],
|
|
2191
2328
|
agents: [],
|
|
2192
2329
|
mcp: [],
|
|
2330
|
+
git: [],
|
|
2193
2331
|
hooks: [],
|
|
2194
2332
|
install: null,
|
|
2195
2333
|
skipped: [],
|
|
@@ -2209,6 +2347,10 @@ const printChanges = (changes) => {
|
|
|
2209
2347
|
}
|
|
2210
2348
|
};
|
|
2211
2349
|
const printInitReport = (cwd, sourceRoot, version, packageManager, changes, options) => {
|
|
2350
|
+
if (!options.verbose && !options.dryRun) {
|
|
2351
|
+
printInitSummary(cwd, sourceRoot, version, packageManager, changes);
|
|
2352
|
+
return;
|
|
2353
|
+
}
|
|
2212
2354
|
console.log(`CWD: ${cwd}`);
|
|
2213
2355
|
console.log(`Target: ${sourceRoot}`);
|
|
2214
2356
|
console.log(`Resolved version: ${version}`);
|
|
@@ -2236,7 +2378,8 @@ const printInitReport = (cwd, sourceRoot, version, packageManager, changes, opti
|
|
|
2236
2378
|
console.log("");
|
|
2237
2379
|
console.log("files");
|
|
2238
2380
|
for (const filePath of changes.files) {
|
|
2239
|
-
|
|
2381
|
+
const hasAction = /^(create|update)\s/u.test(filePath);
|
|
2382
|
+
console.log(` ${hasAction ? filePath : `create ${filePath}`}`);
|
|
2240
2383
|
}
|
|
2241
2384
|
}
|
|
2242
2385
|
if (changes.agents.length > 0) {
|
|
@@ -2260,6 +2403,13 @@ const printInitReport = (cwd, sourceRoot, version, packageManager, changes, opti
|
|
|
2260
2403
|
console.log(` ${options.dryRun ? "would run" : "ran"} ${hook}`);
|
|
2261
2404
|
}
|
|
2262
2405
|
}
|
|
2406
|
+
if (changes.git.length > 0) {
|
|
2407
|
+
console.log("");
|
|
2408
|
+
console.log("git");
|
|
2409
|
+
for (const gitChange of changes.git) {
|
|
2410
|
+
console.log(` ${gitChange}`);
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2263
2413
|
if (changes.install) {
|
|
2264
2414
|
console.log("");
|
|
2265
2415
|
console.log("install");
|
|
@@ -2284,6 +2434,43 @@ const printInitReport = (cwd, sourceRoot, version, packageManager, changes, opti
|
|
|
2284
2434
|
console.log("Dry run enabled, no files were modified.");
|
|
2285
2435
|
}
|
|
2286
2436
|
};
|
|
2437
|
+
const printInitSummary = (cwd, sourceRoot, version, packageManager, changes) => {
|
|
2438
|
+
console.log(`Initialized ${cwd}`);
|
|
2439
|
+
console.log(` source root: ${sourceRoot}`);
|
|
2440
|
+
console.log(` version: ${version}`);
|
|
2441
|
+
console.log(` package manager: ${packageManager}`);
|
|
2442
|
+
const summary = [
|
|
2443
|
+
changes.packageJson.length ? `package.json updated (${changes.packageJson.length} change(s))` : null,
|
|
2444
|
+
changes.directories.length ? `directories created: ${changes.directories.length}` : null,
|
|
2445
|
+
changes.files.length ? `files changed: ${changes.files.length}` : null,
|
|
2446
|
+
changes.agents.length ? "AGENTS.md updated" : null,
|
|
2447
|
+
changes.mcp.length ? "MCP config updated" : null,
|
|
2448
|
+
changes.git.length ? `git: ${changes.git.join(", ")}` : null,
|
|
2449
|
+
changes.hooks.length ? `package hooks ran: ${changes.hooks.length}` : null,
|
|
2450
|
+
changes.install ? `install: ${changes.install}` : null
|
|
2451
|
+
].filter((item) => typeof item === "string");
|
|
2452
|
+
if (summary.length > 0) {
|
|
2453
|
+
console.log("");
|
|
2454
|
+
console.log("changes");
|
|
2455
|
+
for (const item of summary) {
|
|
2456
|
+
console.log(` ${item}`);
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
if (changes.skipped.length > 0) {
|
|
2460
|
+
console.log("");
|
|
2461
|
+
console.log("skipped");
|
|
2462
|
+
for (const skipped of changes.skipped) {
|
|
2463
|
+
console.log(` ${skipped}`);
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
if (changes.warnings.length > 0) {
|
|
2467
|
+
console.log("");
|
|
2468
|
+
console.log("warnings");
|
|
2469
|
+
for (const warning of new Set(changes.warnings)) {
|
|
2470
|
+
console.log(` ${warning}`);
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
};
|
|
2287
2474
|
const isUpKey = (key, keybindings = []) => (
|
|
2288
2475
|
// The up key
|
|
2289
2476
|
key.name === "up" || // Vim keybinding: hjkl keys map to left/down/up/right
|
|
@@ -4320,6 +4507,7 @@ const INIT_ACTION_LABELS = {
|
|
|
4320
4507
|
template: "Создать стартовый шаблон",
|
|
4321
4508
|
agents: "Обновить AGENTS.md",
|
|
4322
4509
|
mcp: "Добавить MCP-настройки",
|
|
4510
|
+
git: "Инициализировать Git",
|
|
4323
4511
|
install: "Запустить установку зависимостей"
|
|
4324
4512
|
};
|
|
4325
4513
|
const INIT_ACTION_DESCRIPTIONS = {
|
|
@@ -4327,8 +4515,20 @@ const INIT_ACTION_DESCRIPTIONS = {
|
|
|
4327
4515
|
template: "Vue-точка входа, страница настроек, виджет заказа, i18n и publish script",
|
|
4328
4516
|
agents: "Общие и пакетные инструкции для AI-агентов",
|
|
4329
4517
|
mcp: ".mcp.json и MCP-инструкции пакетов",
|
|
4518
|
+
git: "git init в каталоге проекта, если Git еще не настроен",
|
|
4330
4519
|
install: "Запуск выбранного package manager после изменения package.json"
|
|
4331
4520
|
};
|
|
4521
|
+
const isGitWorkTree$1 = (cwd) => {
|
|
4522
|
+
try {
|
|
4523
|
+
execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
4524
|
+
cwd,
|
|
4525
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
4526
|
+
});
|
|
4527
|
+
return true;
|
|
4528
|
+
} catch {
|
|
4529
|
+
return false;
|
|
4530
|
+
}
|
|
4531
|
+
};
|
|
4332
4532
|
const resolveDefaultSourceRoot = (cwd, options) => {
|
|
4333
4533
|
if (options.srcDir) {
|
|
4334
4534
|
return options.srcDir;
|
|
@@ -4373,6 +4573,9 @@ const resolveAvailableActions = (options) => {
|
|
|
4373
4573
|
if (!options.noMcp) {
|
|
4374
4574
|
actions.push("mcp");
|
|
4375
4575
|
}
|
|
4576
|
+
if (!options.agentsOnly && !isGitWorkTree$1(options.cwd)) {
|
|
4577
|
+
actions.push("git");
|
|
4578
|
+
}
|
|
4376
4579
|
if (!options.agentsOnly && !options.noInstall) {
|
|
4377
4580
|
actions.push("install");
|
|
4378
4581
|
}
|
|
@@ -4384,6 +4587,7 @@ const applyPromptedActions = (options, selectedActions) => {
|
|
|
4384
4587
|
options.noTemplate = options.noTemplate || !selectedActionSet.has("template");
|
|
4385
4588
|
options.noAgents = options.noAgents || !selectedActionSet.has("agents");
|
|
4386
4589
|
options.noMcp = options.noMcp || !selectedActionSet.has("mcp");
|
|
4590
|
+
options.initGit = options.initGit || selectedActionSet.has("git");
|
|
4387
4591
|
options.noInstall = options.noInstall || !selectedActionSet.has("install");
|
|
4388
4592
|
};
|
|
4389
4593
|
const resolvePromptedActions = async (options) => {
|
|
@@ -4406,12 +4610,18 @@ const resolvePromptedPackageManager = async (detectedPackageManager, explicitPac
|
|
|
4406
4610
|
return explicitPackageManager;
|
|
4407
4611
|
}
|
|
4408
4612
|
const defaultPackageManager = detectedPackageManager ?? "npm";
|
|
4613
|
+
const availablePackageManagers = PACKAGE_MANAGERS.filter(isPackageManagerAvailable);
|
|
4614
|
+
if (availablePackageManagers.length === 0) {
|
|
4615
|
+
throw new Error("No supported package manager binary was found in PATH. Install npm, yarn, pnpm, or bun and rerun init.");
|
|
4616
|
+
}
|
|
4409
4617
|
return select({
|
|
4410
4618
|
message: "Package manager",
|
|
4411
|
-
default: defaultPackageManager,
|
|
4619
|
+
default: availablePackageManagers.includes(defaultPackageManager) ? defaultPackageManager : availablePackageManagers[0],
|
|
4412
4620
|
choices: PACKAGE_MANAGERS.map((packageManager) => ({
|
|
4413
4621
|
name: packageManager,
|
|
4414
|
-
value: packageManager
|
|
4622
|
+
value: packageManager,
|
|
4623
|
+
description: isPackageManagerAvailable(packageManager) ? "found in PATH" : "not found in PATH",
|
|
4624
|
+
disabled: isPackageManagerAvailable(packageManager) ? false : "not found in PATH"
|
|
4415
4625
|
}))
|
|
4416
4626
|
});
|
|
4417
4627
|
};
|
|
@@ -4445,6 +4655,49 @@ const resolveInteractiveInitOptions = async (cwd, options, detectedPackageManage
|
|
|
4445
4655
|
);
|
|
4446
4656
|
return nextOptions;
|
|
4447
4657
|
};
|
|
4658
|
+
const GITIGNORE_SECTION_HEADER = "# RetailCRM embed-ui init";
|
|
4659
|
+
const REQUIRED_GITIGNORE_ENTRIES = [
|
|
4660
|
+
"node_modules/",
|
|
4661
|
+
"dist/",
|
|
4662
|
+
"coverage/",
|
|
4663
|
+
".env",
|
|
4664
|
+
".env.*",
|
|
4665
|
+
"!.env.example",
|
|
4666
|
+
"*.log",
|
|
4667
|
+
"npm-debug.log*",
|
|
4668
|
+
"yarn-debug.log*",
|
|
4669
|
+
"yarn-error.log*",
|
|
4670
|
+
"pnpm-debug.log*",
|
|
4671
|
+
".DS_Store"
|
|
4672
|
+
];
|
|
4673
|
+
const normalizeGitignoreLine = (line) => line.trim().replace(/\/$/u, "");
|
|
4674
|
+
const hasGitignoreEntry = (lines, entry) => {
|
|
4675
|
+
const normalizedEntry = normalizeGitignoreLine(entry);
|
|
4676
|
+
return lines.some((line) => normalizeGitignoreLine(line) === normalizedEntry);
|
|
4677
|
+
};
|
|
4678
|
+
const updateGitignore = (cwd, options, changes) => {
|
|
4679
|
+
if (options.agentsOnly) {
|
|
4680
|
+
return;
|
|
4681
|
+
}
|
|
4682
|
+
const gitignorePath = path.join(cwd, ".gitignore");
|
|
4683
|
+
const fileExists = fs.existsSync(gitignorePath);
|
|
4684
|
+
const currentContent = fileExists ? fs.readFileSync(gitignorePath, "utf8") : "";
|
|
4685
|
+
const lines = currentContent.split(/\r?\n/u);
|
|
4686
|
+
const missingEntries = REQUIRED_GITIGNORE_ENTRIES.filter((entry) => !hasGitignoreEntry(lines, entry));
|
|
4687
|
+
if (missingEntries.length === 0) {
|
|
4688
|
+
changes.skipped.push(`${gitignorePath} already contains required init entries`);
|
|
4689
|
+
return;
|
|
4690
|
+
}
|
|
4691
|
+
const section = [
|
|
4692
|
+
GITIGNORE_SECTION_HEADER,
|
|
4693
|
+
...missingEntries
|
|
4694
|
+
].join(DEFAULT_NEWLINE);
|
|
4695
|
+
const nextContent = currentContent.trimEnd() ? `${currentContent.trimEnd()}${DEFAULT_NEWLINE}${DEFAULT_NEWLINE}${section}${DEFAULT_NEWLINE}` : `${section}${DEFAULT_NEWLINE}`;
|
|
4696
|
+
if (!options.dryRun) {
|
|
4697
|
+
fs.writeFileSync(gitignorePath, nextContent, "utf8");
|
|
4698
|
+
}
|
|
4699
|
+
changes.files.push(`${fileExists ? "update" : "create"} ${gitignorePath}`);
|
|
4700
|
+
};
|
|
4448
4701
|
const DEFAULT_INIT_DIRS = ["endpoint", "pages", "widgets", "shared", "i18n"];
|
|
4449
4702
|
const detectPackageManagerByLockfile = (cwd) => {
|
|
4450
4703
|
const knownLockfiles = [
|
|
@@ -4456,15 +4709,9 @@ const detectPackageManagerByLockfile = (cwd) => {
|
|
|
4456
4709
|
const lockfiles = knownLockfiles.filter(({ file }) => fs.existsSync(path.join(cwd, file)));
|
|
4457
4710
|
return lockfiles.length === 1 ? lockfiles[0].packageManager : null;
|
|
4458
4711
|
};
|
|
4459
|
-
const
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
encoding: "utf8",
|
|
4463
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
4464
|
-
}).trim();
|
|
4465
|
-
} catch {
|
|
4466
|
-
return null;
|
|
4467
|
-
}
|
|
4712
|
+
const resolvePackageManagerMajorVersion = (packageManager) => {
|
|
4713
|
+
const major = resolvePackageManagerVersion(packageManager)?.match(/^\d+/u)?.[0];
|
|
4714
|
+
return major ? Number(major) : null;
|
|
4468
4715
|
};
|
|
4469
4716
|
const promptForPackageManager = async () => {
|
|
4470
4717
|
const readline2 = createInterface({
|
|
@@ -4509,6 +4756,16 @@ const resolveInitPackages = (tokens, extraTokens) => {
|
|
|
4509
4756
|
}
|
|
4510
4757
|
return packages;
|
|
4511
4758
|
};
|
|
4759
|
+
const hasEnabledPackageHook = (selectedPackages, options) => selectedPackages.some((selectedPackage) => selectedPackage.hooks?.some((hook) => {
|
|
4760
|
+
if (hook.type === "agents") {
|
|
4761
|
+
return !options.noAgents && (!hook.requiresMcp || !options.noMcp);
|
|
4762
|
+
}
|
|
4763
|
+
if (hook.type === "config") {
|
|
4764
|
+
return !options.agentsOnly && (!hook.requiresMcp || !options.noMcp);
|
|
4765
|
+
}
|
|
4766
|
+
return false;
|
|
4767
|
+
}) ?? false);
|
|
4768
|
+
const shouldRequirePackageManagerBinary = (selectedPackages, options) => !options.dryRun && (!options.noInstall || hasEnabledPackageHook(selectedPackages, options));
|
|
4512
4769
|
const resolveInitCwd = (options) => {
|
|
4513
4770
|
const cwd = path.resolve(options.cwd);
|
|
4514
4771
|
if (!fs.existsSync(cwd)) {
|
|
@@ -4532,6 +4789,17 @@ const resolveInitSourceRoot = (cwd, options) => {
|
|
|
4532
4789
|
}
|
|
4533
4790
|
return path.join(cwd, "web");
|
|
4534
4791
|
};
|
|
4792
|
+
const isGitWorkTree = (cwd) => {
|
|
4793
|
+
try {
|
|
4794
|
+
execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
4795
|
+
cwd,
|
|
4796
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
4797
|
+
});
|
|
4798
|
+
return true;
|
|
4799
|
+
} catch {
|
|
4800
|
+
return false;
|
|
4801
|
+
}
|
|
4802
|
+
};
|
|
4535
4803
|
const runUpdate = (options) => {
|
|
4536
4804
|
const version = options.version ?? resolveLatestVersion();
|
|
4537
4805
|
const packageJsonPaths = collectPackageJsonPaths(options.target);
|
|
@@ -4698,7 +4966,7 @@ const applyInitTemplate = (cwd, sourceRoot, packageManager, options, changes) =>
|
|
|
4698
4966
|
writeFileIfAllowed(path.join(cwd, "scripts/publish-extension.mjs"), createPublishScript(), options, changes);
|
|
4699
4967
|
writeFileIfAllowed(path.join(cwd, "README.md"), createReadme(cwd, sourceRoot, options, packageManager), options, changes);
|
|
4700
4968
|
};
|
|
4701
|
-
const runInstall = (cwd, packageManager, options, changes, packageJsonChanged) => {
|
|
4969
|
+
const runInstall = async (cwd, packageManager, options, changes, packageJsonChanged) => {
|
|
4702
4970
|
if (options.noInstall || options.agentsOnly) {
|
|
4703
4971
|
return;
|
|
4704
4972
|
}
|
|
@@ -4706,15 +4974,64 @@ const runInstall = (cwd, packageManager, options, changes, packageJsonChanged) =
|
|
|
4706
4974
|
changes.skipped.push("install skipped because package.json was not changed");
|
|
4707
4975
|
return;
|
|
4708
4976
|
}
|
|
4709
|
-
const args =
|
|
4977
|
+
const args = resolveInstallArgs(packageManager);
|
|
4710
4978
|
changes.install = `${packageManager} ${args.join(" ")}`;
|
|
4711
4979
|
if (options.dryRun) {
|
|
4712
4980
|
return;
|
|
4713
4981
|
}
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4982
|
+
try {
|
|
4983
|
+
await runCommandWithTerminalStatus(
|
|
4984
|
+
packageManager,
|
|
4985
|
+
args,
|
|
4986
|
+
{ cwd },
|
|
4987
|
+
`Installing dependencies with ${packageManager}`
|
|
4988
|
+
);
|
|
4989
|
+
} catch (error) {
|
|
4990
|
+
printExecErrorOutput(error);
|
|
4991
|
+
throw error;
|
|
4992
|
+
}
|
|
4993
|
+
};
|
|
4994
|
+
const applyInitGit = async (cwd, options, changes) => {
|
|
4995
|
+
if (!options.initGit) {
|
|
4996
|
+
return;
|
|
4997
|
+
}
|
|
4998
|
+
if (isGitWorkTree(cwd)) {
|
|
4999
|
+
changes.skipped.push("git init skipped because cwd is already inside a Git work tree");
|
|
5000
|
+
return;
|
|
5001
|
+
}
|
|
5002
|
+
changes.git.push("git init");
|
|
5003
|
+
if (options.dryRun) {
|
|
5004
|
+
return;
|
|
5005
|
+
}
|
|
5006
|
+
await runCommandWithTerminalStatus("git", ["init"], { cwd }, "Initializing Git repository");
|
|
5007
|
+
};
|
|
5008
|
+
const resolveInstallArgs = (packageManager) => {
|
|
5009
|
+
if (packageManager === "yarn" && resolvePackageManagerMajorVersion(packageManager) === 1) {
|
|
5010
|
+
return ["install", "--silent"];
|
|
5011
|
+
}
|
|
5012
|
+
if (packageManager === "npm") {
|
|
5013
|
+
return ["install", "--loglevel=error"];
|
|
5014
|
+
}
|
|
5015
|
+
if (packageManager === "pnpm") {
|
|
5016
|
+
return ["install", "--loglevel=error"];
|
|
5017
|
+
}
|
|
5018
|
+
if (packageManager === "bun") {
|
|
5019
|
+
return ["install", "--silent"];
|
|
5020
|
+
}
|
|
5021
|
+
return ["install"];
|
|
5022
|
+
};
|
|
5023
|
+
const printExecErrorOutput = (error) => {
|
|
5024
|
+
if (!error || typeof error !== "object") {
|
|
5025
|
+
return;
|
|
5026
|
+
}
|
|
5027
|
+
const execError = error;
|
|
5028
|
+
for (const field of ["stdout", "stderr"]) {
|
|
5029
|
+
const value = execError[field];
|
|
5030
|
+
const output = value instanceof Buffer ? value.toString("utf8") : value;
|
|
5031
|
+
if (typeof output === "string" && output.trim().length > 0) {
|
|
5032
|
+
console.error(output.trim());
|
|
5033
|
+
}
|
|
5034
|
+
}
|
|
4718
5035
|
};
|
|
4719
5036
|
const runInit = async (options) => {
|
|
4720
5037
|
const cwd = resolveInitCwd(options);
|
|
@@ -4732,17 +5049,22 @@ const runInit = async (options) => {
|
|
|
4732
5049
|
const resolvedOptions = version === "not used" ? interactiveOptions : { ...interactiveOptions, version };
|
|
4733
5050
|
const packageManager = interactiveOptions.agentsOnly ? interactiveOptions.packageManager ?? detectPackageManagerByLockfile(cwd) ?? "npm" : await resolvePackageManager(cwd, interactiveOptions.packageManager);
|
|
4734
5051
|
const changes = createInitChanges();
|
|
5052
|
+
if (shouldRequirePackageManagerBinary(selectedPackages, resolvedOptions)) {
|
|
5053
|
+
assertPackageManagerAvailable(packageManager);
|
|
5054
|
+
}
|
|
4735
5055
|
applyInitPreflight(cwd, sourceRoot, packageManager, selectedPackages, version, resolvedOptions, changes);
|
|
5056
|
+
await applyInitGit(cwd, resolvedOptions, changes);
|
|
4736
5057
|
let packageJsonPath = null;
|
|
4737
5058
|
if (!resolvedOptions.agentsOnly) {
|
|
4738
5059
|
packageJsonPath = applyInitPackageJson(cwd, selectedPackages, version, packageManager, resolvedOptions, changes);
|
|
5060
|
+
updateGitignore(cwd, resolvedOptions, changes);
|
|
4739
5061
|
applyInitDirectories(sourceRoot, resolvedOptions, changes);
|
|
4740
5062
|
applyInitConfigs(cwd, sourceRoot, resolvedOptions, changes);
|
|
4741
5063
|
applyInitTemplate(cwd, sourceRoot, packageManager, resolvedOptions, changes);
|
|
4742
|
-
applyInitPackageConfigHooks(cwd, selectedPackages, packageManager, resolvedOptions, changes);
|
|
4743
5064
|
}
|
|
4744
|
-
|
|
4745
|
-
|
|
5065
|
+
await runInstall(cwd, packageManager, resolvedOptions, changes, Boolean(packageJsonPath && changes.packageJson.length > 0));
|
|
5066
|
+
await applyInitPackageConfigHooks(cwd, selectedPackages, packageManager, resolvedOptions, changes);
|
|
5067
|
+
await applyInitAgents(cwd, selectedPackages, packageManager, resolvedOptions, changes);
|
|
4746
5068
|
printInitReport(cwd, sourceRoot, version, packageManager, changes, resolvedOptions);
|
|
4747
5069
|
};
|
|
4748
5070
|
const main = async (argv = process$2.argv.slice(2)) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retailcrm/embed-ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.9.22-alpha.
|
|
4
|
+
"version": "0.9.22-alpha.5",
|
|
5
5
|
"description": "API and components for creating RetailCRM UI extensions",
|
|
6
6
|
"repository": "git@github.com:retailcrm/embed-ui.git",
|
|
7
7
|
"author": "RetailDriverLLC <integration@retailcrm.ru>",
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
"@omnicajs/symfony-router": "^1.0.0",
|
|
55
55
|
"@omnicajs/vue-remote": "^0.2.23",
|
|
56
56
|
"@remote-ui/rpc": "^1.4.5",
|
|
57
|
-
"@retailcrm/embed-ui-v1-components": "^0.9.22-alpha.
|
|
58
|
-
"@retailcrm/embed-ui-v1-contexts": "^0.9.22-alpha.
|
|
59
|
-
"@retailcrm/embed-ui-v1-endpoint": "^0.9.22-alpha.
|
|
60
|
-
"@retailcrm/embed-ui-v1-types": "^0.9.22-alpha.
|
|
57
|
+
"@retailcrm/embed-ui-v1-components": "^0.9.22-alpha.5",
|
|
58
|
+
"@retailcrm/embed-ui-v1-contexts": "^0.9.22-alpha.5",
|
|
59
|
+
"@retailcrm/embed-ui-v1-endpoint": "^0.9.22-alpha.5",
|
|
60
|
+
"@retailcrm/embed-ui-v1-types": "^0.9.22-alpha.5",
|
|
61
61
|
"yargs": "^17.7.2"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@modulify/git-toolkit": "^0.0.2",
|
|
67
67
|
"@modulify/pkg": "^1.0.1",
|
|
68
68
|
"@omnicajs/eslint-plugin-dependencies": "^0.0.2",
|
|
69
|
-
"@retailcrm/embed-ui-v1-testing": "^0.9.22-alpha.
|
|
69
|
+
"@retailcrm/embed-ui-v1-testing": "^0.9.22-alpha.5",
|
|
70
70
|
"@types/git-semver-tags": "^7.0.0",
|
|
71
71
|
"@types/node": "^22.19.2",
|
|
72
72
|
"@types/semver": "^7.7.1",
|