odant-work 1.0.12 → 1.0.13

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.
@@ -0,0 +1,19 @@
1
+ {
2
+ "enabled": true,
3
+ "docker": { "socketPath": null, "host": null, "port": null },
4
+ "image": "work-computer:latest",
5
+ "images": ["work-computer:latest", "python:3.12-slim", "node:22-slim"],
6
+ "workdir": "/workspace",
7
+ "user": "",
8
+ "limits": { "memoryMb": 1024, "cpus": 1, "pids": 256 },
9
+ "maxPerUser": 2,
10
+ "maxRunning": 4,
11
+ "idleStopMin": 10,
12
+ "execTimeoutSec": 120,
13
+ "maxReadBytes": 1000000,
14
+ "maxWriteBytes": 200000,
15
+ "maxOutput": 200000,
16
+ "network": { "egressName": "work-egress", "sandboxName": "work-sandbox", "ttlMin": 15 },
17
+ "graphical": ["work-computer:latest"],
18
+ "displayWaitSec": 30
19
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "admins": []
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "odant-work",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "ODANT-WORK — платформа цифровой организации (встроенная система учёта, документооборот, управление процессами и приватный мультимодальный ИИ)",
5
5
  "type": "module",
6
6
  "main": "sources/work.js",
package/run.mjs CHANGED
@@ -23,19 +23,36 @@ function readVersion(file) {
23
23
 
24
24
  /**
25
25
  * Нужна ли установка зависимостей.
26
- * Сравниваем ВЕРСИИ, а не mtime файлов: git checkout/revert/reset (и svn update) переписывают
27
- * package.json и package-lock.json, из-за чего прежняя проверка по времени считала пакет
28
- * «устаревшим» на каждом старте, запускала `npm i --production` и завершала процесс кодом 1.
26
+ * 1) Проверяем, разрешаются ли все dependencies из package.json через import.meta.resolve
27
+ * (учитывает как локальный node_modules, так и поднятый родительский node_modules при установке через npm/npx).
28
+ * 2) Если рядом есть package-lock.json (репозиторий Git/SVN), дополнительно сверяем версии package.json и package-lock.json.
29
29
  */
30
30
  function isPackageActual() {
31
- const nodeModules = path.join(currentDirectory, 'node_modules');
32
- if (!fs.existsSync(nodeModules))
33
- return false;
34
- const packageVersion = readVersion(path.join(currentDirectory, 'package.json'));
35
- const lockVersion = readVersion(path.join(currentDirectory, 'package-lock.json'));
36
- if (!packageVersion || !lockVersion)
31
+ try {
32
+ const pkgFile = path.join(currentDirectory, 'package.json');
33
+ if (!fs.existsSync(pkgFile))
34
+ return false;
35
+ const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf8'));
36
+ const deps = Object.keys(pkg.dependencies || {});
37
+ for (const dep of deps) {
38
+ try {
39
+ import.meta.resolve(dep);
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ const lockFile = path.join(currentDirectory, 'package-lock.json');
46
+ if (fs.existsSync(lockFile)) {
47
+ const lockVersion = readVersion(lockFile);
48
+ if (pkg.version && lockVersion && pkg.version !== lockVersion)
49
+ return false;
50
+ }
51
+ return true;
52
+ }
53
+ catch {
37
54
  return false;
38
- return packageVersion === lockVersion;
55
+ }
39
56
  }
40
57
 
41
58
  if (!isPackageActual()) {
@@ -60,12 +77,62 @@ if (!isPackageActual()) {
60
77
  await npmInstall;
61
78
  }
62
79
 
80
+ const workRoot = path.resolve(process.cwd());
81
+ const pkgRoot = path.resolve(currentDirectory);
82
+
83
+ /**
84
+ * Если запуск выполнен через `npx odant-work` или из `node_modules/odant-work` в рабочей папке (например, D:\WORK),
85
+ * автоматически разворачиваем или безопасно обновляем рабочую директорию из установленного пакета.
86
+ */
87
+ if (workRoot !== pkgRoot) {
88
+ const pkgVersion = readVersion(path.join(pkgRoot, 'package.json'));
89
+ const manifestVersion = readVersion(path.join(workRoot, '#system', 'package-manifest.json'));
90
+ const hasServerTree = fs.existsSync(path.join(workRoot, '$server', '$folder'));
91
+ if (!hasServerTree || (pkgVersion && manifestVersion !== pkgVersion)) {
92
+ const { applyUpdateFromDirectory } = await import('./sources/host/auto-updater.js');
93
+ const report = applyUpdateFromDirectory({
94
+ sourceDir: pkgRoot,
95
+ rootDir: workRoot,
96
+ newVersion: pkgVersion || '',
97
+ });
98
+ console.log(`[WORK] Рабочая директория синхронизирована с пакетом odant-work@${report.toVersion} (${workRoot})`);
99
+ }
100
+ }
101
+
102
+ /**
103
+ * При первом запуске в чистой папке автоматически засеваем демонстрационную базу Маслоторг,
104
+ * если класс организации присутствует, а файла work.db ещё нет.
105
+ */
106
+ const maslotorgClass = path.join(workRoot, 'ORGANIZATIONS', 'Маслоторг', '$base', 'class.js');
107
+ const maslotorgDb = path.join(workRoot, 'ORGANIZATIONS', 'Маслоторг', '$base', '#system', 'work.db');
108
+ if (!process.env.WORK_TEST && fs.existsSync(maslotorgClass) && !fs.existsSync(maslotorgDb)) {
109
+ try {
110
+ const { openDataDb } = await import('./sources/data/db.js');
111
+ const { refreshClasses } = await import('./sources/data/classes.js');
112
+ const { queryObjects } = await import('./sources/data/objects.js');
113
+ const { seedDemo, seedDemoOperations } = await import('./scripts/demo-seed.mjs');
114
+ const prefix = '/ORGANIZATIONS/Маслоторг/MODULES/Register';
115
+ const orgBase = '/ORGANIZATIONS/Маслоторг';
116
+ const db = await openDataDb(maslotorgDb);
117
+ await refreshClasses(db, workRoot);
118
+ if (!queryObjects(db, { cid: `${prefix}/CATALOGS/Виды нормативов`, limit: 1 }).total) {
119
+ const ids = seedDemo(db, { prefix });
120
+ seedDemoOperations(db, ids, { prefix, orgBase });
121
+ console.log('[WORK] Инициализирована демонстрационная база данных /ORGANIZATIONS/Маслоторг.');
122
+ }
123
+ db.close();
124
+ }
125
+ catch (err) {
126
+ console.warn('[WORK] Не удалось засеять демо-базу Маслоторг:', err?.message || err);
127
+ }
128
+ }
129
+
63
130
  /**
64
131
  * Если предыдущий экземпляр `run.mjs` остался висеть в фоне и держит порт 8001 / STUN 3478,
65
132
  * аккуратно завершаем его перед стартом нового экземпляра.
66
133
  */
67
134
  async function releasePreviousInstance() {
68
- const pidFile = path.join(currentDirectory, '#system', 'run.pid');
135
+ const pidFile = path.join(workRoot, '#system', 'run.pid');
69
136
  try {
70
137
  if (fs.existsSync(pidFile)) {
71
138
  const oldPid = Number(fs.readFileSync(pidFile, 'utf8').trim());
@@ -66,4 +66,28 @@ if (ignored.length) {
66
66
  console.error(' ' + f);
67
67
  process.exit(1);
68
68
  }
69
- console.log('Код не игнорируется: ' + candidates.length + ' файлов проверено, потерь нет.');
69
+
70
+ // Проверяем также .npmignore через npm pack --dry-run --json (кроме tests и license-server)
71
+ const NPM_CODE_ROOTS = new Set(['$server', 'sources', 'oda', 'scripts', 'rules', 'MODELS', 'NODES', 'SERVICES']);
72
+ const npmCandidates = candidates.filter(f => {
73
+ const top = f.split('/')[0];
74
+ return NPM_CODE_ROOTS.has(top) || !f.includes('/');
75
+ });
76
+ const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
77
+ const packRes = spawnSync(npmCmd, ['pack', '--dry-run', '--json'], { cwd: ROOT, encoding: 'utf-8', shell: process.platform === 'win32' });
78
+ if (!packRes.error && packRes.status === 0 && packRes.stdout) {
79
+ try {
80
+ const packJson = JSON.parse(packRes.stdout);
81
+ const packedLower = new Set((packJson[0]?.files || []).map(f => String(f.path || '').toLowerCase()));
82
+ const missingFromNpm = npmCandidates.filter(f => !packedLower.has(f.toLowerCase()));
83
+ if (missingFromNpm.length) {
84
+ console.error('check-ignored-code: ФАЙЛЫ КОДА ПОДПАДАЮТ ПОД .npmignore и НЕ попадут в пакет npm:');
85
+ for (const f of missingFromNpm)
86
+ console.error(' ' + f);
87
+ process.exit(1);
88
+ }
89
+ }
90
+ catch { /* ignore json parse error */ }
91
+ }
92
+
93
+ console.log('Код не игнорируется (.gitignore и .npmignore): ' + candidates.length + ' файлов проверено, потерь нет.');