ygl-trees 0.76.1 → 0.77.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/apps/cli/src/bin.js +15 -0
- package/dist/bundle/bin.cjs +178 -263
- package/dist/bundle/text-Bce0wNAD.cjs +172 -0
- package/dist/packages/ops/tools/src/plugins.js +33 -4
- package/package.json +2 -2
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-C96Ew50Q.cjs");
|
|
2
|
+
//#region packages/core/text/src/text.ts
|
|
3
|
+
var text_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
|
|
4
|
+
clip: () => clip,
|
|
5
|
+
contentHash: () => contentHash,
|
|
6
|
+
ngram: () => ngram,
|
|
7
|
+
nowIso: () => nowIso,
|
|
8
|
+
parseFrontmatter: () => parseFrontmatter,
|
|
9
|
+
sha1: () => sha1,
|
|
10
|
+
shortId: () => shortId,
|
|
11
|
+
slug: () => slug,
|
|
12
|
+
splitTags: () => splitTags,
|
|
13
|
+
stampId: () => stampId
|
|
14
|
+
});
|
|
15
|
+
function nowIso() {
|
|
16
|
+
const d = /* @__PURE__ */ new Date();
|
|
17
|
+
const p = (n) => String(n).padStart(2, "0");
|
|
18
|
+
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
|
|
19
|
+
}
|
|
20
|
+
function stampId() {
|
|
21
|
+
const d = /* @__PURE__ */ new Date();
|
|
22
|
+
const p = (n) => String(n).padStart(2, "0");
|
|
23
|
+
return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`;
|
|
24
|
+
}
|
|
25
|
+
function slug(text, limit = 40) {
|
|
26
|
+
const s = (text || "").trim().toLowerCase().replace(new RegExp(`[^\\w${CJK}]+`, "gu"), "-").replace(/^-+|-+$/g, "");
|
|
27
|
+
if (s.length <= limit) return s || "item";
|
|
28
|
+
return s.slice(0, limit).replace(/-+$/, "") || "item";
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Tokenize mixed Chinese/English text for SQLite FTS5.
|
|
32
|
+
*
|
|
33
|
+
* FTS5's default unicode61 tokenizer treats a whole CJK sentence as one token,
|
|
34
|
+
* which makes Chinese search degrade to exact match. We expand CJK runs into
|
|
35
|
+
* character bigrams and keep latin words intact.
|
|
36
|
+
*/
|
|
37
|
+
function ngram(text) {
|
|
38
|
+
const src = (text || "").normalize("NFKC").toLowerCase();
|
|
39
|
+
const out = [];
|
|
40
|
+
const segs = src.match(CJK_RUN_RE) || [];
|
|
41
|
+
for (const seg of segs) if (CJK_ONLY_RE.test(seg)) {
|
|
42
|
+
if (seg.length === 1) out.push(seg);
|
|
43
|
+
else for (let i = 0; i < seg.length - 1; i++) out.push(seg.slice(i, i + 2));
|
|
44
|
+
} else {
|
|
45
|
+
const w = seg.replace(/^[^\w]+|[^\w]+$/gu, "");
|
|
46
|
+
if (w) out.push(w);
|
|
47
|
+
}
|
|
48
|
+
return out.join(" ");
|
|
49
|
+
}
|
|
50
|
+
function sha1(text) {
|
|
51
|
+
return require("node:crypto").createHash("sha1").update(text || "").digest("hex");
|
|
52
|
+
}
|
|
53
|
+
/** Content hash for idempotent writes (single source: store writes and the
|
|
54
|
+
* TypeORM write service must produce identical hashes); --force salts it
|
|
55
|
+
* so a duplicate row is explicitly distinct (queryable via `db dups`). */
|
|
56
|
+
function contentHash(content, force) {
|
|
57
|
+
return sha1(content) + (force ? `#f${Date.now()}${Math.random()}` : "");
|
|
58
|
+
}
|
|
59
|
+
function shortId(parts, n = 8) {
|
|
60
|
+
return sha1(parts.join("|") + Date.now() + Math.random()).slice(0, n);
|
|
61
|
+
}
|
|
62
|
+
/** Truncate for table display, collapsing newlines. */
|
|
63
|
+
function clip(text, n = 40) {
|
|
64
|
+
const one = (text || "").replace(/\s+/g, " ").trim();
|
|
65
|
+
return one.length <= n ? one : one.slice(0, Math.max(1, n - 1)) + "…";
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Minimal SKILL.md frontmatter parser: supports `key: value`, quoted scalars,
|
|
69
|
+
* folded blocks (`>-` / `>`) and inline `a,b` lists.
|
|
70
|
+
*/
|
|
71
|
+
function parseFrontmatter(raw) {
|
|
72
|
+
const text = raw.replace(/^/, "");
|
|
73
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
|
|
74
|
+
if (!m) return {
|
|
75
|
+
meta: {},
|
|
76
|
+
body: text
|
|
77
|
+
};
|
|
78
|
+
const meta = {};
|
|
79
|
+
const lines = m[1].split(/\r?\n/);
|
|
80
|
+
let key = null;
|
|
81
|
+
let folded = null;
|
|
82
|
+
const flush = () => {
|
|
83
|
+
if (key && folded) meta[key] = folded.join(" ").replace(/\s+/g, " ").trim();
|
|
84
|
+
key = null;
|
|
85
|
+
folded = null;
|
|
86
|
+
};
|
|
87
|
+
for (const line of lines) {
|
|
88
|
+
const kv = /^([A-Za-z_][\w-]*)\s*:\s*(.*)$/.exec(line);
|
|
89
|
+
if (kv && !/^\s/.test(line)) {
|
|
90
|
+
flush();
|
|
91
|
+
key = kv[1];
|
|
92
|
+
const v = kv[2].trim();
|
|
93
|
+
if (v === ">-" || v === ">" || v === "|" || v === "|-") folded = [];
|
|
94
|
+
else {
|
|
95
|
+
meta[key] = v.replace(/^["']|["']$/g, "");
|
|
96
|
+
key = null;
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (key && folded) folded.push(line.trim());
|
|
101
|
+
}
|
|
102
|
+
flush();
|
|
103
|
+
return {
|
|
104
|
+
meta,
|
|
105
|
+
body: text.slice(m[0].length)
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function splitTags(v) {
|
|
109
|
+
return (v || "").split(/[,,;;\s]+/).map((s) => s.trim()).filter(Boolean);
|
|
110
|
+
}
|
|
111
|
+
var CJK, CJK_RUN_RE, CJK_ONLY_RE;
|
|
112
|
+
var init_text = require_rolldown_runtime.__esmMin((() => {
|
|
113
|
+
CJK = "\\u4e00-\\u9fff\\u3400-\\u4dbf\\uf900-\\ufaff";
|
|
114
|
+
new RegExp(`[${CJK}]`, "u");
|
|
115
|
+
CJK_RUN_RE = new RegExp(`[${CJK}]+|[^\\s${CJK}]+`, "gu");
|
|
116
|
+
CJK_ONLY_RE = new RegExp(`^[${CJK}]+$`, "u");
|
|
117
|
+
}));
|
|
118
|
+
//#endregion
|
|
119
|
+
Object.defineProperty(exports, "clip", {
|
|
120
|
+
enumerable: true,
|
|
121
|
+
get: function() {
|
|
122
|
+
return clip;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
Object.defineProperty(exports, "contentHash", {
|
|
126
|
+
enumerable: true,
|
|
127
|
+
get: function() {
|
|
128
|
+
return contentHash;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
Object.defineProperty(exports, "init_text", {
|
|
132
|
+
enumerable: true,
|
|
133
|
+
get: function() {
|
|
134
|
+
return init_text;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
Object.defineProperty(exports, "ngram", {
|
|
138
|
+
enumerable: true,
|
|
139
|
+
get: function() {
|
|
140
|
+
return ngram;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
Object.defineProperty(exports, "nowIso", {
|
|
144
|
+
enumerable: true,
|
|
145
|
+
get: function() {
|
|
146
|
+
return nowIso;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
Object.defineProperty(exports, "parseFrontmatter", {
|
|
150
|
+
enumerable: true,
|
|
151
|
+
get: function() {
|
|
152
|
+
return parseFrontmatter;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
Object.defineProperty(exports, "sha1", {
|
|
156
|
+
enumerable: true,
|
|
157
|
+
get: function() {
|
|
158
|
+
return sha1;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
Object.defineProperty(exports, "shortId", {
|
|
162
|
+
enumerable: true,
|
|
163
|
+
get: function() {
|
|
164
|
+
return shortId;
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
Object.defineProperty(exports, "text_exports", {
|
|
168
|
+
enumerable: true,
|
|
169
|
+
get: function() {
|
|
170
|
+
return text_exports;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
@@ -162,9 +162,16 @@ function pnpm(home, args) {
|
|
|
162
162
|
// there. Requires pnpm >= 9.4.
|
|
163
163
|
const pm = process.env.YGL_PACKAGE_MANAGER || "pnpm";
|
|
164
164
|
if (process.platform === "win32") {
|
|
165
|
-
const q = (s) => `"${String(s).replace(/["&|<>^]/g, "")}"`;
|
|
166
165
|
const exe = resolvePm(pm);
|
|
167
|
-
|
|
166
|
+
// DEP0190 fix (a2a 7aa5c871 cosmetic): avoid shell:true with args —
|
|
167
|
+
// invoke cmd explicitly instead, args are properly escaped by spawnSync.
|
|
168
|
+
const { spawnSync } = require("node:child_process");
|
|
169
|
+
const r = spawnSync("cmd", ["/c", exe, ...args, "--dir", profileDir(home), "--ignore-workspace"], { stdio: "pipe" });
|
|
170
|
+
if (r.status !== 0) {
|
|
171
|
+
const err = new Error(String(r.stderr || r.stdout || `pnpm exited ${r.status}`));
|
|
172
|
+
err.status = r.status;
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
168
175
|
return;
|
|
169
176
|
}
|
|
170
177
|
(0, node_child_process_1.execFileSync)(pm, [...args, "--dir", profileDir(home), "--ignore-workspace"], { stdio: "pipe" });
|
|
@@ -175,10 +182,10 @@ function resolvePm(pm) {
|
|
|
175
182
|
return cachedPm || pm;
|
|
176
183
|
cachedPm = null;
|
|
177
184
|
try {
|
|
178
|
-
const where = (0, node_child_process_1.execFileSync)("where", [pm], { stdio: "pipe", shell:
|
|
185
|
+
const where = (0, node_child_process_1.execFileSync)("where", [pm], { stdio: "pipe", shell: false }).toString().split(/\r?\n/).filter(Boolean);
|
|
179
186
|
for (const candidate of where) {
|
|
180
187
|
try {
|
|
181
|
-
(0, node_child_process_1.execFileSync)([
|
|
188
|
+
(0, node_child_process_1.execFileSync)("cmd", ["/c", candidate, "--version"], { stdio: "pipe" });
|
|
182
189
|
cachedPm = candidate;
|
|
183
190
|
return candidate;
|
|
184
191
|
}
|
|
@@ -194,6 +201,28 @@ const q2 = (s) => `"${String(s).replace(/["&|<>^]/g, "")}"`;
|
|
|
194
201
|
async function installPlugin(home, spec) {
|
|
195
202
|
initProfile(home);
|
|
196
203
|
const abs = path.resolve(spec);
|
|
204
|
+
// P0 fix (a2a 7aa5c871): validate local paths BEFORE recording anything —
|
|
205
|
+
// a bad path previously degraded to basename "plugin" and bricked the home.
|
|
206
|
+
if (fs.existsSync(abs) && fs.statSync(abs).isDirectory()) {
|
|
207
|
+
// P2 fix: read the real package name, never trust basename
|
|
208
|
+
const pkgPath = path.join(abs, "package.json");
|
|
209
|
+
if (!fs.existsSync(pkgPath)) {
|
|
210
|
+
throw new Error(`local plugin directory has no package.json: ${abs}`);
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
214
|
+
if (!pkg.name || typeof pkg.name !== "string") {
|
|
215
|
+
throw new Error(`package.json missing "name" field: ${abs}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (e) {
|
|
219
|
+
throw new Error(`invalid package.json in ${abs}: ${e?.message || e}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else if (spec.startsWith(".") || spec.startsWith("/") || spec.startsWith("\\") || /^[A-Z]:/.test(spec)) {
|
|
223
|
+
// Looks like a path but doesn't exist — reject before recording
|
|
224
|
+
throw new Error(`plugin path not found: ${abs}`);
|
|
225
|
+
}
|
|
197
226
|
const installSpec = fs.existsSync(abs) && fs.statSync(abs).isDirectory() ? `link:${abs}` : spec;
|
|
198
227
|
const existing = readUserBundle(home).find((p) => p.spec === installSpec || p.spec === spec);
|
|
199
228
|
if (existing)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ygl-trees",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.77.1",
|
|
4
4
|
"description": "猿光 · 科技树 — database-centric CLI for research → production → knowledge reuse, built for AI agents.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/apps/cli/index.js",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"node-sqlite3-wasm": "^0.8.61",
|
|
26
26
|
"reflect-metadata": "^0.2.2",
|
|
27
27
|
"typeorm": "^1.1.2",
|
|
28
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.2",
|
|
28
29
|
"@deepseek-ai/cordis-plugin-timer": "~1.1.7-alpha.2",
|
|
29
30
|
"@deepseek-ai/cosmokit": "~1.8.6-alpha.2",
|
|
30
|
-
"@deepseek-ai/cordis": "~4.0.5-alpha.2",
|
|
31
31
|
"@deepseek-ai/schemastery": "~3.18.5-alpha.2"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|