ai-department 0.1.0 → 0.1.2
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 +2 -1
- package/app/attest.mjs +1 -1
- package/app/cli.mjs +37 -7
- package/app/server.mjs +529 -421
- package/dist/client/assets/{index-CPaeMJ4s.js → index-DL7KuobO.js} +18 -18
- package/dist/client/index.html +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Phòng làm việc của các AI viết code (Codex, Claude Code, Antigravity) c
|
|
|
4
4
|
|
|
5
5
|
## Cần có
|
|
6
6
|
|
|
7
|
-
- **Node.js
|
|
7
|
+
- **Node.js 18 trở lên.** App chạy trên Node 24. Nếu máy đang dùng Node cũ hơn, lần chạy đầu app tự tải một bản Node 24 riêng (khoảng 30 MB, cần có mạng) vào thư mục dữ liệu. Node của máy giữ nguyên, nên các dự án khác không bị ảnh hưởng.
|
|
8
8
|
- Ít nhất một AI đã cài và đăng nhập trên máy: Codex, Claude Code hoặc Antigravity. Có thể cài sau, ngay trong app.
|
|
9
9
|
|
|
10
10
|
## Cài từ npm
|
|
@@ -45,6 +45,7 @@ Muốn đổi chỗ thì đặt biến môi trường `AIDEPT_HOME` trước khi
|
|
|
45
45
|
Bên trong thư mục dữ liệu:
|
|
46
46
|
- `.data/ai-department.sqlite`: dự án, việc, lịch sử.
|
|
47
47
|
- `.data/workspaces`: bản sao làm việc của từng việc. Thư mục này có thể lớn; dọn ở **Theo dõi → Hệ thống**.
|
|
48
|
+
- `runtime`: chỉ có khi máy dùng Node cũ hơn 24. Đây là bản Node 24 riêng của app; xoá đi thì lần chạy sau app tải lại.
|
|
48
49
|
|
|
49
50
|
Muốn sao lưu thì tắt app rồi copy thư mục `.data`.
|
|
50
51
|
|
package/app/attest.mjs
CHANGED
|
@@ -26,7 +26,7 @@ async function executeFile(executable, args2, options = {}) {
|
|
|
26
26
|
windowsHide: true,
|
|
27
27
|
cwd: options.cwd,
|
|
28
28
|
stdio: ["pipe", "pipe", "pipe"],
|
|
29
|
-
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GCM_INTERACTIVE: "never" }
|
|
29
|
+
env: { ...process.env, ...options.env, GIT_TERMINAL_PROMPT: "0", GCM_INTERACTIVE: "never" }
|
|
30
30
|
});
|
|
31
31
|
let stdout = "", stderr = "", bytes = 0, timedOut = false, overflow = false;
|
|
32
32
|
const limit = options.maxOutputBytes ?? 16 * 1024 * 1024;
|
package/app/cli.mjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// It keeps the person's data outside the package, so updating or reinstalling never touches it:
|
|
4
4
|
// ~/.ai-department by default, or the folder in AIDEPT_HOME (the portable zip sets it to its own folder).
|
|
5
5
|
import { spawn } from 'node:child_process';
|
|
6
|
-
import { mkdirSync, readFileSync } from 'node:fs';
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
7
7
|
import { homedir } from 'node:os';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
@@ -26,14 +26,44 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
26
26
|
process.exit(0);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const major = Number(process.versions.node.split('.')[0]);
|
|
30
|
-
if (major < 24) {
|
|
31
|
-
console.error(`AI Department cần Node.js 24 trở lên; máy này đang có ${process.version}. Tải bản mới ở https://nodejs.org`);
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
29
|
const home = path.resolve(process.env.AIDEPT_HOME ?? path.join(homedir(), '.ai-department'));
|
|
36
30
|
mkdirSync(home, { recursive: true });
|
|
31
|
+
|
|
32
|
+
// The app needs Node 24 (built-in SQLite). On an older Node, fetch a private Node 24 into <home>/runtime once, through
|
|
33
|
+
// the person's own npm (the `node` package on npm ships the binary), and run this same script with it. The machine's
|
|
34
|
+
// Node stays as it is, so other projects are not affected.
|
|
35
|
+
const RUNTIME_MAJOR = 24;
|
|
36
|
+
if (Number(process.versions.node.split('.')[0]) < RUNTIME_MAJOR) {
|
|
37
|
+
const runtimeDir = path.join(home, 'runtime');
|
|
38
|
+
const node = path.join(runtimeDir, 'node_modules', 'node', 'bin', process.platform === 'win32' ? 'node.exe' : 'node');
|
|
39
|
+
if (!existsSync(node)) {
|
|
40
|
+
console.log(`Máy đang dùng Node ${process.version}; AI Department cần Node ${RUNTIME_MAJOR}.`);
|
|
41
|
+
console.log(`Đang tải một bản Node ${RUNTIME_MAJOR} riêng cho AI Department (khoảng 30 MB, chỉ một lần) vào ${runtimeDir}\n`);
|
|
42
|
+
mkdirSync(runtimeDir, { recursive: true });
|
|
43
|
+
const ok = await npmInstall(runtimeDir, `node@${RUNTIME_MAJOR}`);
|
|
44
|
+
if (!ok || !existsSync(node)) {
|
|
45
|
+
console.error(`\nKhông tải được Node ${RUNTIME_MAJOR}. Kiểm tra kết nối mạng rồi chạy lại, hoặc cài Node.js ${RUNTIME_MAJOR} từ https://nodejs.org`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Ctrl+C reaches both processes; the child shuts the server down, this one only waits for it.
|
|
50
|
+
process.on('SIGINT', () => undefined);
|
|
51
|
+
const child = spawn(node, [fileURLToPath(import.meta.url), ...args], { stdio: 'inherit' });
|
|
52
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
53
|
+
child.on('error', (error) => { console.error(`Không chạy được ${node}: ${error.message}`); process.exit(1); });
|
|
54
|
+
await new Promise(() => undefined);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** `npm install --prefix <dir> <spec>` with the npm that came with this Node (npm-cli.js sits next to node), else npm on PATH. */
|
|
58
|
+
function npmInstall(dir, spec) {
|
|
59
|
+
const args = ['install', '--prefix', dir, spec, '--no-audit', '--no-fund', '--loglevel', 'error'];
|
|
60
|
+
const bin = path.dirname(process.execPath);
|
|
61
|
+
const cli = [path.join(bin, 'node_modules', 'npm', 'bin', 'npm-cli.js'), path.join(bin, '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js')].find((p) => existsSync(p));
|
|
62
|
+
const child = cli ? spawn(process.execPath, [cli, ...args], { stdio: 'inherit' })
|
|
63
|
+
: spawn(['npm', ...args.map((a) => (/[\s"]/.test(a) ? `"${a}"` : a))].join(' '), { stdio: 'inherit', shell: true });
|
|
64
|
+
return new Promise((resolve) => { child.on('exit', (code) => resolve(code === 0)); child.on('error', () => resolve(false)); });
|
|
65
|
+
}
|
|
66
|
+
|
|
37
67
|
process.chdir(home);
|
|
38
68
|
process.env.AIDEPT_STATIC_DIR ??= path.join(pkgDir, 'dist', 'client');
|
|
39
69
|
process.env.AIDEPT_TOOLS_DIR ??= path.join(pkgDir, 'tools');
|