@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 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
- const installed = list();
5583
- if (!installed.length)
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 installed) {
5586
- for (const v of k.versions) {
5587
- try {
5588
- const r = verify2(k.id, v);
5589
- checks.push({ name: `${prefix}kit:${k.id}@${v}`, status: r.ok ? "ok" : "fail", detail: r.ok ? "一致" : r.drift.join("; ") });
5590
- } catch (e) {
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 readFileSync19 } from "node:fs";
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 = readFileSync19(path, "utf8");
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 readFileSync20, rmSync as rmSync7, writeFileSync as writeFileSync14 } from "node:fs";
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 = readFileSync20(sessionFile2(), "utf8").trim();
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 readFileSync25 } from "node:fs";
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 readFileSync22, readdirSync as readdirSync11, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "node:fs";
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 readFileSync21 } from "node:fs";
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(readFileSync21(pricesFile(), "utf8"));
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(readFileSync22(join29(dir, "run.json"), "utf8"));
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(readFileSync22(join29(dir, "verify.json"), "utf8"));
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(readFileSync22(join29(dir, "redteam.json"), "utf8"));
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(readFileSync22(join29(dir, "run.json"), "utf8"));
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(readFileSync22(f, "utf8"));
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(readFileSync22(join29(runDir, "snapshots.json"), "utf8"))) {
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 = readFileSync22(join29(ws, f), "utf8");
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(readFileSync22(file)).toString("utf8");
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 readFileSync23, readdirSync as readdirSync12 } from "node:fs";
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(readFileSync23(path, "utf8"));
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 = readFileSync23(path, "utf8").split(`
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 readFileSync24,
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(readFileSync24(p, "utf8"));
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(readFileSync24(p)).digest("hex");
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(readFileSync24(p, "utf8"));
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 readFileSync24(file, "utf8").split(`
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(readFileSync24(file, "utf8"));
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(readFileSync25(u, "utf8")).version || "0.0.0");
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") ? readFileSync25(flag(args, "--body-file"), "utf8") : undefined);
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(readFileSync25(join32(install, "install.json"), "utf8")).source || "");
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 / knowledge(**索引新鲜度三态**,过期给重建命令)/ dsh preset / **deps 登记校验** / **platform 版本(读 `docs/platforms/registry.json`)** / wt;exit 0/1/2。不指定 persona 且装了多个 → **逐个自检**(条目加 `<id>.` 前缀),不再整体 `E_SCOPE` |
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 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minonl/dia",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "type": "module",
5
5
  "description": "dia (嗲) — lightweight agent framework: knowledge index, audit, session ingest",
6
6
  "bin": {