@minonl/dia 0.0.16 → 0.0.17

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
@@ -11,6 +11,7 @@ var __esm = (fn, res, err) => () => {
11
11
  };
12
12
 
13
13
  // src/paths.ts
14
+ import { existsSync as existsSync3 } from "node:fs";
14
15
  import { homedir as homedir2 } from "node:os";
15
16
  import { dirname as dirname2, join as join3 } from "node:path";
16
17
  import { fileURLToPath } from "node:url";
@@ -20,26 +21,31 @@ function diaHome() {
20
21
  }
21
22
  function installDir() {
22
23
  const env = process.env.DIA_INSTALL_DIR || process.env.DIA_HOME_INSTALL;
23
- if (env)
24
- return env;
25
- try {
26
- return dirname2(dirname2(fileURLToPath(import.meta.url)));
27
- } catch {
28
- return diaHome();
24
+ if (env) {
25
+ if (existsSync3(env))
26
+ return env;
27
+ process.stderr.write(`! warn: DIA_INSTALL_DIR=${env} 不存在,忽略该覆盖并自动探测安装目录
28
+ `);
29
29
  }
30
+ try {
31
+ const derived = dirname2(dirname2(fileURLToPath(import.meta.url)));
32
+ if (existsSync3(derived))
33
+ return derived;
34
+ } catch {}
35
+ return diaHome();
30
36
  }
31
37
  var personasDir = () => join3(diaHome(), "personas"), msgRoot = () => join3(diaHome(), "msg"), agentsRoot = () => join3(diaHome(), "agents"), stateDir = () => process.env.DIA_STATE_DIR || join3(diaHome(), "state"), cacheRoot = () => join3(diaHome(), "cache"), jobRoot = () => join3(diaHome(), "job"), ingestDir = () => join3(diaHome(), "ingest"), srcCacheDir = () => process.env.DIA_CACHE_DIR || join3(cacheRoot(), "src");
32
38
  var init_paths = () => {};
33
39
 
34
40
  // src/runtime.ts
35
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
41
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
36
42
  import { join as join5 } from "node:path";
37
43
  function callsFile() {
38
44
  return join5(DATA2(), "runtime", "calls.jsonl");
39
45
  }
40
46
  function allCalls() {
41
47
  const f = callsFile();
42
- if (!existsSync4(f))
48
+ if (!existsSync5(f))
43
49
  return [];
44
50
  const out = [];
45
51
  for (const line of readFileSync3(f, "utf8").split(`
@@ -69,10 +75,10 @@ var init_runtime = __esm(() => {
69
75
  });
70
76
 
71
77
  // src/freeze.ts
72
- import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync2, statSync as statSync3 } from "node:fs";
78
+ import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync2, statSync as statSync3 } from "node:fs";
73
79
  import { join as join6 } from "node:path";
74
80
  function status() {
75
- if (!existsSync5(FILE))
81
+ if (!existsSync6(FILE))
76
82
  return { frozen: false };
77
83
  try {
78
84
  const s = JSON.parse(readFileSync4(FILE, "utf8"));
@@ -139,7 +145,7 @@ function thaw(opts) {
139
145
  }
140
146
  function snapshot() {
141
147
  const p = join6(STATE, "freeze-snapshot.json");
142
- if (!existsSync5(p))
148
+ if (!existsSync6(p))
143
149
  return null;
144
150
  return JSON.parse(readFileSync4(p, "utf8"));
145
151
  }
@@ -155,7 +161,7 @@ var init_freeze = __esm(() => {
155
161
  import {
156
162
  appendFileSync as appendFileSync2,
157
163
  chmodSync as chmodSync2,
158
- existsSync as existsSync6,
164
+ existsSync as existsSync7,
159
165
  mkdirSync as mkdirSync4,
160
166
  readFileSync as readFileSync5,
161
167
  realpathSync,
@@ -217,7 +223,7 @@ function checkpointTarget() {
217
223
  };
218
224
  }
219
225
  try {
220
- if (existsSync6(file) && statSync4(file).isDirectory()) {
226
+ if (existsSync7(file) && statSync4(file).isDirectory()) {
221
227
  return { ok: false, path: file, error: `${CHECKPOINT_ENV} points at a directory (${file}); expected a file path` };
222
228
  }
223
229
  } catch {}
@@ -229,7 +235,7 @@ function readCheckpoint(target = checkpointTarget()) {
229
235
  if (!target.ok)
230
236
  return { state: "misconfigured", path: target.path, error: target.error };
231
237
  const file = target.path;
232
- if (!existsSync6(file))
238
+ if (!existsSync7(file))
233
239
  return { state: "missing", path: file };
234
240
  let parsed;
235
241
  try {
@@ -401,7 +407,7 @@ function holderAlive(dir) {
401
407
  }
402
408
  function readHead() {
403
409
  const file = headFile();
404
- if (!existsSync6(file))
410
+ if (!existsSync7(file))
405
411
  return { state: "missing" };
406
412
  let parsed;
407
413
  try {
@@ -498,8 +504,8 @@ function append(ev) {
498
504
  full = { ...base, prev_hash };
499
505
  full.hash = hashEvent(full, prev_hash);
500
506
  const before = {
501
- size: existsSync6(file) ? statSync4(file).size : 0,
502
- head: existsSync6(headFile()) ? readFileSync5(headFile()) : null
507
+ size: existsSync7(file) ? statSync4(file).size : 0,
508
+ head: existsSync7(headFile()) ? readFileSync5(headFile()) : null
503
509
  };
504
510
  const anchored = { last_seq: last.seq ?? 0, last_hash: last.hash ?? GENESIS, row_count: last.count };
505
511
  const cpId = checkpoint_id || randomUUID2();
@@ -568,7 +574,7 @@ function append(ev) {
568
574
  }
569
575
  function rawLines() {
570
576
  const file = auditFile();
571
- if (!existsSync6(file))
577
+ if (!existsSync7(file))
572
578
  return [];
573
579
  return readFileSync5(file, "utf8").split(`
574
580
  `).filter((l) => l.trim());
@@ -1288,7 +1294,7 @@ function getDoc(root, rel, section) {
1288
1294
  // src/ingest.ts
1289
1295
  import { execFileSync } from "node:child_process";
1290
1296
  import { createHash as createHash2 } from "node:crypto";
1291
- import { appendFileSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2, writeFileSync } from "node:fs";
1297
+ import { appendFileSync, existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2, writeFileSync } from "node:fs";
1292
1298
  import { homedir as homedir3 } from "node:os";
1293
1299
  import { basename as basename2, dirname as dirname3, join as join4 } from "node:path";
1294
1300
  import { zstdDecompressSync } from "node:zlib";
@@ -1480,7 +1486,7 @@ async function readOpencode(dbPath, domain, project) {
1480
1486
  }
1481
1487
  function loadState(cacheDir) {
1482
1488
  const p = join4(cacheDir || CACHE, "state.json");
1483
- if (!existsSync3(p))
1489
+ if (!existsSync4(p))
1484
1490
  return {};
1485
1491
  try {
1486
1492
  return JSON.parse(readFileSync2(p, "utf8"));
@@ -1490,7 +1496,7 @@ function loadState(cacheDir) {
1490
1496
  }
1491
1497
  function seenSet(file) {
1492
1498
  const set = new Set;
1493
- if (!existsSync3(file))
1499
+ if (!existsSync4(file))
1494
1500
  return set;
1495
1501
  for (const line of readFileSync2(file, "utf8").split(`
1496
1502
  `)) {
@@ -1518,7 +1524,7 @@ async function ingest(opts = {}) {
1518
1524
  let episodes = [];
1519
1525
  if (sources.includes("dsh")) {
1520
1526
  const root = opts.sessionsRoot || join4(homedir3(), ".dsh", "sessions");
1521
- if (existsSync3(root)) {
1527
+ if (existsSync4(root)) {
1522
1528
  const cutoff = opts.full ? 0 : sinceMs ?? Number(state.dsh?.lastMtime || 0);
1523
1529
  for (const file of walkDsh(root)) {
1524
1530
  const mtime = Math.floor(statSync2(file).mtimeMs);
@@ -1536,7 +1542,7 @@ async function ingest(opts = {}) {
1536
1542
  }
1537
1543
  if (sources.includes("opencode")) {
1538
1544
  const dbPath = opts.opencodeDb || join4(homedir3(), ".local", "share", "opencode", "opencode.db");
1539
- if (existsSync3(dbPath)) {
1545
+ if (existsSync4(dbPath)) {
1540
1546
  const cutoff = opts.full ? 0 : sinceMs ?? Number(state.opencode?.lastUpdated || 0);
1541
1547
  const all = await readOpencode(dbPath, domain, opts.project);
1542
1548
  result.scanned += all.length;
@@ -1699,7 +1705,7 @@ function resumeCard(session) {
1699
1705
 
1700
1706
  // src/persona.ts
1701
1707
  import { createHash as createHash7 } from "node:crypto";
1702
- import { closeSync, cpSync as cpSync2, existsSync as existsSync11, lstatSync as lstatSync2, mkdirSync as mkdirSync10, openSync, readFileSync as readFileSync10, readdirSync as readdirSync6, realpathSync as realpathSync3, renameSync as renameSync4, rmSync as rmSync4, statSync as statSync8, symlinkSync as symlinkSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync8 } from "node:fs";
1708
+ import { closeSync as closeSync2, cpSync as cpSync2, existsSync as existsSync12, lstatSync as lstatSync2, mkdirSync as mkdirSync10, openSync as openSync2, readFileSync as readFileSync10, readdirSync as readdirSync6, realpathSync as realpathSync3, renameSync as renameSync5, rmSync as rmSync4, statSync as statSync8, symlinkSync as symlinkSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync8 } from "node:fs";
1703
1709
  import { homedir as homedir8 } from "node:os";
1704
1710
  import { basename as basename6, dirname as dirname8, join as join13, relative as relative4, resolve as resolve7, sep as sep5 } from "node:path";
1705
1711
  import { execFileSync as execFileSync3 } from "node:child_process";
@@ -1707,14 +1713,17 @@ import { execFileSync as execFileSync3 } from "node:child_process";
1707
1713
  // src/kit.ts
1708
1714
  import { createHash as createHash6 } from "node:crypto";
1709
1715
  import {
1716
+ closeSync,
1710
1717
  cpSync,
1711
- existsSync as existsSync8,
1718
+ existsSync as existsSync9,
1712
1719
  lstatSync,
1713
1720
  mkdirSync as mkdirSync7,
1721
+ openSync,
1714
1722
  readFileSync as readFileSync7,
1715
1723
  readdirSync as readdirSync3,
1716
1724
  readlinkSync,
1717
1725
  realpathSync as realpathSync2,
1726
+ renameSync as renameSync3,
1718
1727
  rmSync as rmSync3,
1719
1728
  statSync as statSync5,
1720
1729
  symlinkSync,
@@ -1728,7 +1737,7 @@ import { execFileSync as execFileSync2 } from "node:child_process";
1728
1737
  // src/config.ts
1729
1738
  init_paths();
1730
1739
  import { createHash as createHash5 } from "node:crypto";
1731
- import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
1740
+ import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
1732
1741
  import { homedir as homedir4 } from "node:os";
1733
1742
  import { dirname as dirname5, join as join9 } from "node:path";
1734
1743
  var home = () => process.env.DIA_HOME || homedir4();
@@ -1811,7 +1820,7 @@ function apply(entries, opts = {}) {
1811
1820
  const applied = [];
1812
1821
  for (const e of entries) {
1813
1822
  const path = expand(e.file);
1814
- const exists = existsSync7(path);
1823
+ const exists = existsSync8(path);
1815
1824
  const before = exists ? readFileSync6(path, "utf8") : "";
1816
1825
  let doc = {};
1817
1826
  if (exists && before.trim()) {
@@ -1846,7 +1855,7 @@ function apply(entries, opts = {}) {
1846
1855
  function revert(records) {
1847
1856
  const restored = [], skipped = [];
1848
1857
  for (const r of records) {
1849
- if (!existsSync7(r.path)) {
1858
+ if (!existsSync8(r.path)) {
1850
1859
  skipped.push(r.path);
1851
1860
  continue;
1852
1861
  }
@@ -1891,13 +1900,64 @@ function assertInsideHome(p) {
1891
1900
  function assertInside(base, p) {
1892
1901
  const abs = resolve5(base, p);
1893
1902
  const rootReal = realpathSync2(base);
1894
- if (!existsSync8(abs))
1903
+ if (!existsSync9(abs))
1895
1904
  throw new Error(`E_MANIFEST: source missing: ${p}`);
1896
1905
  const real = realpathSync2(abs);
1897
1906
  if (real !== rootReal && !real.startsWith(rootReal + sep4))
1898
1907
  throw new Error(`E_MANIFEST: source escapes kit: ${p}`);
1899
1908
  return abs;
1900
1909
  }
1910
+ var EMPTY_TREE_HASH = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
1911
+ function cmpVersion(a, b) {
1912
+ const pa = a.split(/[.+-]/), pb = b.split(/[.+-]/);
1913
+ for (let i = 0;i < Math.max(pa.length, pb.length); i++) {
1914
+ const x = pa[i] ?? "0", y = pb[i] ?? "0";
1915
+ const nx = Number(x), ny = Number(y);
1916
+ const both = !Number.isNaN(nx) && !Number.isNaN(ny);
1917
+ if (both ? nx !== ny : x !== y)
1918
+ return both ? nx - ny : x < y ? -1 : 1;
1919
+ }
1920
+ return 0;
1921
+ }
1922
+ function versionDirs(dir) {
1923
+ return readdirSync3(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name).sort(cmpVersion);
1924
+ }
1925
+ function sleepSync2(ms) {
1926
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
1927
+ }
1928
+ function withInstallLock(lockFile, fn) {
1929
+ const budget = Number(process.env.DIA_KIT_LOCK_MS || 5000);
1930
+ const start = Date.now();
1931
+ mkdirSync7(dirname6(lockFile), { recursive: true });
1932
+ for (;; ) {
1933
+ try {
1934
+ const fd = openSync(lockFile, "wx");
1935
+ writeFileSync5(fd, JSON.stringify({ pid: process.pid, at: Date.now() }));
1936
+ closeSync(fd);
1937
+ break;
1938
+ } catch (e) {
1939
+ if (e?.code !== "EEXIST")
1940
+ throw e;
1941
+ try {
1942
+ const st = statSync5(lockFile);
1943
+ if (Date.now() - st.mtimeMs > 120000) {
1944
+ rmSync3(lockFile, { force: true });
1945
+ continue;
1946
+ }
1947
+ } catch {
1948
+ continue;
1949
+ }
1950
+ if (Date.now() - start > budget)
1951
+ throw new Error(`E_KIT_BUSY: 另一个 dia 进程正在安装 kit(锁 ${lockFile};可用 DIA_KIT_LOCK_MS 调整等待)`);
1952
+ sleepSync2(50);
1953
+ }
1954
+ }
1955
+ try {
1956
+ return fn();
1957
+ } finally {
1958
+ rmSync3(lockFile, { force: true });
1959
+ }
1960
+ }
1901
1961
  var TREE_SKIP = new Set([".git", "node_modules", ".data"]);
1902
1962
  function copyFilter(base) {
1903
1963
  return (p) => !relative3(base, p).split(sep4).some((s) => TREE_SKIP.has(s));
@@ -1927,7 +1987,7 @@ function hashTree(root) {
1927
1987
  }
1928
1988
  function readKitManifest(dir) {
1929
1989
  const p = join10(dir, "dia.json");
1930
- if (!existsSync8(p))
1990
+ if (!existsSync9(p))
1931
1991
  throw new Error("E_MANIFEST: dia.json not found");
1932
1992
  let m;
1933
1993
  try {
@@ -1951,7 +2011,7 @@ function resolveSource(from, ref) {
1951
2011
  const key = createHash6("sha1").update(url).digest("hex").slice(0, 12);
1952
2012
  const dir = join10(cacheDir2(), key);
1953
2013
  const git = (args) => execFileSync2("git", ["-C", dir, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
1954
- if (!existsSync8(dir)) {
2014
+ if (!existsSync9(dir)) {
1955
2015
  mkdirSync7(cacheDir2(), { recursive: true });
1956
2016
  try {
1957
2017
  execFileSync2("git", ["clone", "--quiet", url, dir], { stdio: "pipe" });
@@ -1976,7 +2036,7 @@ function resolveSource(from, ref) {
1976
2036
  return { dir, commit: git(["rev-parse", "HEAD"]).trim() };
1977
2037
  }
1978
2038
  const dir = resolve5(from);
1979
- if (!existsSync8(dir))
2039
+ if (!existsSync9(dir))
1980
2040
  throw new Error("E_SOURCE: path not found");
1981
2041
  let commit = "local";
1982
2042
  try {
@@ -1985,7 +2045,7 @@ function resolveSource(from, ref) {
1985
2045
  return { dir, commit };
1986
2046
  }
1987
2047
  function checkTargetFree(path, kind, expected) {
1988
- if (!existsSync8(path) && !isSymlink(path))
2048
+ if (!existsSync9(path) && !isSymlink(path))
1989
2049
  return;
1990
2050
  if (kind === "file") {
1991
2051
  if (!isSymlink(path) && statSync5(path).isFile() && shaFile(path) === expected)
@@ -2051,7 +2111,7 @@ function renderContent(baseDir, targetDir, m, opts = {}) {
2051
2111
  try {
2052
2112
  if (p.entry.type === "file" && p.content !== undefined) {
2053
2113
  checkTargetFree(p.dest, "file", sha256(Buffer.from(p.content, "base64")));
2054
- } else if (p.linkTarget && (existsSync8(p.dest) || isSymlink(p.dest))) {
2114
+ } else if (p.linkTarget && (existsSync9(p.dest) || isSymlink(p.dest))) {
2055
2115
  if (!linkManaged(p.dest, p.linkTarget))
2056
2116
  conflict = true;
2057
2117
  }
@@ -2065,7 +2125,7 @@ function renderContent(baseDir, targetDir, m, opts = {}) {
2065
2125
  throw new Error(`E_CONFLICT: ${p.dest} exists and differs`);
2066
2126
  throw new Error(`E_CONFLICT: ${p.dest} exists and is not managed`);
2067
2127
  }
2068
- if (!isSymlink(p.dest) && existsSync8(p.dest)) {
2128
+ if (!isSymlink(p.dest) && existsSync9(p.dest)) {
2069
2129
  mkdirSync7(backupDir, { recursive: true });
2070
2130
  cpSync(p.dest, join10(backupDir, basename5(p.dest)));
2071
2131
  }
@@ -2079,7 +2139,7 @@ function renderContent(baseDir, targetDir, m, opts = {}) {
2079
2139
  writeFileSync5(p.dest, Buffer.from(p.content, "base64"));
2080
2140
  p.entry.value = shaFile(p.dest);
2081
2141
  } else if (p.linkTarget) {
2082
- if (existsSync8(p.dest) || isSymlink(p.dest))
2142
+ if (existsSync9(p.dest) || isSymlink(p.dest))
2083
2143
  unlinkSync(p.dest);
2084
2144
  symlinkSync(resolve5(p.linkTarget), p.dest);
2085
2145
  p.entry.value = relative3(targetDir, resolve5(p.linkTarget));
@@ -2095,8 +2155,9 @@ function renderContent(baseDir, targetDir, m, opts = {}) {
2095
2155
  function install(from, opts = {}) {
2096
2156
  const src = resolveSource(from, opts.ref);
2097
2157
  const m = readKitManifest(src.dir);
2098
- const target = resolve5(dataDir2(), "kits", m.id, m.version);
2099
- if (!target.startsWith(resolve5(dataDir2(), "kits") + sep4))
2158
+ const kitsRoot = resolve5(dataDir2(), "kits");
2159
+ const target = resolve5(kitsRoot, m.id, m.version);
2160
+ if (!target.startsWith(kitsRoot + sep4))
2100
2161
  throw new Error("E_MANIFEST: version escapes install dir");
2101
2162
  const kitRootRel = m.root ?? ".";
2102
2163
  const kitRoot = resolve5(target, kitRootRel);
@@ -2108,43 +2169,78 @@ function install(from, opts = {}) {
2108
2169
  const planned = renderContent(src.dir, target, m, { dryRun: true }) ?? [];
2109
2170
  if (opts.dryRun)
2110
2171
  return { id: m.id, version: m.version, dir: target, root: kitRoot, rendered: planned, hash: null, changed: false };
2111
- const alreadyInstalled = existsSync8(join10(target, "kit.lock"));
2112
- if (!alreadyInstalled || hashTree(src.dir) !== hashTree(target)) {
2113
- rmSync3(target, { recursive: true, force: true });
2114
- mkdirSync7(target, { recursive: true });
2115
- cpSync(src.dir, target, { recursive: true, dereference: true, filter: copyFilter(src.dir) });
2116
- }
2117
- const rendered = renderContent(src.dir, target, m) ?? planned;
2118
- const appliedConfig = apply(m.config ?? []);
2119
- const hash = hashTree(target);
2120
- if (hash === "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") {
2121
- rmSync3(target, { recursive: true, force: true });
2122
- throw new Error(`E_KIT_EMPTY: kit ${m.id}@${m.version} 内容为空(检查 source 与清单路径)`);
2123
- }
2124
- writeFileSync5(join10(target, "kit.lock"), JSON.stringify({
2125
- id: m.id,
2126
- version: m.version,
2127
- commit: src.commit,
2128
- root: kitRootRel,
2129
- hash,
2130
- rendered,
2131
- commands: m.commands ?? [],
2132
- knowledge: m.knowledge ?? [],
2133
- dataRoot: m.data_root ?? null,
2134
- env: m.env ?? null,
2135
- config: appliedConfig
2136
- }, null, 1));
2137
- return { id: m.id, version: m.version, dir: target, root: kitRoot, rendered, hash, changed: true };
2172
+ return withInstallLock(join10(kitsRoot, ".install.lock"), () => {
2173
+ const alreadyInstalled = existsSync9(join10(target, "kit.lock"));
2174
+ const changed = !alreadyInstalled || hashTree(src.dir) !== hashTree(target);
2175
+ if (changed) {
2176
+ const staging = join10(kitsRoot, ".staging", `${m.id}-${m.version}-${process.pid}-${Date.now()}`);
2177
+ mkdirSync7(staging, { recursive: true });
2178
+ try {
2179
+ cpSync(src.dir, staging, { recursive: true, dereference: true, filter: copyFilter(src.dir) });
2180
+ const stagedHash = hashTree(staging);
2181
+ if (stagedHash === EMPTY_TREE_HASH)
2182
+ throw new Error(`E_KIT_EMPTY: kit ${m.id}@${m.version} 内容为空(检查 source 与清单路径)`);
2183
+ writeFileSync5(join10(staging, "kit.lock"), JSON.stringify({
2184
+ id: m.id,
2185
+ version: m.version,
2186
+ commit: src.commit,
2187
+ root: kitRootRel,
2188
+ hash: stagedHash,
2189
+ rendered: [],
2190
+ commands: m.commands ?? [],
2191
+ knowledge: m.knowledge ?? [],
2192
+ dataRoot: m.data_root ?? null,
2193
+ env: m.env ?? null,
2194
+ config: []
2195
+ }, null, 1));
2196
+ mkdirSync7(dirname6(target), { recursive: true });
2197
+ if (existsSync9(target)) {
2198
+ const bak = `${target}.old-${process.pid}-${Date.now()}`;
2199
+ renameSync3(target, bak);
2200
+ try {
2201
+ renameSync3(staging, target);
2202
+ rmSync3(bak, { recursive: true, force: true });
2203
+ } catch (e) {
2204
+ try {
2205
+ renameSync3(bak, target);
2206
+ } catch {}
2207
+ throw e;
2208
+ }
2209
+ } else {
2210
+ renameSync3(staging, target);
2211
+ }
2212
+ } finally {
2213
+ rmSync3(staging, { recursive: true, force: true });
2214
+ }
2215
+ }
2216
+ const rendered = renderContent(src.dir, target, m) ?? planned;
2217
+ const appliedConfig = apply(m.config ?? []);
2218
+ const hash = hashTree(target);
2219
+ writeFileSync5(join10(target, "kit.lock"), JSON.stringify({
2220
+ id: m.id,
2221
+ version: m.version,
2222
+ commit: src.commit,
2223
+ root: kitRootRel,
2224
+ hash,
2225
+ rendered,
2226
+ commands: m.commands ?? [],
2227
+ knowledge: m.knowledge ?? [],
2228
+ dataRoot: m.data_root ?? null,
2229
+ env: m.env ?? null,
2230
+ config: appliedConfig
2231
+ }, null, 1));
2232
+ return { id: m.id, version: m.version, dir: target, root: kitRoot, rendered, hash, changed };
2233
+ });
2138
2234
  }
2139
2235
  function installed() {
2140
2236
  const root = join10(dataDir2(), "kits");
2141
- if (!existsSync8(root))
2237
+ if (!existsSync9(root))
2142
2238
  return [];
2143
2239
  const out = [];
2144
2240
  for (const e of readdirSync3(root, { withFileTypes: true })) {
2145
- if (!e.isDirectory())
2241
+ if (!e.isDirectory() || e.name.startsWith("."))
2146
2242
  continue;
2147
- const versions = readdirSync3(join10(root, e.name)).filter((v) => statSync5(join10(root, e.name, v)).isDirectory()).sort();
2243
+ const versions = versionDirs(join10(root, e.name));
2148
2244
  const version = versions[versions.length - 1];
2149
2245
  if (!version)
2150
2246
  continue;
@@ -2159,10 +2255,10 @@ function installed() {
2159
2255
  }
2160
2256
  function list() {
2161
2257
  const root = join10(dataDir2(), "kits");
2162
- if (!existsSync8(root))
2258
+ if (!existsSync9(root))
2163
2259
  return [];
2164
- return readdirSync3(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => {
2165
- const versions = readdirSync3(join10(root, e.name)).filter((v) => statSync5(join10(root, e.name, v)).isDirectory()).sort();
2260
+ return readdirSync3(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => {
2261
+ const versions = versionDirs(join10(root, e.name));
2166
2262
  const latest = versions[versions.length - 1];
2167
2263
  let tags = [];
2168
2264
  if (latest) {
@@ -2175,11 +2271,11 @@ function list() {
2175
2271
  }
2176
2272
  function readLock(id, version) {
2177
2273
  const idDir = join10(dataDir2(), "kits", id);
2178
- if (!existsSync8(idDir))
2274
+ if (!existsSync9(idDir))
2179
2275
  throw new Error("E_NOT_INSTALLED");
2180
- const v = version || readdirSync3(idDir).sort().pop();
2276
+ const v = version || versionDirs(idDir).pop();
2181
2277
  const lockFile = join10(idDir, v, "kit.lock");
2182
- if (!existsSync8(lockFile))
2278
+ if (!existsSync9(lockFile))
2183
2279
  throw new Error("E_NOT_INSTALLED");
2184
2280
  return { version: v, lock: JSON.parse(readFileSync7(lockFile, "utf8")) };
2185
2281
  }
@@ -2196,7 +2292,7 @@ function verify2(id, version) {
2196
2292
  for (const r of lock.rendered) {
2197
2293
  if (r.type === "dir")
2198
2294
  continue;
2199
- if (!existsSync8(r.path)) {
2295
+ if (!existsSync9(r.path)) {
2200
2296
  drift.push(`missing: ${r.path}`);
2201
2297
  continue;
2202
2298
  }
@@ -2220,19 +2316,19 @@ function verify2(id, version) {
2220
2316
  }
2221
2317
  function remove(id) {
2222
2318
  const idDir = join10(dataDir2(), "kits", id);
2223
- if (!existsSync8(idDir))
2319
+ if (!existsSync9(idDir))
2224
2320
  throw new Error("E_NOT_INSTALLED");
2225
2321
  const removed = [];
2226
2322
  const skipped = [];
2227
2323
  for (const v of readdirSync3(idDir)) {
2228
2324
  const dir = join10(idDir, v);
2229
2325
  const lockFile = join10(dir, "kit.lock");
2230
- if (existsSync8(lockFile)) {
2326
+ if (existsSync9(lockFile)) {
2231
2327
  const lock = JSON.parse(readFileSync7(lockFile, "utf8"));
2232
2328
  for (const r of lock.rendered) {
2233
2329
  if (r.type === "dir")
2234
2330
  continue;
2235
- if (!existsSync8(r.path) && !isSymlink(r.path))
2331
+ if (!existsSync9(r.path) && !isSymlink(r.path))
2236
2332
  continue;
2237
2333
  if (r.type === "file") {
2238
2334
  if (!isSymlink(r.path) && shaFile(r.path) === r.value) {
@@ -2249,7 +2345,7 @@ function remove(id) {
2249
2345
  continue;
2250
2346
  }
2251
2347
  const want = resolve5(dir, r.value);
2252
- if (existsSync8(want) && cur === realpathSync2(want)) {
2348
+ if (existsSync9(want) && cur === realpathSync2(want)) {
2253
2349
  unlinkSync(r.path);
2254
2350
  removed.push(r.path);
2255
2351
  } else
@@ -2264,7 +2360,7 @@ function remove(id) {
2264
2360
  }
2265
2361
 
2266
2362
  // src/default-msg.ts
2267
- import { existsSync as existsSync9, mkdirSync as mkdirSync8, readdirSync as readdirSync4, readFileSync as readFileSync8, renameSync as renameSync3, statSync as statSync6, writeFileSync as writeFileSync6 } from "node:fs";
2363
+ import { existsSync as existsSync10, mkdirSync as mkdirSync8, readdirSync as readdirSync4, readFileSync as readFileSync8, renameSync as renameSync4, statSync as statSync6, writeFileSync as writeFileSync6 } from "node:fs";
2268
2364
  import { homedir as homedir6 } from "node:os";
2269
2365
  import { dirname as dirname7, join as join11, resolve as resolve6 } from "node:path";
2270
2366
  init_paths();
@@ -2290,7 +2386,7 @@ function writeConfig(c) {
2290
2386
  const tmp = `${file}.tmp.${process.pid}`;
2291
2387
  writeFileSync6(tmp, JSON.stringify(next, null, 1) + `
2292
2388
  `, { mode: 384 });
2293
- renameSync3(tmp, file);
2389
+ renameSync4(tmp, file);
2294
2390
  return next;
2295
2391
  }
2296
2392
  function setEnabled(enabled, personaId) {
@@ -2317,7 +2413,7 @@ function isEnabled(personaId) {
2317
2413
  }
2318
2414
  function installedVersion() {
2319
2415
  const dir = join11(diaHome(), "kits", "dia-msg");
2320
- if (!existsSync9(dir))
2416
+ if (!existsSync10(dir))
2321
2417
  return null;
2322
2418
  try {
2323
2419
  const rows = readdirSync4(dir).filter((v) => statSync6(join11(dir, v)).isDirectory()).sort();
@@ -2333,6 +2429,27 @@ function autoInstallAllowed() {
2333
2429
  return false;
2334
2430
  return resolve6(diaHome()) === resolve6(join11(homedir6(), ".dia"));
2335
2431
  }
2432
+ function pkgVersion() {
2433
+ try {
2434
+ return String(JSON.parse(readFileSync8(join11(installDir(), "package.json"), "utf8")).version || "unknown");
2435
+ } catch {
2436
+ return "unknown";
2437
+ }
2438
+ }
2439
+ var stampFile = () => join11(stateDir(), "bootstrap.json");
2440
+ function readStamp() {
2441
+ try {
2442
+ return JSON.parse(readFileSync8(stampFile(), "utf8"));
2443
+ } catch {
2444
+ return null;
2445
+ }
2446
+ }
2447
+ function writeStamp(kitId) {
2448
+ try {
2449
+ mkdirSync8(stateDir(), { recursive: true });
2450
+ writeFileSync6(stampFile(), JSON.stringify({ pkg: pkgVersion(), kit: kitId ?? null, at: new Date().toISOString() }, null, 1));
2451
+ } catch {}
2452
+ }
2336
2453
  function ensure(personaId, opts = {}) {
2337
2454
  const gate = isEnabled(personaId);
2338
2455
  if (!gate.enabled && !opts.force)
@@ -2340,10 +2457,11 @@ function ensure(personaId, opts = {}) {
2340
2457
  if (!opts.force && !autoInstallAllowed())
2341
2458
  return { ok: false, reason: "auto-install-skipped:non-default-root(dia collab enable 可强制安装)" };
2342
2459
  const source = builtinKitDir();
2343
- if (!existsSync9(join11(source, "dia.json")))
2460
+ if (!existsSync10(join11(source, "dia.json")))
2344
2461
  return { ok: false, reason: `missing-kit:${source}` };
2345
2462
  try {
2346
2463
  const r = install(source);
2464
+ writeStamp(r.id);
2347
2465
  return { ok: true, kit: `${r.id}@${r.version}` };
2348
2466
  } catch (e) {
2349
2467
  return { ok: false, reason: `kit-install:${e?.message || String(e)}` };
@@ -2372,7 +2490,7 @@ function ensureForPersona(id, capabilities) {
2372
2490
 
2373
2491
  // src/active.ts
2374
2492
  init_paths();
2375
- import { existsSync as existsSync10, mkdirSync as mkdirSync9, readFileSync as readFileSync9, readdirSync as readdirSync5, statSync as statSync7, appendFileSync as appendFileSync4, writeFileSync as writeFileSync7 } from "node:fs";
2493
+ import { existsSync as existsSync11, mkdirSync as mkdirSync9, readFileSync as readFileSync9, readdirSync as readdirSync5, statSync as statSync7, appendFileSync as appendFileSync4, writeFileSync as writeFileSync7 } from "node:fs";
2376
2494
  import { userInfo } from "node:os";
2377
2495
  import { join as join12 } from "node:path";
2378
2496
  var dataDir3 = () => diaHome();
@@ -2388,10 +2506,10 @@ function readAll() {
2388
2506
  }
2389
2507
  function installedVersions(id) {
2390
2508
  const dir = join12(dataDir3(), "personas", id);
2391
- if (!existsSync10(dir))
2509
+ if (!existsSync11(dir))
2392
2510
  return [];
2393
2511
  const verRoot = join12(dir, "versions");
2394
- if (existsSync10(verRoot))
2512
+ if (existsSync11(verRoot))
2395
2513
  return readdirSync5(verRoot).filter((v) => statSync7(join12(verRoot, v)).isDirectory()).sort();
2396
2514
  const skip = new Set(["current", "latest", "data", "repo", "repo.git", "worktrees", "versions", ".lock"]);
2397
2515
  return readdirSync5(dir).filter((v) => !skip.has(v) && !v.startsWith(".staging-") && statSync7(join12(dir, v)).isDirectory()).sort();
@@ -2439,7 +2557,7 @@ function use(id, version, opts = {}) {
2439
2557
  return { previous, current: entry };
2440
2558
  }
2441
2559
  function history(id, limit = 20) {
2442
- if (!existsSync10(auditFile2()))
2560
+ if (!existsSync11(auditFile2()))
2443
2561
  return [];
2444
2562
  const rows = readFileSync9(auditFile2(), "utf8").split(`
2445
2563
  `).filter(Boolean).map((l) => {
@@ -2736,7 +2854,7 @@ var opencodeConfigDir = () => process.env.DIA_OPENCODE_CONFIG_DIR || join13(home
2736
2854
  var opencodeConfigCandidates = () => process.env.DIA_OPENCODE_CONFIG ? [process.env.DIA_OPENCODE_CONFIG] : OPENCODE_CONFIG_NAMES.map((n) => join13(opencodeConfigDir(), n));
2737
2855
  var opencodeConfig = () => {
2738
2856
  const candidates = opencodeConfigCandidates();
2739
- return candidates.find((p) => existsSync11(p)) ?? candidates[0];
2857
+ return candidates.find((p) => existsSync12(p)) ?? candidates[0];
2740
2858
  };
2741
2859
  function shaFile2(p) {
2742
2860
  return createHash7("sha256").update(readFileSync10(p)).digest("hex");
@@ -2758,7 +2876,7 @@ function walkFiles2(root) {
2758
2876
  }
2759
2877
  function readManifest(dir) {
2760
2878
  const p = join13(dir, "dia.json");
2761
- if (!existsSync11(p))
2879
+ if (!existsSync12(p))
2762
2880
  throw new Error("E_MANIFEST: dia.json not found");
2763
2881
  let m;
2764
2882
  try {
@@ -2782,7 +2900,7 @@ function resolveSource2(from, ref) {
2782
2900
  const key = createHash7("sha1").update(url).digest("hex").slice(0, 12);
2783
2901
  const dir = join13(cacheDir3(), key);
2784
2902
  const git = (args) => execFileSync3("git", ["-C", dir, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
2785
- if (!existsSync11(dir)) {
2903
+ if (!existsSync12(dir)) {
2786
2904
  mkdirSync10(cacheDir3(), { recursive: true });
2787
2905
  try {
2788
2906
  execFileSync3("git", ["clone", "--quiet", url, dir], { stdio: "pipe" });
@@ -2808,7 +2926,7 @@ function resolveSource2(from, ref) {
2808
2926
  return { dir, commit };
2809
2927
  }
2810
2928
  const dir = resolve7(from);
2811
- if (!existsSync11(dir))
2929
+ if (!existsSync12(dir))
2812
2930
  throw new Error("E_SOURCE: path not found");
2813
2931
  let commit = "local";
2814
2932
  try {
@@ -2847,7 +2965,7 @@ function install2(from, opts = {}) {
2847
2965
  if (!entry)
2848
2966
  throw new Error("E_MANIFEST: missing entry.opencode");
2849
2967
  const entryAbs = resolve7(src.dir, entry);
2850
- if (!existsSync11(entryAbs))
2968
+ if (!existsSync12(entryAbs))
2851
2969
  throw new Error("E_MANIFEST: entry.opencode file missing");
2852
2970
  if (lstatSync2(entryAbs).isSymbolicLink())
2853
2971
  throw new Error("E_MANIFEST: entry must not be a symlink");
@@ -2856,7 +2974,7 @@ function install2(from, opts = {}) {
2856
2974
  if (!entryReal.startsWith(srcReal + sep5))
2857
2975
  throw new Error("E_MANIFEST: entry escapes persona dir");
2858
2976
  const dest = join13(opencodeAgents(), `${m.id}.md`);
2859
- if (existsSync11(dest) && !readFileSync10(dest).equals(readFileSync10(entryAbs))) {
2977
+ if (existsSync12(dest) && !readFileSync10(dest).equals(readFileSync10(entryAbs))) {
2860
2978
  if (!opts.force)
2861
2979
  throw new Error("E_CONFLICT: agent file exists and differs; remove it first (或 --force 覆盖,覆盖前会备份)");
2862
2980
  overwrites.push(dest);
@@ -2867,7 +2985,7 @@ function install2(from, opts = {}) {
2867
2985
  if (!dshEntry)
2868
2986
  throw new Error("E_MANIFEST: missing entry.dsh");
2869
2987
  const dshSrc = resolve7(src.dir, dshEntry);
2870
- if (!existsSync11(dshSrc) || !statSync8(dshSrc).isDirectory())
2988
+ if (!existsSync12(dshSrc) || !statSync8(dshSrc).isDirectory())
2871
2989
  throw new Error("E_MANIFEST: entry.dsh dir missing");
2872
2990
  if (!realpathSync3(dshSrc).startsWith(realpathSync3(src.dir) + sep5) && realpathSync3(dshSrc) !== realpathSync3(src.dir))
2873
2991
  throw new Error("E_MANIFEST: entry escapes persona dir");
@@ -2878,12 +2996,12 @@ function install2(from, opts = {}) {
2878
2996
  if (!codexEntry)
2879
2997
  throw new Error("E_MANIFEST: missing entry.codex");
2880
2998
  const abs = resolve7(src.dir, codexEntry);
2881
- if (!existsSync11(abs) || !statSync8(abs).isFile())
2999
+ if (!existsSync12(abs) || !statSync8(abs).isFile())
2882
3000
  throw new Error("E_MANIFEST: entry.codex file missing");
2883
3001
  if (!realpathSync3(abs).startsWith(realpathSync3(src.dir) + sep5))
2884
3002
  throw new Error("E_MANIFEST: entry escapes persona dir");
2885
3003
  const dest = join13(codexHome, ".codex", "AGENTS.md");
2886
- if (existsSync11(dest) && !readFileSync10(dest).equals(readFileSync10(abs))) {
3004
+ if (existsSync12(dest) && !readFileSync10(dest).equals(readFileSync10(abs))) {
2887
3005
  if (!opts.force)
2888
3006
  throw new Error("E_CONFLICT: codex AGENTS.md exists and differs; use --force (备份后再覆盖)");
2889
3007
  overwrites.push(dest);
@@ -2902,12 +3020,12 @@ function install2(from, opts = {}) {
2902
3020
  let lockFd = null;
2903
3021
  try {
2904
3022
  try {
2905
- lockFd = openSync(lockPath, "wx");
3023
+ lockFd = openSync2(lockPath, "wx");
2906
3024
  } catch {
2907
3025
  const st = statSync8(lockPath);
2908
3026
  if (Date.now() - st.mtimeMs > 10 * 60000) {
2909
3027
  rmSync4(lockPath, { force: true });
2910
- lockFd = openSync(lockPath, "wx");
3028
+ lockFd = openSync2(lockPath, "wx");
2911
3029
  } else
2912
3030
  throw new Error("E_LOCKED: 另一个安装正在进行(10 分钟后视为陈旧)");
2913
3031
  }
@@ -2918,7 +3036,7 @@ function install2(from, opts = {}) {
2918
3036
  cpSync2(src.dir, staging, { recursive: true, dereference: true, filter: copyFilter(src.dir) });
2919
3037
  const stagingHash = hashTree2(staging);
2920
3038
  let reuseTarget = false;
2921
- if (existsSync11(target)) {
3039
+ if (existsSync12(target)) {
2922
3040
  const existing = (() => {
2923
3041
  try {
2924
3042
  return JSON.parse(readFileSync10(join13(target, "dia.lock"), "utf8"));
@@ -2937,11 +3055,11 @@ function install2(from, opts = {}) {
2937
3055
  }
2938
3056
  }
2939
3057
  if (!reuseTarget)
2940
- renameSync4(staging, target);
3058
+ renameSync5(staging, target);
2941
3059
  } finally {
2942
3060
  if (lockFd !== null) {
2943
3061
  try {
2944
- closeSync(lockFd);
3062
+ closeSync2(lockFd);
2945
3063
  } catch {}
2946
3064
  }
2947
3065
  try {
@@ -2967,7 +3085,7 @@ function install2(from, opts = {}) {
2967
3085
  const renderedDirs = [];
2968
3086
  if (hosts.includes("dsh")) {
2969
3087
  const dshDest = resolve7(dshProfiles(), m.id);
2970
- if (existsSync11(dshDest) && !existsSync11(join13(dshDest, ".dia-managed"))) {
3088
+ if (existsSync12(dshDest) && !existsSync12(join13(dshDest, ".dia-managed"))) {
2971
3089
  throw new Error("E_CONFLICT: dsh profile exists and is not managed by dia");
2972
3090
  }
2973
3091
  rmSync4(dshDest, { recursive: true, force: true });
@@ -2988,7 +3106,7 @@ function install2(from, opts = {}) {
2988
3106
  const srcSkill = resolve7(target, sk.from);
2989
3107
  if (!srcSkill.startsWith(target + sep5))
2990
3108
  throw new Error("E_MANIFEST: skill escapes persona dir: " + sk.from);
2991
- if (!existsSync11(srcSkill))
3109
+ if (!existsSync12(srcSkill))
2992
3110
  continue;
2993
3111
  const name = sk.name || basename6(srcSkill);
2994
3112
  mkdirSync10(skillRoot, { recursive: true });
@@ -3010,7 +3128,7 @@ function install2(from, opts = {}) {
3010
3128
  const kitDir = resolve7(target, ref);
3011
3129
  if (!kitDir.startsWith(target + sep5))
3012
3130
  throw new Error(`E_MANIFEST: kit escapes persona dir: ${ref}`);
3013
- if (!existsSync11(join13(kitDir, "dia.json")))
3131
+ if (!existsSync12(join13(kitDir, "dia.json")))
3014
3132
  throw new Error(`E_MANIFEST: kit manifest missing: ${ref}`);
3015
3133
  const r = install(kitDir);
3016
3134
  kitRefs.push({ id: r.id, version: r.version });
@@ -3038,13 +3156,13 @@ function install2(from, opts = {}) {
3038
3156
  }
3039
3157
  function list2() {
3040
3158
  const root = join13(dataDir4(), "personas");
3041
- if (!existsSync11(root))
3159
+ if (!existsSync12(root))
3042
3160
  return [];
3043
- return readdirSync6(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => ({ id: e.name, versions: versionDirs(join13(root, e.name)) }));
3161
+ return readdirSync6(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => ({ id: e.name, versions: versionDirs2(join13(root, e.name)) }));
3044
3162
  }
3045
- function versionDirs(idDir) {
3163
+ function versionDirs2(idDir) {
3046
3164
  const verRoot = join13(idDir, "versions");
3047
- const scan = (root, keep) => existsSync11(root) ? readdirSync6(root).filter((n) => {
3165
+ const scan = (root, keep) => existsSync12(root) ? readdirSync6(root).filter((n) => {
3048
3166
  if (!keep(n))
3049
3167
  return false;
3050
3168
  try {
@@ -3053,14 +3171,14 @@ function versionDirs(idDir) {
3053
3171
  return false;
3054
3172
  }
3055
3173
  }).sort() : [];
3056
- if (existsSync11(verRoot))
3174
+ if (existsSync12(verRoot))
3057
3175
  return scan(verRoot, () => true);
3058
3176
  const keep = (n) => !["current", "latest", "data", "repo", "repo.git", "worktrees", "versions"].includes(n) && !n.startsWith(".staging-") && n !== ".lock";
3059
3177
  return scan(idDir, keep);
3060
3178
  }
3061
3179
  function resolveVersion(id, sel) {
3062
3180
  const dir = join13(dataDir4(), "personas", id);
3063
- const all = versionDirs(dir);
3181
+ const all = versionDirs2(dir);
3064
3182
  if (all.includes(sel))
3065
3183
  return sel;
3066
3184
  const hits = all.filter((v) => v === sel || v.startsWith(sel + "+") || v.startsWith(sel + "-"));
@@ -3076,12 +3194,12 @@ function dirOf(id, version) {
3076
3194
  return null;
3077
3195
  const flat = join13(dataDir4(), "personas", id, v);
3078
3196
  const nested = join13(dataDir4(), "personas", id, "versions", v);
3079
- const dir = existsSync11(nested) ? nested : flat;
3080
- return existsSync11(dir) ? { dir, version: v } : null;
3197
+ const dir = existsSync12(nested) ? nested : flat;
3198
+ return existsSync12(dir) ? { dir, version: v } : null;
3081
3199
  }
3082
3200
  function readMarker(dir) {
3083
3201
  const p = join13(dir, ".dia-managed");
3084
- if (!existsSync11(p))
3202
+ if (!existsSync12(p))
3085
3203
  return null;
3086
3204
  try {
3087
3205
  return JSON.parse(readFileSync10(p, "utf8"));
@@ -3110,9 +3228,9 @@ function cmpSemver(a, b) {
3110
3228
  }
3111
3229
  function gc(id, opts = {}) {
3112
3230
  const idDir = join13(dataDir4(), "personas", id);
3113
- if (!existsSync11(idDir))
3231
+ if (!existsSync12(idDir))
3114
3232
  throw new Error("E_NOT_INSTALLED");
3115
- const all = versionDirs(idDir);
3233
+ const all = versionDirs2(idDir);
3116
3234
  const activeVer = effective(id)?.version;
3117
3235
  const keep = Math.max(1, opts.keep ?? 3);
3118
3236
  const sorted = [...all].sort((a, b) => cmpSemver(b, a));
@@ -3136,12 +3254,12 @@ function gc(id, opts = {}) {
3136
3254
  }
3137
3255
  function verify3(id, version) {
3138
3256
  const idDir = join13(dataDir4(), "personas", id);
3139
- if (!existsSync11(idDir))
3257
+ if (!existsSync12(idDir))
3140
3258
  throw new Error("E_NOT_INSTALLED");
3141
- const v = version || effective(id)?.version || versionDirs(idDir).sort((a, b) => cmpSemver(b, a))[0];
3259
+ const v = version || effective(id)?.version || versionDirs2(idDir).sort((a, b) => cmpSemver(b, a))[0];
3142
3260
  if (!v)
3143
3261
  throw new Error("E_NOT_INSTALLED");
3144
- const dir = existsSync11(join13(idDir, "versions", v)) ? join13(idDir, "versions", v) : join13(idDir, v);
3262
+ const dir = existsSync12(join13(idDir, "versions", v)) ? join13(idDir, "versions", v) : join13(idDir, v);
3145
3263
  const lock = JSON.parse(readFileSync10(join13(dir, "dia.lock"), "utf8"));
3146
3264
  const files = walkFiles2(dir).filter((f) => basename6(f) !== "dia.lock");
3147
3265
  const h = createHash7("sha256");
@@ -3153,13 +3271,13 @@ function verify3(id, version) {
3153
3271
  if (real !== lock.hash)
3154
3272
  issues.push(`内容哈希不一致(期望 ${lock.hash.slice(0, 8)} 实得 ${real.slice(0, 8)})`);
3155
3273
  for (const [f, expectedHash] of Object.entries(lock.renderedHashes || {})) {
3156
- if (!existsSync11(f))
3274
+ if (!existsSync12(f))
3157
3275
  issues.push(`产物缺失:${f}`);
3158
3276
  else if (shaFile2(f) !== expectedHash)
3159
3277
  issues.push(`产物被改动:${f}`);
3160
3278
  }
3161
3279
  for (const d of lock.renderedDirs || []) {
3162
- if (!existsSync11(d.path)) {
3280
+ if (!existsSync12(d.path)) {
3163
3281
  issues.push(`宿主 profile 缺失:${d.path}`);
3164
3282
  continue;
3165
3283
  }
@@ -3172,7 +3290,7 @@ function verify3(id, version) {
3172
3290
  for (const r of lock.content?.rendered ?? []) {
3173
3291
  if (r.type === "dir")
3174
3292
  continue;
3175
- if (!existsSync11(r.path)) {
3293
+ if (!existsSync12(r.path)) {
3176
3294
  issues.push(`内容产物缺失:${r.path}`);
3177
3295
  continue;
3178
3296
  }
@@ -3188,7 +3306,7 @@ function verify3(id, version) {
3188
3306
  continue;
3189
3307
  }
3190
3308
  const want = resolve7(dir, r.value);
3191
- if (!existsSync11(want) || cur !== realpathSync3(want))
3309
+ if (!existsSync12(want) || cur !== realpathSync3(want))
3192
3310
  issues.push(`内容产物指向不符:${r.path}`);
3193
3311
  }
3194
3312
  }
@@ -3305,7 +3423,7 @@ function create(id, opts = {}) {
3305
3423
  const hosts = opts.hosts?.length ? opts.hosts : ["opencode", "dsh"];
3306
3424
  for (const h of hosts)
3307
3425
  assertHost(h);
3308
- if (existsSync11(dir) && readdirSync6(dir).length)
3426
+ if (existsSync12(dir) && readdirSync6(dir).length)
3309
3427
  throw new Error(`E_CONFLICT: ${dir} 非空`);
3310
3428
  const files = skeleton(id, hosts, opts.msg !== false);
3311
3429
  if (!opts.dryRun) {
@@ -3333,7 +3451,7 @@ function compareDir(expected, actual) {
3333
3451
  if (HOST_OWNED_FILES.has(rel))
3334
3452
  continue;
3335
3453
  const dest = join13(actual, rel);
3336
- if (!existsSync11(dest))
3454
+ if (!existsSync12(dest))
3337
3455
  out.push({ path: dest, action: "missing" });
3338
3456
  else if (shaFile2(dest) !== shaFile2(f))
3339
3457
  out.push({ path: dest, action: "changed" });
@@ -3342,7 +3460,7 @@ function compareDir(expected, actual) {
3342
3460
  }
3343
3461
  function render(id, opts = {}) {
3344
3462
  const idDir = join13(dataDir4(), "personas", id);
3345
- if (!existsSync11(idDir))
3463
+ if (!existsSync12(idDir))
3346
3464
  throw new Error(`E_NOT_INSTALLED: persona ${id}`);
3347
3465
  const version = effective(id)?.version ?? readdirSync6(idDir).filter((v) => statSync8(join13(idDir, v)).isDirectory()).sort().pop();
3348
3466
  const dir = join13(idDir, version);
@@ -3361,10 +3479,10 @@ function render(id, opts = {}) {
3361
3479
  agentSrc = resolve7(dir, entry);
3362
3480
  if (!agentSrc.startsWith(dir + sep5))
3363
3481
  throw new Error("E_MANIFEST: entry escapes persona dir");
3364
- if (!existsSync11(agentSrc))
3482
+ if (!existsSync12(agentSrc))
3365
3483
  throw new Error("E_MANIFEST: entry.opencode file missing");
3366
3484
  agentDest = join13(opencodeAgents(), `${id}.md`);
3367
- if (!existsSync11(agentDest))
3485
+ if (!existsSync12(agentDest))
3368
3486
  drift.push({ path: agentDest, action: "missing" });
3369
3487
  else if (shaFile2(agentDest) !== shaFile2(agentSrc))
3370
3488
  drift.push({ path: agentDest, action: "changed" });
@@ -3376,10 +3494,10 @@ function render(id, opts = {}) {
3376
3494
  codexSrc = resolve7(dir, entry);
3377
3495
  if (!codexSrc.startsWith(dir + sep5))
3378
3496
  throw new Error("E_MANIFEST: entry escapes persona dir");
3379
- if (!existsSync11(codexSrc))
3497
+ if (!existsSync12(codexSrc))
3380
3498
  throw new Error("E_MANIFEST: entry.codex file missing");
3381
3499
  codexDest = join13(codexHomeFor(opts, m), ".codex", "AGENTS.md");
3382
- if (!existsSync11(codexDest))
3500
+ if (!existsSync12(codexDest))
3383
3501
  drift.push({ path: codexDest, action: "missing" });
3384
3502
  else if (shaFile2(codexDest) !== shaFile2(codexSrc))
3385
3503
  drift.push({ path: codexDest, action: "changed" });
@@ -3391,15 +3509,15 @@ function render(id, opts = {}) {
3391
3509
  dshSrc = resolve7(dir, entry);
3392
3510
  if (!dshSrc.startsWith(dir + sep5))
3393
3511
  throw new Error("E_MANIFEST: entry escapes persona dir");
3394
- if (!existsSync11(dshSrc))
3512
+ if (!existsSync12(dshSrc))
3395
3513
  throw new Error("E_MANIFEST: entry.dsh dir missing");
3396
3514
  dshDest = resolve7(dshProfiles(), id);
3397
- if (!existsSync11(dshDest))
3515
+ if (!existsSync12(dshDest))
3398
3516
  drift.push({ path: dshDest, action: "missing" });
3399
3517
  else {
3400
3518
  drift.push(...compareDir(dshSrc, dshDest));
3401
3519
  const marker = join13(dshDest, ".dia-managed");
3402
- if (!existsSync11(marker))
3520
+ if (!existsSync12(marker))
3403
3521
  drift.push({ path: marker, action: "missing" });
3404
3522
  else {
3405
3523
  try {
@@ -3419,7 +3537,7 @@ function render(id, opts = {}) {
3419
3537
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
3420
3538
  const bdir = join13(dataDir4(), "backups", `render-${stamp}`);
3421
3539
  for (const d of drift) {
3422
- if (!existsSync11(d.path))
3540
+ if (!existsSync12(d.path))
3423
3541
  continue;
3424
3542
  mkdirSync10(bdir, { recursive: true });
3425
3543
  const dest = join13(bdir, basename6(d.path));
@@ -3470,14 +3588,14 @@ function render(id, opts = {}) {
3470
3588
  }
3471
3589
  function renderDrift(id, opts = {}) {
3472
3590
  const idDir = join13(dataDir4(), "personas", id);
3473
- if (!existsSync11(idDir))
3591
+ if (!existsSync12(idDir))
3474
3592
  throw new Error(`E_NOT_INSTALLED: persona ${id}`);
3475
3593
  const version = effective(id)?.version ?? readdirSync6(idDir).filter((v) => statSync8(join13(idDir, v)).isDirectory()).sort().pop();
3476
3594
  if (!version)
3477
3595
  return { id, version: "", drift: [], skipped: `无已安装版本:${idDir}` };
3478
3596
  const dir = join13(idDir, version);
3479
3597
  const lockPath = join13(dir, "dia.lock");
3480
- if (!existsSync11(lockPath))
3598
+ if (!existsSync12(lockPath))
3481
3599
  return { id, version, drift: [], skipped: `无 dia.lock(安装未完成):${dir}` };
3482
3600
  let lock;
3483
3601
  try {
@@ -3495,18 +3613,18 @@ function renderDrift(id, opts = {}) {
3495
3613
  }
3496
3614
  };
3497
3615
  for (const [f, expected] of Object.entries(lock.renderedHashes ?? {})) {
3498
- if (!existsSync11(f))
3616
+ if (!existsSync12(f))
3499
3617
  push({ path: f, action: "missing" });
3500
3618
  else if (shaFile2(f) !== expected)
3501
3619
  push({ path: f, action: "changed" });
3502
3620
  }
3503
3621
  for (const d of lock.renderedDirs ?? []) {
3504
- if (!existsSync11(d.path)) {
3622
+ if (!existsSync12(d.path)) {
3505
3623
  push({ path: d.path, action: "missing" });
3506
3624
  continue;
3507
3625
  }
3508
3626
  const marker = join13(d.path, ".dia-managed");
3509
- if (!existsSync11(marker)) {
3627
+ if (!existsSync12(marker)) {
3510
3628
  push({ path: marker, action: "missing" });
3511
3629
  continue;
3512
3630
  }
@@ -3520,7 +3638,7 @@ function renderDrift(id, opts = {}) {
3520
3638
  for (const c of lock.content?.rendered ?? []) {
3521
3639
  if (c.type === "dir")
3522
3640
  continue;
3523
- if (!existsSync11(c.path)) {
3641
+ if (!existsSync12(c.path)) {
3524
3642
  push({ path: c.path, action: "missing" });
3525
3643
  continue;
3526
3644
  }
@@ -3537,22 +3655,22 @@ function renderDrift(id, opts = {}) {
3537
3655
  continue;
3538
3656
  }
3539
3657
  const want = resolve7(dir, c.value);
3540
- if (!existsSync11(want) || cur !== realpathSync3(want))
3658
+ if (!existsSync12(want) || cur !== realpathSync3(want))
3541
3659
  push({ path: c.path, action: "changed" });
3542
3660
  }
3543
3661
  return { id, version: r.version, drift };
3544
3662
  }
3545
3663
  function remove2(id) {
3546
3664
  const idDir = join13(dataDir4(), "personas", id);
3547
- if (!existsSync11(idDir))
3665
+ if (!existsSync12(idDir))
3548
3666
  throw new Error("E_NOT_INSTALLED");
3549
3667
  const removed = [];
3550
3668
  const skipped = [];
3551
3669
  const allowed = resolve7(opencodeAgents(), `${id}.md`);
3552
- for (const v of versionDirs(idDir)) {
3553
- const dir = existsSync11(join13(idDir, "versions", v)) ? join13(idDir, "versions", v) : join13(idDir, v);
3670
+ for (const v of versionDirs2(idDir)) {
3671
+ const dir = existsSync12(join13(idDir, "versions", v)) ? join13(idDir, "versions", v) : join13(idDir, v);
3554
3672
  const lockFile = join13(dir, "dia.lock");
3555
- if (existsSync11(lockFile)) {
3673
+ if (existsSync12(lockFile)) {
3556
3674
  const lock = JSON.parse(readFileSync10(lockFile, "utf8"));
3557
3675
  for (const d of lock.renderedDirs || []) {
3558
3676
  const abs = resolve7(d.path);
@@ -3560,7 +3678,7 @@ function remove2(id) {
3560
3678
  skipped.push(abs);
3561
3679
  continue;
3562
3680
  }
3563
- if (!existsSync11(abs))
3681
+ if (!existsSync12(abs))
3564
3682
  continue;
3565
3683
  const m = readMarker(abs);
3566
3684
  if (!m || m.id !== id) {
@@ -3573,10 +3691,10 @@ function remove2(id) {
3573
3691
  for (const r of lock.content?.rendered ?? []) {
3574
3692
  if (r.type === "dir")
3575
3693
  continue;
3576
- if (!existsSync11(r.path))
3694
+ if (!existsSync12(r.path))
3577
3695
  continue;
3578
3696
  if (r.type === "file") {
3579
- if (!existsSync11(r.path) || shaFile2(r.path) !== r.value) {
3697
+ if (!existsSync12(r.path) || shaFile2(r.path) !== r.value) {
3580
3698
  skipped.push(r.path);
3581
3699
  continue;
3582
3700
  }
@@ -3591,7 +3709,7 @@ function remove2(id) {
3591
3709
  continue;
3592
3710
  }
3593
3711
  const want = resolve7(dir, r.value);
3594
- if (existsSync11(want) && cur === realpathSync3(want)) {
3712
+ if (existsSync12(want) && cur === realpathSync3(want)) {
3595
3713
  unlinkSync2(r.path);
3596
3714
  removed.push(r.path);
3597
3715
  } else
@@ -3606,7 +3724,7 @@ function remove2(id) {
3606
3724
  continue;
3607
3725
  }
3608
3726
  const expectedHash = lock.renderedHashes?.[f];
3609
- if (!expectedHash || !existsSync11(abs) || shaFile2(abs) !== expectedHash) {
3727
+ if (!expectedHash || !existsSync12(abs) || shaFile2(abs) !== expectedHash) {
3610
3728
  skipped.push(abs);
3611
3729
  continue;
3612
3730
  }
@@ -3637,7 +3755,7 @@ function showDefaultAgent(opts = {}) {
3637
3755
  if (host !== "opencode")
3638
3756
  throw new Error("E_HOST: only opencode has default_agent");
3639
3757
  const file = opencodeConfig();
3640
- if (!existsSync11(file))
3758
+ if (!existsSync12(file))
3641
3759
  return { file, current: null };
3642
3760
  const cfg = readOpencodeConfig(file);
3643
3761
  return { file, current: typeof cfg.default_agent === "string" ? cfg.default_agent : null };
@@ -3655,13 +3773,13 @@ function setDefaultAgent(id, opts = {}) {
3655
3773
  if (host !== "opencode")
3656
3774
  throw new Error("E_HOST: only opencode has default_agent");
3657
3775
  const file = opencodeConfig();
3658
- if (!existsSync11(file))
3776
+ if (!existsSync12(file))
3659
3777
  throw new Error(`E_CONFIG: ${file} 不存在(先装宿主,或设 DIA_OPENCODE_CONFIG)`);
3660
3778
  const raw = readFileSync10(file, "utf8");
3661
3779
  const cfg = readOpencodeConfig(file);
3662
3780
  const stateFile = join13(dataDir4(), "state", "default-agent.json");
3663
3781
  let state = { file, previous: null, set_at: null };
3664
- if (existsSync11(stateFile)) {
3782
+ if (existsSync12(stateFile)) {
3665
3783
  try {
3666
3784
  state = JSON.parse(readFileSync10(stateFile, "utf8"));
3667
3785
  } catch {}
@@ -3684,7 +3802,7 @@ function setDefaultAgent(id, opts = {}) {
3684
3802
  }
3685
3803
  function checkUpstream(id, version) {
3686
3804
  const idDir = join13(dataDir4(), "personas", id);
3687
- if (!existsSync11(idDir))
3805
+ if (!existsSync12(idDir))
3688
3806
  throw new Error("E_NOT_INSTALLED");
3689
3807
  const v = version || (effective(id)?.version ?? readdirSync6(idDir).sort().pop());
3690
3808
  const lock = JSON.parse(readFileSync10(join13(idDir, v, "dia.lock"), "utf8"));
@@ -3718,7 +3836,7 @@ function checkUpstream(id, version) {
3718
3836
  }
3719
3837
  function update(id, opts = {}) {
3720
3838
  const idDir = join13(dataDir4(), "personas", id);
3721
- if (!existsSync11(idDir))
3839
+ if (!existsSync12(idDir))
3722
3840
  throw new Error("E_NOT_INSTALLED");
3723
3841
  const cur = effective(id)?.version ?? readdirSync6(idDir).sort().pop();
3724
3842
  const lock = JSON.parse(readFileSync10(join13(idDir, cur, "dia.lock"), "utf8"));
@@ -3732,7 +3850,7 @@ function update(id, opts = {}) {
3732
3850
 
3733
3851
  // src/msg.ts
3734
3852
  init_paths();
3735
- import { existsSync as existsSync12, mkdirSync as mkdirSync11, readdirSync as readdirSync7, readFileSync as readFileSync11, renameSync as renameSync5, statSync as statSync9, writeFileSync as writeFileSync9 } from "node:fs";
3853
+ import { existsSync as existsSync13, mkdirSync as mkdirSync11, readdirSync as readdirSync7, readFileSync as readFileSync11, renameSync as renameSync6, statSync as statSync9, writeFileSync as writeFileSync9 } from "node:fs";
3736
3854
  import { join as join14 } from "node:path";
3737
3855
  import { randomBytes } from "node:crypto";
3738
3856
  var msgRoot2 = () => msgRoot();
@@ -3744,11 +3862,11 @@ function atomicWrite(path, data) {
3744
3862
  mkdirSync11(join14(path, ".."), { recursive: true });
3745
3863
  const tmp = `${path}.tmp.${process.pid}.${randomBytes(2).toString("hex")}`;
3746
3864
  writeFileSync9(tmp, data);
3747
- renameSync5(tmp, path);
3865
+ renameSync6(tmp, path);
3748
3866
  }
3749
3867
  function readAll2(agent) {
3750
3868
  const dir = dirOf2(agent);
3751
- if (!existsSync12(dir))
3869
+ if (!existsSync13(dir))
3752
3870
  return [];
3753
3871
  return readdirSync7(dir).filter((f) => f.endsWith(".json")).map((f) => {
3754
3872
  try {
@@ -3767,7 +3885,7 @@ function newId(prefix) {
3767
3885
  }
3768
3886
  function allInboxes() {
3769
3887
  const root = msgRoot2();
3770
- if (!existsSync12(root))
3888
+ if (!existsSync13(root))
3771
3889
  return [];
3772
3890
  return readdirSync7(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => ({ agent: e.name, messages: readAll2(e.name) }));
3773
3891
  }
@@ -3780,7 +3898,7 @@ function send(opts) {
3780
3898
  throw new Error("E_USAGE: --subject 必填");
3781
3899
  if (opts.body && opts.bodyFile)
3782
3900
  throw new Error("E_USAGE: --body 与 --body-file 只能给一个");
3783
- if (opts.bodyFile && !existsSync12(opts.bodyFile))
3901
+ if (opts.bodyFile && !existsSync13(opts.bodyFile))
3784
3902
  throw new Error(`E_USAGE: body file 不存在: ${opts.bodyFile}`);
3785
3903
  const threadId = opts.threadId || newId("th");
3786
3904
  const existing = [...readAll2(opts.to), ...readAll2(opts.from)].filter((m) => m.thread_id === threadId);
@@ -3823,7 +3941,7 @@ function inbox(agent, opts = {}) {
3823
3941
  }
3824
3942
  function findInbox(agent, id) {
3825
3943
  const dir = dirOf2(agent);
3826
- if (!existsSync12(dir))
3944
+ if (!existsSync13(dir))
3827
3945
  return null;
3828
3946
  for (const f of readdirSync7(dir)) {
3829
3947
  if (!f.endsWith(".json"))
@@ -3932,7 +4050,7 @@ function stuck(minutes = 30, now = new Date) {
3932
4050
  }
3933
4051
  function agents() {
3934
4052
  const root = msgRoot2();
3935
- if (!existsSync12(root))
4053
+ if (!existsSync13(root))
3936
4054
  return [];
3937
4055
  return readdirSync7(root, { withFileTypes: true }).filter((e) => e.isDirectory() && statSync9(join14(root, e.name)).isDirectory()).map((e) => e.name);
3938
4056
  }
@@ -3940,13 +4058,13 @@ function agents() {
3940
4058
  // src/collab.ts
3941
4059
  init_paths();
3942
4060
  import {
3943
- closeSync as closeSync2,
3944
- existsSync as existsSync13,
4061
+ closeSync as closeSync3,
4062
+ existsSync as existsSync14,
3945
4063
  mkdirSync as mkdirSync12,
3946
- openSync as openSync2,
4064
+ openSync as openSync3,
3947
4065
  readdirSync as readdirSync8,
3948
4066
  readFileSync as readFileSync12,
3949
- renameSync as renameSync6,
4067
+ renameSync as renameSync7,
3950
4068
  rmSync as rmSync5,
3951
4069
  statSync as statSync10,
3952
4070
  writeFileSync as writeFileSync10
@@ -3985,7 +4103,7 @@ function writeAtomic(path, data) {
3985
4103
  ensureDir(dirname9(path));
3986
4104
  const tmp = `${path}.tmp.${process.pid}.${randomBytes2(2).toString("hex")}`;
3987
4105
  writeFileSync10(tmp, data, { mode: 384 });
3988
- renameSync6(tmp, path);
4106
+ renameSync7(tmp, path);
3989
4107
  }
3990
4108
  function sleep(ms) {
3991
4109
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
@@ -3998,7 +4116,7 @@ function withLock(name, fn) {
3998
4116
  let fd;
3999
4117
  for (let i = 0;i < 150; i++) {
4000
4118
  try {
4001
- fd = openSync2(lock, "wx", 384);
4119
+ fd = openSync3(lock, "wx", 384);
4002
4120
  break;
4003
4121
  } catch (e) {
4004
4122
  if (e?.code !== "EEXIST")
@@ -4016,7 +4134,7 @@ function withLock(name, fn) {
4016
4134
  return fn();
4017
4135
  } finally {
4018
4136
  try {
4019
- closeSync2(fd);
4137
+ closeSync3(fd);
4020
4138
  } catch {}
4021
4139
  try {
4022
4140
  rmSync5(lock, { force: true });
@@ -4084,7 +4202,7 @@ function messageFile(sessionId, id) {
4084
4202
  }
4085
4203
  function readAll3(sessionId) {
4086
4204
  const dir = join15(inboxRoot(), normalizeSessionId(sessionId));
4087
- if (!existsSync13(dir))
4205
+ if (!existsSync14(dir))
4088
4206
  return [];
4089
4207
  const out = [];
4090
4208
  for (const f of readdirSync8(dir)) {
@@ -4098,7 +4216,7 @@ function readAll3(sessionId) {
4098
4216
  return out.sort((a, b) => a.msg.created_at.localeCompare(b.msg.created_at) || a.msg.seq - b.msg.seq);
4099
4217
  }
4100
4218
  function allSessionsWithInbox() {
4101
- if (!existsSync13(inboxRoot()))
4219
+ if (!existsSync14(inboxRoot()))
4102
4220
  return [];
4103
4221
  return readdirSync8(inboxRoot(), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
4104
4222
  }
@@ -4121,7 +4239,7 @@ function legacySlug(agent) {
4121
4239
  return `${base}-${createHash8("sha1").update(agent).digest("hex").slice(0, 6)}`;
4122
4240
  }
4123
4241
  function legacyAll() {
4124
- if (!existsSync13(legacyRoot()))
4242
+ if (!existsSync14(legacyRoot()))
4125
4243
  return [];
4126
4244
  const out = [];
4127
4245
  for (const slug of readdirSync8(legacyRoot(), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name)) {
@@ -4163,7 +4281,7 @@ function readBody(opts) {
4163
4281
  throw new Error(`E_USAGE: body 超过 ${MAX_BODY} 字节,请拆分或引用文件`);
4164
4282
  return { body: opts.body, body_bytes: bytes };
4165
4283
  }
4166
- if (!existsSync13(opts.bodyFile))
4284
+ if (!existsSync14(opts.bodyFile))
4167
4285
  throw new Error(`E_USAGE: body file 不存在: ${opts.bodyFile}`);
4168
4286
  const buf = readFileSync12(opts.bodyFile);
4169
4287
  if (buf.byteLength > MAX_BODY)
@@ -4343,13 +4461,13 @@ function close(sessionId, id, reason) {
4343
4461
  }
4344
4462
  function migrateLegacy(opts = {}) {
4345
4463
  const oldRoot = join15(diaHome(), "msg");
4346
- if (!existsSync13(oldRoot))
4464
+ if (!existsSync14(oldRoot))
4347
4465
  return { total: 0, migrated: 0, skipped: 0, messages: [] };
4348
4466
  const rows = [];
4349
4467
  let migrated = 0, skipped = 0, total = 0;
4350
4468
  for (const agent of readdirSync8(oldRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name)) {
4351
4469
  const dir = join15(oldRoot, agent, "inbox");
4352
- if (!existsSync13(dir))
4470
+ if (!existsSync14(dir))
4353
4471
  continue;
4354
4472
  const slug = legacySlug(agent);
4355
4473
  for (const f of readdirSync8(dir)) {
@@ -4367,7 +4485,7 @@ function migrateLegacy(opts = {}) {
4367
4485
  continue;
4368
4486
  }
4369
4487
  const target = join15(legacyRoot(), slug, `${legacyId}.json`);
4370
- if (existsSync13(target)) {
4488
+ if (existsSync14(target)) {
4371
4489
  skipped++;
4372
4490
  continue;
4373
4491
  }
@@ -4379,7 +4497,7 @@ function migrateLegacy(opts = {}) {
4379
4497
  const allowed = [resolve8(oldRoot), resolve8(tmpdir())].some((base) => abs === base || abs.startsWith(base + sep6));
4380
4498
  if (!allowed) {
4381
4499
  bodyMissing = true;
4382
- } else if (existsSync13(abs)) {
4500
+ } else if (existsSync14(abs)) {
4383
4501
  const buf = readFileSync12(abs);
4384
4502
  bodyBytes = buf.byteLength;
4385
4503
  if (bodyBytes > MAX_BODY) {
@@ -4427,7 +4545,7 @@ function migrateLegacy(opts = {}) {
4427
4545
 
4428
4546
  // src/claims.ts
4429
4547
  init_paths();
4430
- import { appendFileSync as appendFileSync5, existsSync as existsSync14, mkdirSync as mkdirSync13, readFileSync as readFileSync13, renameSync as renameSync7, writeFileSync as writeFileSync11 } from "node:fs";
4548
+ import { appendFileSync as appendFileSync5, existsSync as existsSync15, mkdirSync as mkdirSync13, readFileSync as readFileSync13, renameSync as renameSync8, writeFileSync as writeFileSync11 } from "node:fs";
4431
4549
  import { execFileSync as execFileSync4 } from "node:child_process";
4432
4550
  import { randomBytes as randomBytes3 } from "node:crypto";
4433
4551
  import { basename as basename7, join as join16, relative as relative5, resolve as resolve9, sep as sep7 } from "node:path";
@@ -4439,7 +4557,7 @@ function append2(e) {
4439
4557
  `, { mode: 384 });
4440
4558
  }
4441
4559
  function fold() {
4442
- if (!existsSync14(file()))
4560
+ if (!existsSync15(file()))
4443
4561
  return [];
4444
4562
  const map = new Map;
4445
4563
  for (const line of readFileSync13(file(), "utf8").split(`
@@ -4551,7 +4669,7 @@ function compact(opts = {}) {
4551
4669
  const cutoff = now.getTime() - days * 86400000;
4552
4670
  return withLock("claims", () => {
4553
4671
  const f = file();
4554
- if (!existsSync14(f))
4672
+ if (!existsSync15(f))
4555
4673
  return { before: 0, after: 0, dropped: 0 };
4556
4674
  const raw = readFileSync13(f, "utf8");
4557
4675
  const lines = raw.split(`
@@ -4591,16 +4709,16 @@ function compact(opts = {}) {
4591
4709
  writeFileSync11(tmp, kept.join(`
4592
4710
  `) + (kept.length ? `
4593
4711
  ` : ""), { mode: 384 });
4594
- renameSync7(tmp, f);
4712
+ renameSync8(tmp, f);
4595
4713
  }
4596
- const after = existsSync14(f) ? readFileSync13(f, "utf8").length : 0;
4714
+ const after = existsSync15(f) ? readFileSync13(f, "utf8").length : 0;
4597
4715
  return { before: raw.length, after, dropped };
4598
4716
  });
4599
4717
  }
4600
4718
 
4601
4719
  // src/task.ts
4602
4720
  init_paths();
4603
- import { appendFileSync as appendFileSync6, existsSync as existsSync15, mkdirSync as mkdirSync14, readFileSync as readFileSync14 } from "node:fs";
4721
+ import { appendFileSync as appendFileSync6, existsSync as existsSync16, mkdirSync as mkdirSync14, readFileSync as readFileSync14 } from "node:fs";
4604
4722
  import { join as join17 } from "node:path";
4605
4723
  import { createHash as createHash9 } from "node:crypto";
4606
4724
  var DATA5 = () => diaHome();
@@ -4634,7 +4752,7 @@ function file2() {
4634
4752
  var uniq = (xs) => [...new Set(xs.filter(Boolean))];
4635
4753
  function fold2() {
4636
4754
  const map = new Map;
4637
- if (!existsSync15(file2()))
4755
+ if (!existsSync16(file2()))
4638
4756
  return map;
4639
4757
  for (const line of readFileSync14(file2(), "utf8").split(`
4640
4758
  `)) {
@@ -6150,7 +6268,7 @@ init_paths();
6150
6268
 
6151
6269
  // src/agents.ts
6152
6270
  init_paths();
6153
- import { existsSync as existsSync16, mkdirSync as mkdirSync15, readdirSync as readdirSync9, readFileSync as readFileSync15, renameSync as renameSync8, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "node:fs";
6271
+ import { existsSync as existsSync17, mkdirSync as mkdirSync15, readdirSync as readdirSync9, readFileSync as readFileSync15, renameSync as renameSync9, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "node:fs";
6154
6272
  import { basename as basename8, join as join18, resolve as resolve10 } from "node:path";
6155
6273
  import { execFileSync as execFileSync5 } from "node:child_process";
6156
6274
  var agentsRoot2 = () => agentsRoot();
@@ -6159,7 +6277,7 @@ function atomicWrite2(path, data) {
6159
6277
  mkdirSync15(join18(path, ".."), { recursive: true });
6160
6278
  const tmp = `${path}.tmp.${process.pid}`;
6161
6279
  writeFileSync12(tmp, data);
6162
- renameSync8(tmp, path);
6280
+ renameSync9(tmp, path);
6163
6281
  }
6164
6282
  function sh(cmd, args) {
6165
6283
  try {
@@ -6180,14 +6298,14 @@ function register(rec) {
6180
6298
  }
6181
6299
  function unregister(agent) {
6182
6300
  const p = fileOf(agent);
6183
- if (!existsSync16(p))
6301
+ if (!existsSync17(p))
6184
6302
  return false;
6185
6303
  rmSync6(p, { force: true });
6186
6304
  return true;
6187
6305
  }
6188
6306
  function read2(agent) {
6189
6307
  const p = fileOf(agent);
6190
- if (!existsSync16(p))
6308
+ if (!existsSync17(p))
6191
6309
  return null;
6192
6310
  try {
6193
6311
  return JSON.parse(readFileSync15(p, "utf8"));
@@ -6197,7 +6315,7 @@ function read2(agent) {
6197
6315
  }
6198
6316
  function all() {
6199
6317
  const root = agentsRoot2();
6200
- if (!existsSync16(root))
6318
+ if (!existsSync17(root))
6201
6319
  return [];
6202
6320
  return readdirSync9(root).filter((f) => f.endsWith(".json")).map((f) => {
6203
6321
  try {
@@ -6463,7 +6581,7 @@ async function deliverAcp(agent, id, opts = {}) {
6463
6581
  }
6464
6582
 
6465
6583
  // src/scope.ts
6466
- import { existsSync as existsSync17, readFileSync as readFileSync16, readdirSync as readdirSync10, statSync as statSync11 } from "node:fs";
6584
+ import { existsSync as existsSync18, readFileSync as readFileSync16, readdirSync as readdirSync10, statSync as statSync11 } from "node:fs";
6467
6585
  init_paths();
6468
6586
  import { homedir as homedir9 } from "node:os";
6469
6587
  import { join as join20, resolve as resolve11 } from "node:path";
@@ -6503,7 +6621,7 @@ function loadKit(id, version) {
6503
6621
  }
6504
6622
  function installedPersonas() {
6505
6623
  const p = join20(dataDir5(), "personas");
6506
- if (!existsSync17(p))
6624
+ if (!existsSync18(p))
6507
6625
  return [];
6508
6626
  return readdirSync10(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
6509
6627
  }
@@ -6519,7 +6637,7 @@ function current(explicit) {
6519
6637
  if (!id)
6520
6638
  return null;
6521
6639
  const idDir = join20(dataDir5(), "personas", id);
6522
- if (!existsSync17(idDir))
6640
+ if (!existsSync18(idDir))
6523
6641
  throw new Error(`E_SCOPE: persona not installed: ${id}`);
6524
6642
  const version = effective(id)?.version ?? latest(idDir);
6525
6643
  const dir = join20(idDir, version);
@@ -6569,13 +6687,13 @@ function scopeEnv(s, extra = {}) {
6569
6687
  }
6570
6688
 
6571
6689
  // src/doctor.ts
6572
- import { closeSync as closeSync3, existsSync as existsSync22, openSync as openSync3, readFileSync as readFileSync19, readSync, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
6690
+ import { closeSync as closeSync4, existsSync as existsSync23, openSync as openSync4, readFileSync as readFileSync19, readSync, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
6573
6691
  import { homedir as homedir12 } from "node:os";
6574
6692
  import { delimiter, dirname as dirname13, join as join25, resolve as resolve13 } from "node:path";
6575
6693
 
6576
6694
  // src/dsh.ts
6577
6695
  import { execFileSync as execFileSync7 } from "node:child_process";
6578
- import { existsSync as existsSync18, realpathSync as realpathSync4 } from "node:fs";
6696
+ import { existsSync as existsSync19, realpathSync as realpathSync4 } from "node:fs";
6579
6697
  import { dirname as dirname10, join as join21 } from "node:path";
6580
6698
  var dshBin = () => process.env.DIA_DSH_BIN || "dsh";
6581
6699
  function which(cmd) {
@@ -6583,7 +6701,7 @@ function which(cmd) {
6583
6701
  if (!dir)
6584
6702
  continue;
6585
6703
  const p = join21(dir, cmd);
6586
- if (existsSync18(p))
6704
+ if (existsSync19(p))
6587
6705
  return p;
6588
6706
  }
6589
6707
  return null;
@@ -6606,7 +6724,7 @@ var packageFor = (id) => `@deepseek-ai/dsh-${id}`;
6606
6724
  function requireConfig(root, id) {
6607
6725
  const pkg = packageFor(id);
6608
6726
  const dir = join21(root, "node_modules", ...pkg.split("/"), "lib", "index.js");
6609
- if (!existsSync18(dir))
6727
+ if (!existsSync19(dir))
6610
6728
  return { required: false };
6611
6729
  try {
6612
6730
  const out = execFileSync7(process.execPath, [
@@ -6651,7 +6769,7 @@ function pluginsWithoutConfig(dump, personaId) {
6651
6769
  return missing;
6652
6770
  }
6653
6771
  function checkPreset(personaId, profileDir) {
6654
- if (!existsSync18(profileDir))
6772
+ if (!existsSync19(profileDir))
6655
6773
  return { ok: true, skipped: "未渲染 dsh profile", issues: [] };
6656
6774
  let dump;
6657
6775
  try {
@@ -6679,7 +6797,7 @@ function checkPreset(personaId, profileDir) {
6679
6797
  }
6680
6798
 
6681
6799
  // src/platforms.ts
6682
- import { existsSync as existsSync19, readFileSync as readFileSync17 } from "node:fs";
6800
+ import { existsSync as existsSync20, readFileSync as readFileSync17 } from "node:fs";
6683
6801
  init_paths();
6684
6802
  import { join as join22 } from "node:path";
6685
6803
  import { execFileSync as execFileSync8 } from "node:child_process";
@@ -6694,7 +6812,7 @@ function registryCandidates() {
6694
6812
  return out;
6695
6813
  }
6696
6814
  function registryPath() {
6697
- return registryCandidates().find((p) => existsSync19(p)) ?? null;
6815
+ return registryCandidates().find((p) => existsSync20(p)) ?? null;
6698
6816
  }
6699
6817
  function load() {
6700
6818
  const p = registryPath();
@@ -6768,7 +6886,7 @@ function checks(reg) {
6768
6886
 
6769
6887
  // src/deps.ts
6770
6888
  init_paths();
6771
- import { existsSync as existsSync20, readFileSync as readFileSync18, mkdirSync as mkdirSync16, writeFileSync as writeFileSync14, chmodSync as chmodSync3 } from "node:fs";
6889
+ import { existsSync as existsSync21, readFileSync as readFileSync18, mkdirSync as mkdirSync16, writeFileSync as writeFileSync14, chmodSync as chmodSync3 } from "node:fs";
6772
6890
  import { homedir as homedir10 } from "node:os";
6773
6891
  import { dirname as dirname11, join as join23 } from "node:path";
6774
6892
  import { execFileSync as execFileSync9 } from "node:child_process";
@@ -6784,7 +6902,7 @@ function candidates() {
6784
6902
  return out;
6785
6903
  }
6786
6904
  function file3() {
6787
- return candidates().find((p) => existsSync20(p)) ?? null;
6905
+ return candidates().find((p) => existsSync21(p)) ?? null;
6788
6906
  }
6789
6907
  function load2(p) {
6790
6908
  const path = p ?? file3();
@@ -6846,7 +6964,7 @@ function check(e) {
6846
6964
  return { id: e.id, status: "ok", detail: `${e.id}:无固定路径(跳过探测)` };
6847
6965
  }
6848
6966
  const path = expand3(r.replace(/^link:/, ""));
6849
- return existsSync20(path) ? { id: e.id, status: "ok", detail: `${e.id}:${path}` } : missing(`${path} 不存在`);
6967
+ return existsSync21(path) ? { id: e.id, status: "ok", detail: `${e.id}:${path}` } : missing(`${path} 不存在`);
6850
6968
  }
6851
6969
  return { id: e.id, status: "ok", detail: `${e.id}:kind=${e.kind} 无探测规则` };
6852
6970
  }
@@ -6874,7 +6992,7 @@ function append4(entry, p) {
6874
6992
  mkdirSync16(dirname11(path), { recursive: true });
6875
6993
  const line = JSON.stringify(entry) + `
6876
6994
  `;
6877
- const prev = existsSync20(path) ? readFileSync18(path, "utf8") : "";
6995
+ const prev = existsSync21(path) ? readFileSync18(path, "utf8") : "";
6878
6996
  writeFileSync14(path, prev.endsWith(`
6879
6997
  `) || !prev ? prev + line : prev + `
6880
6998
  ` + line);
@@ -6890,7 +7008,7 @@ init_paths();
6890
7008
  // src/job.ts
6891
7009
  init_paths();
6892
7010
  import { spawnSync as spawnSync2 } from "node:child_process";
6893
- import { existsSync as existsSync21 } from "node:fs";
7011
+ import { existsSync as existsSync22 } from "node:fs";
6894
7012
  import { homedir as homedir11 } from "node:os";
6895
7013
  import { dirname as dirname12, join as join24, resolve as resolve12 } from "node:path";
6896
7014
  import { fileURLToPath as fileURLToPath2 } from "node:url";
@@ -6898,7 +7016,7 @@ function jobBin() {
6898
7016
  const env = process.env.DIA_JOB_BIN;
6899
7017
  if (env) {
6900
7018
  const abs = resolve12(env);
6901
- return existsSync21(abs) ? { bin: abs } : { bin: null, error: `DIA_JOB_BIN 不存在:${abs}` };
7019
+ return existsSync22(abs) ? { bin: abs } : { bin: null, error: `DIA_JOB_BIN 不存在:${abs}` };
6902
7020
  }
6903
7021
  const here = dirname12(fileURLToPath2(import.meta.url));
6904
7022
  const candidates = [
@@ -6906,7 +7024,7 @@ function jobBin() {
6906
7024
  join24(here, "..", "..", "packages", "job", "bin", "dia-job"),
6907
7025
  join24(homedir11(), ".local", "bin", "dia-job")
6908
7026
  ];
6909
- const found = candidates.find((p) => existsSync21(p));
7027
+ const found = candidates.find((p) => existsSync22(p));
6910
7028
  return found ? { bin: found } : { bin: null };
6911
7029
  }
6912
7030
  function jobRootResolved() {
@@ -6914,7 +7032,7 @@ function jobRootResolved() {
6914
7032
  return process.env.DIA_JOB_ROOT;
6915
7033
  const next = jobRoot();
6916
7034
  const legacy = join24(homedir11(), ".local", "share", "dia-job");
6917
- return !existsSync21(next) && existsSync21(legacy) ? legacy : next;
7035
+ return !existsSync22(next) && existsSync22(legacy) ? legacy : next;
6918
7036
  }
6919
7037
  function runJobCapture(argv) {
6920
7038
  const { bin, error } = jobBin();
@@ -6976,13 +7094,13 @@ function pkgShimPath(p) {
6976
7094
  const st = statSync12(p);
6977
7095
  if (!st.isFile() || st.size > 1024 * 1024)
6978
7096
  return false;
6979
- const fd = openSync3(p, "r");
7097
+ const fd = openSync4(p, "r");
6980
7098
  try {
6981
7099
  const buf = Buffer.alloc(8192);
6982
7100
  const n = readSync(fd, buf, 0, buf.length, 0);
6983
7101
  return /@minonl\/dia|node_modules\/(@minonl\/)?dia\//.test(buf.subarray(0, n).toString("utf8"));
6984
7102
  } finally {
6985
- closeSync3(fd);
7103
+ closeSync4(fd);
6986
7104
  }
6987
7105
  } catch {
6988
7106
  return false;
@@ -7035,7 +7153,7 @@ function installShadowCheck() {
7035
7153
  const name = "install_shadow";
7036
7154
  const install = installDir();
7037
7155
  const installNpm = npmOwnedPath(realOrSelf(install));
7038
- if (!installNpm && !existsSync22(join25(install, "install.json"))) {
7156
+ if (!installNpm && !existsSync23(join25(install, "install.json"))) {
7039
7157
  return { name, status: "ok", detail: `源码运行(install=${install} 无 install.json,跳过一致性判定)` };
7040
7158
  }
7041
7159
  const bin = whichDia();
@@ -7050,10 +7168,20 @@ function installShadowCheck() {
7050
7168
  const fix = installNpm ? `ln -sfn "$(npm prefix -g)/bin/dia" ${quoteArg(bin)}` : `ln -sfn ${quoteArg(join25(install, "bin/dia.js"))} ${quoteArg(bin)}`;
7051
7169
  return {
7052
7170
  name,
7053
- status: "fail",
7171
+ status: "warn",
7054
7172
  detail: `安装类型不一致:install=${install}(${kind(installNpm)})但 PATH dia=${binReal}(${kind(binNpm)});修复:${fix}`
7055
7173
  };
7056
7174
  }
7175
+ function bootstrapCheck() {
7176
+ const stamp = readStamp();
7177
+ const pkg = pkgVersion();
7178
+ if (!stamp)
7179
+ return { name: "bootstrap", status: "warn", detail: "内置能力尚未装配(首次 persona add/render 或 dia collab enable 会自动装)" };
7180
+ if (stamp.pkg !== pkg) {
7181
+ return { name: "bootstrap", status: "warn", detail: `内置能力可能过期:自举戳 pkg=${stamp.pkg},当前 ${pkg};修复:dia collab enable` };
7182
+ }
7183
+ return { name: "bootstrap", status: "ok", detail: `内置能力已装配(pkg=${pkg},kit=${stamp.kit ?? "-"})` };
7184
+ }
7057
7185
  function describeStale(st) {
7058
7186
  const diff = st.added + st.removed + st.changed;
7059
7187
  const parts = [st.added ? `新增 ${st.added}` : "", st.removed ? `删除 ${st.removed}` : "", st.changed ? `修改 ${st.changed}` : ""].filter(Boolean);
@@ -7062,7 +7190,7 @@ function describeStale(st) {
7062
7190
  }
7063
7191
  async function knowledgeCheck(id, prefix, root) {
7064
7192
  const name = `${prefix}knowledge`;
7065
- if (!existsSync22(root))
7193
+ if (!existsSync23(root))
7066
7194
  return { name, status: "fail", detail: root };
7067
7195
  const rebuild = `dia kb index --persona ${quoteArg(id)}`;
7068
7196
  let st;
@@ -7200,20 +7328,21 @@ async function run(opts = {}) {
7200
7328
  detail: `install=${install} data=${diaHome()}${install === diaHome() ? "(安装物与数据同根)" : ""}`
7201
7329
  });
7202
7330
  checks.push(installShadowCheck());
7331
+ checks.push(bootstrapCheck());
7203
7332
  const wt = join25(install, "packages/wt/bin/dia-wt");
7204
- checks.push({ name: "wt", status: existsSync22(wt) ? "ok" : "warn", detail: existsSync22(wt) ? wt : "dia wt 未安装(dia install.sh)" });
7333
+ checks.push({ name: "wt", status: existsSync23(wt) ? "ok" : "warn", detail: existsSync23(wt) ? wt : "dia wt 未安装(dia install.sh)" });
7205
7334
  const jobRoot = jobRootResolved();
7206
7335
  checks.push({
7207
7336
  name: "job",
7208
- status: existsSync22(jobRoot) ? "ok" : "warn",
7209
- detail: `${jobRoot}${existsSync22(jobRoot) ? "" : "(未创建;dia job install 首次运行会建)"}`
7337
+ status: existsSync23(jobRoot) ? "ok" : "warn",
7338
+ detail: `${jobRoot}${existsSync23(jobRoot) ? "" : "(未创建;dia job install 首次运行会建)"}`
7210
7339
  });
7211
7340
  const verdict = checks.some((c) => c.status === "fail") ? "fail" : checks.some((c) => c.status === "warn") ? "warn" : "ok";
7212
7341
  return { persona: ids.length === 1 ? ids[0] : null, personas: ids, checks, verdict };
7213
7342
  }
7214
7343
 
7215
7344
  // src/env.ts
7216
- import { existsSync as existsSync23, readFileSync as readFileSync20 } from "node:fs";
7345
+ import { existsSync as existsSync24, readFileSync as readFileSync20 } from "node:fs";
7217
7346
  import { homedir as homedir13 } from "node:os";
7218
7347
  import { join as join26 } from "node:path";
7219
7348
  import { spawnSync as spawnSync3 } from "node:child_process";
@@ -7257,7 +7386,7 @@ function loadValues(cfg) {
7257
7386
  return all;
7258
7387
  }
7259
7388
  function list6(cfg) {
7260
- const files = cfg.files.map((p) => ({ path: p, exists: existsSync23(p), keys: existsSync23(p) ? Object.keys(parseFile(p)).length : 0 }));
7389
+ const files = cfg.files.map((p) => ({ path: p, exists: existsSync24(p), keys: existsSync24(p) ? Object.keys(parseFile(p)).length : 0 }));
7261
7390
  const values = loadValues(cfg);
7262
7391
  return { files, keys: cfg.keys.map((k) => ({ key: k, found: !!values[k] })) };
7263
7392
  }
@@ -7298,7 +7427,7 @@ function run2(cfg, cmd, opts = {}) {
7298
7427
  }
7299
7428
 
7300
7429
  // src/bw.ts
7301
- import { chmodSync as chmodSync4, existsSync as existsSync24, mkdirSync as mkdirSync17, readFileSync as readFileSync21, rmSync as rmSync7, writeFileSync as writeFileSync15 } from "node:fs";
7430
+ import { chmodSync as chmodSync4, existsSync as existsSync25, mkdirSync as mkdirSync17, readFileSync as readFileSync21, rmSync as rmSync7, writeFileSync as writeFileSync15 } from "node:fs";
7302
7431
  init_paths();
7303
7432
  import { join as join27 } from "node:path";
7304
7433
  import { execFileSync as execFileSync10 } from "node:child_process";
@@ -7513,7 +7642,7 @@ function serve(opts = {}) {
7513
7642
  }
7514
7643
  function askBroker(req, timeoutMs = 5000) {
7515
7644
  const sock = socketFile();
7516
- if (!existsSync24(sock))
7645
+ if (!existsSync25(sock))
7517
7646
  return Promise.resolve(null);
7518
7647
  return new Promise((resolve, reject) => {
7519
7648
  const conn = connect(sock);
@@ -7552,19 +7681,19 @@ function askBroker(req, timeoutMs = 5000) {
7552
7681
 
7553
7682
  // packages/cli/src/index.ts
7554
7683
  import { execFileSync as execFileSync12, spawn as spawn3, spawnSync as spawnSync5 } from "node:child_process";
7555
- import { mkdirSync as mkdirSync20, openSync as openSync4 } from "node:fs";
7684
+ import { mkdirSync as mkdirSync20, openSync as openSync5 } from "node:fs";
7556
7685
  import { basename as basename10, join as join32 } from "node:path";
7557
- import { existsSync as existsSync29, readFileSync as readFileSync26, writeFileSync as writeFileSync18 } from "node:fs";
7686
+ import { existsSync as existsSync30, readFileSync as readFileSync26, writeFileSync as writeFileSync18 } from "node:fs";
7558
7687
  import { fileURLToPath as fileURLToPath4 } from "node:url";
7559
7688
  import { resolve as resolvePath, sep as pathSep } from "node:path";
7560
7689
 
7561
7690
  // src/team.ts
7562
- import { appendFileSync as appendFileSync8, cpSync as cpSync3, existsSync as existsSync26, mkdirSync as mkdirSync18, readFileSync as readFileSync23, readdirSync as readdirSync11, rmSync as rmSync8, writeFileSync as writeFileSync16 } from "node:fs";
7691
+ import { appendFileSync as appendFileSync8, cpSync as cpSync3, existsSync as existsSync27, mkdirSync as mkdirSync18, readFileSync as readFileSync23, readdirSync as readdirSync11, rmSync as rmSync8, writeFileSync as writeFileSync16 } from "node:fs";
7563
7692
  import { homedir as homedir15, tmpdir as tmpdir3 } from "node:os";
7564
7693
  import { join as join29, resolve as resolve14 } from "node:path";
7565
7694
 
7566
7695
  // src/pricing.ts
7567
- import { existsSync as existsSync25, readFileSync as readFileSync22 } from "node:fs";
7696
+ import { existsSync as existsSync26, readFileSync as readFileSync22 } from "node:fs";
7568
7697
  import { homedir as homedir14 } from "node:os";
7569
7698
  import { join as join28 } from "node:path";
7570
7699
  var DEFAULT = {
@@ -7576,7 +7705,7 @@ function pricesFile() {
7576
7705
  return process.env.DIA_PRICES_FILE || join28(homedir14(), ".config", "dia", "prices.json");
7577
7706
  }
7578
7707
  function loadPrices() {
7579
- if (!existsSync25(pricesFile()))
7708
+ if (!existsSync26(pricesFile()))
7580
7709
  return { ...DEFAULT };
7581
7710
  try {
7582
7711
  const user = JSON.parse(readFileSync22(pricesFile(), "utf8"));
@@ -7662,7 +7791,7 @@ function judgeWorkspace(dir, fallback) {
7662
7791
  function gate(id) {
7663
7792
  const dir = runDir(id);
7664
7793
  const need = ["plan.md", "diff.patch", "test.log", "verify.json", "redteam.json", "packet.md", "run.json"];
7665
- const missing = need.filter((f) => !existsSync26(join29(dir, f)));
7794
+ const missing = need.filter((f) => !existsSync27(join29(dir, f)));
7666
7795
  if (missing.length)
7667
7796
  return { ok: false, reason: "missing: " + missing.join(",") };
7668
7797
  let verify, redteam, run;
@@ -7708,7 +7837,7 @@ function gate(id) {
7708
7837
  return { ok: false, reason: "mock run 不能作为验收证据(请用 --acp/--dsh 真跑判据)" };
7709
7838
  }
7710
7839
  const workspace = String(run.workspace || "");
7711
- if (!workspace || !existsSync26(workspace))
7840
+ if (!workspace || !existsSync27(workspace))
7712
7841
  return { ok: false, reason: "run.json workspace 不存在" };
7713
7842
  const started = Date.now();
7714
7843
  let exit = 1, out = "";
@@ -8116,11 +8245,11 @@ Return only the JSON object.`);
8116
8245
  }
8117
8246
  function dshSessionFile(sessionId) {
8118
8247
  const root = join29(homedir15(), ".dsh", "sessions");
8119
- if (!existsSync26(root))
8248
+ if (!existsSync27(root))
8120
8249
  return null;
8121
8250
  for (const d of readdirSync11(root)) {
8122
8251
  const f = join29(root, d, sessionId, "session.v4.jsonl.zstd");
8123
- if (existsSync26(f))
8252
+ if (existsSync27(f))
8124
8253
  return f;
8125
8254
  }
8126
8255
  return null;
@@ -8410,7 +8539,7 @@ function reject(id, reason) {
8410
8539
  var DEFAULT_ACP_TIMEOUT = 600000;
8411
8540
 
8412
8541
  // src/proposal.ts
8413
- import { existsSync as existsSync27, readFileSync as readFileSync24, readdirSync as readdirSync12 } from "node:fs";
8542
+ import { existsSync as existsSync28, readFileSync as readFileSync24, readdirSync as readdirSync12 } from "node:fs";
8414
8543
  import { join as join30 } from "node:path";
8415
8544
  import { createHash as createHash10 } from "node:crypto";
8416
8545
  init_paths();
@@ -8433,7 +8562,7 @@ function readJson3(path) {
8433
8562
  }
8434
8563
  function collectRuns(out) {
8435
8564
  const root = join30(DATA7(), "runs");
8436
- if (!existsSync27(root))
8565
+ if (!existsSync28(root))
8437
8566
  return;
8438
8567
  for (const id of readdirSync12(root)) {
8439
8568
  const dir = join30(root, id);
@@ -8477,7 +8606,7 @@ function collectTasks(out) {
8477
8606
  }
8478
8607
  }
8479
8608
  function collectDeps(out, path) {
8480
- if (!existsSync27(path))
8609
+ if (!existsSync28(path))
8481
8610
  return;
8482
8611
  for (const e of load2(path)) {
8483
8612
  if (e.result === "unknown" || e.support === "unknown") {
@@ -8510,7 +8639,7 @@ function expandIds(cell) {
8510
8639
  return out;
8511
8640
  }
8512
8641
  function collectHypotheses(out, path) {
8513
- if (!existsSync27(path))
8642
+ if (!existsSync28(path))
8514
8643
  return;
8515
8644
  const lines = readFileSync24(path, "utf8").split(`
8516
8645
  `);
@@ -8552,7 +8681,7 @@ import { createHash as createHash11, randomBytes as randomBytes4 } from "node:cr
8552
8681
  import {
8553
8682
  appendFileSync as appendFileSync9,
8554
8683
  cpSync as cpSync4,
8555
- existsSync as existsSync28,
8684
+ existsSync as existsSync29,
8556
8685
  lstatSync as lstatSync3,
8557
8686
  mkdirSync as mkdirSync19,
8558
8687
  readFileSync as readFileSync25,
@@ -8746,7 +8875,7 @@ function validateServiceManifest(m) {
8746
8875
  }
8747
8876
  function readServiceManifest(dir) {
8748
8877
  const p = join31(dir, "dia.json");
8749
- if (!existsSync28(p))
8878
+ if (!existsSync29(p))
8750
8879
  throw new Error(`E_NO_MANIFEST: dia.json not found in ${dir}(adopted 服务需先补 dia.json)`);
8751
8880
  let raw;
8752
8881
  try {
@@ -9017,7 +9146,7 @@ function diaCmd() {
9017
9146
  resolve15(dirname14(process.argv[1] ?? ""), "..", "src", "cli.ts"),
9018
9147
  resolve15(dirname14(process.argv[1] ?? ""), "..", "dist", "cli.js")
9019
9148
  ];
9020
- const entry = entries.find((p) => existsSync28(p));
9149
+ const entry = entries.find((p) => existsSync29(p));
9021
9150
  return entry ? `${q(process.execPath)} ${q(entry)}` : "dia";
9022
9151
  }
9023
9152
  function decorateStatus(text, view) {
@@ -9045,10 +9174,10 @@ var serviceDir = (id) => join31(servicesRoot(), id);
9045
9174
  var serviceLockPath = (id) => join31(serviceDir(id), "service.lock.json");
9046
9175
  var healthStatePath = (id) => process.env.DIA_SERVICE_HEALTH_FILE || join31(jobRoot2(), "tasks", `${healthJobName(id)}.state.jsonl`);
9047
9176
  function readLockFile(id) {
9048
- if (!existsSync28(serviceDir(id)))
9177
+ if (!existsSync29(serviceDir(id)))
9049
9178
  throw new Error(`E_NOT_INSTALLED: service ${id}`);
9050
9179
  const p = serviceLockPath(id);
9051
- if (!existsSync28(p))
9180
+ if (!existsSync29(p))
9052
9181
  throw new Error(`E_NOT_INSTALLED: service ${id}(缺 lock)`);
9053
9182
  try {
9054
9183
  return JSON.parse(readFileSync25(p, "utf8"));
@@ -9069,7 +9198,7 @@ function generationOf(id) {
9069
9198
  return `g-sess${(++ephemeralGen).toString(16).padStart(4, "0")}`;
9070
9199
  }
9071
9200
  function readHealthLines(file) {
9072
- if (!existsSync28(file))
9201
+ if (!existsSync29(file))
9073
9202
  return [];
9074
9203
  const rows = [];
9075
9204
  const lines = readFileSync25(file, "utf8").split(`
@@ -9151,7 +9280,7 @@ function listServices(opts = {}) {
9151
9280
  const reg = opts.registry === null ? null : readRegistryTasks(opts.registry ?? registryPath2());
9152
9281
  const rows = [];
9153
9282
  const seen = new Set;
9154
- if (existsSync28(root)) {
9283
+ if (existsSync29(root)) {
9155
9284
  for (const e of readdirSync13(root, { withFileTypes: true })) {
9156
9285
  if (!e.isDirectory() || e.name.startsWith("."))
9157
9286
  continue;
@@ -9160,7 +9289,7 @@ function listServices(opts = {}) {
9160
9289
  }
9161
9290
  }
9162
9291
  const adoptRoot = join31(root, "adopted");
9163
- if (existsSync28(adoptRoot)) {
9292
+ if (existsSync29(adoptRoot)) {
9164
9293
  for (const e of readdirSync13(adoptRoot, { withFileTypes: true })) {
9165
9294
  if (!e.isDirectory() || seen.has(e.name))
9166
9295
  continue;
@@ -9448,7 +9577,7 @@ function whichTimeout1() {
9448
9577
  var serviceJobName = (id) => `svc-${id}`;
9449
9578
  var healthJobName = (id) => `svc-${id}-health`;
9450
9579
  function readRegistryTasks(file = registryPath2()) {
9451
- if (!existsSync28(file))
9580
+ if (!existsSync29(file))
9452
9581
  return null;
9453
9582
  try {
9454
9583
  const d = JSON.parse(readFileSync25(file, "utf8"));
@@ -9470,7 +9599,7 @@ function collectManagedFiles(base, hc) {
9470
9599
  const out = {};
9471
9600
  const rel = "dia.json";
9472
9601
  const p = join31(base, rel);
9473
- if (existsSync28(p))
9602
+ if (existsSync29(p))
9474
9603
  out[rel] = shaFile3(p);
9475
9604
  if (!hc)
9476
9605
  return out;
@@ -9499,11 +9628,11 @@ function verify4(dir, opts = {}) {
9499
9628
  const svc = readServiceManifest(dir);
9500
9629
  const entry = resolveEntry(entryCmdOf(svc), dir);
9501
9630
  const drift = [];
9502
- if (!existsSync28(entry.path))
9631
+ if (!existsSync29(entry.path))
9503
9632
  drift.push({ code: "entry_missing", detail: `entry 不存在:${entry.path}` });
9504
9633
  else if (!isExecutableFile(entry.path))
9505
9634
  drift.push({ code: "entry_not_executable", detail: `entry 不可执行:${entry.path}` });
9506
- const lock = opts.lock === undefined ? existsSync28(serviceDir(svc.id)) ? tryLock(svc.id) : null : opts.lock;
9635
+ const lock = opts.lock === undefined ? existsSync29(serviceDir(svc.id)) ? tryLock(svc.id) : null : opts.lock;
9507
9636
  if (lock) {
9508
9637
  if (entry.kind === "ref") {
9509
9638
  const want = lock.entry.link ? resolve15(lock.entry.link) : null;
@@ -9540,7 +9669,7 @@ function tryLock(id) {
9540
9669
  return null;
9541
9670
  }
9542
9671
  }
9543
- var looksLikeRepo = (from) => existsSync28(join31(from, "dia.json")) || existsSync28(join31(from, ".git")) || existsSync28(join31(from, "package.json"));
9672
+ var looksLikeRepo = (from) => existsSync29(join31(from, "dia.json")) || existsSync29(join31(from, ".git")) || existsSync29(join31(from, "package.json"));
9544
9673
  function linkEntry(path) {
9545
9674
  const dir = entryDir();
9546
9675
  mkdirSync19(dir, { recursive: true });
@@ -9548,7 +9677,7 @@ function linkEntry(path) {
9548
9677
  const dest = join31(dir, name);
9549
9678
  if (isSymlink2(dest))
9550
9679
  unlinkSync3(dest);
9551
- else if (existsSync28(dest))
9680
+ else if (existsSync29(dest))
9552
9681
  throw new Error(`E_CONFLICT: 稳定入口 ${dest} 已存在且不是软链`);
9553
9682
  symlinkSync3(resolve15(path), dest);
9554
9683
  return dest;
@@ -9573,7 +9702,7 @@ function add2(opts) {
9573
9702
  let copied = false;
9574
9703
  if (opts.from !== undefined) {
9575
9704
  const src = resolve15(opts.from);
9576
- if (!existsSync28(src))
9705
+ if (!existsSync29(src))
9577
9706
  throw new Error(`E_SOURCE: path not found: ${src}`);
9578
9707
  if (looksLikeRepo(src))
9579
9708
  cloneInto(src, rawDir);
@@ -9601,7 +9730,7 @@ function add2(opts) {
9601
9730
  if (svc.healthcheck)
9602
9731
  healthJobInterval(svc);
9603
9732
  const entry = resolveEntry(entryCmdOf(svc), dir);
9604
- if (!existsSync28(entry.path))
9733
+ if (!existsSync29(entry.path))
9605
9734
  throw new Error(`E_UNSTABLE_ENTRY: entry 不存在:${entry.path}`);
9606
9735
  if (!isExecutableFile(entry.path))
9607
9736
  throw new Error(`E_UNSTABLE_ENTRY: entry 不可执行:${entry.path}`);
@@ -9633,7 +9762,7 @@ function add2(opts) {
9633
9762
  err.code = code;
9634
9763
  throw err;
9635
9764
  };
9636
- if (existsSync28(serviceLockPath(svc.id)))
9765
+ if (existsSync29(serviceLockPath(svc.id)))
9637
9766
  remove3({ id: svc.id, runner });
9638
9767
  let entryPath = entry.path;
9639
9768
  if (entry.kind === "repo") {
@@ -9704,7 +9833,7 @@ function copyTree(from, to) {
9704
9833
  cpSync4(from, to, { recursive: true, dereference: true, filter: (p) => !isRuntimeNoise(relative6(from, p)) });
9705
9834
  }
9706
9835
  function copyAdopted(from, to) {
9707
- if (existsSync28(to))
9836
+ if (existsSync29(to))
9708
9837
  throw new Error(`E_CONFLICT: ${to} 已存在`);
9709
9838
  mkdirSync19(dirname14(to), { recursive: true });
9710
9839
  if (statSync13(from).isDirectory())
@@ -9715,7 +9844,7 @@ function copyAdopted(from, to) {
9715
9844
  }
9716
9845
  }
9717
9846
  function isGitRepo(p) {
9718
- return existsSync28(join31(p, ".git"));
9847
+ return existsSync29(join31(p, ".git"));
9719
9848
  }
9720
9849
  function remove3(opts) {
9721
9850
  const lock = readLockFile(opts.id);
@@ -9742,7 +9871,7 @@ function remove3(opts) {
9742
9871
  function runServiceHealth(id, opts = {}) {
9743
9872
  const root = opts.servicesRoot ?? servicesRoot();
9744
9873
  const dir = join31(root, id);
9745
- if (!existsSync28(dir))
9874
+ if (!existsSync29(dir))
9746
9875
  throw usageError(`E_NOT_INSTALLED: service ${id}`);
9747
9876
  const svc = readServiceManifest(dir);
9748
9877
  if (!svc.healthcheck)
@@ -10018,6 +10147,8 @@ async function kb(argv) {
10018
10147
  continue;
10019
10148
  let kr = [];
10020
10149
  try {
10150
+ if ((await indexStatus(k.dir)).state !== "ok")
10151
+ await buildIndex(k.dir);
10021
10152
  kr = await search(k.dir, q, undefined, limit);
10022
10153
  } catch {
10023
10154
  try {
@@ -10033,8 +10164,13 @@ async function kb(argv) {
10033
10164
  kitHits++;
10034
10165
  }
10035
10166
  }
10036
- if (kitHits)
10037
- rows.sort((a, b) => (b.score ?? 0) - (a.score ?? 0)).splice(limit);
10167
+ if (kitHits) {
10168
+ const kitRows = rows.filter((r) => r.source);
10169
+ const personaRows = rows.filter((r) => !r.source);
10170
+ const kitQuota = Math.min(kitRows.length, Math.max(1, Math.floor(limit / 2)));
10171
+ const picked = [...personaRows.slice(0, limit - kitQuota), ...kitRows.slice(0, kitQuota)];
10172
+ rows = picked.sort((a, b) => (b.score ?? 0) - (a.score ?? 0)).slice(0, limit);
10173
+ }
10038
10174
  const full = sub === "query" && has(args, "--full");
10039
10175
  const bytes = sub === "query" && has(args, "--bytes");
10040
10176
  const enrich = rows.map((r) => {
@@ -10527,7 +10663,7 @@ async function graphCli(argv) {
10527
10663
  const argPath = flag(argv, "--export-html");
10528
10664
  const positionalOut = argPath && !argPath.startsWith("-") ? argPath : "";
10529
10665
  const outPath = flag(argv, "--out") || positionalOut || join32(diaHome(), "export", `graph-${stamp}.html`);
10530
- if (existsSync29(outPath) && !has(argv, "--force")) {
10666
+ if (existsSync30(outPath) && !has(argv, "--force")) {
10531
10667
  err(`E_GRAPH: 已存在 ${outPath}(用 --force 覆盖)`);
10532
10668
  return 2;
10533
10669
  }
@@ -10647,7 +10783,7 @@ function spawnDetachedDelivery(args) {
10647
10783
  const dir = join32(root, agent);
10648
10784
  mkdirSync20(dir, { recursive: true });
10649
10785
  const log = join32(dir, `deliver-${id}.log`);
10650
- const fd = openSync4(log, "a");
10786
+ const fd = openSync5(log, "a");
10651
10787
  const bin = process.argv[1];
10652
10788
  const child = spawn3(process.execPath, [bin, "msg", "deliver", ...args, "--wait"], {
10653
10789
  detached: true,
@@ -11012,6 +11148,8 @@ async function collabCli(argv) {
11012
11148
  }
11013
11149
  const kitInfo = sub === "enable" ? ensure(personaId, { force: true }) : null;
11014
11150
  out(asJson ? JSON.stringify({ ...c, removed, kit: kitInfo }, null, 1) : `${sub}d: enabled=${c.enabled}${c.disabled_personas.length ? ` disabled_personas=${c.disabled_personas.join(",")}` : ""}` + (removed.length ? ` removed=${removed.length}` : "") + (kitInfo ? kitInfo.ok ? ` kit=${kitInfo.kit}` : ` ⚠ ${kitInfo.reason}` : ""));
11151
+ if (kitInfo && !kitInfo.ok)
11152
+ return 32;
11015
11153
  return 0;
11016
11154
  }
11017
11155
  if (sub === "whoami") {
@@ -11538,7 +11676,7 @@ function wtCli(argv) {
11538
11676
  home,
11539
11677
  resolvePath(fileURLToPath4(new URL("../", import.meta.url)), "packages/wt/bin/dia-wt")
11540
11678
  ].filter(Boolean);
11541
- const bin = candidates.find((c) => existsSync29(c));
11679
+ const bin = candidates.find((c) => existsSync30(c));
11542
11680
  if (!bin) {
11543
11681
  err("E_WT: dia-wt 未安装(先跑 dia install.sh,或设 DIA_WT_BIN)");
11544
11682
  return 33;