ygl-trees 0.76.0 → 0.77.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const require_rolldown_runtime = require("./rolldown-runtime-C96Ew50Q.cjs");
4
+ const require_text = require("./text-Bce0wNAD.cjs");
4
5
  let node_os = require("node:os");
5
6
  node_os = require_rolldown_runtime.__toESM(node_os);
6
7
  let node_path = require("node:path");
@@ -12,130 +13,13 @@ let node_crypto = require("node:crypto");
12
13
  let _deepseek_ai_cordis = require("@deepseek-ai/cordis");
13
14
  require("reflect-metadata");
14
15
  let typeorm = require("typeorm");
16
+ let node_events = require("node:events");
15
17
  let _deepseek_ai_cordis_plugin_timer = require("@deepseek-ai/cordis-plugin-timer");
16
18
  _deepseek_ai_cordis_plugin_timer = require_rolldown_runtime.__toESM(_deepseek_ai_cordis_plugin_timer);
17
19
  let node_child_process = require("node:child_process");
18
20
  let _deepseek_ai_dsh_atomic_write = require("@deepseek-ai/dsh-atomic-write");
19
- let node_events = require("node:events");
20
21
  let _deepseek_ai_schemastery = require("@deepseek-ai/schemastery");
21
22
  _deepseek_ai_schemastery = require_rolldown_runtime.__toESM(_deepseek_ai_schemastery);
22
- //#region packages/core/text/src/text.ts
23
- var text_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
24
- clip: () => clip,
25
- contentHash: () => contentHash,
26
- ngram: () => ngram,
27
- nowIso: () => nowIso,
28
- parseFrontmatter: () => parseFrontmatter,
29
- sha1: () => sha1,
30
- shortId: () => shortId,
31
- slug: () => slug,
32
- splitTags: () => splitTags,
33
- stampId: () => stampId
34
- });
35
- function nowIso() {
36
- const d = /* @__PURE__ */ new Date();
37
- const p = (n) => String(n).padStart(2, "0");
38
- return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
39
- }
40
- function stampId() {
41
- const d = /* @__PURE__ */ new Date();
42
- const p = (n) => String(n).padStart(2, "0");
43
- return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`;
44
- }
45
- function slug(text, limit = 40) {
46
- const s = (text || "").trim().toLowerCase().replace(new RegExp(`[^\\w${CJK}]+`, "gu"), "-").replace(/^-+|-+$/g, "");
47
- if (s.length <= limit) return s || "item";
48
- return s.slice(0, limit).replace(/-+$/, "") || "item";
49
- }
50
- /**
51
- * Tokenize mixed Chinese/English text for SQLite FTS5.
52
- *
53
- * FTS5's default unicode61 tokenizer treats a whole CJK sentence as one token,
54
- * which makes Chinese search degrade to exact match. We expand CJK runs into
55
- * character bigrams and keep latin words intact.
56
- */
57
- function ngram(text) {
58
- const src = (text || "").normalize("NFKC").toLowerCase();
59
- const out = [];
60
- const segs = src.match(CJK_RUN_RE) || [];
61
- for (const seg of segs) if (CJK_ONLY_RE.test(seg)) {
62
- if (seg.length === 1) out.push(seg);
63
- else for (let i = 0; i < seg.length - 1; i++) out.push(seg.slice(i, i + 2));
64
- } else {
65
- const w = seg.replace(/^[^\w]+|[^\w]+$/gu, "");
66
- if (w) out.push(w);
67
- }
68
- return out.join(" ");
69
- }
70
- function sha1(text) {
71
- return require("node:crypto").createHash("sha1").update(text || "").digest("hex");
72
- }
73
- /** Content hash for idempotent writes (single source: store writes and the
74
- * TypeORM write service must produce identical hashes); --force salts it
75
- * so a duplicate row is explicitly distinct (queryable via `db dups`). */
76
- function contentHash(content, force) {
77
- return sha1(content) + (force ? `#f${Date.now()}${Math.random()}` : "");
78
- }
79
- function shortId(parts, n = 8) {
80
- return sha1(parts.join("|") + Date.now() + Math.random()).slice(0, n);
81
- }
82
- /** Truncate for table display, collapsing newlines. */
83
- function clip(text, n = 40) {
84
- const one = (text || "").replace(/\s+/g, " ").trim();
85
- return one.length <= n ? one : one.slice(0, Math.max(1, n - 1)) + "…";
86
- }
87
- /**
88
- * Minimal SKILL.md frontmatter parser: supports `key: value`, quoted scalars,
89
- * folded blocks (`>-` / `>`) and inline `a,b` lists.
90
- */
91
- function parseFrontmatter(raw) {
92
- const text = raw.replace(/^/, "");
93
- const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
94
- if (!m) return {
95
- meta: {},
96
- body: text
97
- };
98
- const meta = {};
99
- const lines = m[1].split(/\r?\n/);
100
- let key = null;
101
- let folded = null;
102
- const flush = () => {
103
- if (key && folded) meta[key] = folded.join(" ").replace(/\s+/g, " ").trim();
104
- key = null;
105
- folded = null;
106
- };
107
- for (const line of lines) {
108
- const kv = /^([A-Za-z_][\w-]*)\s*:\s*(.*)$/.exec(line);
109
- if (kv && !/^\s/.test(line)) {
110
- flush();
111
- key = kv[1];
112
- const v = kv[2].trim();
113
- if (v === ">-" || v === ">" || v === "|" || v === "|-") folded = [];
114
- else {
115
- meta[key] = v.replace(/^["']|["']$/g, "");
116
- key = null;
117
- }
118
- continue;
119
- }
120
- if (key && folded) folded.push(line.trim());
121
- }
122
- flush();
123
- return {
124
- meta,
125
- body: text.slice(m[0].length)
126
- };
127
- }
128
- function splitTags(v) {
129
- return (v || "").split(/[,,;;\s]+/).map((s) => s.trim()).filter(Boolean);
130
- }
131
- var CJK, CJK_RUN_RE, CJK_ONLY_RE;
132
- var init_text = require_rolldown_runtime.__esmMin((() => {
133
- CJK = "\\u4e00-\\u9fff\\u3400-\\u4dbf\\uf900-\\ufaff";
134
- new RegExp(`[${CJK}]`, "u");
135
- CJK_RUN_RE = new RegExp(`[${CJK}]+|[^\\s${CJK}]+`, "gu");
136
- CJK_ONLY_RE = new RegExp(`^[${CJK}]+$`, "u");
137
- }));
138
- //#endregion
139
23
  //#region packages/core/database/src/db.ts
140
24
  /**
141
25
  * Database: single source of truth for ygl-trees.
@@ -158,7 +42,7 @@ function dbPath(home) {
158
42
  }
159
43
  var SCHEMA_SQL, DB, EDGE_RELS, EDGE_MODES, COND_KINDS;
160
44
  var init_db = require_rolldown_runtime.__esmMin((() => {
161
- init_text();
45
+ require_text.init_text();
162
46
  SCHEMA_SQL = `
163
47
  -- ---------------------------------------------------------------- meta
164
48
  -- runtime state the tool writes itself (current selections, bookkeeping);
@@ -688,7 +572,7 @@ CREATE UNIQUE INDEX IF NOT EXISTS uq_skill_refs ON skill_refs(skill_id, path);
688
572
  const group = (s.scope ? `${r[s.scope]}|` : "") + content;
689
573
  const n = (seen.get(group) || 0) + 1;
690
574
  seen.set(group, n);
691
- const h = n > 1 ? `${sha1(content)}#dup${n}` : sha1(content);
575
+ const h = n > 1 ? `${require_text.sha1(content)}#dup${n}` : require_text.sha1(content);
692
576
  this.run(`UPDATE ${s.t} SET content_hash=? WHERE rowid=?`, [h, r.__rid]);
693
577
  }
694
578
  }
@@ -1477,6 +1361,45 @@ var init_orm = require_rolldown_runtime.__esmMin((() => {
1477
1361
  cached = null;
1478
1362
  }));
1479
1363
  //#endregion
1364
+ //#region packages/core/text/src/eventbus.ts
1365
+ /**
1366
+ * Cross-domain event bus — connects logEvent writes to real-time consumers.
1367
+ *
1368
+ * Architecture: a process-wide EventEmitter singleton. Write services call
1369
+ * `emitEvent()` after logEvent persists to the events table; consumers
1370
+ * (webui SSE, user plugins, future watchers) subscribe with `onEvent()`.
1371
+ *
1372
+ * This makes "ctx.on reactivity" real without requiring a full Cordis
1373
+ * event system — a lightweight bridge that the webui and plugins can use.
1374
+ *
1375
+ * @module @ygl/core-text/eventbus
1376
+ */
1377
+ var eventbus_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
1378
+ emitEvent: () => emitEvent,
1379
+ onEvent: () => onEvent,
1380
+ onEventKind: () => onEventKind
1381
+ });
1382
+ /** Publish a cross-domain event (called after events table write). */
1383
+ function emitEvent(evt) {
1384
+ bus.emit("ygl", evt);
1385
+ bus.emit(`ygl:${evt.kind}`, evt);
1386
+ }
1387
+ /** Subscribe to all events. Returns an unsubscribe function. */
1388
+ function onEvent(handler) {
1389
+ bus.on("ygl", handler);
1390
+ return () => bus.off("ygl", handler);
1391
+ }
1392
+ /** Subscribe to a specific kind (e.g. "node.unlock"). Returns unsubscribe. */
1393
+ function onEventKind(kind, handler) {
1394
+ bus.on(`ygl:${kind}`, handler);
1395
+ return () => bus.off(`ygl:${kind}`, handler);
1396
+ }
1397
+ var bus;
1398
+ var init_eventbus = require_rolldown_runtime.__esmMin((() => {
1399
+ bus = new node_events.EventEmitter();
1400
+ bus.setMaxListeners(50);
1401
+ }));
1402
+ //#endregion
1480
1403
  //#region packages/core/database/src/plugin.ts
