@trungtamcongnghedigital/vsaf 1.4.2 → 1.4.3-rc.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 +5 -2
- package/package.json +1 -1
- package/packages/cli/dist/commands/domains/domains.d.ts +92 -0
- package/packages/cli/dist/commands/domains/domains.d.ts.map +1 -0
- package/packages/cli/dist/commands/domains/domains.js +215 -0
- package/packages/cli/dist/commands/domains/domains.js.map +1 -0
- package/packages/cli/dist/commands/domains/sync.d.ts +52 -0
- package/packages/cli/dist/commands/domains/sync.d.ts.map +1 -0
- package/packages/cli/dist/commands/domains/sync.js +197 -0
- package/packages/cli/dist/commands/domains/sync.js.map +1 -0
- package/packages/cli/dist/commands/install.d.ts +1 -1
- package/packages/cli/dist/commands/source/knowledge-okf.d.ts +9 -0
- package/packages/cli/dist/commands/source/knowledge-okf.d.ts.map +1 -0
- package/packages/cli/dist/commands/source/knowledge-okf.js +247 -0
- package/packages/cli/dist/commands/source/knowledge-okf.js.map +1 -0
- package/packages/cli/dist/commands/source/knowledge-raw.d.ts +6 -0
- package/packages/cli/dist/commands/source/knowledge-raw.d.ts.map +1 -0
- package/packages/cli/dist/commands/source/knowledge-raw.js +112 -0
- package/packages/cli/dist/commands/source/knowledge-raw.js.map +1 -0
- package/packages/cli/dist/commands/source/knowledge-status.d.ts +23 -0
- package/packages/cli/dist/commands/source/knowledge-status.d.ts.map +1 -0
- package/packages/cli/dist/commands/source/knowledge-status.js +116 -0
- package/packages/cli/dist/commands/source/knowledge-status.js.map +1 -0
- package/packages/cli/dist/commands/source/knowledge-types.d.ts +39 -0
- package/packages/cli/dist/commands/source/knowledge-types.d.ts.map +1 -0
- package/packages/cli/dist/commands/source/knowledge-types.js +9 -0
- package/packages/cli/dist/commands/source/knowledge-types.js.map +1 -0
- package/packages/cli/dist/commands/source/knowledge.d.ts +10 -0
- package/packages/cli/dist/commands/source/knowledge.d.ts.map +1 -0
- package/packages/cli/dist/commands/source/knowledge.js +87 -0
- package/packages/cli/dist/commands/source/knowledge.js.map +1 -0
- package/packages/cli/dist/commands/source/mcp-tools.d.ts +0 -10
- package/packages/cli/dist/commands/source/mcp-tools.d.ts.map +1 -1
- package/packages/cli/dist/commands/source/mcp-tools.js +0 -19
- package/packages/cli/dist/commands/source/mcp-tools.js.map +1 -1
- package/packages/cli/dist/index.js +37 -0
- package/packages/cli/dist/index.js.map +1 -1
- package/packages/cli/dist/mcp/server.d.ts +36 -9
- package/packages/cli/dist/mcp/server.d.ts.map +1 -1
- package/packages/cli/dist/mcp/server.js +26 -15
- package/packages/cli/dist/mcp/server.js.map +1 -1
- package/scripts/probe/dem-chu-nhay-cam.sh +49 -0
- package/scripts/probe/do-lop-va.mjs +313 -0
- package/scripts/probe/ho-so/domains.json +21 -0
- package/scripts/probe/soi-chu-nhay-cam.sh +106 -0
- package/scripts/probe/soi-master-knowledge.sh +188 -0
- package/scripts/probe/ten-nguoi.vi-du.txt +18 -0
package/README.md
CHANGED
|
@@ -163,8 +163,11 @@ vsaf source list [--json] # List every declared source
|
|
|
163
163
|
vsaf source remove kho # Drop one
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
Declared in `~/.vsaf/sources.yaml`, a separate file next to `registry.yaml`.
|
|
167
|
-
|
|
166
|
+
Declared in `~/.vsaf/sources.yaml`, a separate file next to `registry.yaml`.
|
|
167
|
+
|
|
168
|
+
These CLI commands are unchanged: they print paths, for humans and scripts. Agents take a
|
|
169
|
+
different road — the read-only MCP tool `vsaf_knowledge_query` returns **content** with citation
|
|
170
|
+
labels and never a path. The two older path-returning tools were removed in this release.
|
|
168
171
|
|
|
169
172
|
Full guide (Vietnamese): [docs/huong-dan-nguon-tren-may.md](docs/huong-dan-nguon-tren-may.md).
|
|
170
173
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Danh bạ domain của Master Knowledge: tên domain → các dự án của nó.
|
|
3
|
+
*
|
|
4
|
+
* File RIÊNG, KHÔNG trộn vào `registry.yaml`. Lý do không phải gọn gàng mà là một tai nạn
|
|
5
|
+
* đo được: `readRegistry()` duyệt MỌI khoá cấp 1 và đòi mỗi khoá có `repo:` TRƯỚC KHI tra
|
|
6
|
+
* tên người dùng vừa gõ — nên một khoá lạ nằm trong đó giết luôn `vsaf install NTAPP`,
|
|
7
|
+
* một flow không liên quan gì.
|
|
8
|
+
*
|
|
9
|
+
* Bài học rộng hơn "tách file ra": một bộ đọc kiểm mọi khoá sẽ giết những lệnh không liên
|
|
10
|
+
* quan khi gặp một khoá hỏng. Nên file này phải được đọc CHỈ trên đường của master — tách
|
|
11
|
+
* ra mà vẫn đọc trên đường cài chung thì chỉ DỜI cái bẫy sang chỗ mới.
|
|
12
|
+
*
|
|
13
|
+
* Engine sở hữu **cơ chế file**: đường dẫn, đọc, ghi, luật `from:`, báo cũ khi mất mạng.
|
|
14
|
+
* Nó cố ý KHÔNG biết "domain" nghĩa là gì — ý nghĩa nội dung là của master.
|
|
15
|
+
*/
|
|
16
|
+
/** Tên file. Nằm cạnh `registry.yaml` và `sources.yaml` trong thư mục nhà của vsaf. */
|
|
17
|
+
export declare const DOMAINS_FILE = "domains.yaml";
|
|
18
|
+
export interface DomainEntry {
|
|
19
|
+
/**
|
|
20
|
+
* Địa chỉ master đang quản mục này.
|
|
21
|
+
*
|
|
22
|
+
* CÓ dòng này = mục MÁY QUẢN: lượt đồng bộ sau ghi đè cả mục.
|
|
23
|
+
* KHÔNG có = người dùng tự giữ: máy không đụng, kể cả khi master khai domain cùng tên.
|
|
24
|
+
*
|
|
25
|
+
* Đây là công tắc duy nhất, và nó nằm trong tay người dùng: xoá một dòng là ghim.
|
|
26
|
+
*/
|
|
27
|
+
from?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Mốc đồng bộ THÀNH CÔNG gần nhất của CHÍNH mục này, dạng ISO-8601 UTC.
|
|
30
|
+
*
|
|
31
|
+
* Theo từng mục chứ không một mốc chung cho cả file: người dùng ghim một domain (xoá
|
|
32
|
+
* `from:`) thì mốc chung không còn nói đúng về domain đó, mà một mốc nói sai về một
|
|
33
|
+
* phần dữ liệu đúng là thứ cơ chế này sinh ra để tránh.
|
|
34
|
+
*/
|
|
35
|
+
synced_at?: string;
|
|
36
|
+
/** Tên dự án → địa chỉ spec repo. Master ghi sẵn tên; engine KHÔNG suy lại lúc đọc. */
|
|
37
|
+
projects?: Record<string, string>;
|
|
38
|
+
}
|
|
39
|
+
/** Lỗi có MÃ THOÁT đi kèm — cùng giao kèo với `SourceError`. */
|
|
40
|
+
export declare class DomainError extends Error {
|
|
41
|
+
readonly exitCode: number;
|
|
42
|
+
constructor(exitCode: number, message: string);
|
|
43
|
+
}
|
|
44
|
+
export declare const DOMAIN_EXIT: {
|
|
45
|
+
/** File cấu hình hỏng, hoặc tên domain sai hình dạng. */
|
|
46
|
+
readonly brokenFile: 6;
|
|
47
|
+
/**
|
|
48
|
+
* Gặp một ca trang yêu cầu KHÔNG nói tới.
|
|
49
|
+
*
|
|
50
|
+
* Nguyên tắc của dự án: ca nào tài liệu không nói thì MÁY DỪNG VÀ HỎI NGƯỜI, không tự
|
|
51
|
+
* quyết. Mã riêng để người gọi phân biệt "file hỏng" với "file đúng nhưng có một tình
|
|
52
|
+
* huống cần người xử".
|
|
53
|
+
*/
|
|
54
|
+
readonly canNguoiXu: 7;
|
|
55
|
+
};
|
|
56
|
+
export declare function assertDomainName(name: string): void;
|
|
57
|
+
export declare function domainsPath(): string;
|
|
58
|
+
/**
|
|
59
|
+
* Toàn bộ danh bạ, theo đúng thứ tự người dùng viết.
|
|
60
|
+
*
|
|
61
|
+
* Chưa có file thì coi như RỖNG và KHÔNG tự tạo. Khác `readRegistry()` một cách có chủ ý:
|
|
62
|
+
* thiếu `registry.yaml` là bế tắc thật (không cài được flow nào), còn thiếu `domains.yaml`
|
|
63
|
+
* là trạng thái BÌNH THƯỜNG của máy chưa cài master bao giờ. Đọc theo nghĩa chặt "cùng
|
|
64
|
+
* luật với registry.yaml" thì lượt cài master ĐẦU TIÊN bất khả thi — một cách đọc tự loại
|
|
65
|
+
* mình bằng hệ quả của chính nó.
|
|
66
|
+
*
|
|
67
|
+
* File hỏng thì DỪNG, không trả map rỗng: người vừa khai mười domain mà nhận câu "chưa
|
|
68
|
+
* khai domain nào" sẽ đi sửa đúng chỗ không hỏng.
|
|
69
|
+
*/
|
|
70
|
+
export declare function readDomains(): Map<string, DomainEntry>;
|
|
71
|
+
/** Mục này do máy quản (có `from:`) hay người dùng tự giữ? */
|
|
72
|
+
export declare function mayQuan(entry: DomainEntry): boolean;
|
|
73
|
+
export interface MocDongBo {
|
|
74
|
+
domain: string;
|
|
75
|
+
/** Mốc đồng bộ thành công gần nhất, hoặc `undefined` nếu chưa từng. */
|
|
76
|
+
syncedAt?: string;
|
|
77
|
+
/** Người dùng đã ghim mục này (xoá `from:`) — máy không đụng tới. */
|
|
78
|
+
nguoiGiu: boolean;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Mốc đồng bộ của từng domain, để BÁO RA khi dùng bản đã lưu.
|
|
82
|
+
*
|
|
83
|
+
* Trang yêu cầu nói: mất mạng thì "máy dùng bản danh bạ đã lưu lần trước **và báo bản đó
|
|
84
|
+
* cũ từ ngày nào**". Vế sau mới là phần người dùng cần — dùng bản cũ mà không nói thì
|
|
85
|
+
* người ta tưởng mình đang nhìn danh bạ hôm nay.
|
|
86
|
+
*
|
|
87
|
+
* Trả về theo TỪNG domain, không phải một mốc chung: xem lý do ở `DomainEntry.synced_at`.
|
|
88
|
+
*/
|
|
89
|
+
export declare function mocDongBo(entries: Map<string, DomainEntry>): MocDongBo[];
|
|
90
|
+
/** Câu người dùng đọc khi máy phải dùng bản danh bạ đã lưu. */
|
|
91
|
+
export declare function cauBaoCu(moc: MocDongBo[]): string;
|
|
92
|
+
//# sourceMappingURL=domains.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domains.d.ts","sourceRoot":"","sources":["../../../src/commands/domains/domains.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;GAcG;AAEH,uFAAuF;AACvF,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC1B;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,gEAAgE;AAChE,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK9C;AAED,eAAO,MAAM,WAAW;IACtB,yDAAyD;;IAEzD;;;;;;OAMG;;CAEK,CAAC;AAkBX,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAYnD;AAED,wBAAgB,WAAW,IAAI,MAAM,CAMpC;AAmBD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAuFtD;AAED,8DAA8D;AAC9D,wBAAgB,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAEnD;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,SAAS,EAAE,CAMxE;AAED,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,MAAM,CAQjD"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DOMAIN_EXIT = exports.DomainError = exports.DOMAINS_FILE = void 0;
|
|
4
|
+
exports.assertDomainName = assertDomainName;
|
|
5
|
+
exports.domainsPath = domainsPath;
|
|
6
|
+
exports.readDomains = readDomains;
|
|
7
|
+
exports.mayQuan = mayQuan;
|
|
8
|
+
exports.mocDongBo = mocDongBo;
|
|
9
|
+
exports.cauBaoCu = cauBaoCu;
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const os_1 = require("os");
|
|
12
|
+
const path_1 = require("path");
|
|
13
|
+
const js_yaml_1 = require("js-yaml");
|
|
14
|
+
/**
|
|
15
|
+
* Danh bạ domain của Master Knowledge: tên domain → các dự án của nó.
|
|
16
|
+
*
|
|
17
|
+
* File RIÊNG, KHÔNG trộn vào `registry.yaml`. Lý do không phải gọn gàng mà là một tai nạn
|
|
18
|
+
* đo được: `readRegistry()` duyệt MỌI khoá cấp 1 và đòi mỗi khoá có `repo:` TRƯỚC KHI tra
|
|
19
|
+
* tên người dùng vừa gõ — nên một khoá lạ nằm trong đó giết luôn `vsaf install NTAPP`,
|
|
20
|
+
* một flow không liên quan gì.
|
|
21
|
+
*
|
|
22
|
+
* Bài học rộng hơn "tách file ra": một bộ đọc kiểm mọi khoá sẽ giết những lệnh không liên
|
|
23
|
+
* quan khi gặp một khoá hỏng. Nên file này phải được đọc CHỈ trên đường của master — tách
|
|
24
|
+
* ra mà vẫn đọc trên đường cài chung thì chỉ DỜI cái bẫy sang chỗ mới.
|
|
25
|
+
*
|
|
26
|
+
* Engine sở hữu **cơ chế file**: đường dẫn, đọc, ghi, luật `from:`, báo cũ khi mất mạng.
|
|
27
|
+
* Nó cố ý KHÔNG biết "domain" nghĩa là gì — ý nghĩa nội dung là của master.
|
|
28
|
+
*/
|
|
29
|
+
/** Tên file. Nằm cạnh `registry.yaml` và `sources.yaml` trong thư mục nhà của vsaf. */
|
|
30
|
+
exports.DOMAINS_FILE = 'domains.yaml';
|
|
31
|
+
/** Lỗi có MÃ THOÁT đi kèm — cùng giao kèo với `SourceError`. */
|
|
32
|
+
class DomainError extends Error {
|
|
33
|
+
exitCode;
|
|
34
|
+
constructor(exitCode, message) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.name = 'DomainError';
|
|
37
|
+
this.exitCode = exitCode;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.DomainError = DomainError;
|
|
41
|
+
exports.DOMAIN_EXIT = {
|
|
42
|
+
/** File cấu hình hỏng, hoặc tên domain sai hình dạng. */
|
|
43
|
+
brokenFile: 6,
|
|
44
|
+
/**
|
|
45
|
+
* Gặp một ca trang yêu cầu KHÔNG nói tới.
|
|
46
|
+
*
|
|
47
|
+
* Nguyên tắc của dự án: ca nào tài liệu không nói thì MÁY DỪNG VÀ HỎI NGƯỜI, không tự
|
|
48
|
+
* quyết. Mã riêng để người gọi phân biệt "file hỏng" với "file đúng nhưng có một tình
|
|
49
|
+
* huống cần người xử".
|
|
50
|
+
*/
|
|
51
|
+
canNguoiXu: 7,
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Tên domain hợp lệ.
|
|
55
|
+
*
|
|
56
|
+
* Cấm `://`, `@`, dấu phẩy và khoảng trắng KHÔNG phải để cho đẹp. Luật phân biệt hai dạng
|
|
57
|
+
* của `--clone` chỉ đứng được nhờ nó: `--clone <giá-trị>` đọc ra LINK REPO khi thấy `://`
|
|
58
|
+
* hoặc `@…:`, đọc ra TÊN DOMAIN với mọi thứ còn lại. Cho phép `@` trong tên domain là phá
|
|
59
|
+
* phép phân biệt đó ở một chỗ khác hẳn trong mã, và lỗi hiện ra dưới dạng
|
|
60
|
+
* "`--clone payment@v2` tự nhiên đi tải một repo".
|
|
61
|
+
*
|
|
62
|
+
* Ai nới luật này thì BẮT BUỘC sửa phép phân biệt `--clone` cùng lượt. Chúng là một cặp.
|
|
63
|
+
*
|
|
64
|
+
* `/` và `\` và `..` bị chặn thêm một lý do nữa: tên domain đi vào đường dẫn thư mục, nên
|
|
65
|
+
* một tên mang dấu phân cách là một đường trỏ ra ngoài chỗ nó được phép ghi.
|
|
66
|
+
*/
|
|
67
|
+
const DOMAIN_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
68
|
+
function assertDomainName(name) {
|
|
69
|
+
// `..` phải chặn RIÊNG: mẫu trên cho phép `.` (để đặt được `v2.core`), nên `a..b` lọt
|
|
70
|
+
// qua mẫu. Chú thích nói chặn mà mẫu không chặn là đúng loại lỗi khó thấy nhất — chính
|
|
71
|
+
// test của luật này bắt được nó.
|
|
72
|
+
if (name.includes('..') || !DOMAIN_PATTERN.test(name)) {
|
|
73
|
+
throw new DomainError(exports.DOMAIN_EXIT.brokenFile, `Tên domain không hợp lệ: "${name}"\n`
|
|
74
|
+
+ ' Tên bắt đầu bằng chữ hoặc số, rồi chỉ gồm chữ, số và . _ -\n'
|
|
75
|
+
+ ' Không chứa "://", "@", dấu phẩy, khoảng trắng, "/" hay "..".');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function domainsPath() {
|
|
79
|
+
// `||` chứ không phải `??`, cùng lý do với `registryPath` và `sourcesPath`:
|
|
80
|
+
// `VSAF_HOME=""` vẫn phải rơi về mặc định, nếu không đường dẫn thành tương đối so với
|
|
81
|
+
// thư mục hiện hành.
|
|
82
|
+
const home = process.env.VSAF_HOME || (0, path_1.join)((0, os_1.homedir)(), '.vsaf');
|
|
83
|
+
return (0, path_1.join)(home, exports.DOMAINS_FILE);
|
|
84
|
+
}
|
|
85
|
+
/** Số dòng (đếm từ 1) của dòng khai một khoá, hoặc 0 nếu không tìm ra. */
|
|
86
|
+
function lineOfKey(text, key) {
|
|
87
|
+
const lines = text.split('\n');
|
|
88
|
+
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
89
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
90
|
+
if (new RegExp(`^["']?${escaped}["']?\\s*:`).test(lines[i]))
|
|
91
|
+
return i + 1;
|
|
92
|
+
}
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
/** Một trường tuỳ chọn: chuỗi rỗng cũng là bỏ trống, không phải một giá trị. */
|
|
96
|
+
function textOrNothing(value) {
|
|
97
|
+
if (typeof value !== 'string')
|
|
98
|
+
return undefined;
|
|
99
|
+
const text = value.trim();
|
|
100
|
+
return text === '' ? undefined : text;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Toàn bộ danh bạ, theo đúng thứ tự người dùng viết.
|
|
104
|
+
*
|
|
105
|
+
* Chưa có file thì coi như RỖNG và KHÔNG tự tạo. Khác `readRegistry()` một cách có chủ ý:
|
|
106
|
+
* thiếu `registry.yaml` là bế tắc thật (không cài được flow nào), còn thiếu `domains.yaml`
|
|
107
|
+
* là trạng thái BÌNH THƯỜNG của máy chưa cài master bao giờ. Đọc theo nghĩa chặt "cùng
|
|
108
|
+
* luật với registry.yaml" thì lượt cài master ĐẦU TIÊN bất khả thi — một cách đọc tự loại
|
|
109
|
+
* mình bằng hệ quả của chính nó.
|
|
110
|
+
*
|
|
111
|
+
* File hỏng thì DỪNG, không trả map rỗng: người vừa khai mười domain mà nhận câu "chưa
|
|
112
|
+
* khai domain nào" sẽ đi sửa đúng chỗ không hỏng.
|
|
113
|
+
*/
|
|
114
|
+
function readDomains() {
|
|
115
|
+
const path = domainsPath();
|
|
116
|
+
if (!(0, fs_1.existsSync)(path))
|
|
117
|
+
return new Map();
|
|
118
|
+
const text = (0, fs_1.readFileSync)(path, 'utf-8');
|
|
119
|
+
let parsed;
|
|
120
|
+
try {
|
|
121
|
+
parsed = (0, js_yaml_1.load)(text);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const nguyenVan = error.message;
|
|
125
|
+
if (/duplicated mapping key/i.test(nguyenVan)) {
|
|
126
|
+
// Trang yêu cầu không nói ca này. Theo nguyên tắc: máy BÁO NGƯỜI, không tự chọn
|
|
127
|
+
// mục nào thắng — hai mục cho cùng một domain là một mâu thuẫn, không phải một
|
|
128
|
+
// lựa chọn, và đoán hộ ở đây là lặng lẽ bỏ đi một nửa danh bạ.
|
|
129
|
+
throw new DomainError(exports.DOMAIN_EXIT.canNguoiXu, `${path} khai hai lần cùng một domain.\n`
|
|
130
|
+
+ ` ${nguyenVan.split('\n')[0]}\n`
|
|
131
|
+
+ ' Máy không tự chọn mục nào thắng. Mở file trên, xoá bớt một mục rồi chạy lại.');
|
|
132
|
+
}
|
|
133
|
+
throw new DomainError(exports.DOMAIN_EXIT.brokenFile, `Không đọc được ${path}:\n ${nguyenVan}`);
|
|
134
|
+
}
|
|
135
|
+
// File rỗng cho ra `null`, và đó là một file hợp lệ: chưa khai domain nào.
|
|
136
|
+
if (parsed === null || parsed === undefined)
|
|
137
|
+
return new Map();
|
|
138
|
+
if (typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
139
|
+
throw new DomainError(exports.DOMAIN_EXIT.brokenFile, `${path} phải là danh sách tên domain → mục, không phải ${Array.isArray(parsed) ? 'một dãy' : typeof parsed}.\n`
|
|
140
|
+
+ ' Một dãy thì tra theo TÊN phải quét tuần tự, và không có gì chặn hai mục trùng tên.');
|
|
141
|
+
}
|
|
142
|
+
const entries = new Map();
|
|
143
|
+
for (const [name, value] of Object.entries(parsed)) {
|
|
144
|
+
assertDomainName(name);
|
|
145
|
+
const dong = lineOfKey(text, name);
|
|
146
|
+
const tai = `${path}${dong > 0 ? `, dòng ${dong}` : ''}`;
|
|
147
|
+
const entry = (value ?? {});
|
|
148
|
+
const from = textOrNothing(entry.from);
|
|
149
|
+
const syncedAt = textOrNothing(entry.synced_at);
|
|
150
|
+
let projects;
|
|
151
|
+
if (entry.projects !== undefined && entry.projects !== null) {
|
|
152
|
+
if (typeof entry.projects !== 'object' || Array.isArray(entry.projects)) {
|
|
153
|
+
throw new DomainError(exports.DOMAIN_EXIT.brokenFile, `Domain "${name}" (${tai}) khai "projects" không phải danh sách tên → địa chỉ.`);
|
|
154
|
+
}
|
|
155
|
+
projects = {};
|
|
156
|
+
const thay = new Map();
|
|
157
|
+
for (const [tenDuAn, diaChi] of Object.entries(entry.projects)) {
|
|
158
|
+
const url = textOrNothing(diaChi);
|
|
159
|
+
if (url === undefined) {
|
|
160
|
+
throw new DomainError(exports.DOMAIN_EXIT.brokenFile, `Dự án "${tenDuAn}" của domain "${name}" (${tai}) không khai địa chỉ.`);
|
|
161
|
+
}
|
|
162
|
+
// So theo tên ĐÃ CẮT khoảng trắng. YAML coi `a-spec` và `a-spec ` là hai khoá
|
|
163
|
+
// khác nhau, nhưng người đọc thì không phân biệt được — và hai mục trông giống
|
|
164
|
+
// hệt nhau trong danh bạ là đúng lớp lỗi ta đang tránh. Cắt để SO, giữ nguyên
|
|
165
|
+
// chữ người dùng viết để NÓI trong câu lỗi.
|
|
166
|
+
const khoa = tenDuAn.trim();
|
|
167
|
+
const daCo = thay.get(khoa);
|
|
168
|
+
if (daCo !== undefined) {
|
|
169
|
+
throw new DomainError(exports.DOMAIN_EXIT.canNguoiXu, `Domain "${name}" (${tai}) có hai dự án cùng tên "${khoa}":\n`
|
|
170
|
+
+ ` ${daCo}\n ${url}\n`
|
|
171
|
+
+ ' Máy không tự đổi tên và không tự ghi đè. Admin đặt tên khác cho một trong hai.');
|
|
172
|
+
}
|
|
173
|
+
thay.set(khoa, url);
|
|
174
|
+
projects[khoa] = url;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Khoá lạ bỏ qua: một file viết cho bản sau vẫn phải đọc được bằng bản này.
|
|
178
|
+
entries.set(name, { from, synced_at: syncedAt, projects });
|
|
179
|
+
}
|
|
180
|
+
return entries;
|
|
181
|
+
}
|
|
182
|
+
/** Mục này do máy quản (có `from:`) hay người dùng tự giữ? */
|
|
183
|
+
function mayQuan(entry) {
|
|
184
|
+
return entry.from !== undefined;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Mốc đồng bộ của từng domain, để BÁO RA khi dùng bản đã lưu.
|
|
188
|
+
*
|
|
189
|
+
* Trang yêu cầu nói: mất mạng thì "máy dùng bản danh bạ đã lưu lần trước **và báo bản đó
|
|
190
|
+
* cũ từ ngày nào**". Vế sau mới là phần người dùng cần — dùng bản cũ mà không nói thì
|
|
191
|
+
* người ta tưởng mình đang nhìn danh bạ hôm nay.
|
|
192
|
+
*
|
|
193
|
+
* Trả về theo TỪNG domain, không phải một mốc chung: xem lý do ở `DomainEntry.synced_at`.
|
|
194
|
+
*/
|
|
195
|
+
function mocDongBo(entries) {
|
|
196
|
+
return [...entries.entries()].map(([domain, entry]) => ({
|
|
197
|
+
domain,
|
|
198
|
+
syncedAt: mayQuan(entry) ? entry.synced_at : undefined,
|
|
199
|
+
nguoiGiu: !mayQuan(entry),
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
/** Câu người dùng đọc khi máy phải dùng bản danh bạ đã lưu. */
|
|
203
|
+
function cauBaoCu(moc) {
|
|
204
|
+
if (moc.length === 0)
|
|
205
|
+
return 'Chưa có danh bạ domain nào trên máy này.';
|
|
206
|
+
const dong = moc.map(m => {
|
|
207
|
+
if (m.nguoiGiu)
|
|
208
|
+
return ` ${m.domain} — bạn tự giữ (không có dòng "from:"), máy không cập nhật`;
|
|
209
|
+
if (m.syncedAt === undefined)
|
|
210
|
+
return ` ${m.domain} — chưa đồng bộ lần nào`;
|
|
211
|
+
return ` ${m.domain} — bản lưu từ ${m.syncedAt}`;
|
|
212
|
+
});
|
|
213
|
+
return `Đang dùng danh bạ đã lưu trên máy:\n${dong.join('\n')}`;
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=domains.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domains.js","sourceRoot":"","sources":["../../../src/commands/domains/domains.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ghi danh bạ domain theo thứ master khai.
|
|
3
|
+
*
|
|
4
|
+
* Engine KHÔNG đọc `federation.yaml` và không biết nó có hình gì — flow trích rồi đưa
|
|
5
|
+
* vào một JSON phẳng. Ranh giới ấy do nhóm chốt: engine sở hữu **cơ chế file**, flow sở
|
|
6
|
+
* hữu **ý nghĩa nội dung**. Giữ nó thì flow đổi cấu trúc `federation.yaml` lúc nào cũng
|
|
7
|
+
* được mà không phải chờ engine ra bản mới.
|
|
8
|
+
*/
|
|
9
|
+
/** Thứ master khai, sau khi flow đã trích. Chỉ hai trường; engine không cần gì hơn. */
|
|
10
|
+
export interface DomainTuMaster {
|
|
11
|
+
projects?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
export interface KetQuaGhi {
|
|
14
|
+
/** Domain mới, chưa có trên máy. */
|
|
15
|
+
them: string[];
|
|
16
|
+
/** Domain máy quản, đã ghi đè theo bản master. */
|
|
17
|
+
capNhat: string[];
|
|
18
|
+
/** Domain người dùng đã ghim (không có `from:`) — KHÔNG đụng. */
|
|
19
|
+
nguoiGiu: string[];
|
|
20
|
+
/**
|
|
21
|
+
* Domain máy quản mà master KHÔNG còn khai.
|
|
22
|
+
*
|
|
23
|
+
* Trang yêu cầu không nói một chữ nào về ca này, nên theo nguyên tắc của dự án: máy
|
|
24
|
+
* BÁO NGƯỜI, không tự xử. Không xoá, không đánh dấu, không gỡ `from:`.
|
|
25
|
+
*/
|
|
26
|
+
canNguoiXu: string[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Trộn bản master vào danh bạ trên máy.
|
|
30
|
+
*
|
|
31
|
+
* Năm cảnh, và cảnh thứ năm là cảnh trang yêu cầu không nói — máy báo người.
|
|
32
|
+
*/
|
|
33
|
+
export declare function tronDanhBa(tuMaster: Map<string, DomainTuMaster>, from: string, luc: string): KetQuaGhi;
|
|
34
|
+
/** Đọc JSON từ stdin. Flow trích `federation.yaml` rồi đẩy vào đây. */
|
|
35
|
+
export declare function docTuStdin(raw: string): Map<string, DomainTuMaster>;
|
|
36
|
+
export interface KetQuaLenh {
|
|
37
|
+
code: number;
|
|
38
|
+
out: string[];
|
|
39
|
+
err: string[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* `vsaf domains sync --from <url>` — đọc JSON ở stdin, trộn vào danh bạ.
|
|
43
|
+
*
|
|
44
|
+
* Mọi lượt `vsaf install MASTER` đều gọi lệnh này, bất kể cờ nào: `--new`, `--clone`,
|
|
45
|
+
* `--update`. Trang yêu cầu nói danh bạ *"tự cập nhật, không cần link"*, mà không có lịch
|
|
46
|
+
* chạy định kỳ ở đợt này — nên lượt cài là chỗ duy nhất nó được làm mới.
|
|
47
|
+
*
|
|
48
|
+
* `--update` KHÁC `--clone` ở chỗ tải về máy, KHÔNG ở chỗ danh bạ: cả hai đều làm mới đủ
|
|
49
|
+
* mọi tên domain, chỉ `--clone` mới tải thêm domain mới về.
|
|
50
|
+
*/
|
|
51
|
+
export declare function syncCommand(stdin: string, from: string, luc?: string): KetQuaLenh;
|
|
52
|
+
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/commands/domains/sync.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AAEH,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,SAAS;IACxB,oCAAoC;IACpC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,kDAAkD;IAClD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;OAKG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAoDD;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,EACrC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,SAAS,CAoDX;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAwCnE;AAED,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE;AAE1E;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,CA6BjF"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tronDanhBa = tronDanhBa;
|
|
4
|
+
exports.docTuStdin = docTuStdin;
|
|
5
|
+
exports.syncCommand = syncCommand;
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const domains_js_1 = require("./domains.js");
|
|
9
|
+
/** Khối YAML của một mục máy quản. Chỉ sinh cho mục máy quản — mục ghim không đi qua đây. */
|
|
10
|
+
function khoiYaml(ten, from, syncedAt, muc) {
|
|
11
|
+
const dong = [`${ten}:`, ` from: ${from}`, ` synced_at: "${syncedAt}"`];
|
|
12
|
+
const duAn = Object.entries(muc.projects ?? {});
|
|
13
|
+
if (duAn.length > 0) {
|
|
14
|
+
dong.push(' projects:');
|
|
15
|
+
for (const [tenDuAn, url] of duAn)
|
|
16
|
+
dong.push(` ${tenDuAn}: ${url}`);
|
|
17
|
+
}
|
|
18
|
+
return dong.join('\n');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Dải dòng (bắt đầu, kết thúc — nửa mở) của từng khoá cấp 1 trong file.
|
|
22
|
+
*
|
|
23
|
+
* Làm trên VĂN BẢN chứ không dựng lại file từ dữ liệu đã đọc, vì `D4` đòi mục người dùng
|
|
24
|
+
* ghim phải còn nguyên **từng ký tự**: chú thích họ tự viết, thứ tự họ tự sắp, khoảng
|
|
25
|
+
* trắng họ tự để. Dựng lại từ dữ liệu là mất hết những thứ đó trong một lượt mà họ không
|
|
26
|
+
* hề yêu cầu.
|
|
27
|
+
*/
|
|
28
|
+
function daiCuaKhoa(text) {
|
|
29
|
+
const dong = text.split('\n');
|
|
30
|
+
const dai = new Map();
|
|
31
|
+
let dangMo;
|
|
32
|
+
/**
|
|
33
|
+
* Dòng trống và dòng chú thích NGAY TRƯỚC một khoá thuộc về khoá ĐÓ, không thuộc khoá
|
|
34
|
+
* phía trên.
|
|
35
|
+
*
|
|
36
|
+
* Bỏ qua chuyện này là lỗi đo được: ghi đè `payment` nuốt luôn dòng trống và dòng
|
|
37
|
+
* `# tôi trỏ sang bản nội bộ vì mạng công ty chặn` của `lending` nằm bên dưới — tức
|
|
38
|
+
* xoá đúng câu giải thích VÌ SAO người dùng ghim mục đó. Mục ghim thì còn, lý do ghim
|
|
39
|
+
* thì mất, và không ai được báo.
|
|
40
|
+
*/
|
|
41
|
+
const luiVeCuoiThat = (den) => {
|
|
42
|
+
let i = den;
|
|
43
|
+
while (i > 0 && (dong[i - 1].trim() === '' || dong[i - 1].trimStart().startsWith('#')))
|
|
44
|
+
i -= 1;
|
|
45
|
+
return i;
|
|
46
|
+
};
|
|
47
|
+
for (let i = 0; i < dong.length; i += 1) {
|
|
48
|
+
const khop = /^(["']?)([^\s:#][^:]*?)\1\s*:/.exec(dong[i]);
|
|
49
|
+
if (khop) {
|
|
50
|
+
if (dangMo)
|
|
51
|
+
dai.set(dangMo.ten, { dau: dangMo.dau, cuoi: luiVeCuoiThat(i) });
|
|
52
|
+
dangMo = { ten: khop[2], dau: i };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (dangMo)
|
|
56
|
+
dai.set(dangMo.ten, { dau: dangMo.dau, cuoi: luiVeCuoiThat(dong.length) });
|
|
57
|
+
return dai;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Trộn bản master vào danh bạ trên máy.
|
|
61
|
+
*
|
|
62
|
+
* Năm cảnh, và cảnh thứ năm là cảnh trang yêu cầu không nói — máy báo người.
|
|
63
|
+
*/
|
|
64
|
+
function tronDanhBa(tuMaster, from, luc) {
|
|
65
|
+
for (const ten of tuMaster.keys())
|
|
66
|
+
(0, domains_js_1.assertDomainName)(ten);
|
|
67
|
+
const daCo = (0, domains_js_1.readDomains)();
|
|
68
|
+
const path = (0, domains_js_1.domainsPath)();
|
|
69
|
+
const text = (0, fs_1.existsSync)(path) ? (0, fs_1.readFileSync)(path, 'utf-8') : '';
|
|
70
|
+
const dai = daiCuaKhoa(text);
|
|
71
|
+
const dong = text === '' ? [] : text.split('\n');
|
|
72
|
+
const ra = { them: [], capNhat: [], nguoiGiu: [], canNguoiXu: [] };
|
|
73
|
+
// Thay tại chỗ: gom việc rồi áp từ DƯỚI LÊN, để số dòng của việc chưa áp không trôi.
|
|
74
|
+
const thayTaiCho = [];
|
|
75
|
+
for (const [ten, muc] of tuMaster) {
|
|
76
|
+
const cu = daCo.get(ten);
|
|
77
|
+
if (cu === undefined) {
|
|
78
|
+
ra.them.push(ten);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (!(0, domains_js_1.mayQuan)(cu)) {
|
|
82
|
+
// Người dùng đã ghim bằng cách xoá dòng `from:`. Không đụng — đây là công tắc duy
|
|
83
|
+
// nhất họ có, và nó chỉ có nghĩa nếu máy thật sự tôn trọng nó.
|
|
84
|
+
ra.nguoiGiu.push(ten);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const vt = dai.get(ten);
|
|
88
|
+
if (vt) {
|
|
89
|
+
thayTaiCho.push({ dau: vt.dau, cuoi: vt.cuoi, moi: khoiYaml(ten, from, luc, muc).split('\n') });
|
|
90
|
+
ra.capNhat.push(ten);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Mục máy quản mà master không còn khai: BÁO, không xử.
|
|
94
|
+
for (const [ten, muc] of daCo) {
|
|
95
|
+
if (!tuMaster.has(ten) && (0, domains_js_1.mayQuan)(muc))
|
|
96
|
+
ra.canNguoiXu.push(ten);
|
|
97
|
+
}
|
|
98
|
+
thayTaiCho.sort((a, b) => b.dau - a.dau);
|
|
99
|
+
for (const v of thayTaiCho)
|
|
100
|
+
dong.splice(v.dau, v.cuoi - v.dau, ...v.moi);
|
|
101
|
+
const themMoi = ra.them.map(ten => khoiYaml(ten, from, luc, tuMaster.get(ten)));
|
|
102
|
+
if (themMoi.length > 0) {
|
|
103
|
+
if (dong.length > 0 && dong[dong.length - 1].trim() !== '')
|
|
104
|
+
dong.push('');
|
|
105
|
+
for (const khoi of themMoi) {
|
|
106
|
+
dong.push(khoi);
|
|
107
|
+
dong.push('');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (thayTaiCho.length > 0 || themMoi.length > 0) {
|
|
111
|
+
(0, fs_1.mkdirSync)((0, path_1.dirname)(path), { recursive: true });
|
|
112
|
+
(0, fs_1.writeFileSync)(path, `${dong.join('\n').replace(/\n*$/, '')}\n`);
|
|
113
|
+
}
|
|
114
|
+
return ra;
|
|
115
|
+
}
|
|
116
|
+
/** Đọc JSON từ stdin. Flow trích `federation.yaml` rồi đẩy vào đây. */
|
|
117
|
+
function docTuStdin(raw) {
|
|
118
|
+
const text = raw.trim();
|
|
119
|
+
if (text === '') {
|
|
120
|
+
throw new domains_js_1.DomainError(domains_js_1.DOMAIN_EXIT.brokenFile, 'Không nhận được gì ở stdin.\n'
|
|
121
|
+
+ ' Đưa vào một JSON dạng {"<domain>": {"projects": {"<tên>": "<địa chỉ>"}}}\n'
|
|
122
|
+
+ ' Ví dụ: echo \'{"payment":{"projects":{}}}\' | vsaf domains sync --from <url>');
|
|
123
|
+
}
|
|
124
|
+
let parsed;
|
|
125
|
+
try {
|
|
126
|
+
parsed = JSON.parse(text);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
throw new domains_js_1.DomainError(domains_js_1.DOMAIN_EXIT.brokenFile, `stdin không phải JSON hợp lệ:\n ${error.message}`);
|
|
130
|
+
}
|
|
131
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
132
|
+
throw new domains_js_1.DomainError(domains_js_1.DOMAIN_EXIT.brokenFile, 'stdin phải là một đối tượng JSON: tên domain → mục.');
|
|
133
|
+
}
|
|
134
|
+
const ra = new Map();
|
|
135
|
+
for (const [ten, giaTri] of Object.entries(parsed)) {
|
|
136
|
+
const muc = (giaTri ?? {});
|
|
137
|
+
let projects;
|
|
138
|
+
if (muc.projects !== undefined && muc.projects !== null) {
|
|
139
|
+
if (typeof muc.projects !== 'object' || Array.isArray(muc.projects)) {
|
|
140
|
+
throw new domains_js_1.DomainError(domains_js_1.DOMAIN_EXIT.brokenFile, `Domain "${ten}": "projects" phải là tên → địa chỉ.`);
|
|
141
|
+
}
|
|
142
|
+
projects = {};
|
|
143
|
+
for (const [k, v] of Object.entries(muc.projects)) {
|
|
144
|
+
if (typeof v !== 'string' || v.trim() === '') {
|
|
145
|
+
throw new domains_js_1.DomainError(domains_js_1.DOMAIN_EXIT.brokenFile, `Dự án "${k}" của domain "${ten}" không có địa chỉ.`);
|
|
146
|
+
}
|
|
147
|
+
projects[k.trim()] = v.trim();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
ra.set(ten, { projects });
|
|
151
|
+
}
|
|
152
|
+
return ra;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* `vsaf domains sync --from <url>` — đọc JSON ở stdin, trộn vào danh bạ.
|
|
156
|
+
*
|
|
157
|
+
* Mọi lượt `vsaf install MASTER` đều gọi lệnh này, bất kể cờ nào: `--new`, `--clone`,
|
|
158
|
+
* `--update`. Trang yêu cầu nói danh bạ *"tự cập nhật, không cần link"*, mà không có lịch
|
|
159
|
+
* chạy định kỳ ở đợt này — nên lượt cài là chỗ duy nhất nó được làm mới.
|
|
160
|
+
*
|
|
161
|
+
* `--update` KHÁC `--clone` ở chỗ tải về máy, KHÔNG ở chỗ danh bạ: cả hai đều làm mới đủ
|
|
162
|
+
* mọi tên domain, chỉ `--clone` mới tải thêm domain mới về.
|
|
163
|
+
*/
|
|
164
|
+
function syncCommand(stdin, from, luc) {
|
|
165
|
+
const out = [];
|
|
166
|
+
const err = [];
|
|
167
|
+
try {
|
|
168
|
+
if (from.trim() === '') {
|
|
169
|
+
throw new domains_js_1.DomainError(domains_js_1.DOMAIN_EXIT.brokenFile, 'Thiếu --from <địa-chỉ-master>: không biết mục nào do master nào quản.');
|
|
170
|
+
}
|
|
171
|
+
const tuMaster = docTuStdin(stdin);
|
|
172
|
+
const kq = tronDanhBa(tuMaster, from.trim(), luc ?? new Date().toISOString().replace(/\.\d{3}Z$/, 'Z'));
|
|
173
|
+
if (kq.them.length > 0)
|
|
174
|
+
out.push(`Thêm: ${kq.them.join(', ')}`);
|
|
175
|
+
if (kq.capNhat.length > 0)
|
|
176
|
+
out.push(`Cập nhật: ${kq.capNhat.join(', ')}`);
|
|
177
|
+
for (const ten of kq.nguoiGiu) {
|
|
178
|
+
out.push(`Bỏ qua "${ten}" — bạn tự giữ (mục không có dòng "from:"). Máy không đụng tới.`);
|
|
179
|
+
}
|
|
180
|
+
if (kq.canNguoiXu.length > 0) {
|
|
181
|
+
err.push(`Master không còn khai ${kq.canNguoiXu.length} domain đang có trên máy: ${kq.canNguoiXu.join(', ')}`);
|
|
182
|
+
err.push(` Máy KHÔNG tự xoá và KHÔNG tự đánh dấu — trang yêu cầu không nói ca này.`);
|
|
183
|
+
err.push(` Bạn quyết: giữ thì xoá dòng "from:" của mục đó, bỏ thì xoá cả mục.`);
|
|
184
|
+
err.push(` Sửa tại: ${(0, domains_js_1.domainsPath)()}`);
|
|
185
|
+
return { code: domains_js_1.DOMAIN_EXIT.canNguoiXu, out, err };
|
|
186
|
+
}
|
|
187
|
+
if (out.length === 0)
|
|
188
|
+
out.push('Danh bạ không đổi.');
|
|
189
|
+
return { code: 0, out, err };
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (error instanceof domains_js_1.DomainError)
|
|
193
|
+
return { code: error.exitCode, out, err: [error.message] };
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../src/commands/domains/sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -99,7 +99,7 @@ export interface InstallResult {
|
|
|
99
99
|
* không ai đặt chúng nữa — đường duy nhất còn lại là file kế hoạch mà `apply-pack` đọc,
|
|
100
100
|
* và hiện chưa có bên nào ghi file đó.
|
|
101
101
|
*
|
|
102
|
-
* Giữ lại chứ không xoá vì chúng là đầu vào của phần nối dây đa repo, và
|
|
102
|
+
* Giữ lại chứ không xoá vì chúng là đầu vào của phần nối dây đa repo, và chủ dự án chốt là
|
|
103
103
|
* phần đó **chuyển sang `install.sh` của flow, sửa sau** — chứ không phải bỏ. Xoá bây
|
|
104
104
|
* giờ là ném đi thứ sắp được gọi lại từ chỗ khác. Ai đọc tới đây mà `install.sh` đã có
|
|
105
105
|
* cách tự khai: nối nó vào đây, đừng dựng lại cờ ở engine.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SearchHit } from './knowledge-types.js';
|
|
2
|
+
/** Tìm thư mục `.okf` trong kho. Trả chuỗi rỗng nếu không có. */
|
|
3
|
+
export declare function thuMucOkf(goc: string, ghiChu?: string[]): string;
|
|
4
|
+
export declare function coOkf(goc: string): boolean;
|
|
5
|
+
export declare function timTrenOkf(goc: string, query: string, tenNguon: string): {
|
|
6
|
+
hits: SearchHit[];
|
|
7
|
+
note: string;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=knowledge-okf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge-okf.d.ts","sourceRoot":"","sources":["../../../src/commands/source/knowledge-okf.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AA0BjD,iEAAiE;AACjE,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,EAAO,GAAG,MAAM,CAWpE;AAED,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE1C;AAcD,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf;IAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CA8BrC"}
|