@minonl/dia 0.0.7 → 0.0.8
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/dist/cli.js +49 -39
- package/docs/cli.md +2 -2
- package/docs/status.md +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2098,6 +2098,9 @@ function install(from, opts = {}) {
|
|
|
2098
2098
|
const kitRoot = resolve5(target, kitRootRel);
|
|
2099
2099
|
if (!kitRoot.startsWith(target + sep4) && kitRoot !== target)
|
|
2100
2100
|
throw new Error("E_MANIFEST: root escapes kit");
|
|
2101
|
+
const hasContent = ["files", "skills", "bin", "dirs", "knowledge", "commands", "config"].some((k) => (m[k]?.length ?? 0) > 0);
|
|
2102
|
+
if (!hasContent)
|
|
2103
|
+
throw new Error("E_MANIFEST: kit 未声明任何内容(files/skills/bin/dirs/knowledge/commands/config)");
|
|
2101
2104
|
const planned = renderContent(src.dir, target, m, { dryRun: true }) ?? [];
|
|
2102
2105
|
if (opts.dryRun)
|
|
2103
2106
|
return { id: m.id, version: m.version, dir: target, root: kitRoot, rendered: planned, hash: null, changed: false };
|
|
@@ -2110,6 +2113,10 @@ function install(from, opts = {}) {
|
|
|
2110
2113
|
const rendered = renderContent(src.dir, target, m) ?? planned;
|
|
2111
2114
|
const appliedConfig = apply(m.config ?? []);
|
|
2112
2115
|
const hash = hashTree(target);
|
|
2116
|
+
if (hash === "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") {
|
|
2117
|
+
rmSync3(target, { recursive: true, force: true });
|
|
2118
|
+
throw new Error(`E_KIT_EMPTY: kit ${m.id}@${m.version} 内容为空(检查 source 与清单路径)`);
|
|
2119
|
+
}
|
|
2113
2120
|
writeFileSync5(join10(target, "kit.lock"), JSON.stringify({
|
|
2114
2121
|
id: m.id,
|
|
2115
2122
|
version: m.version,
|
|
@@ -5137,7 +5144,7 @@ function scopeEnv(s, extra = {}) {
|
|
|
5137
5144
|
}
|
|
5138
5145
|
|
|
5139
5146
|
// src/doctor.ts
|
|
5140
|
-
import { existsSync as existsSync22 } from "node:fs";
|
|
5147
|
+
import { existsSync as existsSync22, readFileSync as readFileSync19 } from "node:fs";
|
|
5141
5148
|
import { homedir as homedir12 } from "node:os";
|
|
5142
5149
|
import { join as join25, resolve as resolve13 } from "node:path";
|
|
5143
5150
|
|
|
@@ -5579,17 +5586,20 @@ async function personaChecks(id, prefix, shared) {
|
|
|
5579
5586
|
} catch (e) {
|
|
5580
5587
|
checks.push({ name: `${prefix}persona.render`, status: "ok", detail: `跳过(${e?.message || String(e)})` });
|
|
5581
5588
|
}
|
|
5582
|
-
|
|
5583
|
-
|
|
5589
|
+
let refs = [];
|
|
5590
|
+
try {
|
|
5591
|
+
refs = JSON.parse(readFileSync19(join25(sc.dir, "dia.lock"), "utf8")).kits ?? [];
|
|
5592
|
+
} catch {
|
|
5593
|
+
refs = [];
|
|
5594
|
+
}
|
|
5595
|
+
if (!refs.length)
|
|
5584
5596
|
checks.push({ name: `${prefix}kits`, status: "ok", detail: "无独立 kit(内容由 persona 自带)" });
|
|
5585
|
-
for (const k of
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
}
|
|
5591
|
-
checks.push({ name: `${prefix}kit:${k.id}@${v}`, status: "fail", detail: e?.message });
|
|
5592
|
-
}
|
|
5597
|
+
for (const k of refs) {
|
|
5598
|
+
try {
|
|
5599
|
+
const r = verify2(k.id, k.version);
|
|
5600
|
+
checks.push({ name: `${prefix}kit:${k.id}@${k.version}`, status: r.ok ? "ok" : "fail", detail: r.ok ? "一致" : r.drift.join("; ") });
|
|
5601
|
+
} catch (e) {
|
|
5602
|
+
checks.push({ name: `${prefix}kit:${k.id}@${k.version}`, status: "fail", detail: e?.message });
|
|
5593
5603
|
}
|
|
5594
5604
|
}
|
|
5595
5605
|
if (sc.knowledgeRoot) {
|
|
@@ -5672,7 +5682,7 @@ async function run(opts = {}) {
|
|
|
5672
5682
|
}
|
|
5673
5683
|
|
|
5674
5684
|
// src/env.ts
|
|
5675
|
-
import { existsSync as existsSync23, readFileSync as
|
|
5685
|
+
import { existsSync as existsSync23, readFileSync as readFileSync20 } from "node:fs";
|
|
5676
5686
|
import { homedir as homedir13 } from "node:os";
|
|
5677
5687
|
import { join as join26 } from "node:path";
|
|
5678
5688
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
@@ -5687,7 +5697,7 @@ function parseFile(path) {
|
|
|
5687
5697
|
const out = {};
|
|
5688
5698
|
let text = "";
|
|
5689
5699
|
try {
|
|
5690
|
-
text =
|
|
5700
|
+
text = readFileSync20(path, "utf8");
|
|
5691
5701
|
} catch {
|
|
5692
5702
|
return out;
|
|
5693
5703
|
}
|
|
@@ -5757,7 +5767,7 @@ function run2(cfg, cmd, opts = {}) {
|
|
|
5757
5767
|
}
|
|
5758
5768
|
|
|
5759
5769
|
// src/bw.ts
|
|
5760
|
-
import { chmodSync as chmodSync4, existsSync as existsSync24, mkdirSync as mkdirSync17, readFileSync as
|
|
5770
|
+
import { chmodSync as chmodSync4, existsSync as existsSync24, mkdirSync as mkdirSync17, readFileSync as readFileSync21, rmSync as rmSync7, writeFileSync as writeFileSync14 } from "node:fs";
|
|
5761
5771
|
init_paths();
|
|
5762
5772
|
import { join as join27 } from "node:path";
|
|
5763
5773
|
import { execFileSync as execFileSync10 } from "node:child_process";
|
|
@@ -5770,7 +5780,7 @@ function sessionFile2() {
|
|
|
5770
5780
|
}
|
|
5771
5781
|
function readSession2() {
|
|
5772
5782
|
try {
|
|
5773
|
-
const s =
|
|
5783
|
+
const s = readFileSync21(sessionFile2(), "utf8").trim();
|
|
5774
5784
|
return s || null;
|
|
5775
5785
|
} catch {
|
|
5776
5786
|
return null;
|
|
@@ -6013,17 +6023,17 @@ function askBroker(req, timeoutMs = 5000) {
|
|
|
6013
6023
|
import { execFileSync as execFileSync12, spawn as spawn2, spawnSync as spawnSync5 } from "node:child_process";
|
|
6014
6024
|
import { mkdirSync as mkdirSync20, openSync as openSync3 } from "node:fs";
|
|
6015
6025
|
import { basename as basename10, join as join32 } from "node:path";
|
|
6016
|
-
import { existsSync as existsSync29, readFileSync as
|
|
6026
|
+
import { existsSync as existsSync29, readFileSync as readFileSync26 } from "node:fs";
|
|
6017
6027
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
6018
6028
|
import { resolve as resolvePath, sep as pathSep } from "node:path";
|
|
6019
6029
|
|
|
6020
6030
|
// src/team.ts
|
|
6021
|
-
import { appendFileSync as appendFileSync8, cpSync as cpSync3, existsSync as existsSync26, mkdirSync as mkdirSync18, readFileSync as
|
|
6031
|
+
import { appendFileSync as appendFileSync8, cpSync as cpSync3, existsSync as existsSync26, mkdirSync as mkdirSync18, readFileSync as readFileSync23, readdirSync as readdirSync11, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "node:fs";
|
|
6022
6032
|
import { homedir as homedir15, tmpdir as tmpdir3 } from "node:os";
|
|
6023
6033
|
import { join as join29, resolve as resolve14 } from "node:path";
|
|
6024
6034
|
|
|
6025
6035
|
// src/pricing.ts
|
|
6026
|
-
import { existsSync as existsSync25, readFileSync as
|
|
6036
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22 } from "node:fs";
|
|
6027
6037
|
import { homedir as homedir14 } from "node:os";
|
|
6028
6038
|
import { join as join28 } from "node:path";
|
|
6029
6039
|
var DEFAULT = {
|
|
@@ -6038,7 +6048,7 @@ function loadPrices() {
|
|
|
6038
6048
|
if (!existsSync25(pricesFile()))
|
|
6039
6049
|
return { ...DEFAULT };
|
|
6040
6050
|
try {
|
|
6041
|
-
const user = JSON.parse(
|
|
6051
|
+
const user = JSON.parse(readFileSync22(pricesFile(), "utf8"));
|
|
6042
6052
|
return { ...DEFAULT, ...user };
|
|
6043
6053
|
} catch {
|
|
6044
6054
|
return { ...DEFAULT };
|
|
@@ -6111,7 +6121,7 @@ function writeUsage(dir, id, acc) {
|
|
|
6111
6121
|
}
|
|
6112
6122
|
function judgeWorkspace(dir, fallback) {
|
|
6113
6123
|
try {
|
|
6114
|
-
const run = JSON.parse(
|
|
6124
|
+
const run = JSON.parse(readFileSync23(join29(dir, "run.json"), "utf8"));
|
|
6115
6125
|
const ws = String(run?.workspace || "");
|
|
6116
6126
|
if (ws)
|
|
6117
6127
|
return ws;
|
|
@@ -6126,17 +6136,17 @@ function gate(id) {
|
|
|
6126
6136
|
return { ok: false, reason: "missing: " + missing.join(",") };
|
|
6127
6137
|
let verify, redteam, run;
|
|
6128
6138
|
try {
|
|
6129
|
-
verify = JSON.parse(
|
|
6139
|
+
verify = JSON.parse(readFileSync23(join29(dir, "verify.json"), "utf8"));
|
|
6130
6140
|
} catch {
|
|
6131
6141
|
return { ok: false, reason: "bad verify.json" };
|
|
6132
6142
|
}
|
|
6133
6143
|
try {
|
|
6134
|
-
redteam = JSON.parse(
|
|
6144
|
+
redteam = JSON.parse(readFileSync23(join29(dir, "redteam.json"), "utf8"));
|
|
6135
6145
|
} catch {
|
|
6136
6146
|
return { ok: false, reason: "bad redteam.json" };
|
|
6137
6147
|
}
|
|
6138
6148
|
try {
|
|
6139
|
-
run = JSON.parse(
|
|
6149
|
+
run = JSON.parse(readFileSync23(join29(dir, "run.json"), "utf8"));
|
|
6140
6150
|
} catch {
|
|
6141
6151
|
return { ok: false, reason: "bad run.json" };
|
|
6142
6152
|
}
|
|
@@ -6282,7 +6292,7 @@ function snapPath(id, dir, tag) {
|
|
|
6282
6292
|
const f = join29(dir, "snapshots.json");
|
|
6283
6293
|
let list = [];
|
|
6284
6294
|
try {
|
|
6285
|
-
list = JSON.parse(
|
|
6295
|
+
list = JSON.parse(readFileSync23(f, "utf8"));
|
|
6286
6296
|
} catch {
|
|
6287
6297
|
list = [];
|
|
6288
6298
|
}
|
|
@@ -6305,7 +6315,7 @@ function cleanupSnapshots(runDir) {
|
|
|
6305
6315
|
if (process.env.DIA_KEEP_SNAPSHOTS === "1")
|
|
6306
6316
|
return;
|
|
6307
6317
|
try {
|
|
6308
|
-
for (const p of JSON.parse(
|
|
6318
|
+
for (const p of JSON.parse(readFileSync23(join29(runDir, "snapshots.json"), "utf8"))) {
|
|
6309
6319
|
if (resolve14(p).startsWith(resolve14(tmpdir3()) + "/"))
|
|
6310
6320
|
rmSync8(p, { recursive: true, force: true });
|
|
6311
6321
|
}
|
|
@@ -6392,7 +6402,7 @@ function gitDiff(ws) {
|
|
|
6392
6402
|
const untracked = execFileSync11("git", ["-C", ws, "ls-files", "--others", "--exclude-standard"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).split(`
|
|
6393
6403
|
`).filter(Boolean);
|
|
6394
6404
|
for (const f of untracked) {
|
|
6395
|
-
const body =
|
|
6405
|
+
const body = readFileSync23(join29(ws, f), "utf8");
|
|
6396
6406
|
out += `
|
|
6397
6407
|
--- /dev/null
|
|
6398
6408
|
+++ b/${f}
|
|
@@ -6585,7 +6595,7 @@ function dshSessionFile(sessionId) {
|
|
|
6585
6595
|
return null;
|
|
6586
6596
|
}
|
|
6587
6597
|
function dshUsages(file) {
|
|
6588
|
-
const raw = zstdDecompressSync2(
|
|
6598
|
+
const raw = zstdDecompressSync2(readFileSync23(file)).toString("utf8");
|
|
6589
6599
|
const out = [];
|
|
6590
6600
|
for (const line of raw.split(`
|
|
6591
6601
|
`)) {
|
|
@@ -6869,7 +6879,7 @@ function reject(id, reason) {
|
|
|
6869
6879
|
var DEFAULT_ACP_TIMEOUT = 600000;
|
|
6870
6880
|
|
|
6871
6881
|
// src/proposal.ts
|
|
6872
|
-
import { existsSync as existsSync27, readFileSync as
|
|
6882
|
+
import { existsSync as existsSync27, readFileSync as readFileSync24, readdirSync as readdirSync12 } from "node:fs";
|
|
6873
6883
|
import { join as join30 } from "node:path";
|
|
6874
6884
|
import { createHash as createHash10 } from "node:crypto";
|
|
6875
6885
|
init_paths();
|
|
@@ -6885,7 +6895,7 @@ function push(out, p) {
|
|
|
6885
6895
|
}
|
|
6886
6896
|
function readJson3(path) {
|
|
6887
6897
|
try {
|
|
6888
|
-
return JSON.parse(
|
|
6898
|
+
return JSON.parse(readFileSync24(path, "utf8"));
|
|
6889
6899
|
} catch {
|
|
6890
6900
|
return null;
|
|
6891
6901
|
}
|
|
@@ -6971,7 +6981,7 @@ function expandIds(cell) {
|
|
|
6971
6981
|
function collectHypotheses(out, path) {
|
|
6972
6982
|
if (!existsSync27(path))
|
|
6973
6983
|
return;
|
|
6974
|
-
const lines =
|
|
6984
|
+
const lines = readFileSync24(path, "utf8").split(`
|
|
6975
6985
|
`);
|
|
6976
6986
|
const titles = new Map;
|
|
6977
6987
|
for (const line of lines) {
|
|
@@ -7014,7 +7024,7 @@ import {
|
|
|
7014
7024
|
existsSync as existsSync28,
|
|
7015
7025
|
lstatSync as lstatSync3,
|
|
7016
7026
|
mkdirSync as mkdirSync19,
|
|
7017
|
-
readFileSync as
|
|
7027
|
+
readFileSync as readFileSync25,
|
|
7018
7028
|
readdirSync as readdirSync13,
|
|
7019
7029
|
readlinkSync as readlinkSync2,
|
|
7020
7030
|
rmSync as rmSync9,
|
|
@@ -7153,7 +7163,7 @@ function readServiceManifest(dir) {
|
|
|
7153
7163
|
throw new Error(`E_NO_MANIFEST: dia.json not found in ${dir}(adopted 服务需先补 dia.json)`);
|
|
7154
7164
|
let raw;
|
|
7155
7165
|
try {
|
|
7156
|
-
raw = JSON.parse(
|
|
7166
|
+
raw = JSON.parse(readFileSync25(p, "utf8"));
|
|
7157
7167
|
} catch {
|
|
7158
7168
|
throw new Error("E_MANIFEST: invalid json");
|
|
7159
7169
|
}
|
|
@@ -7194,7 +7204,7 @@ function isSymlink2(p) {
|
|
|
7194
7204
|
return false;
|
|
7195
7205
|
}
|
|
7196
7206
|
}
|
|
7197
|
-
var shaFile3 = (p) => createHash11("sha256").update(
|
|
7207
|
+
var shaFile3 = (p) => createHash11("sha256").update(readFileSync25(p)).digest("hex");
|
|
7198
7208
|
var UNKNOWN = "unknown";
|
|
7199
7209
|
var SIGNALS = { 6: "SIGABRT", 9: "SIGKILL", 11: "SIGSEGV", 13: "SIGPIPE", 15: "SIGTERM" };
|
|
7200
7210
|
function judgeHealth(exit, opts = {}) {
|
|
@@ -7425,7 +7435,7 @@ function readLockFile(id) {
|
|
|
7425
7435
|
if (!existsSync28(p))
|
|
7426
7436
|
throw new Error(`E_NOT_INSTALLED: service ${id}(缺 lock)`);
|
|
7427
7437
|
try {
|
|
7428
|
-
return JSON.parse(
|
|
7438
|
+
return JSON.parse(readFileSync25(p, "utf8"));
|
|
7429
7439
|
} catch {
|
|
7430
7440
|
throw new Error(`E_DRIFT: service.lock.json 不可解析(${p})`);
|
|
7431
7441
|
}
|
|
@@ -7446,7 +7456,7 @@ function readHealthLines(file) {
|
|
|
7446
7456
|
if (!existsSync28(file))
|
|
7447
7457
|
return [];
|
|
7448
7458
|
const rows = [];
|
|
7449
|
-
for (const line of
|
|
7459
|
+
for (const line of readFileSync25(file, "utf8").split(`
|
|
7450
7460
|
`)) {
|
|
7451
7461
|
if (!line.trim())
|
|
7452
7462
|
continue;
|
|
@@ -7643,7 +7653,7 @@ function readRegistryTasks(file = registryPath2()) {
|
|
|
7643
7653
|
if (!existsSync28(file))
|
|
7644
7654
|
return null;
|
|
7645
7655
|
try {
|
|
7646
|
-
const d = JSON.parse(
|
|
7656
|
+
const d = JSON.parse(readFileSync25(file, "utf8"));
|
|
7647
7657
|
return new Set(Object.keys(d?.tasks ?? {}));
|
|
7648
7658
|
} catch {
|
|
7649
7659
|
return null;
|
|
@@ -8009,7 +8019,7 @@ function cliVersion() {
|
|
|
8009
8019
|
];
|
|
8010
8020
|
for (const u of candidates) {
|
|
8011
8021
|
try {
|
|
8012
|
-
return String(JSON.parse(
|
|
8022
|
+
return String(JSON.parse(readFileSync26(u, "utf8")).version || "0.0.0");
|
|
8013
8023
|
} catch {}
|
|
8014
8024
|
}
|
|
8015
8025
|
return "0.0.0";
|
|
@@ -9049,7 +9059,7 @@ async function collabCli(argv) {
|
|
|
9049
9059
|
}
|
|
9050
9060
|
if (sub === "reply") {
|
|
9051
9061
|
const id = positional(args)[0];
|
|
9052
|
-
const body = flag(args, "--body") ?? (flag(args, "--body-file") ?
|
|
9062
|
+
const body = flag(args, "--body") ?? (flag(args, "--body-file") ? readFileSync26(flag(args, "--body-file"), "utf8") : undefined);
|
|
9053
9063
|
if (!id || body === undefined) {
|
|
9054
9064
|
err("usage: dia reply <id> --body B|--body-file F [--session S]");
|
|
9055
9065
|
return 2;
|
|
@@ -9766,7 +9776,7 @@ async function main(rawArgv) {
|
|
|
9766
9776
|
if (!npmManaged) {
|
|
9767
9777
|
let source = "";
|
|
9768
9778
|
try {
|
|
9769
|
-
source = String(JSON.parse(
|
|
9779
|
+
source = String(JSON.parse(readFileSync26(join32(install, "install.json"), "utf8")).source || "");
|
|
9770
9780
|
} catch {}
|
|
9771
9781
|
out(`这是脚本安装,不走 npm 升级。升级方式:`);
|
|
9772
9782
|
out(` cd ${source || "<dia 仓库>"} && git pull && bun run build && bash install.sh`);
|
package/docs/cli.md
CHANGED
|
@@ -95,11 +95,11 @@ dia persona remove dabo
|
|
|
95
95
|
| `persona update <id>` | **已实现** | 从 lock 记录的 source+ref 重装,并把 active 指向新版本;本地源亦可;`--force` 覆盖宿主/内联内容冲突(先备份) |
|
|
96
96
|
| `persona default <id>` | **已实现** | 改宿主 `default_agent`:备份原文件 + 记原值,`--unset` 精确还原;非严格 JSON 直接拒绝 |
|
|
97
97
|
| `persona create / render` | **已实现** | `create` 出骨架;`render --check` 只比对不写盘(跳过宿主自写文件,如 dsh `cordis.yml` / `package.json` / 锁文件);`render` 只覆盖 persona 产物,不整树重建宿主 profile |
|
|
98
|
-
| `kit add / list / verify / remove` | **已实现** | 复制/软链/记账;冲突写盘前全量检查(`E_CONFLICT`);`src/kit.ts` + `tests/kit.test.ts` |
|
|
98
|
+
| `kit add / list / verify / remove` | **已实现** | 复制/软链/记账;冲突写盘前全量检查(`E_CONFLICT`);**空清单/空内容拒绝**(`E_MANIFEST`/`E_KIT_EMPTY`);`src/kit.ts` + `tests/kit.test.ts` |
|
|
99
99
|
| `env list / check / run` | **已实现** | 白名单注入、不回显值、`--redact`、密钥不进 argv;清单由 persona 声明(`src/env.ts` + `tests/env.test.ts`) |
|
|
100
100
|
| `update [--check]` | **已实现** | 查 npm `dist-tags`;`--check` 有新版 exit 1、领先/最新 exit 0;**按安装方式分流**:npm 全局包 → `npm i -g`;脚本安装 → 提示 `git pull && bun run build && bash install.sh`(避免装到不在 PATH 的 npm prefix) |
|
|
101
101
|
| `deps list / record` | **已实现** | `list` = 登记 + 实测派生视图(required 缺失 exit 2);`record` = 只追加一行(`--id/--kind/--version` 必填);`src/deps.ts` + `tests/deps*.test.ts` |
|
|
102
|
-
| `doctor` | **已实现** | 组合自检:persona verify / **persona.render(宿主产物只读漂移,warn + 修复命令)** / default_agent / kit
|
|
102
|
+
| `doctor` | **已实现** | 组合自检:persona verify / **persona.render(宿主产物只读漂移,warn + 修复命令)** / default_agent / kit(**只查该 persona 引用的**,孤儿 kit 不拖红)/ knowledge(**索引新鲜度三态**,过期给重建命令)/ dsh preset / **deps 登记校验** / **platform 版本(读 `docs/platforms/registry.json`)** / wt;exit 0/1/2。不指定 persona 且装了多个 → **逐个自检**(条目加 `<id>.` 前缀),不再整体 `E_SCOPE` |
|
|
103
103
|
| `wt …` | **已实现(需安装包)** | 转发 `packages/wt/bin/dia-wt`(create/adopt/doctor/gate/list/status/check/clean/prune-merged;详见 [worktree.md](worktree.md));未装时 `E_WT`(exit 33),`install.sh` 会分发 |
|
|
104
104
|
| `kb index/search/query/get/lint/path/review` | **已实现** | persona 作用域下索引过期自动重建;显式 `--root` 保持「缺索引即报错」 |
|
|
105
105
|
| `kb <域命令>` | **已实现(委派)** | 未命中内置 → persona `commands` → 委派;argv 透传、exit code 原样 |
|
package/docs/status.md
CHANGED
|
@@ -90,6 +90,7 @@
|
|
|
90
90
|
| D0.21 | worktree 抽取 `packages/wt` | **完成** | 7 处 python→node;`dia wt`;4 套测试原样迁移全绿 |
|
|
91
91
|
| D0.23 | doctor 平台版本自检 | **完成** | `platform:opencode` / `platform:dsh` 报版本(缺宿主 = warn,不判红);`tests/active-doctor.test.ts` |
|
|
92
92
|
| D0.44 | 配置迁移走 LLM 任务 | **完成** | `docs/migrations/llm-migration.md`:升级只改声明;迁移=任务+判据+回滚;禁止代码里堆版本分支(安全敏感/原子场景例外) |
|
|
93
|
+
| D0.61 | kit 空内容拒绝 + doctor 只查引用 kit | **完成** | `kit add` 拒绝空清单/空树(E_MANIFEST/E_KIT_EMPTY);doctor 按 persona lock 的 kits 校验,孤儿不再拖红 |
|
|
93
94
|
| D0.60 | persona --force 覆盖内联内容 / update --force | **完成** | `kit.renderContent` 支持 force(写盘前备份到 `backups/force-*`);`persona update --force`;版本冲突错误给可执行提示;`tests/kit.test.ts` |
|
|
94
95
|
| D0.59 | 包内容守卫 | **完成** | 单测覆盖 docs 回退;publish workflow 发布前断言 tarball 含 docs/deps.jsonl + docs/platforms/registry.json(防「发完才发现缺文件」) |
|
|
95
96
|
| D0.58 | 推送前敏感扫描 | **完成** | `dia wt adopt` 的 pre-push 扫描新增行:真实家目录/私钥/token 形态;`DIA_WT_GUARD_SCAN=0` 逃生;`adopt.test.sh` 34 pass |
|