1481
1404
  /**
1482
1405
  * DatabasePlugin — provides ctx.database (DatabaseService).
@@ -1509,6 +1432,36 @@ var DatabaseService = class extends _deepseek_ai_cordis.Service {
1509
1432
  };
1510
1433
  function apply$3(ctx, config) {
1511
1434
  new DatabaseService(ctx, config.file);
1435
+ try {
1436
+ const { onEvent, onEventKind } = (init_eventbus(), require_rolldown_runtime.__toCommonJS(eventbus_exports));
1437
+ const kindSubs = [onEvent((evt) => {
1438
+ try {
1439
+ ctx.emit("ygl", evt);
1440
+ } catch {}
1441
+ })];
1442
+ for (const kind of [
1443
+ "node.unlock",
1444
+ "node.lock",
1445
+ "node.add",
1446
+ "node.link",
1447
+ "kb.add",
1448
+ "kb.rm",
1449
+ "claim.resolve",
1450
+ "claim.add",
1451
+ "task.status",
1452
+ "project.new",
1453
+ "skill.add"
1454
+ ]) kindSubs.push(onEventKind(kind, (evt) => {
1455
+ try {
1456
+ ctx.emit(`ygl:${kind}`, evt);
1457
+ } catch {}
1458
+ }));
1459
+ ctx.fiber?.collect?.(() => {
1460
+ for (const u of kindSubs) try {
1461
+ u();
1462
+ } catch {}
1463
+ });
1464
+ } catch {}
1512
1465
  }
1513
1466
  //#endregion
1514
1467
  //#region packages/web/app/src/index.ts
@@ -1942,7 +1895,7 @@ var init_eval = require_rolldown_runtime.__esmMin((() => {
1942
1895
  //#endregion
1943
1896
  //#region packages/techtree/model/src/reads.ts
1944
1897
  init_db();
1945
- init_text();
1898
+ require_text.init_text();
1946
1899
  init_eval();
1947
1900
  var TreeStore = class {
1948
1901
  db;
@@ -2020,7 +1973,7 @@ var TreeStore = class {
2020
1973
  if (p.id === c.id) throw new Error("self-loop rejected");
2021
1974
  if (this.reaches(treeId, c.id, p.id)) throw new Error(`cycle rejected: ${childKey} already reaches ${parentKey}`);
2022
1975
  }
2023
- const id = shortId([
1976
+ const id = require_text.shortId([
2024
1977
  "edge",
2025
1978
  p.id,
2026
1979
  c.id,
@@ -2102,7 +2055,7 @@ var TreeStore = class {
2102
2055
  this.db.run("DELETE FROM node_conditions WHERE id=?", [condId]);
2103
2056
  }
2104
2057
  markDirty(treeId) {
2105
- this.db.run("INSERT INTO node_index(tree_id,built_at,dirty) VALUES(?,?,1) ON CONFLICT(tree_id) DO UPDATE SET dirty=1", [treeId, nowIso()]);
2058
+ this.db.run("INSERT INTO node_index(tree_id,built_at,dirty) VALUES(?,?,1) ON CONFLICT(tree_id) DO UPDATE SET dirty=1", [treeId, require_text.nowIso()]);
2106
2059
  }
2107
2060
  /** Rebuild the transitive closure (BFS from every node). */
2108
2061
  rebuildClosure(treeId) {
@@ -2219,7 +2172,7 @@ var TreeStore = class {
2219
2172
  JSON.stringify(topo),
2220
2173
  JSON.stringify(tiers),
2221
2174
  JSON.stringify(inDegree),
2222
- nowIso()
2175
+ require_text.nowIso()
2223
2176
  ]);
