@mison/ling 1.0.1 → 1.1.0
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 +22 -3
- package/README.md +38 -25
- package/bin/adapters/codex.js +6 -6
- package/bin/adapters/gemini.js +1 -1
- package/bin/interactive.js +68 -1
- package/bin/{ag-kit.js → ling-cli.js} +553 -120
- package/bin/ling.js +1 -1
- package/bin/utils/managed-block.js +17 -4
- package/bin/utils.js +1 -1
- package/docs/TECH.md +16 -7
- package/package.json +7 -5
- package/scripts/ci-verify.js +9 -3
- package/scripts/postinstall-check.js +5 -6
- package/tests/clean-script.test.js +1 -1
- package/tests/cli-smoke.test.js +85 -0
- package/tests/managed-block.test.js +18 -1
- package/tests/phase-c.test.js +2 -2
- package/tests/standards-compliance.test.js +1 -1
- package/tests/transformer.test.js +1 -1
- package/tests/versioning.test.js +0 -10
package/bin/ling.js
CHANGED
|
@@ -10,6 +10,14 @@ function detectLineEnding(content) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
function buildMarkers(blockId) {
|
|
13
|
+
const id = String(blockId || "default").trim();
|
|
14
|
+
return {
|
|
15
|
+
begin: `<!-- BEGIN LING MANAGED BLOCK: ${id} -->`,
|
|
16
|
+
end: `<!-- END LING MANAGED BLOCK: ${id} -->`,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function buildLegacyMarkers(blockId) {
|
|
13
21
|
const id = String(blockId || "default").trim();
|
|
14
22
|
return {
|
|
15
23
|
begin: `<!-- BEGIN AG-KIT MANAGED BLOCK: ${id} -->`,
|
|
@@ -29,10 +37,9 @@ function upsertManagedBlock(filePath, blockId, body, options = {}) {
|
|
|
29
37
|
const lineEnding = detectLineEnding(original);
|
|
30
38
|
const managedBlock = buildManagedBlock(blockId, body, lineEnding);
|
|
31
39
|
const markers = buildMarkers(blockId);
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
);
|
|
40
|
+
const legacyMarkers = buildLegacyMarkers(blockId);
|
|
41
|
+
const blockRegex = new RegExp(`${escapeRegex(markers.begin)}[\\s\\S]*?${escapeRegex(markers.end)}`, "m");
|
|
42
|
+
const legacyRegex = new RegExp(`${escapeRegex(legacyMarkers.begin)}[\\s\\S]*?${escapeRegex(legacyMarkers.end)}`, "m");
|
|
36
43
|
|
|
37
44
|
let next = "";
|
|
38
45
|
let action = "unchanged";
|
|
@@ -46,6 +53,12 @@ function upsertManagedBlock(filePath, blockId, body, options = {}) {
|
|
|
46
53
|
if (next && !/\r?\n$/.test(next)) {
|
|
47
54
|
next += lineEnding;
|
|
48
55
|
}
|
|
56
|
+
} else if (legacyRegex.test(original)) {
|
|
57
|
+
next = original.replace(legacyRegex, managedBlock);
|
|
58
|
+
action = "updated";
|
|
59
|
+
if (next && !/\r?\n$/.test(next)) {
|
|
60
|
+
next += lineEnding;
|
|
61
|
+
}
|
|
49
62
|
} else {
|
|
50
63
|
next = `${original.replace(/\r?\n?$/, "")}${lineEnding}${lineEnding}${managedBlock}${lineEnding}`;
|
|
51
64
|
action = "appended";
|
package/bin/utils.js
CHANGED
|
@@ -49,7 +49,7 @@ function cloneBranchAgentDir(branch, options) {
|
|
|
49
49
|
throw new Error(`非法分支名: ${branch}`);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "
|
|
52
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "ling-"));
|
|
53
53
|
const logFn = options && options.logger ? options.logger : console.log;
|
|
54
54
|
|
|
55
55
|
if (!options.quiet) logFn(`[download] 正在从 ${REPO_URL} 拉取分支 ${safeBranch} ...`);
|
package/docs/TECH.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## 快速验证(维护者)
|
|
4
4
|
```bash
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
cd web &&
|
|
5
|
+
npm install
|
|
6
|
+
npm test
|
|
7
|
+
npm run ci:verify
|
|
8
|
+
npm run health-check
|
|
9
|
+
cd web && npm install && npm run lint
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
## 核心目录与职责
|
|
@@ -20,6 +20,9 @@ cd web && bun install && bun run lint
|
|
|
20
20
|
### 项目级(功能最完整)
|
|
21
21
|
- `gemini`:项目根目录 `.agent/`
|
|
22
22
|
- `codex`:项目根目录 `.agents/`(受管)+ `.agents-backup/`(漂移覆盖备份)
|
|
23
|
+
- 项目级预备份(覆盖前快照):
|
|
24
|
+
- Gemini:`<project>/.agent-backup/<timestamp>/preflight/.agent/`
|
|
25
|
+
- Codex:`<project>/.agents-backup/<timestamp>/preflight/.agents/` 或 `<project>/.agents-backup/<timestamp>/preflight/.codex/`
|
|
23
26
|
|
|
24
27
|
### 全局级(仅同步 Skills)
|
|
25
28
|
- `codex`:`$HOME/.codex/skills/`
|
|
@@ -31,9 +34,16 @@ cd web && bun install && bun run lint
|
|
|
31
34
|
## 端到端链路(简述)
|
|
32
35
|
### 项目安装 / 更新
|
|
33
36
|
- `init`:选择目标 -> 适配器 `install()` -> 落盘目标目录(Gemini: `.agent/`;Codex: `.agents/`)->(Codex)注入托管区块到工作区 `AGENTS.md` 与 `ling.rules`
|
|
34
|
-
- `update`:自动检测已安装目标(或通过 `--target/--targets`
|
|
37
|
+
- `update`:自动检测已安装目标(或通过 `--target/--targets` 指定)->(冲突时交互确认或默认预备份)-> 适配器 `update()` ->(Codex)漂移检测与备份 -> 原子替换
|
|
35
38
|
- `doctor`:检查完整性;`--fix` 尝试修复(Codex 支持迁移 `.codex/` 与重写托管区块)
|
|
36
39
|
|
|
40
|
+
### 已有资产冲突处理(项目级)
|
|
41
|
+
- 触发条件:
|
|
42
|
+
- `gemini`:`.agent/` 已存在且与内置模板不一致
|
|
43
|
+
- `codex`:`.agents/` 或 `.codex/` 已存在且存在漂移、缺失 `manifest.json` 或包含未知文件
|
|
44
|
+
- 交互终端会逐项询问处理方式:保留 / 备份后移除 / 直接移除,并支持按资产类别复用选择
|
|
45
|
+
- 非交互环境不会进入询问:需要覆盖时默认执行“备份后覆盖”;`init` 若检测到已有资产且未显式 `--force` 则报错
|
|
46
|
+
|
|
37
47
|
### Codex 构建(Workflow -> Skill)
|
|
38
48
|
- 输入:`.agents/skills/` 与 `.agents/workflows/`
|
|
39
49
|
- 规则:每个 Workflow `<name>.md` 会转换为一个 Skill:`workflow-<name>/SKILL.md`
|
|
@@ -161,7 +171,6 @@ cp -a "$HOME/.ling/backups/global/$ts/antigravity/$skill" "$HOME/.gemini/antigra
|
|
|
161
171
|
|
|
162
172
|
## 安装提示机制
|
|
163
173
|
- npm 全局安装:`postinstall` 会尽力检测并提示上游英文版 `@vudovn/ag-kit` 冲突。
|
|
164
|
-
- Bun 全局安装:Bun 默认会阻止本包 `postinstall`;因此冲突提示以内置 CLI 运行期检查为准,会在 `init` / `update` / `update-all` / `global sync` 时提示。
|
|
165
174
|
- 冲突提示只负责提醒,不会自动修改当前安装状态;如需清理可执行 `npm uninstall -g @vudovn/ag-kit`。
|
|
166
175
|
|
|
167
176
|
## 常见故障
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mison/ling",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "面向 Gemini CLI、Antigravity 与 Codex 的中文 AI Agent 模板工具包",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/MisonL/Ling.git"
|
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
"skills",
|
|
19
19
|
"templates"
|
|
20
20
|
],
|
|
21
|
-
"author": "
|
|
21
|
+
"author": "Mison",
|
|
22
|
+
"contributors": [
|
|
23
|
+
"vudovn"
|
|
24
|
+
],
|
|
22
25
|
"license": "MIT",
|
|
23
26
|
"scripts": {
|
|
24
27
|
"clean": "node scripts/clean.js",
|
|
@@ -50,7 +53,6 @@
|
|
|
50
53
|
"docs/TECH.md"
|
|
51
54
|
],
|
|
52
55
|
"bin": {
|
|
53
|
-
"ling": "bin/ling.js"
|
|
54
|
-
"ag-kit": "bin/ag-kit.js"
|
|
56
|
+
"ling": "bin/ling.js"
|
|
55
57
|
}
|
|
56
58
|
}
|
package/scripts/ci-verify.js
CHANGED
|
@@ -9,6 +9,7 @@ const REPO_ROOT = path.resolve(__dirname, "..");
|
|
|
9
9
|
const CLI_PATH = path.join(REPO_ROOT, "bin", "ling.js");
|
|
10
10
|
|
|
11
11
|
function runCli(args, options = {}) {
|
|
12
|
+
const allowedStatuses = options.allowedStatuses || [0];
|
|
12
13
|
const env = {
|
|
13
14
|
...process.env,
|
|
14
15
|
LING_SKIP_UPSTREAM_CHECK: "1",
|
|
@@ -21,9 +22,11 @@ function runCli(args, options = {}) {
|
|
|
21
22
|
encoding: "utf8",
|
|
22
23
|
});
|
|
23
24
|
|
|
24
|
-
if (result.status
|
|
25
|
+
if (!allowedStatuses.includes(result.status)) {
|
|
25
26
|
const message = result.stderr || result.stdout || "";
|
|
26
|
-
throw new Error(
|
|
27
|
+
throw new Error(
|
|
28
|
+
`命令失败: ling ${args.join(" ")}\n(exit=${result.status})\n${message}`.trim(),
|
|
29
|
+
);
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
return result.stdout || "";
|
|
@@ -82,7 +85,10 @@ function main() {
|
|
|
82
85
|
throw new Error(`spec status 结果异常: ${specStatus}`);
|
|
83
86
|
}
|
|
84
87
|
runCli(["spec", "disable", "--target", "codex", "--quiet"], { env });
|
|
85
|
-
const specStatusAfterDisable = runCli(["spec", "status", "--quiet"], {
|
|
88
|
+
const specStatusAfterDisable = runCli(["spec", "status", "--quiet"], {
|
|
89
|
+
env,
|
|
90
|
+
allowedStatuses: [0, 2],
|
|
91
|
+
}).trim();
|
|
86
92
|
if (specStatusAfterDisable !== "missing") {
|
|
87
93
|
throw new Error(`spec disable 后状态异常: ${specStatusAfterDisable}`);
|
|
88
94
|
}
|
|
@@ -58,7 +58,7 @@ async function main() {
|
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
if (process.env.LING_SKIP_UPSTREAM_CHECK === "1"
|
|
61
|
+
if (process.env.LING_SKIP_UPSTREAM_CHECK === "1") {
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -72,13 +72,12 @@ async function main() {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
console.warn(`\n[warn] 检测到全局已安装上游英文版 ${UPSTREAM_GLOBAL_PACKAGE}`);
|
|
75
|
-
console.warn("[warn]
|
|
76
|
-
console.warn("[warn] 为避免后续混淆,建议仅保留一个来源。\n");
|
|
75
|
+
console.warn("[warn] 为避免 Skills/模板来源混用导致的行为差异,建议仅保留一个来源。\n");
|
|
77
76
|
|
|
78
77
|
if (!canPromptUser()) {
|
|
79
78
|
console.warn("[info] 当前环境不是交互式终端,无法确认是否自动卸载。");
|
|
80
79
|
console.warn(`[hint] 如需卸载,请手动执行: npm uninstall -g ${UPSTREAM_GLOBAL_PACKAGE}`);
|
|
81
|
-
console.warn("[info]
|
|
80
|
+
console.warn("[info] 本次将继续安装;安装完成后请使用 `ling`。\n");
|
|
82
81
|
return;
|
|
83
82
|
}
|
|
84
83
|
|
|
@@ -86,7 +85,7 @@ async function main() {
|
|
|
86
85
|
|
|
87
86
|
if (!shouldUninstall) {
|
|
88
87
|
console.warn(`[info] 已保留 ${UPSTREAM_GLOBAL_PACKAGE},继续安装当前版本。`);
|
|
89
|
-
console.warn("[info]
|
|
88
|
+
console.warn("[info] 结果说明:安装完成后请使用 `ling`。\n");
|
|
90
89
|
return;
|
|
91
90
|
}
|
|
92
91
|
|
|
@@ -101,7 +100,7 @@ async function main() {
|
|
|
101
100
|
console.warn(`[error] 自动卸载 ${UPSTREAM_GLOBAL_PACKAGE} 失败,将继续安装当前版本。`);
|
|
102
101
|
console.warn("[info] 若需手动处理,请执行:");
|
|
103
102
|
console.warn(` npm uninstall -g ${UPSTREAM_GLOBAL_PACKAGE}`);
|
|
104
|
-
console.warn("[info]
|
|
103
|
+
console.warn("[info] 安装完成后请使用 `ling`。\n");
|
|
105
104
|
}
|
|
106
105
|
|
|
107
106
|
main().catch((err) => {
|
package/tests/cli-smoke.test.js
CHANGED
|
@@ -27,6 +27,37 @@ describe("CLI Smoke", () => {
|
|
|
27
27
|
let workspaceDir;
|
|
28
28
|
let indexPath;
|
|
29
29
|
|
|
30
|
+
function findFirstTimestampDir(backupRoot) {
|
|
31
|
+
if (!fs.existsSync(backupRoot)) {
|
|
32
|
+
return "";
|
|
33
|
+
}
|
|
34
|
+
const entries = fs
|
|
35
|
+
.readdirSync(backupRoot, { withFileTypes: true })
|
|
36
|
+
.filter((entry) => entry.isDirectory())
|
|
37
|
+
.map((entry) => entry.name)
|
|
38
|
+
.sort();
|
|
39
|
+
return entries.length > 0 ? path.join(backupRoot, entries[entries.length - 1]) : "";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function findTimestampDirContaining(backupRoot, relPath) {
|
|
43
|
+
if (!fs.existsSync(backupRoot)) {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
const entries = fs
|
|
47
|
+
.readdirSync(backupRoot, { withFileTypes: true })
|
|
48
|
+
.filter((entry) => entry.isDirectory())
|
|
49
|
+
.map((entry) => entry.name)
|
|
50
|
+
.sort();
|
|
51
|
+
|
|
52
|
+
for (const name of entries) {
|
|
53
|
+
const candidate = path.join(backupRoot, name, relPath);
|
|
54
|
+
if (fs.existsSync(candidate)) {
|
|
55
|
+
return path.join(backupRoot, name);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return "";
|
|
59
|
+
}
|
|
60
|
+
|
|
30
61
|
beforeEach(() => {
|
|
31
62
|
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "ling-cli-test-"));
|
|
32
63
|
workspaceDir = path.join(tempDir, "workspace");
|
|
@@ -273,6 +304,60 @@ describe("CLI Smoke", () => {
|
|
|
273
304
|
assert.strictEqual(result.status, 0, result.stderr || result.stdout);
|
|
274
305
|
});
|
|
275
306
|
|
|
307
|
+
test("init --force should create preflight backup for existing gemini .agent", () => {
|
|
308
|
+
const agentDir = path.join(workspaceDir, ".agent");
|
|
309
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
310
|
+
fs.writeFileSync(path.join(agentDir, "custom.txt"), "custom", "utf8");
|
|
311
|
+
|
|
312
|
+
const result = runCli(
|
|
313
|
+
["init", "--target", "gemini", "--path", workspaceDir, "--force", "--quiet"],
|
|
314
|
+
{ env: { LING_INDEX_PATH: indexPath } },
|
|
315
|
+
);
|
|
316
|
+
assert.strictEqual(result.status, 0, result.stderr || result.stdout);
|
|
317
|
+
|
|
318
|
+
const backupRoot = path.join(workspaceDir, ".agent-backup");
|
|
319
|
+
const tsDir = findFirstTimestampDir(backupRoot);
|
|
320
|
+
assert.ok(tsDir, "expected .agent-backup timestamp directory to exist");
|
|
321
|
+
assert.ok(fs.existsSync(path.join(tsDir, "preflight", ".agent", "custom.txt")));
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
test("update should create preflight backup for gemini when overwriting in non-interactive mode", () => {
|
|
325
|
+
const agentDir = path.join(workspaceDir, ".agent");
|
|
326
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
327
|
+
fs.writeFileSync(path.join(agentDir, "custom.txt"), "custom", "utf8");
|
|
328
|
+
|
|
329
|
+
const result = runCli(
|
|
330
|
+
["update", "--target", "gemini", "--path", workspaceDir, "--quiet"],
|
|
331
|
+
{ env: { LING_INDEX_PATH: indexPath } },
|
|
332
|
+
);
|
|
333
|
+
assert.strictEqual(result.status, 0, result.stderr || result.stdout);
|
|
334
|
+
|
|
335
|
+
const backupRoot = path.join(workspaceDir, ".agent-backup");
|
|
336
|
+
const tsDir = findFirstTimestampDir(backupRoot);
|
|
337
|
+
assert.ok(tsDir, "expected .agent-backup timestamp directory to exist");
|
|
338
|
+
assert.ok(fs.existsSync(path.join(tsDir, "preflight", ".agent", "custom.txt")));
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test("update should create preflight backup for codex when unknown files exist in managed dir", () => {
|
|
342
|
+
const initResult = runCli(
|
|
343
|
+
["init", "--target", "codex", "--path", workspaceDir, "--quiet"],
|
|
344
|
+
{ env: { LING_INDEX_PATH: indexPath } },
|
|
345
|
+
);
|
|
346
|
+
assert.strictEqual(initResult.status, 0, initResult.stderr || initResult.stdout);
|
|
347
|
+
|
|
348
|
+
fs.writeFileSync(path.join(workspaceDir, ".agents", "unknown.txt"), "unknown", "utf8");
|
|
349
|
+
|
|
350
|
+
const updateResult = runCli(
|
|
351
|
+
["update", "--target", "codex", "--path", workspaceDir, "--quiet"],
|
|
352
|
+
{ env: { LING_INDEX_PATH: indexPath } },
|
|
353
|
+
);
|
|
354
|
+
assert.strictEqual(updateResult.status, 0, updateResult.stderr || updateResult.stdout);
|
|
355
|
+
|
|
356
|
+
const backupRoot = path.join(workspaceDir, ".agents-backup");
|
|
357
|
+
const tsDir = findTimestampDirContaining(backupRoot, path.join("preflight", ".agents", "unknown.txt"));
|
|
358
|
+
assert.ok(tsDir, "expected .agents-backup preflight backup to exist");
|
|
359
|
+
});
|
|
360
|
+
|
|
276
361
|
test("status --quiet should report missing with exit code 2 when nothing is installed", () => {
|
|
277
362
|
const result = runCli(
|
|
278
363
|
["status", "--path", workspaceDir, "--quiet"],
|
|
@@ -25,7 +25,7 @@ describe("ManagedBlock", () => {
|
|
|
25
25
|
assert.strictEqual(result.action, "appended");
|
|
26
26
|
const content = fs.readFileSync(targetFile, "utf8");
|
|
27
27
|
assert.ok(content.includes("User Content"));
|
|
28
|
-
assert.ok(content.includes("BEGIN
|
|
28
|
+
assert.ok(content.includes("BEGIN LING MANAGED BLOCK: codex-core-rules"));
|
|
29
29
|
assert.ok(content.includes("managed line"));
|
|
30
30
|
});
|
|
31
31
|
|
|
@@ -38,4 +38,21 @@ describe("ManagedBlock", () => {
|
|
|
38
38
|
assert.ok(content.includes("v2"));
|
|
39
39
|
assert.ok(!content.includes("v1"));
|
|
40
40
|
});
|
|
41
|
+
|
|
42
|
+
test("should migrate legacy AG-KIT markers when updating managed block", () => {
|
|
43
|
+
fs.writeFileSync(
|
|
44
|
+
targetFile,
|
|
45
|
+
`# User Content\n\n<!-- BEGIN AG-KIT MANAGED BLOCK: codex-core-rules -->\nlegacy\n<!-- END AG-KIT MANAGED BLOCK: codex-core-rules -->\n`,
|
|
46
|
+
"utf8",
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const result = upsertManagedBlock(targetFile, "codex-core-rules", "v2");
|
|
50
|
+
|
|
51
|
+
assert.strictEqual(result.action, "updated");
|
|
52
|
+
const content = fs.readFileSync(targetFile, "utf8");
|
|
53
|
+
assert.ok(content.includes("BEGIN LING MANAGED BLOCK: codex-core-rules"));
|
|
54
|
+
assert.ok(!content.includes("BEGIN AG-KIT MANAGED BLOCK: codex-core-rules"));
|
|
55
|
+
assert.ok(content.includes("v2"));
|
|
56
|
+
assert.ok(!content.includes("legacy"));
|
|
57
|
+
});
|
|
41
58
|
});
|
package/tests/phase-c.test.js
CHANGED
|
@@ -66,9 +66,9 @@ describe('Phase C Integration', () => {
|
|
|
66
66
|
// Verification 4: Workspace managed block injection
|
|
67
67
|
const workspaceAgents = fs.readFileSync(path.join(workDir, 'AGENTS.md'), 'utf8');
|
|
68
68
|
const workspaceRules = fs.readFileSync(path.join(workDir, 'ling.rules'), 'utf8');
|
|
69
|
-
assert.ok(workspaceAgents.includes('BEGIN
|
|
69
|
+
assert.ok(workspaceAgents.includes('BEGIN LING MANAGED BLOCK: codex-core-rules'));
|
|
70
70
|
assert.ok(workspaceAgents.includes('test-skill'));
|
|
71
|
-
assert.ok(workspaceRules.includes('BEGIN
|
|
71
|
+
assert.ok(workspaceRules.includes('BEGIN LING MANAGED BLOCK: codex-risk-controls'));
|
|
72
72
|
|
|
73
73
|
const codexJson = JSON.parse(fs.readFileSync(path.join(codexDir, 'codex.json'), 'utf8'));
|
|
74
74
|
assert.strictEqual(codexJson.version, pkg.version);
|
|
@@ -79,7 +79,7 @@ describe('Standards Compliance', () => {
|
|
|
79
79
|
|
|
80
80
|
test('critical mechanism tokens should remain aligned with reference snapshot', { skip: !fs.existsSync(REF_ROOT) }, () => {
|
|
81
81
|
const refRoot = REF_ROOT;
|
|
82
|
-
const tokenRegex = /(
|
|
82
|
+
const tokenRegex = /(ling|python3?|checklist\.py|verify_all\.py|security_scan\.py|ux_audit\.py|accessibility_checker\.py|schema_validator\.py|lint_runner\.py|type_coverage\.py|playwright_runner\.py|lighthouse_audit\.py|api_validator\.py|mobile_audit\.py|seo_checker\.py|geo_checker\.py|i18n_checker\.py|\.agent\/|\.agents\/|\.agents-backup\/|\.codex\/|AGENTS\.md|antigravity\.rules|ling\.rules|manifest\.json|--target|--targets|--fix|--path|--no-index|--dry-run|--quiet|--force)/g;
|
|
83
83
|
const slashCommandRegex = /(?:^|[\s`"'(\[])(\/(?:brainstorm|create|debug|deploy|enhance|orchestrate|plan|preview|status|test|ui-ux-pro-max))(?=$|[\s`"',。,.::)\]])/gm;
|
|
84
84
|
|
|
85
85
|
const markdownFiles = [];
|
|
@@ -9,7 +9,7 @@ describe("ResourceTransformer", () => {
|
|
|
9
9
|
let tempDir;
|
|
10
10
|
|
|
11
11
|
beforeEach(() => {
|
|
12
|
-
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "
|
|
12
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "ling-transformer-test-"));
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
afterEach(() => {
|
package/tests/versioning.test.js
CHANGED
|
@@ -7,7 +7,6 @@ const { spawnSync } = require("node:child_process");
|
|
|
7
7
|
|
|
8
8
|
const REPO_ROOT = path.resolve(__dirname, "..");
|
|
9
9
|
const LING_CLI = path.join(REPO_ROOT, "bin", "ling.js");
|
|
10
|
-
const AG_KIT_CLI = path.join(REPO_ROOT, "bin", "ag-kit.js");
|
|
11
10
|
const pkg = require(path.join(REPO_ROOT, "package.json"));
|
|
12
11
|
|
|
13
12
|
function runCli(cliPath, args, envOverrides = {}) {
|
|
@@ -40,12 +39,3 @@ test("ling --version should print ling- prefixed version tag", () => {
|
|
|
40
39
|
assert.strictEqual(stdout, `ling version ling-${pkg.version}`);
|
|
41
40
|
assert.ok(!stdout.includes("[warn]"), "ling entry should not include legacy alias warning");
|
|
42
41
|
});
|
|
43
|
-
|
|
44
|
-
test("ag-kit --version should warn and print ling- prefixed version tag", () => {
|
|
45
|
-
const result = runCli(AG_KIT_CLI, ["--version"]);
|
|
46
|
-
assert.strictEqual(result.status, 0, result.stderr || result.stdout);
|
|
47
|
-
const lines = String(result.stdout || "").trim().split(/\r?\n/);
|
|
48
|
-
assert.ok(lines.some((line) => line.includes("[warn]")), "ag-kit entry should include legacy alias warning");
|
|
49
|
-
assert.strictEqual(lines[lines.length - 1], `ling version ling-${pkg.version}`);
|
|
50
|
-
});
|
|
51
|
-
|