2224
2177
  return {
2225
2178
  topo,
@@ -2446,7 +2399,7 @@ var TreeStore = class {
2446
2399
  /** Full-text search over nodes. Title/key substring hits outrank same-hit
2447
2400
  * rows (same ranking semantics as kb/skill/source search). */
2448
2401
  nodeSearch(treeId, q, limit = 20) {
2449
- const tokens = Array.from(new Set(String((init_text(), require_rolldown_runtime.__toCommonJS(text_exports)).ngram(q) || "").split(/\s+/).filter(Boolean)));
2402
+ const tokens = Array.from(new Set(String((require_text.init_text(), require_rolldown_runtime.__toCommonJS(require_text.text_exports)).ngram(q) || "").split(/\s+/).filter(Boolean)));
2450
2403
  if (!tokens.length) return [];
2451
2404
  const agg = /* @__PURE__ */ new Map();
2452
2405
  const st = this.db.db.prepare(`SELECT n.id,n.key,n.name,n.tier, bm25(nodes_fts) AS score
@@ -2668,7 +2621,7 @@ function apply$1(ctx) {
2668
2621
  }
2669
2622
  //#endregion
2670
2623
  //#region packages/research/pipeline/src/reads.ts
2671
- init_text();
2624
+ require_text.init_text();
2672
2625
  var Store = class {
2673
2626
  db;
2674
2627
  constructor(db) {
@@ -2676,8 +2629,8 @@ var Store = class {
2676
2629
  }
2677
2630
  log(kind, entity = "", entityId = "", payload = "", actor = "cli") {
2678
2631
  this.db.run("INSERT INTO events(id,ts,actor,kind,entity,entity_id,payload) VALUES(?,?,?,?,?,?,?)", [
2679
- shortId([kind, entity], 12),
2680
- nowIso(),
2632
+ require_text.shortId([kind, entity], 12),
2633
+ require_text.nowIso(),
2681
2634
  actor,
2682
2635
  kind,
2683
2636
  entity,
@@ -2799,7 +2752,7 @@ var Store = class {
2799
2752
  skillEnabled(name, on) {
2800
2753
  return this.db.run("UPDATE skills SET enabled=?, updated=? WHERE name=?", [
2801
2754
  on ? 1 : 0,
2802
- nowIso(),
2755
+ require_text.nowIso(),
2803
2756
  name
2804
2757
  ]).changes > 0;
2805
2758
  }
@@ -2875,7 +2828,7 @@ var Store = class {
2875
2828
  * works for CJK and latin alike.
2876
2829
  */
2877
2830
  fts(o) {
2878
- const tokens = Array.from(new Set(ngram(o.q).split(/\s+/).filter(Boolean)));
2831
+ const tokens = Array.from(new Set(require_text.ngram(o.q).split(/\s+/).filter(Boolean)));
2879
2832
  if (!tokens.length) return o.fallback();
2880
2833
  const cond = [o.where, `${o.table} MATCH ?`].filter(Boolean).join(" AND ");
2881
2834
  const agg = /* @__PURE__ */ new Map();
@@ -2948,7 +2901,7 @@ var Store = class {
2948
2901
  relate(srcType, srcId, dstType, dstId, rel = "related", weight = 1) {
2949
2902
  this.db.run(`INSERT INTO relations(id,src_type,src_id,dst_type,dst_id,rel,weight) VALUES(?,?,?,?,?,?,?)
2950
2903
  ON CONFLICT(src_type,src_id,dst_type,dst_id,rel) DO UPDATE SET weight=excluded.weight`, [
2951
- shortId([
2904
+ require_text.shortId([
2952
2905
  srcType,
2953
2906
  srcId,
2954
2907
  dstType,
@@ -2999,25 +2952,25 @@ var Store = class {
2999
2952
  const p = (n) => String(n).padStart(2, "0");
3000
2953
  const cut = `${cutoff.getFullYear()}-${p(cutoff.getMonth() + 1)}-${p(cutoff.getDate())} ${p(cutoff.getHours())}:${p(cutoff.getMinutes())}:${p(cutoff.getSeconds())}`;
3001
2954
  return this.db.run(`UPDATE runs SET finished=?, rc=126, output=COALESCE(NULLIF(output,''),'') || '(reaped: process was killed mid-run)'
3002
- WHERE finished='' AND started < ?`, [nowIso(), cut]).changes;
2955
+ WHERE finished='' AND started < ?`, [require_text.nowIso(), cut]).changes;
3003
2956
  }
3004
2957
  jobStart(jobId) {
3005
- const id = shortId(["run", jobId], 12);
2958
+ const id = require_text.shortId(["run", jobId], 12);
3006
2959
  this.db.run("INSERT INTO runs(id,job_id,started) VALUES(?,?,?)", [
3007
2960
  id,
3008
2961
  jobId,
3009
- nowIso()
2962
+ require_text.nowIso()
3010
2963
  ]);
3011
2964
  return id;
3012
2965
  }
3013
2966
  jobFinish(runId, rc, output) {
3014
2967
  this.db.run("UPDATE runs SET finished=?, rc=?, output=? WHERE id=?", [
3015
- nowIso(),
2968
+ require_text.nowIso(),
3016
2969
  rc,
3017
2970
  output.slice(0, 8e3)
3018
2971
  ]);
3019
2972
  this.db.run("UPDATE jobs SET runs=runs+1, last_run=?, status=? WHERE id=(SELECT job_id FROM runs WHERE id=?)", [
3020
- nowIso(),
2973
+ require_text.nowIso(),
3021
2974
  rc === 0 ? "ok" : "failed",
3022
2975
  runId
3023
2976
  ]);
@@ -3060,7 +3013,8 @@ function str(v) {
3060
3013
  */
3061
3014
  function deriveL1(body, title) {
3062
3015
  const lines = body.split("\n").map((l) => l.replace(/\*\*/g, "").trim()).filter(Boolean).filter((l) => !/^#{1,6}\s/.test(l)).filter((l) => !/^_generated/i.test(l) && !/^generated/i.test(l));
3063
- return `${clip((lines.slice(0, 20).find((l) => /^[-*]\s+|^\d+[.)]\s+/.test(l)) || lines[0] || title).replace(/^[-*]\s+|^\d+[.)]\s+/, "").replace(/^[✓✗⚠?*☐☑]\s*/, "").replace(/\s*\[\d+\]/g, "").replace(/\s+/g, " ").trim(), 200)}(提炼自《${clip(title, 60)}》)`;
3016
+ const pick = (lines.slice(0, 20).find((l) => /^[-*]\s+|^\d+[.)]\s+/.test(l)) || lines[0] || title).replace(/^[-*]\s+|^\d+[.)]\s+/, "").replace(/^[✓✗⚠?*☐☑]\s*/, "").replace(/\s*\[\d+\]/g, "").replace(/\s+/g, " ").trim();
3017
+ return `${require_text.clip(pick, 200)}(提炼自《${require_text.clip(title, 60)}》)`;
3064
3018
  }
3065
3019
  //#endregion
3066
3020
  //#region packages/research/pipeline/src/plugin.ts
@@ -3180,18 +3134,21 @@ function writeUserBundle(home, specs) {
3180
3134
  function pnpm(home, args) {
3181
3135
  const pm = process.env.YGL_PACKAGE_MANAGER || "pnpm";
3182
3136
  if (process.platform === "win32") {
3183
- const q = (s) => `"${String(s).replace(/["&|<>^]/g, "")}"`;
3184
3137
  const exe = resolvePm(pm);
3185
- (0, node_child_process.execFileSync)([
3186
- q(exe),
3187
- ...args.map(q),
3138
+ const { spawnSync } = require("node:child_process");
3139
+ const r = spawnSync("cmd", [
3140
+ "/c",
3141
+ exe,
3142
+ ...args,
3188
3143
  "--dir",
3189
- q(profileDir(home)),
3144
+ profileDir(home),
3190
3145
  "--ignore-workspace"
3191
- ].join(" "), {
3192
- stdio: "pipe",
3193
- shell: true
3194
- });
3146
+ ], { stdio: "pipe" });
3147
+ if (r.status !== 0) {
3148
+ const err = new Error(String(r.stderr || r.stdout || `pnpm exited ${r.status}`));
3149
+ err.status = r.status;
3150
+ throw err;
3151
+ }
3195
3152
  return;
3196
3153
  }
3197
3154
  (0, node_child_process.execFileSync)(pm, [
@@ -3225,6 +3182,16 @@ function resolvePm(pm) {
3225
3182
  async function installPlugin(home, spec) {
3226
3183
  initProfile(home);
3227
3184
  const abs = node_path.resolve(spec);
3185
+ if (node_fs.existsSync(abs) && node_fs.statSync(abs).isDirectory()) {
3186
+ const pkgPath = node_path.join(abs, "package.json");
3187
+ if (!node_fs.existsSync(pkgPath)) throw new Error(`local plugin directory has no package.json: ${abs}`);
3188
+ try {
3189
+ const pkg = JSON.parse(node_fs.readFileSync(pkgPath, "utf8"));
3190
+ if (!pkg.name || typeof pkg.name !== "string") throw new Error(`package.json missing "name" field: ${abs}`);
3191
+ } catch (e) {
3192
+ throw new Error(`invalid package.json in ${abs}: ${e?.message || e}`);
3193
+ }
3194
+ } else if (spec.startsWith(".") || spec.startsWith("/") || spec.startsWith("\\") || /^[A-Z]:/.test(spec)) throw new Error(`plugin path not found: ${abs}`);
3228
3195
  const installSpec = node_fs.existsSync(abs) && node_fs.statSync(abs).isDirectory() ? `link:${abs}` : spec;
3229
3196
  const existing = readUserBundle(home).find((p) => p.spec === installSpec || p.spec === spec);
3230
3197
  if (existing) return existing;
@@ -3509,6 +3476,7 @@ function createProcessShutdown(dispose, forceExit = (code) => process.exit(code)
3509
3476
  }
3510
3477
  //#endregion
3511
3478
  //#region apps/cli/src/plugin.ts
3479
+ var plugin_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({ runPluginCommand: () => runPluginCommand });
3512
3480
  init_plugins();
3513
3481
  function runPluginCommand(env, action, rest, args) {
3514
3482
  const { ctx } = env;
@@ -3632,7 +3600,7 @@ function runPluginCommand(env, action, rest, args) {
3632
3600
  }
3633
3601
  //#endregion
3634
3602
  //#region packages/ops/tools/src/pgsync.ts
3635
- init_text();
3603
+ require_text.init_text();
3636
3604
  /** Mirror targets, FK-dependency-safe order (same list as `db export`). */
3637
3605
  const MIRROR_TABLES = [
3638
3606
  "meta",
@@ -3691,7 +3659,7 @@ async function copyTable(client, db, t) {
3691
3659
  const v = r[c];
3692
3660
  return v === void 0 ? null : v;
3693
3661
  });
3694
- if (NGRAM_INPUT[t]) vals.push(ngram(NGRAM_INPUT[t](r)));
3662
+ if (NGRAM_INPUT[t]) vals.push(require_text.ngram(NGRAM_INPUT[t](r)));
3695
3663
  params.push(...vals);
3696
3664
  return `(${vals.map((_, j) => `$${params.length - vals.length + j + 1}`).join(",")})`;
3697
3665
  });
@@ -3989,45 +3957,6 @@ function preflightTypeCheck(db) {
3989
3957
  return issues;
3990
3958
  }
3991
3959
  //#endregion
3992
- //#region packages/core/text/src/eventbus.ts
3993
- /**
3994
- * Cross-domain event bus — connects logEvent writes to real-time consumers.
3995
- *
3996
- * Architecture: a process-wide EventEmitter singleton. Write services call
3997
- * `emitEvent()` after logEvent persists to the events table; consumers
3998
- * (webui SSE, user plugins, future watchers) subscribe with `onEvent()`.
3999
- *
4000
- * This makes "ctx.on reactivity" real without requiring a full Cordis
4001
- * event system — a lightweight bridge that the webui and plugins can use.
4002
- *
4003
- * @module @ygl/core-text/eventbus
4004
- */
4005
- var eventbus_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
4006
- emitEvent: () => emitEvent,
4007
- onEvent: () => onEvent,
4008
- onEventKind: () => onEventKind
4009
- });
4010
- /** Publish a cross-domain event (called after events table write). */
4011
- function emitEvent(evt) {
4012
- bus.emit("ygl", evt);
4013
- bus.emit(`ygl:${evt.kind}`, evt);
4014
- }
4015
- /** Subscribe to all events. Returns an unsubscribe function. */
4016
- function onEvent(handler) {
4017
- bus.on("ygl", handler);
4018
- return () => bus.off("ygl", handler);
4019
- }
4020
- /** Subscribe to a specific kind (e.g. "node.unlock"). Returns unsubscribe. */
4021
- function onEventKind(kind, handler) {
4022
- bus.on(`ygl:${kind}`, handler);
4023
- return () => bus.off(`ygl:${kind}`, handler);
4024
- }
4025
- var bus;
4026
- var init_eventbus = require_rolldown_runtime.__esmMin((() => {
4027
- bus = new node_events.EventEmitter();
4028
- bus.setMaxListeners(50);
4029
- }));
4030
- //#endregion
4031
3960
  //#region packages/research/pipeline/src/writes.ts
4032
3961
  var writes_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
4033
3962
  artifactAdd: () => artifactAdd,
@@ -4059,8 +3988,8 @@ async function logEvent$1(mgr, kind, entity, entityId, payload, level = "info")
4059
3988
  };
4060
3989
  const p = typeof obj === "string" ? obj : JSON.stringify(obj);
4061
3990
  await mgr.insert(Event, {
4062
- id: shortId([kind, entity], 12),
4063
- ts: nowIso(),
3991
+ id: require_text.shortId([kind, entity], 12),
3992
+ ts: require_text.nowIso(),
4064
3993
  actor: "cli",
4065
3994
  kind,
4066
3995
  entity,
@@ -4080,7 +4009,7 @@ async function logEvent$1(mgr, kind, entity, entityId, payload, level = "info")
4080
4009
  } catch {}
4081
4010
  }
4082
4011
  async function queryAdd(ds, projectId, text, engine = "", force = false) {
4083
- const hash = contentHash(text, force);
4012
+ const hash = require_text.contentHash(text, force);
4084
4013
  return ds.transaction(async (mgr) => {
4085
4014
  const ex = await mgr.findOne(Query, { where: {
4086
4015
  projectId,
@@ -4091,7 +4020,7 @@ async function queryAdd(ds, projectId, text, engine = "", force = false) {
4091
4020
  dup: true
4092
4021
  };
4093
4022
  const q = new Query();
4094
- q.id = shortId([
4023
+ q.id = require_text.shortId([
4095
4024
  "q",
4096
4025
  projectId,
4097
4026
  text
@@ -4102,7 +4031,7 @@ async function queryAdd(ds, projectId, text, engine = "", force = false) {
4102
4031
  q.status = "pending";
4103
4032
  q.note = "";
4104
4033
  q.contentHash = hash;
4105
- q.created = nowIso();
4034
+ q.created = require_text.nowIso();
4106
4035
  await mgr.save(q);
4107
4036
  await logEvent$1(mgr, "query.add", "query", q.id, text);
4108
4037
  return {
@@ -4125,7 +4054,7 @@ function mapQuery(q) {
4125
4054
  }
4126
4055
  async function sourceAdd(ds, projectId, o) {
4127
4056
  const url = o.url || "";
4128
- const urlHash = sha1(url || o.title || "");
4057
+ const urlHash = require_text.sha1(url || o.title || "");
4129
4058
  return ds.transaction(async (mgr) => {
4130
4059
  const ex = await mgr.findOne(Source, { where: {
4131
4060
  projectId,
@@ -4140,7 +4069,7 @@ async function sourceAdd(ds, projectId, o) {
4140
4069
  const abstract_ = o.abstract || "";
4141
4070
  const content = o.content || "";
4142
4071
  const s = new Source();
4143
- s.id = shortId([
4072
+ s.id = require_text.shortId([
4144
4073
  "src",
4145
4074
  projectId,
4146
4075
  urlHash
@@ -4149,22 +4078,22 @@ async function sourceAdd(ds, projectId, o) {
4149
4078
  s.url = url;
4150
4079
  s.title = title;
4151
4080
  s.urlHash = urlHash;
4152
- s.contentHash = sha1(content || abstract_);
4081
+ s.contentHash = require_text.sha1(content || abstract_);
4153
4082
  s.abstract = abstract_;
4154
4083
  s.content = content;
4155
4084
  s.engine = o.engine || "";
4156
4085
  s.relevance = o.relevance ?? 0;
4157
4086
  s.confidence = o.confidence || "B";
4158
4087
  s.tags = o.tags || "";
4159
- s.retrievedAt = nowIso();
4160
- s.created = nowIso();
4088
+ s.retrievedAt = require_text.nowIso();
4089
+ s.created = require_text.nowIso();
4161
4090
  await mgr.save(s);
4162
4091
  await mgr.query(`INSERT INTO sources_fts(id,title,abstract,content,ngram) VALUES(?,?,?,?,?)`, [
4163
4092
  s.id,
4164
4093
  title,
4165
4094
  abstract_,
4166
4095
  content,
4167
- ngram(`${title} ${abstract_} ${content} ${o.tags || ""}`)
4096
+ require_text.ngram(`${title} ${abstract_} ${content} ${o.tags || ""}`)
4168
4097
  ]);
4169
4098
  await logEvent$1(mgr, "source.add", "source", s.id, title);
4170
4099
  return {
@@ -4192,7 +4121,7 @@ function mapSource(s) {
4192
4121
  };
4193
4122
  }
4194
4123
  async function evidenceAdd(ds, projectId, sourceId, quote, note = "", locator = "", force = false) {
4195
- const hash = contentHash(quote, force);
4124
+ const hash = require_text.contentHash(quote, force);
4196
4125
  return ds.transaction(async (mgr) => {
4197
4126
  if (!await mgr.findOne(Source, { where: {
4198
4127
  id: sourceId,
@@ -4207,7 +4136,7 @@ async function evidenceAdd(ds, projectId, sourceId, quote, note = "", locator =
4207
4136
  dup: true
4208
4137
  };
4209
4138
  const e = new Evidence();
4210
- e.id = shortId([
4139
+ e.id = require_text.shortId([
4211
4140
  "ev",
4212
4141
  sourceId,
4213
4142
  quote
@@ -4218,12 +4147,12 @@ async function evidenceAdd(ds, projectId, sourceId, quote, note = "", locator =
4218
4147
  e.note = note;
4219
4148
  e.locator = locator;
4220
4149
  e.contentHash = hash;
4221
- e.created = nowIso();
4150
+ e.created = require_text.nowIso();
4222
4151
  await mgr.save(e);
4223
4152
  await mgr.query(`INSERT INTO evidence_fts(id,quote,ngram) VALUES(?,?,?)`, [
4224
4153
  e.id,
4225
4154
  quote,
4226
- ngram(quote)
4155
+ require_text.ngram(quote)
4227
4156
  ]);
4228
4157
  await logEvent$1(mgr, "evidence.add", "evidence", e.id, quote.slice(0, 60));
4229
4158
  return {
@@ -4245,7 +4174,7 @@ function mapEvidence(e) {
4245
4174
  };
4246
4175
  }
4247
4176
  async function claimAdd(ds, projectId, text, confidence = "B", force = false) {
4248
- const hash = contentHash(text, force);
4177
+ const hash = require_text.contentHash(text, force);
4249
4178
  return ds.transaction(async (mgr) => {
4250
4179
  const ex = await mgr.findOne(Claim, { where: {
4251
4180
  projectId,
@@ -4256,7 +4185,7 @@ async function claimAdd(ds, projectId, text, confidence = "B", force = false) {
4256
4185
  dup: true
4257
4186
  };
4258
4187
  const c = new Claim();
4259
- c.id = shortId([
4188
+ c.id = require_text.shortId([
4260
4189
  "cl",
4261
4190
  projectId,
4262
4191
  text
@@ -4266,8 +4195,8 @@ async function claimAdd(ds, projectId, text, confidence = "B", force = false) {
4266
4195
  c.status = "unverified";
4267
4196
  c.confidence = confidence;
4268
4197
  c.contentHash = hash;
4269
- c.created = nowIso();
4270
- c.updated = nowIso();
4198
+ c.created = require_text.nowIso();
4199
+ c.updated = require_text.nowIso();
4271
4200
  await mgr.save(c);
4272
4201
  await logEvent$1(mgr, "claim.add", "claim", c.id, text.slice(0, 60));
4273
4202
  return {
@@ -4311,7 +4240,7 @@ async function claimResolve(ds, claimId, status, note = "") {
4311
4240
  return ds.transaction(async (mgr) => {
4312
4241
  await mgr.update(Claim, { id: claimId }, {
4313
4242
  status,
4314
- updated: nowIso()
4243
+ updated: require_text.nowIso()
4315
4244
  });
4316
4245
  await logEvent$1(mgr, "claim.resolve", "claim", claimId, `${status}${note ? " | " + note : ""}`);
4317
4246
  });
@@ -4340,7 +4269,7 @@ async function queryAttach(ds, projectId, queryIdOrText, sourceId, note = "") {
4340
4269
  qs.queryId = q.id;
4341
4270
  qs.sourceId = s.id;
4342
4271
  qs.note = note;
4343
- qs.created = nowIso();
4272
+ qs.created = require_text.nowIso();
4344
4273
  await mgr.save(qs);
4345
4274
  await logEvent$1(mgr, "query.attach", "query", q.id, s.id);
4346
4275
  }
@@ -4353,15 +4282,15 @@ async function queryAttach(ds, projectId, queryIdOrText, sourceId, note = "") {
4353
4282
  });
4354
4283
  }
4355
4284
  async function kbAdd(ds, o) {
4356
- const hash = contentHash(`${o.title}\n${o.body}`, !!o.force);
4285
+ const hash = require_text.contentHash(`${o.title}\n${o.body}`, !!o.force);
4357
4286
  return ds.transaction(async (mgr) => {
4358
4287
  const ex = await mgr.query(`SELECT * FROM kb_notes WHERE content_hash=?`, [hash]);
4359
4288
  if (ex.length) return {
4360
4289
  row: ex[0],
4361
4290
  dup: true
4362
4291
  };
4363
- const id = shortId(["kb", o.title], 10);
4364
- const now = nowIso();
4292
+ const id = require_text.shortId(["kb", o.title], 10);
4293
+ const now = require_text.nowIso();
4365
4294
  await mgr.query(`INSERT INTO kb_notes(id,title,body,source_url,origin,tags,confidence,reuse,content_hash,created,updated)
4366
4295
  VALUES(?,?,?,?,?,?,?,0,?,?,?)`, [
4367
4296
  id,
@@ -4379,7 +4308,7 @@ async function kbAdd(ds, o) {
4379
4308
  id,
4380
4309
  o.title,
4381
4310
  o.tags || "",
4382
- ngram(`${o.title} ${o.tags || ""} ${o.body}`)
4311
+ require_text.ngram(`${o.title} ${o.tags || ""} ${o.body}`)
4383
4312
  ]);
4384
4313
  await logEvent$1(mgr, "kb.add", "kb_note", id, o.title);
4385
4314
  return {
@@ -4417,13 +4346,13 @@ async function kbImportBulk(ds, items) {
4417
4346
  let added = 0;
4418
4347
  let dups = 0;
4419
4348
  for (const o of items) {
4420
- const hash = contentHash(`${o.title}\n${o.body}`, false);
4349
+ const hash = require_text.contentHash(`${o.title}\n${o.body}`, false);
4421
4350
  if ((await mgr.query(`SELECT id FROM kb_notes WHERE content_hash=?`, [hash])).length) {
4422
4351
  dups++;
4423
4352
  continue;
4424
4353
  }
4425
- const id = shortId(["kb", o.title], 10);
4426
- const now = nowIso();
4354
+ const id = require_text.shortId(["kb", o.title], 10);
4355
+ const now = require_text.nowIso();
4427
4356
  await mgr.query(`INSERT INTO kb_notes(id,title,body,source_url,origin,tags,confidence,reuse,content_hash,created,updated)
4428
4357
  VALUES(?,?,?,?,?,?,?,0,?,?,?)`, [
4429
4358
  id,
@@ -4441,7 +4370,7 @@ async function kbImportBulk(ds, items) {
4441
4370
  id,
4442
4371
  o.title,
4443
4372
  o.tags || "",
4444
- ngram(`${o.title} ${o.tags || ""} ${o.body}`)
4373
+ require_text.ngram(`${o.title} ${o.tags || ""} ${o.body}`)
4445
4374
  ]);
4446
4375
  await logEvent$1(mgr, "kb.add", "kb_note", id, o.title);
4447
4376
  added++;
@@ -4464,8 +4393,8 @@ async function jobAdd(ds, o) {
4464
4393
  let i = 2;
4465
4394
  while ((await mgr.query(`SELECT 1 AS hit FROM jobs WHERE title=?`, [title])).length) title = `${o.title}-${i++}`;
4466
4395
  }
4467
- const id = shortId(["job", title], 10);
4468
- const created = nowIso();
4396
+ const id = require_text.shortId(["job", title], 10);
4397
+ const created = require_text.nowIso();
4469
4398
  await mgr.query(`INSERT INTO jobs(id,title,command,every_minutes,at,enabled,runs,last_run,status,created)
4470
4399
  VALUES(?,?,?,?,?,1,0,'','pending',?)`, [
4471
4400
  id,
@@ -4501,14 +4430,14 @@ async function artifactAdd(ds, projectId, kind, title, content, format = "markdo
4501
4430
  title
4502
4431
  ]);
4503
4432
  const ver = Number(max?.[0]?.m ?? 0) + 1;
4504
- const id = shortId([
4433
+ const id = require_text.shortId([
4505
4434
  "art",
4506
4435
  projectId,
4507
4436
  kind,
4508
4437
  title,
4509
4438
  String(ver)
4510
4439
  ], 10);
4511
- const created = nowIso();
4440
+ const created = require_text.nowIso();
4512
4441
  await mgr.query(`INSERT INTO artifacts(id,project_id,kind,title,format,content,version,created,meta) VALUES(?,?,?,?,?,?,?,?,?)`, [
4513
4442
  id,
4514
4443
  projectId,
@@ -4557,7 +4486,7 @@ async function taskSetStatus(ds, taskId, status) {
4557
4486
  ...meta,
4558
4487
  status
4559
4488
  }),
4560
- nowIso(),
4489
+ require_text.nowIso(),
4561
4490
  taskId
4562
4491
  ]);
4563
4492
  await logEvent$1(mgr, "task.status", "task", taskId, `${from} → ${status}`, status === "done" ? "info" : "info");
@@ -4571,13 +4500,13 @@ async function taskSetStatus(ds, taskId, status) {
4571
4500
  }
4572
4501
  async function skillUpsert(ds, o) {
4573
4502
  return ds.transaction(async (mgr) => {
4574
- const now = nowIso();
4503
+ const now = require_text.nowIso();
4575
4504
  await mgr.query(`INSERT INTO skills(id,name,version,description,body,tags,origin,created,updated)
4576
4505
  VALUES(?,?,?,?,?,?,?,?,?)
4577
4506
  ON CONFLICT(name) DO UPDATE SET
4578
4507
  version=excluded.version, description=excluded.description, body=excluded.body,
4579
4508
  tags=excluded.tags, origin=excluded.origin, updated=excluded.updated`, [
4580
- shortId(["skill", o.name], 10),
4509
+ require_text.shortId(["skill", o.name], 10),
4581
4510
  o.name,
4582
4511
  o.version || "0.1.0",
4583
4512
  o.description || "",
@@ -4594,7 +4523,7 @@ async function skillUpsert(ds, o) {
4594
4523
  s.name,
4595
4524
  s.description,
4596
4525
  s.tags,
4597
- ngram(`${s.name} ${s.description} ${s.tags} ${s.body}`)
4526
+ require_text.ngram(`${s.name} ${s.description} ${s.tags} ${s.body}`)
4598
4527
  ]);
4599
4528
  await logEvent$1(mgr, "skill.upsert", "skill", s.id, s.name);
4600
4529
  return s;
@@ -4614,7 +4543,7 @@ async function skillEnabled(ds, name, on) {
4614
4543
  if (!rows.length) return false;
4615
4544
  await mgr.query(`UPDATE skills SET enabled=?, updated=? WHERE id=?`, [
4616
4545
  on ? 1 : 0,
4617
- nowIso(),
4546
+ require_text.nowIso(),
4618
4547
  rows[0].id
4619
4548
  ]);
4620
4549
  return true;
@@ -4624,7 +4553,7 @@ async function skillRefAdd(ds, skillName, refPath, content) {
4624
4553
  return ds.transaction(async (mgr) => {
4625
4554
  const s = await mgr.query(`SELECT id FROM skills WHERE name=?`, [skillName]);
4626
4555
  if (!s.length) throw new Error(`skill not found: ${skillName}`);
4627
- const id = shortId([
4556
+ const id = require_text.shortId([
4628
4557
  "ref",
4629
4558
  s[0].id,
4630
4559
  refPath
@@ -4649,8 +4578,8 @@ async function projectCreate(ds, name, question = "") {
4649
4578
  duplicate: true
4650
4579
  };
4651
4580
  }
4652
- const now = nowIso();
4653
- const id = shortId(["proj", name], 10);
4581
+ const now = require_text.nowIso();
4582
+ const id = require_text.shortId(["proj", name], 10);
4654
4583
  await mgr.query(`INSERT INTO projects(id,name,question,status,created,updated) VALUES(?,?,?,'active',?,?)`, [
4655
4584
  id,
4656
4585
  name,
@@ -4667,7 +4596,7 @@ var TASK_STATUSES;
4667
4596
  var init_writes = require_rolldown_runtime.__esmMin((() => {
4668
4597
  init_entities$1();
4669
4598
  init_entities();
4670
- init_text();
4599
+ require_text.init_text();
4671
4600
  TASK_STATUSES = [
4672
4601
  "todo",
4673
4602
  "doing",
@@ -4708,7 +4637,7 @@ async function autoImportBuiltinSkills(env, dbFile) {
4708
4637
  }
4709
4638
  const { getOrm } = (init_orm(), require_rolldown_runtime.__toCommonJS(orm_exports));
4710
4639
  const writes = (init_writes(), require_rolldown_runtime.__toCommonJS(writes_exports));
4711
- const { parseFrontmatter } = (init_text(), require_rolldown_runtime.__toCommonJS(text_exports));
4640
+ const { parseFrontmatter } = (require_text.init_text(), require_rolldown_runtime.__toCommonJS(require_text.text_exports));
4712
4641
  const ds = await getOrm(dbFile);
4713
4642
  let count = 0;
4714
4643
  for (const entry of fs2.readdirSync(skillsDir)) {
@@ -5239,7 +5168,7 @@ function sqlLit(v) {
5239
5168
  }
5240
5169
  //#endregion
5241
5170
  //#region packages/ops/tools/src/config.ts
5242
- init_text();
5171
+ require_text.init_text();
5243
5172
  const CONFIG_REGISTRY = [
5244
5173
  {
5245
5174
  key: "eval.pass_threshold",
@@ -5352,11 +5281,11 @@ function configSet(db, key, value) {
5352
5281
  key,
5353
5282
  v,
5354
5283
  spec.note,
5355
- nowIso()
5284
+ require_text.nowIso()
5356
5285
  ]);
5357
5286
  db.run("INSERT INTO events(id,ts,actor,kind,entity,entity_id,payload) VALUES(?,?,?,?,?,?,?)", [
5358
5287
  `${key}-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`,
5359
- nowIso(),
5288
+ require_text.nowIso(),
5360
5289
  "cli",
5361
5290
  "config.set",
5362
5291
  "config",
@@ -5469,7 +5398,7 @@ function run$11(env, action, rest, args) {
5469
5398
  * Writes (add) run on the TypeORM write service (src/writes.ts). */
5470
5399
  var job_cmds_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({ run: () => run$10 });
5471
5400
  init_fmt();
5472
- init_text();
5401
+ require_text.init_text();
5473
5402
  init_orm();
5474
5403
  init_writes();
5475
5404
  function run$10(env, action, rest, args) {
@@ -5617,7 +5546,7 @@ function execute(env, job) {
5617
5546
  store.jobFinish(runId, rc, output);
5618
5547
  if (rc === 0) ok(ctx, `${job.title} ok ${ms}ms`);
5619
5548
  else bad(ctx, `${job.title} rc=${rc} ${output.slice(0, 160)}`);
5620
- store.log("job.run", "job", job.id, `rc=${rc} ${nowIso()}`);
5549
+ store.log("job.run", "job", job.id, `rc=${rc} ${require_text.nowIso()}`);
5621
5550
  }
5622
5551
  /**
5623
5552
  * Concurrency guard for `job tick`: mkdir-based lock (same primitive the
@@ -5677,7 +5606,7 @@ var agent_cmds_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
5677
5606
  run: () => run$9
5678
5607
  });
5679
5608
  init_fmt();
5680
- init_text();
5609
+ require_text.init_text();
5681
5610
  /** Build the brief payload (where am I / what exists / what next).
5682
5611
  * Shared by the `agent brief` command and the WebUI dashboard. */
5683
5612
  function buildBrief(env) {
@@ -5695,7 +5624,7 @@ function buildBrief(env) {
5695
5624
  counts: stats,
5696
5625
  top_skills: skills.map((s) => ({
5697
5626
  name: s.name,
5698
- description: clip(s.description, 120)
5627
+ description: require_text.clip(s.description, 120)
5699
5628
  })),
5700
5629
  recent_notes: notes.map((n) => ({
5701
5630
  id: n.id,
@@ -5722,7 +5651,7 @@ function buildBrief(env) {
5722
5651
  };
5723
5652
  payload.unverified_claims = claims.filter((c) => c.status !== "supported").map((c) => ({
5724
5653
  id: c.id,
5725
- text: clip(c.text, 80),
5654
+ text: require_text.clip(c.text, 80),
5726
5655
  status: c.status
5727
5656
  }));
5728
5657
  if (!src.length) payload.next_actions.push(`ygl-trees research source add --title "..." --url "..."`);
@@ -5930,7 +5859,7 @@ function run$9(env, action, rest, args) {
5930
5859
  out(ctx, ` counts skills ${stats.skills} · kb ${stats.kb_notes} · jobs ${stats.jobs} · events ${stats.events}`);
5931
5860
  if (skills.length) {
5932
5861
  out(ctx, paint(C.bold, "\n available skills", ctx.color));
5933
- for (const s of skills) out(ctx, ` - ${s.name} ${paint(C.dim, clip(s.description, 90), ctx.color)}`);
5862
+ for (const s of skills) out(ctx, ` - ${s.name} ${paint(C.dim, require_text.clip(s.description, 90), ctx.color)}`);
5934
5863
  }
5935
5864
  out(ctx, paint(C.bold, "\n next actions", ctx.color));
5936
5865
  for (const a of payload.next_actions) out(ctx, ` → ${a}`);
@@ -6220,7 +6149,7 @@ var init_eval_enhance = require_rolldown_runtime.__esmMin((() => {
6220
6149
  * List commands run on TypeORM (src/orm.ts); search stays raw SQL (FTS5). */
6221
6150
  var cmds_exports$2 = /* @__PURE__ */ require_rolldown_runtime.__exportAll({ run: () => run$8 });
6222
6151
  init_fmt();
6223
- init_text();
6152
+ require_text.init_text();
6224
6153
  init_orm();
6225
6154
  init_writes();
6226
6155
  init_entities$1();
@@ -6261,7 +6190,7 @@ function run$8(env, action, rest, args) {
6261
6190
  return 2;
6262
6191
  }
6263
6192
  const engine = String(args.flags.engine || "");
6264
- return runWrite(env, (ds) => queryAdd(ds, project.id, text, engine, force), (r) => `query registered: ${r.id} ${clip(text, 60)}`);
6193
+ return runWrite(env, (ds) => queryAdd(ds, project.id, text, engine, force), (r) => `query registered: ${r.id} ${require_text.clip(text, 60)}`);
6265
6194
  }
6266
6195
  if (subAction === "attach") {
6267
6196
  if (!rest[1] || !rest[2]) {
@@ -6271,7 +6200,7 @@ function run$8(env, action, rest, args) {
6271
6200
  const note = String(args.flags.note || "");
6272
6201
  return getOrm(env.db.path).then((ds) => queryAttach(ds, project.id, rest[1], rest[2], note)).then((r) => {
6273
6202
  if (r.dup) out(ctx, paint(C.yellow, ` ! already attached: ${r.sourceId}`, ctx.color));
6274
- else ok(ctx, `attached: ${clip(r.sourceTitle || r.sourceId, 40)} → "${clip(r.queryText, 40)}"`);
6203
+ else ok(ctx, `attached: ${require_text.clip(r.sourceTitle || r.sourceId, 40)} → "${require_text.clip(r.queryText, 40)}"`);
6275
6204
  return 0;
6276
6205
  }).catch((e) => {
6277
6206
  bad(ctx, e?.message || String(e));
@@ -6357,7 +6286,7 @@ function run$8(env, action, rest, args) {
6357
6286
  return 2;
6358
6287
  }
6359
6288
  if (url && !/^https?:\/\/|^file:\/\//.test(url)) {
6360
- bad(ctx, `--url must be http(s):// or file:// (got: "${clip(url, 30)}")`);
6289
+ bad(ctx, `--url must be http(s):// or file:// (got: "${require_text.clip(url, 30)}")`);
6361
6290
  return 2;
6362
6291
  }
6363
6292
  const spec = {
@@ -6373,10 +6302,10 @@ function run$8(env, action, rest, args) {
6373
6302
  const qRef = String(args.flags.query || "");
6374
6303
  return getOrm(env.db.path).then(async (ds) => {
6375
6304
  const r = await sourceAdd(ds, project.id, spec);
6376
- writeResult(ctx, r, (row) => `source added: ${row.id} ${clip(row.title, 60)}`);
6305
+ writeResult(ctx, r, (row) => `source added: ${row.id} ${require_text.clip(row.title, 60)}`);
6377
6306
  if (qRef) {
6378
6307
  const at = await queryAttach(ds, project.id, qRef, r.row.id);
6379
- if (!ctx.json && !at.dup) out(ctx, paint(C.dim, ` attached to query: "${clip(at.queryText, 40)}"`, ctx.color));
6308
+ if (!ctx.json && !at.dup) out(ctx, paint(C.dim, ` attached to query: "${require_text.clip(at.queryText, 40)}"`, ctx.color));
6380
6309
  }
6381
6310
  return 0;
6382
6311
  }).catch((e) => {
@@ -6419,7 +6348,7 @@ function run$8(env, action, rest, args) {
6419
6348
  confidence: String(args.flags.confidence || configGet(env.db, "default_confidence")),
6420
6349
  tags: String(args.flags.tags || (thin ? "needs_review" : ""))
6421
6350
  });
6422
- writeResult(ctx, r, (row) => `fetched: ${row.id} ${clip(title, 60)}`);
6351
+ writeResult(ctx, r, (row) => `fetched: ${row.id} ${require_text.clip(title, 60)}`);
6423
6352
  if (!ctx.json) out(ctx, paint(C.dim, ` ${(text.length / 1e3).toFixed(1)}k chars text · ${metaDesc ? "meta description" : "no meta"}${thin ? " · thin content → tagged needs_review" : ""}`, ctx.color));
6424
6353
  return 0;
6425
6354
  }).catch((e) => {
@@ -6477,7 +6406,7 @@ function run$8(env, action, rest, args) {
6477
6406
  }
6478
6407
  table(ctx, store.sourceSearch(project.id, q).map((r) => ({
6479
6408
  id: r.id,
6480
- title: clip(r.title, 50),
6409
+ title: require_text.clip(r.title, 50),
6481
6410
  rel: r.relevance,
6482
6411
  conf: r.confidence,
6483
6412
  score: typeof r.score === "number" ? r.score.toFixed(2) : "-"
@@ -6531,7 +6460,7 @@ function run$8(env, action, rest, args) {
6531
6460
  }
6532
6461
  const note = String(args.flags.note || "");
6533
6462
  const locator = String(args.flags.locator || "");
6534
- return runWrite(env, (ds) => evidenceAdd(ds, project.id, sourceId, quote, note, locator, force), (r) => `evidence added: ${r.id} ${clip(quote, 50)}`);
6463
+ return runWrite(env, (ds) => evidenceAdd(ds, project.id, sourceId, quote, note, locator, force), (r) => `evidence added: ${r.id} ${require_text.clip(quote, 50)}`);
6535
6464
  }
6536
6465
  if (action === "evidence" && subAction === "assess") {
6537
6466
  const id = rest[1];
@@ -6564,7 +6493,7 @@ function run$8(env, action, rest, args) {
6564
6493
  else {
6565
6494
  head(ctx, `evidence assess: ${id}`);
6566
6495
  show(ctx, {
6567
- 引文: clip(ev.quote, 60),
6496
+ 引文: require_text.clip(ev.quote, 60),
6568
6497
  来源: ev.source_title || "-",
6569
6498
  模型评分: result.quality_score !== null ? `${result.quality_score}/5` : "离线",
6570
6499
  可靠性: result.reliability
@@ -6586,7 +6515,7 @@ function run$8(env, action, rest, args) {
6586
6515
  id: e.id,
6587
6516
  source: e.source?.title ?? "",
6588
6517
  locator: e.locator,
6589
- quote: clip(e.quote, 60),
6518
+ quote: require_text.clip(e.quote, 60),
6590
6519
  used_by: e.claimEvidence?.length ?? 0
6591
6520
  }));
6592
6521
  table(ctx, rows, [
@@ -6622,7 +6551,7 @@ function run$8(env, action, rest, args) {
6622
6551
  return 2;
6623
6552
  }
6624
6553
  const confidence = String(args.flags.confidence || configGet(env.db, "default_confidence"));
6625
- return runWrite(env, (ds) => claimAdd(ds, project.id, text, confidence, force), (r) => `claim added: ${r.id} ${clip(text, 60)}`);
6554
+ return runWrite(env, (ds) => claimAdd(ds, project.id, text, confidence, force), (r) => `claim added: ${r.id} ${require_text.clip(text, 60)}`);
6626
6555
  }
6627
6556
  if (subAction === "link") {
6628
6557
  if (!rest[1] || !rest[2]) {
@@ -6744,7 +6673,7 @@ function run$8(env, action, rest, args) {
6744
6673
  else {
6745
6674
  head(ctx, `claim evaluate: ${id}`);
6746
6675
  show(ctx, {
6747
- 断言: clip(claim.text, 60),
6676
+ 断言: require_text.clip(claim.text, 60),
6748
6677
  当前状态: claim.status,
6749
6678
  当前置信度: claim.confidence,
6750
6679
  模型评分: result.confidence_score !== null ? `${result.confidence_score}/5` : "离线",
@@ -6763,7 +6692,7 @@ function run$8(env, action, rest, args) {
6763
6692
  order: { created: "ASC" }
6764
6693
  })).map((c) => ({
6765
6694
  id: c.id,
6766
- text: clip(c.text, 60),
6695
+ text: require_text.clip(c.text, 60),
6767
6696
  status: c.status,
6768
6697
  confidence: c.confidence,
6769
6698
  sup: (c.claimEvidence ?? []).filter((ce) => ce.stance === "supports").length,
@@ -6936,7 +6865,7 @@ function run$7(env, action, rest, args) {
6936
6865
  * Store until their own migration batch. */
6937
6866
  var produce_cmds_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({ run: () => run$6 });
6938
6867
  init_fmt();
6939
- init_text();
6868
+ require_text.init_text();
6940
6869
  init_orm();
6941
6870
  init_writes();
6942
6871
  function run$6(env, action, rest, args) {
@@ -6983,7 +6912,7 @@ function run$6(env, action, rest, args) {
6983
6912
  lines.push("", "## 证据基础", "");
6984
6913
  const ev = store.evidenceList(pid);
6985
6914
  if (!ev.length) lines.push("_(尚无 evidence)_", "");
6986
- ev.forEach((e, i) => lines.push(`- [${i + 1}] ${e.source}:${clip(e.quote, 80)}`));
6915
+ ev.forEach((e, i) => lines.push(`- [${i + 1}] ${e.source}:${require_text.clip(e.quote, 80)}`));
6987
6916
  const content = lines.join("\n");
6988
6917
  return getOrm(env.db.path).then((ds) => artifactAdd(ds, pid, "outline", `${project.name} outline`, content)).then((r) => {
6989
6918
  if (ctx.json) console.log(JSON.stringify(r.row, null, 2));
@@ -7229,9 +7158,9 @@ function run$6(env, action, rest, args) {
7229
7158
  //#endregion
7230
7159
  //#region packages/techtree/model/src/writes.ts
7231
7160
  init_db();
7232
- init_text();
7161
+ require_text.init_text();
7233
7162
  async function markDirty(mgr, treeId) {
7234
- await mgr.query(`INSERT INTO node_index(tree_id,built_at,dirty) VALUES(?,?,1) ON CONFLICT(tree_id) DO UPDATE SET dirty=1`, [treeId, nowIso()]);
7163
+ await mgr.query(`INSERT INTO node_index(tree_id,built_at,dirty) VALUES(?,?,1) ON CONFLICT(tree_id) DO UPDATE SET dirty=1`, [treeId, require_text.nowIso()]);
7235
7164
  }
7236
7165
  /** R10.1 (0.30): tree-domain audit trail — overturns the 0.12 "no events"
7237
7166
  * exception. Same shape as the research-domain logEvent (raw SQL here since
@@ -7243,8 +7172,8 @@ async function logEvent(mgr, kind, entityId, payload, level = "info") {
7243
7172
  run
7244
7173
  }) : JSON.stringify(payload ?? {});
7245
7174
  await mgr.query(`INSERT INTO events(id,ts,actor,kind,entity,entity_id,payload,level) VALUES(?,?,?,?,?,?,?,?)`, [
7246
- shortId([kind, entityId], 12),
7247
- nowIso(),
7175
+ require_text.shortId([kind, entityId], 12),
7176
+ require_text.nowIso(),
7248
7177
  "cli",
7249
7178
  kind,
7250
7179
  "node",
@@ -7373,7 +7302,7 @@ async function buildIndex(mgr, treeId) {
7373
7302
  JSON.stringify(topo),
7374
7303
  JSON.stringify(tiers),
7375
7304
  JSON.stringify(inDegree),
7376
- nowIso()
7305
+ require_text.nowIso()
7377
7306
  ]);
7378
7307
  return {
7379
7308
  topo,
@@ -7388,13 +7317,13 @@ async function treeCreate(ds, name, projectId = "", note = "") {
7388
7317
  ...existing[0],
7389
7318
  duplicate: true
7390
7319
  };
7391
- const id = shortId(["tree", name], 10);
7320
+ const id = require_text.shortId(["tree", name], 10);
7392
7321
  await mgr.query(`INSERT INTO trees(id,project_id,name,note,created) VALUES(?,?,?,?,?)`, [
7393
7322
  id,
7394
7323
  projectId || null,
7395
7324
  name,
7396
7325
  note,
7397
- nowIso()
7326
+ require_text.nowIso()
7398
7327
  ]);
7399
7328
  await markDirty(mgr, id);
7400
7329
  return (await mgr.query(`SELECT * FROM trees WHERE id=?`, [id]))[0];
@@ -7407,7 +7336,7 @@ async function nodeAdd(ds, treeId, o) {
7407
7336
  row: ex[0],
7408
7337
  created: false
7409
7338
  };
7410
- const id = shortId([
7339
+ const id = require_text.shortId([
7411
7340
  "node",
7412
7341
  treeId,
7413
7342
  o.key
@@ -7424,14 +7353,14 @@ async function nodeAdd(ds, treeId, o) {
7424
7353
  o.cost_unit || "",
7425
7354
  o.payload || "",
7426
7355
  o.tags || "",
7427
- nowIso()
7356
+ require_text.nowIso()
7428
7357
  ]);
7429
7358
  await mgr.query(`INSERT INTO nodes_fts(id,key,name,tags,ngram) VALUES(?,?,?,?,?)`, [
7430
7359
  id,
7431
7360
  o.key,
7432
7361
  name,
7433
7362
  o.tags || "",
7434
- ngram(`${o.key} ${name} ${o.tags || ""}`)
7363
+ require_text.ngram(`${o.key} ${name} ${o.tags || ""}`)
7435
7364
  ]);
7436
7365
  await markDirty(mgr, treeId);
7437
7366
  await logEvent(mgr, "node.add", id, {
@@ -7492,7 +7421,7 @@ async function link(ds, treeId, parentKey, childKey, o = {}) {
7492
7421
  rel
7493
7422
  ]);
7494
7423
  const duplicate = before.length > 0;
7495
- const id = duplicate ? before[0].id : shortId([
7424
+ const id = duplicate ? before[0].id : require_text.shortId([
7496
7425
  "edge",
7497
7426
  p[0].id,
7498
7427
  c[0].id,
@@ -7513,7 +7442,7 @@ async function link(ds, treeId, parentKey, childKey, o = {}) {
7513
7442
  o.min_level ?? 1,
7514
7443
  o.weight ?? 1,
7515
7444
  o.note || "",
7516
- nowIso()
7445
+ require_text.nowIso()
7517
7446
  ]);
7518
7447
  await rebuildClosure(mgr, treeId);
7519
7448
  await logEvent(mgr, "node.link", id, {
@@ -7574,7 +7503,7 @@ async function condAdd(ds, treeId, keyOrId, o) {
7574
7503
  if (!n.length) throw new Error(`node not found: ${keyOrId}`);
7575
7504
  const kind = o.kind || "flag";
7576
7505
  if (!COND_KINDS.includes(kind)) throw new Error(`kind must be one of ${COND_KINDS.join("|")}`);
7577
- const id = shortId([
7506
+ const id = require_text.shortId([
7578
7507
  "cond",
7579
7508
  n[0].id,
7580
7509
  o.name
@@ -7621,7 +7550,7 @@ async function stateSet(ds, treeId, keyOrId, status, context = "default", level
7621
7550
  status,
7622
7551
  level,
7623
7552
  status === "unlocked" ? 1 : 0,
7624
- nowIso()
7553
+ require_text.nowIso()
7625
7554
  ]);
7626
7555
  await logEvent(mgr, status === "unlocked" ? "node.unlock" : "node.lock", n[0].id, {
7627
7556
  tree: treeId,
@@ -7714,13 +7643,13 @@ async function importTree(ds, spec, opts = {}) {
7714
7643
  let tid;
7715
7644
  if (existing.length) tid = existing[0].id;
7716
7645
  else {
7717
- tid = shortId(["tree", name], 10);
7646
+ tid = require_text.shortId(["tree", name], 10);
7718
7647
  await mgr.query(`INSERT INTO trees(id,project_id,name,note,created) VALUES(?,?,?,?,?)`, [
7719
7648
  tid,
7720
7649
  null,
7721
7650
  name,
7722
7651
  String(spec.tree?.note || ""),
7723
- nowIso()
7652
+ require_text.nowIso()
7724
7653
  ]);
7725
7654
  }
7726
7655
  const nodeId = /* @__PURE__ */ new Map();
@@ -7730,7 +7659,7 @@ async function importTree(ds, spec, opts = {}) {
7730
7659
  nodeId.set(String(n.key), ex[0].id);
7731
7660
  continue;
7732
7661
  }
7733
- const id = shortId([
7662
+ const id = require_text.shortId([
7734
7663
  "node",
7735
7664
  tid,
7736
7665
  String(n.key)
@@ -7748,14 +7677,14 @@ async function importTree(ds, spec, opts = {}) {
7748
7677
  n.cost_unit === void 0 ? "" : String(n.cost_unit),
7749
7678
  n.payload === void 0 || n.payload === null ? "" : typeof n.payload === "object" ? JSON.stringify(n.payload) : String(n.payload),
7750
7679
  n.tags === void 0 ? "" : String(n.tags),
7751
- nowIso()
7680
+ require_text.nowIso()
7752
7681
  ]);
7753
7682
  await mgr.query(`INSERT INTO nodes_fts(id,key,name,tags,ngram) VALUES(?,?,?,?,?)`, [
7754
7683
  id,
7755
7684
  String(n.key),
7756
7685
  nm,
7757
7686
  n.tags === void 0 ? "" : String(n.tags),
7758
- ngram(`${n.key} ${nm} ${n.tags || ""}`)
7687
+ require_text.ngram(`${n.key} ${nm} ${n.tags || ""}`)
7759
7688
  ]);
7760
7689
  }
7761
7690
  for (const e of edges) {
@@ -7766,7 +7695,7 @@ async function importTree(ds, spec, opts = {}) {
7766
7695
  ON CONFLICT(parent_id,child_id,rel) DO UPDATE SET
7767
7696
  mode=excluded.mode, required=excluded.required, min_level=excluded.min_level,
7768
7697
  weight=excluded.weight, note=excluded.note`, [
7769
- shortId([
7698
+ require_text.shortId([
7770
7699
  "edge",
7771
7700
  tid,
7772
7701
  pid,
@@ -7782,7 +7711,7 @@ async function importTree(ds, spec, opts = {}) {
7782
7711
  Number(e.min_level ?? 1),
7783
7712
  Number(e.weight ?? 1),
7784
7713
  String(e.note || ""),
7785
- nowIso()
7714
+ require_text.nowIso()
7786
7715
  ]);
7787
7716
  }
7788
7717
  for (const c of conds) {
@@ -7790,7 +7719,7 @@ async function importTree(ds, spec, opts = {}) {
7790
7719
  await mgr.query(`DELETE FROM node_conditions WHERE node_id=? AND name=?`, [nid, String(c.name)]);
7791
7720
  await mgr.query(`INSERT INTO node_conditions(id,node_id,name,kind,expr,op,value,required,effect,weight,note)
7792
7721
  VALUES(?,?,?,?,?,?,?,?,?,?,?)`, [
7793
- shortId([
7722
+ require_text.shortId([
7794
7723
  "cond",
7795
7724
  tid,
7796
7725
  nid,
@@ -7839,7 +7768,7 @@ var cmds_exports$1 = /* @__PURE__ */ require_rolldown_runtime.__exportAll({ run:
7839
7768
  init_fmt();
7840
7769
  init_orm();
7841
7770
  init_eval();
7842
- init_text();
7771
+ require_text.init_text();
7843
7772
  function run$5(env, action, rest, args) {
7844
7773
  const { ctx, db } = env;
7845
7774
  const trees = new TreeStore(db);
@@ -8193,12 +8122,12 @@ function run$5(env, action, rest, args) {
8193
8122
  try {
8194
8123
  const run = process.env.YGL_RUN_ID || "";
8195
8124
  db.run("INSERT INTO events(id,ts,actor,kind,entity,entity_id,payload,level) VALUES(?,?,?,?,?,?,?,'info')", [
8196
- shortId([
8125
+ require_text.shortId([
8197
8126
  "eval.gate",
8198
8127
  "node",
8199
8128
  key
8200
8129
  ], 12),
8201
- nowIso(),
8130
+ require_text.nowIso(),
8202
8131
  "cli",
8203
8132
  "eval.gate",
8204
8133
  "node",
@@ -8376,12 +8305,12 @@ function run$5(env, action, rest, args) {
8376
8305
  try {
8377
8306
  const run = process.env.YGL_RUN_ID || "";
8378
8307
  db.run("INSERT INTO events(id,ts,actor,kind,entity,entity_id,payload,level) VALUES(?,?,?,?,?,?,?,'info')", [
8379
- shortId([
8308
+ require_text.shortId([
8380
8309
  "eval.ready",
8381
8310
  "tree",
8382
8311
  tid
8383
8312
  ], 12),
8384
- nowIso(),
8313
+ require_text.nowIso(),
8385
8314
  "cli",
8386
8315
  "eval.ready",
8387
8316
  "tree",
@@ -8684,7 +8613,7 @@ function parseState(args) {
8684
8613
  * Writes run on the TypeORM write service (src/writes.ts). */
8685
8614
  var skill_cmds_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({ run: () => run$4 });
8686
8615
  init_fmt();
8687
- init_text();
8616
+ require_text.init_text();
8688
8617
  init_orm();
8689
8618
  init_writes();
8690
8619
  function run$4(env, action, rest, args) {
@@ -8700,7 +8629,8 @@ function run$4(env, action, rest, args) {
8700
8629
  switch (action) {
8701
8630
  case "import": {
8702
8631
  if (!need(name, "file")) return 2;
8703
- const { meta, body } = parseFrontmatter(node_fs.readFileSync(name, "utf8"));
8632
+ const raw = node_fs.readFileSync(name, "utf8");
8633
+ const { meta, body } = require_text.parseFrontmatter(raw);
8704
8634
  const spec = {
8705
8635
  name: meta.name || node_path.basename(name, ".md"),
8706
8636
  description: meta.description || "",
@@ -8825,7 +8755,23 @@ function run$4(env, action, rest, args) {
8825
8755
  return 0;
8826
8756
  case "link": {
8827
8757
  const os = require("node:os");
8828
- const targetDir = args?.flags?.global === true ? node_path.join(os.homedir(), ".agents", "skills") : node_path.join(process.cwd(), ".agents", "skills");
8758
+ const globalFlag = args?.flags?.global === true;
8759
+ const aiName = String(args?.flags?.ai || "").toLowerCase();
8760
+ const customTo = String(args?.flags?.to || "");
8761
+ const AI_SKILL_DIRS = {
8762
+ pi: () => node_path.join(os.homedir(), ".pi", "agent", "skills"),
8763
+ claude: () => node_path.join(os.homedir(), ".claude", "skills"),
8764
+ cursor: () => node_path.join(os.homedir(), ".cursor", "skills"),
8765
+ windsurf: () => node_path.join(os.homedir(), ".windsurf", "skills")
8766
+ };
8767
+ let targetDir;
8768
+ if (customTo) targetDir = node_path.resolve(customTo);
8769
+ else if (aiName && AI_SKILL_DIRS[aiName]) targetDir = AI_SKILL_DIRS[aiName]();
8770
+ else if (aiName && aiName !== "custom") {
8771
+ bad(ctx, `unknown AI agent: ${aiName}`);
8772
+ out(ctx, ` supported: ${Object.keys(AI_SKILL_DIRS).join(", ")} | custom (with --to <path>)`);
8773
+ return 2;
8774
+ } else targetDir = globalFlag ? node_path.join(os.homedir(), ".agents", "skills") : node_path.join(process.cwd(), ".agents", "skills");
8829
8775
  let skillsDir = null;
8830
8776
  for (let dir = process.cwd(), i = 0; i < 6; i++, dir = node_path.dirname(dir)) {
8831
8777
  const candidate = node_path.join(dir, "skills");
@@ -9002,7 +8948,7 @@ function wrap(text, indent = 4) {
9002
8948
  * Writes (add/ingest) run on the TypeORM write service (src/writes.ts). */
9003
8949
  var cmds_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({ run: () => run$3 });
9004
8950
  init_fmt();
9005
- init_text();
8951
+ require_text.init_text();
9006
8952
  init_orm();
9007
8953
  init_writes();
9008
8954
  function run$3(env, action, rest, args) {
@@ -9035,7 +8981,7 @@ function run$3(env, action, rest, args) {
9035
8981
  confidence: String(args.flags.confidence || configGet(env.db, "default_confidence")),
9036
8982
  force
9037
8983
  })).then((r) => {
9038
- writeResult(ctx, r, (row) => `note stored: ${row.id} ${clip(title, 50)}`);
8984
+ writeResult(ctx, r, (row) => `note stored: ${row.id} ${require_text.clip(title, 50)}`);
9039
8985
  return 0;
9040
8986
  }).catch((e) => {
9041
8987
  bad(ctx, e?.message || String(e));
@@ -9061,7 +9007,7 @@ function run$3(env, action, rest, args) {
9061
9007
  const orig = idToRaw.get(rr.id);
9062
9008
  return {
9063
9009
  id: rr.id,
9064
- title: clip(orig.title, 42),
9010
+ title: require_text.clip(orig.title, 42),
9065
9011
  semantic: rr.semantic_relevance !== null ? rr.semantic_relevance.toFixed(2) : "离线",
9066
9012
  orig_rank: rr.original_rank,
9067
9013
  tags: orig.tags || "-",
@@ -9093,7 +9039,7 @@ function run$3(env, action, rest, args) {
9093
9039
  }
9094
9040
  table(ctx, raw.map((r) => ({
9095
9041
  id: r.id,
9096
- title: clip(r.title, 46),
9042
+ title: require_text.clip(r.title, 46),
9097
9043
  tags: r.tags || "-",
9098
9044
  conf: r.confidence,
9099
9045
  reuse: r.reuse,
@@ -9194,7 +9140,7 @@ function run$3(env, action, rest, args) {
9194
9140
  }
9195
9141
  const forceKb = args.flags.force === true || args.flags.force === "true";
9196
9142
  return getOrm(env.db.path).then((ds) => kbIngestArtifact(ds, rest[0], forceKb)).then((r) => {
9197
- writeResult(ctx, r, (row) => `artifact ingested into kb: ${row.id} ${clip(row.title, 50)}`);
9143
+ writeResult(ctx, r, (row) => `artifact ingested into kb: ${row.id} ${require_text.clip(row.title, 50)}`);
9198
9144
  return 0;
9199
9145
  }).catch((e) => {
9200
9146
  bad(ctx, e?.message || String(e));
@@ -9220,7 +9166,7 @@ function run$3(env, action, rest, args) {
9220
9166
  origin: `kb:${note.id}`
9221
9167
  })).then((s) => {
9222
9168
  ok(ctx, `promoted to skill: ${s.name}`);
9223
- out(ctx, paint(C.dim, ` L1: ${clip(String(s.description), 100)}`, ctx.color));
9169
+ out(ctx, paint(C.dim, ` L1: ${require_text.clip(String(s.description), 100)}`, ctx.color));
9224
9170
  return 0;
9225
9171
  }).catch((e) => {
9226
9172
  bad(ctx, e?.message || String(e));
@@ -9270,7 +9216,8 @@ function run$3(env, action, rest, args) {
9270
9216
  return 1;
9271
9217
  }
9272
9218
  const items = importable.map((f) => {
9273
- const { meta, body } = parseFrontmatter(node_fs.readFileSync(f, "utf8"));
9219
+ const raw = node_fs.readFileSync(f, "utf8");
9220
+ const { meta, body } = require_text.parseFrontmatter(raw);
9274
9221
  const heading = /^#\s+(.+)\s*$/m.exec(body)?.[1]?.trim();
9275
9222
  return {
9276
9223
  title: meta.title || meta.name || heading || node_path.basename(f, ".md"),
@@ -9315,7 +9262,7 @@ var rels_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
9315
9262
  run: () => run$2
9316
9263
  });
9317
9264
  init_fmt();
9318
- init_text();
9265
+ require_text.init_text();
9319
9266
  init_orm();
9320
9267
  const REL_TYPES = [
9321
9268
  "node",
@@ -9448,7 +9395,7 @@ async function relAdd(env, srcRef, dstRef, rel = "related") {
9448
9395
  row: (await mgr.query(`SELECT * FROM relations WHERE id=?`, [ex[0].id]))[0],
9449
9396
  duplicate: true
9450
9397
  };
9451
- const id = shortId([
9398
+ const id = require_text.shortId([
9452
9399
  "rel",
9453
9400
  src.id,
9454
9401
  dst.id,
@@ -9461,15 +9408,15 @@ async function relAdd(env, srcRef, dstRef, rel = "related") {
9461
9408
  dst.type,
9462
9409
  dst.id,
9463
9410
  rel,
9464
- nowIso()
9411
+ require_text.nowIso()
9465
9412
  ]);
9466
9413
  await mgr.query(`INSERT INTO events(id,ts,actor,kind,entity,entity_id,payload) VALUES(?,?,?,?,?,?,?)`, [
9467
- shortId([
9414
+ require_text.shortId([
9468
9415
  "ev",
9469
9416
  "rel.add",
9470
9417
  id
9471
9418
  ], 12),
9472
- nowIso(),
9419
+ require_text.nowIso(),
9473
9420
  "cli",
9474
9421
  "rel.add",
9475
9422
  "relation",
@@ -11113,6 +11060,20 @@ async function main(argv) {
11113
11060
  });
11114
11061
  } catch (e) {
11115
11062
  if (e instanceof StartupError) {
11063
+ if (group === "plugin") {
11064
+ const pluginCmds = await Promise.resolve().then(() => plugin_exports);
11065
+ const { dbPath } = await Promise.resolve().then(() => (init_db(), db_exports));
11066
+ const env2 = {
11067
+ home,
11068
+ dbFile: dbPath(home),
11069
+ ctx,
11070
+ db: null,
11071
+ store: null,
11072
+ cordis: null
11073
+ };
11074
+ out(ctx, paint(C.yellow, " ! degraded mode: user plugins failed to load — plugin commands only", ctx.color));
11075
+ return pluginCmds.runPluginCommand(env2, action || "list", args._.slice(2), args);
11076
+ }
11116
11077
  reportStartupFailure(e, home, VERSION);
11117
11078
  return 1;
11118
11079
  }