dsh-featherhunter-plugin-base 0.0.1 → 0.0.2-drill

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/node/cli.js CHANGED
@@ -1,26 +1,695 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/node/cli.ts
4
- import { readFileSync } from "node:fs";
4
+ import { readFileSync as readFileSync2 } from "node:fs";
5
+ import { resolve as resolve2 } from "node:path";
5
6
  import { pathToFileURL } from "node:url";
7
+
8
+ // src/node/readme-sync.ts
9
+ import { randomBytes } from "node:crypto";
10
+ import {
11
+ chmodSync,
12
+ existsSync,
13
+ readFileSync,
14
+ renameSync,
15
+ statSync,
16
+ unlinkSync,
17
+ writeFileSync
18
+ } from "node:fs";
19
+ import { basename, dirname, join, resolve } from "node:path";
20
+
21
+ // src/node/readme-compare.ts
22
+ var CONFLICT_START = /^\s*<{7}(?:\s|$)/;
23
+ var CONFLICT_SEPARATOR = /^\s*={7}\s*$/;
24
+ var CONFLICT_END = /^\s*>{7}(?:\s|$)/;
25
+ var MERGE_RESIDUE = /<{7}\s+\S|>{7}\s+\S/;
26
+ function findSuspiciousLines(markdown) {
27
+ const found = [];
28
+ markdown.split(/\r?\n/).forEach((line, index) => {
29
+ let reason = null;
30
+ if (CONFLICT_START.test(line)) reason = "conflict-start";
31
+ else if (CONFLICT_SEPARATOR.test(line)) reason = "conflict-separator";
32
+ else if (CONFLICT_END.test(line)) reason = "conflict-end";
33
+ else if (MERGE_RESIDUE.test(line)) reason = "merge-conflict-residue";
34
+ if (reason !== null) found.push({ line: index + 1, text: line, reason });
35
+ });
36
+ return found;
37
+ }
38
+ var NAMED_ENTITIES = {
39
+ amp: "&",
40
+ lt: "<",
41
+ gt: ">",
42
+ quot: '"',
43
+ apos: "'",
44
+ nbsp: " "
45
+ };
46
+ function decodeEntities(text) {
47
+ return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (entity, body) => {
48
+ if (body.startsWith("#x") || body.startsWith("#X")) {
49
+ const code = Number.parseInt(body.slice(2), 16);
50
+ return Number.isNaN(code) ? entity : String.fromCodePoint(code);
51
+ }
52
+ if (body.startsWith("#")) {
53
+ const code = Number.parseInt(body.slice(1), 10);
54
+ return Number.isNaN(code) ? entity : String.fromCodePoint(code);
55
+ }
56
+ return NAMED_ENTITIES[body.toLowerCase()] ?? entity;
57
+ });
58
+ }
59
+ function stripTags(html) {
60
+ let text = html.replace(/<!--[\s\S]*?-->/g, " ");
61
+ text = text.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1");
62
+ text = text.replace(/\[([^\]]*)\]\([^)]*\)/g, "$1");
63
+ text = text.replace(/<[^>]+>/g, " ");
64
+ text = decodeEntities(text);
65
+ return text.replace(/\s+/g, " ").trim();
66
+ }
67
+ function parseAttributes(attributeText) {
68
+ const attributes = {};
69
+ const pattern = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>\`]+)))?/g;
70
+ let match;
71
+ while ((match = pattern.exec(attributeText)) !== null) {
72
+ const value = match[2] ?? match[3] ?? match[4] ?? "";
73
+ attributes[match[1].toLowerCase()] = decodeEntities(value);
74
+ }
75
+ return attributes;
76
+ }
77
+ function assetName(src) {
78
+ const clean = src.split(/[?#]/)[0].trim();
79
+ const segments = clean.split(/[\\/]+/).filter(Boolean);
80
+ return segments.length > 0 ? segments[segments.length - 1] : "";
81
+ }
82
+ function toWidth(value) {
83
+ if (value === void 0) return null;
84
+ const parsed = Number.parseInt(value, 10);
85
+ return Number.isNaN(parsed) ? null : parsed;
86
+ }
87
+ function parseHeading(raw) {
88
+ const html = /<h2\b[^>]*>([\s\S]*?)<\/h2>/i.exec(raw);
89
+ const markdown = /^##\s+(.+)$/m.exec(raw);
90
+ const inner = html !== null ? html[1] : markdown !== null ? markdown[1] : null;
91
+ if (inner === null) return null;
92
+ const subMatch = /<sub>([\s\S]*?)<\/sub>/i.exec(inner);
93
+ const sub = subMatch !== null ? stripTags(subMatch[1]) : null;
94
+ const text = stripTags(inner.replace(/<sub>[\s\S]*?<\/sub>/i, " "));
95
+ return { sub: sub !== null && sub !== "" ? sub : null, text };
96
+ }
97
+ function parseContactBlock(raw) {
98
+ const variant = /<h2\b/i.test(raw) ? "html-heading" : "markdown-heading";
99
+ const heading = parseHeading(raw);
100
+ const table = /<table\b[^>]*>([\s\S]*?)<\/table>/i.exec(raw);
101
+ const rows = table !== null ? [...table[1].matchAll(/<tr\b[^>]*>([\s\S]*?)<\/tr>/gi)] : [];
102
+ const titleRow = rows.find((row) => /<b\b/i.test(row[1]));
103
+ const imageRow = rows.find((row) => /<img\b/i.test(row[1]));
104
+ const titles = titleRow !== void 0 ? [...titleRow[1].matchAll(/<b\b[^>]*>([\s\S]*?)<\/b>/gi)].map((match) => stripTags(match[1])) : [];
105
+ const images = imageRow !== void 0 ? [...imageRow[1].matchAll(/<img\b([^>]*)>/gi)].map((match) => parseAttributes(match[1])) : [];
106
+ const groups = images.map((attributes, index) => {
107
+ const src = attributes.src ?? "";
108
+ return {
109
+ title: titles[index] ?? "",
110
+ src,
111
+ asset: assetName(src),
112
+ width: toWidth(attributes.width),
113
+ alt: attributes.alt ?? ""
114
+ };
115
+ });
116
+ let rest = raw;
117
+ const htmlHeading = /<h2\b[^>]*>[\s\S]*?<\/h2>/i.exec(rest);
118
+ if (htmlHeading !== null) rest = rest.replace(htmlHeading[0], " ");
119
+ else rest = rest.replace(/^##\s+.*$/m, " ");
120
+ rest = rest.replace(/<table\b[^>]*>[\s\S]*?<\/table>/gi, " ");
121
+ const welcome = stripTags(rest);
122
+ return { variant, heading, welcome: welcome === "" ? null : welcome, groups };
123
+ }
124
+
125
+ // src/core/baseline.ts
126
+ var BASELINE = {
127
+ "manifest": {
128
+ "schema": 1,
129
+ "version": "0.0.2-drill",
130
+ "revision": 2,
131
+ "updatedAt": "2026-10-31T00:00:00+08:00",
132
+ "fallbackUrl": "https://github.com/FeatherHunter/featherhunter-plugin-manage",
133
+ "groups": [
134
+ {
135
+ "id": "feishu",
136
+ "platform": "feishu",
137
+ "order": 10,
138
+ "readmeTitle": {
139
+ "zh": "\u98DE\u4E66\u7FA4\uFF08\u4E3B\uFF09",
140
+ "en": "Feishu Group (Main)"
141
+ },
142
+ "alt": {
143
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4 \u98DE\u4E66\u7FA4\u4E8C\u7EF4\u7801",
144
+ "en": "DSH plugin community group Feishu QR code"
145
+ },
146
+ "card": "card-feishu.png",
147
+ "qr": {
148
+ "kind": "bundled",
149
+ "key": "qr-feishu"
150
+ },
151
+ "title": {
152
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4",
153
+ "en": "DSH Plugin Community"
154
+ },
155
+ "subtitle": {
156
+ "zh": "\u7528\u6237418832\u7684\u7EC4\u7EC7",
157
+ "en": "User 418832's organization"
158
+ },
159
+ "note": {
160
+ "zh": "\u8BE5\u4E8C\u7EF4\u7801\u6C38\u4E45\u6709\u6548",
161
+ "en": "This QR code never expires"
162
+ }
163
+ },
164
+ {
165
+ "id": "qq",
166
+ "platform": "qq",
167
+ "order": 20,
168
+ "readmeTitle": {
169
+ "zh": "QQ\u7FA4\uFF08\u65B0\uFF09",
170
+ "en": "QQ Group (New)"
171
+ },
172
+ "alt": {
173
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4 QQ \u7FA4\u4E8C\u7EF4\u7801",
174
+ "en": "DSH plugin community group QQ QR code"
175
+ },
176
+ "card": "card-qq.png",
177
+ "qr": {
178
+ "kind": "bundled",
179
+ "key": "qr-qq"
180
+ },
181
+ "title": {
182
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4",
183
+ "en": "DSH Plugin Community"
184
+ },
185
+ "subtitle": {
186
+ "zh": "\u7FA4\u53F7\uFF1A1020866453",
187
+ "en": "Group ID: 1020866453"
188
+ },
189
+ "note": {
190
+ "zh": "\u626B\u4E00\u626B\u4E8C\u7EF4\u7801\uFF0C\u52A0\u5165\u7FA4\u804A",
191
+ "en": "Scan the QR code to join the group chat"
192
+ }
193
+ },
194
+ {
195
+ "id": "wechat",
196
+ "platform": "wechat",
197
+ "order": 30,
198
+ "readmeTitle": {
199
+ "zh": "\u5FAE\u4FE1\u7FA4\uFF08\u65B0\uFF09",
200
+ "en": "WeChat Group (New)"
201
+ },
202
+ "alt": {
203
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4\u5FAE\u4FE1\u7FA4\u4E8C\u7EF4\u7801",
204
+ "en": "DSH plugin community group WeChat QR code"
205
+ },
206
+ "card": "card-wechat-2026-11-06.png",
207
+ "qr": {
208
+ "kind": "remote",
209
+ "path": "qr-wechat-2026-11-06.png"
210
+ },
211
+ "title": {
212
+ "zh": "DSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4",
213
+ "en": "DSH Plugin Community"
214
+ },
215
+ "subtitle": {
216
+ "zh": "\u7FA4\u804A\uFF1ADSH \u63D2\u4EF6\u4EA4\u6D41\u7FA4",
217
+ "en": "Group chat: DSH Plugin Community"
218
+ },
219
+ "validUntil": "2026-11-06"
220
+ }
221
+ ],
222
+ "plugins": [
223
+ {
224
+ "id": "deck",
225
+ "order": 10,
226
+ "verifiedAt": "2026-10-30",
227
+ "name": "dsh-mattpocock-skills-deck",
228
+ "repo": "FeatherHunter/dsh-mattpocock-skills-deck",
229
+ "desc": {
230
+ "zh": "\u8FD1 30 \u4E07 star \u7684 mattpocock/skills \u6574\u5957\u9884\u7F6E\u597D\uFF0827 \u4E2A\u6280\u80FD\uFF09\uFF0C\u88C5\u597D\u5373\u7528\u3002",
231
+ "en": "The whole mattpocock/skills set (nearly 300k stars) preinstalled \u2014 27 skills, ready as soon as it is installed."
232
+ },
233
+ "url": "https://github.com/FeatherHunter/dsh-mattpocock-skills-deck"
234
+ },
235
+ {
236
+ "id": "prompt",
237
+ "order": 20,
238
+ "verifiedAt": "2026-10-30",
239
+ "name": "dsh-prompt",
240
+ "repo": "FeatherHunter/dsh-prompt",
241
+ "desc": {
242
+ "zh": "\u7ECF\u5E38\u53CD\u590D\u91CD\u590D\u7684\u6A21\u677F\u5316\u63D0\u793A\u8BCD\uFF0C\u5B58\u6210\u81EA\u5B9A\u4E49\u6A21\u677F\uFF0C\u9009\u4E2D\u540E\u76F4\u63A5\u6CE8\u5165\uFF0C\u4E0D\u518D\u9700\u8981\u8017\u8D39\u7CBE\u529B\u3002",
243
+ "en": "The boilerplate prompts you keep retyping, saved as custom templates and injected on selection \u2014 no more wasted effort."
244
+ },
245
+ "url": "https://github.com/FeatherHunter/dsh-prompt"
246
+ },
247
+ {
248
+ "id": "palette",
249
+ "order": 30,
250
+ "verifiedAt": "2026-10-30",
251
+ "name": "dsh-opencode-palette",
252
+ "repo": "FeatherHunter/dsh-opencode-palette",
253
+ "desc": {
254
+ "zh": "38 \u6B3E opencode \u7ECF\u5178\u914D\u8272 + 20+\u81EA\u5B9A\u4E49\u4E3B\u9898 \u4E00\u952E\u6362\u88C5 DSH\u3002",
255
+ "en": "38 classic opencode themes + 20+ custom themes \u2014 reskin DSH in one click."
256
+ },
257
+ "url": "https://github.com/FeatherHunter/dsh-opencode-palette"
258
+ },
259
+ {
260
+ "id": "im",
261
+ "order": 40,
262
+ "verifiedAt": "2026-10-30",
263
+ "name": "dsh-im-companion",
264
+ "repo": "FeatherHunter/dsh-im-companion",
265
+ "desc": {
266
+ "zh": "\u7ED9 dsh-im \u52A0\u4E86\u300C\u52A9\u7406\u300D\u548C\u300C\u5BB6\u300D\u7684\u6982\u5FF5\u3002",
267
+ "en": "Adds the ideas of an \u201Cassistant\u201D and a \u201Chome\u201D to dsh-im."
268
+ },
269
+ "url": "https://github.com/FeatherHunter/dsh-im-companion"
270
+ },
271
+ {
272
+ "id": "ilife",
273
+ "order": 50,
274
+ "verifiedAt": "2026-10-30",
275
+ "name": "ilife",
276
+ "repo": "FeatherHunter/ilife",
277
+ "desc": {
278
+ "zh": "\u26A0\uFE0F\u5EFA\u8BBE\u4E2D\u26A0\uFE0F\u7231\u751F\u6D3B\uFF1A\u5C45\u5BB6\u751F\u6D3B\u5957\u4EF6\uFF0C\u8BB0\u8D26\u3001\u8FD0\u52A8\u3001\u996E\u98DF\u3001\u4F53\u91CD\u3001\u98DF\u8C31\u3001\u7269\u54C1\u7BA1\u7406\u3001\u4F5C\u606F\u89C4\u5212\u3001\u5907\u5FD8\u5F55\u7B49\u3002",
279
+ "en": "\u26A0\uFE0FWork in progress\u26A0\uFE0F iLife, the home-life suite: bookkeeping, exercise, diet, weight, recipes, item management, schedule planning, memos and more."
280
+ },
281
+ "url": "https://github.com/FeatherHunter/ilife"
282
+ }
283
+ ]
284
+ },
285
+ "qr": {
286
+ "qr-feishu": "data:image/png;base64,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",
287
+ "qr-qq": "data:image/png;base64,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"
288
+ }
289
+ };
290
+
291
+ // src/core/index.ts
292
+ var DAY_MS = 24 * 60 * 60 * 1e3;
293
+ function pickText(text, lang) {
294
+ if (!text) return "";
295
+ return text[lang] ?? text.zh ?? text.en ?? "";
296
+ }
297
+ function sortByOrder(items) {
298
+ return [...items].sort((a, b) => a.order - b.order);
299
+ }
300
+
301
+ // src/node/renderers.ts
302
+ var DEFAULT_CDN_BASE = "https://cdn.jsdelivr.net/npm/dsh-featherhunter-plugin-base";
303
+ var CONTACT_CARD_WIDTH = 260;
304
+ var CONTACT_TEXT = {
305
+ sub: "CONNECT",
306
+ heading: {
307
+ zh: "\u53CD\u9988\u4E0E\u8054\u7CFB",
308
+ en: "Feedback and Contact"
309
+ },
310
+ welcome: {
311
+ zh: "\u{1F44F}\u6B22\u8FCE\u63D0\u4EA4PR\u3001ISSUE\u3002\u661F\u661F\u4E4B\u706B\u53EF\u4EE5\u71CE\u539F\u{1F525}\u6709\u4EFB\u4F55\u5EFA\u8BAE\u3001\u610F\u89C1\u3001\u60F3\u6CD5\u3001\u5410\u69FD\u3001idea\u90FD\u53EF\u4EE5\u8FDB\u7FA4\u4EA4\u6D41\u3002",
312
+ en: "\u{1F44F}Welcome PRs and issues. A single spark can start a prairie fire \u{1F525}. Any suggestion, opinion, idea or rant \u2014 come join the group and talk."
313
+ }
314
+ };
315
+ var DATE_IN_FILENAME = /(\d{4})-(\d{2})-(\d{2})/;
316
+ var DATE_IN_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})/;
317
+ function resolveManifest(options) {
318
+ return options.manifest ?? BASELINE.manifest;
319
+ }
320
+ function resolveLang(options) {
321
+ return options.lang ?? "zh";
322
+ }
323
+ function escapeAttribute(value) {
324
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
325
+ }
326
+ function contactCardCacheDate(group, manifest) {
327
+ const fromCard = DATE_IN_FILENAME.exec(group.card);
328
+ if (fromCard !== null) return fromCard[1] + fromCard[2] + fromCard[3];
329
+ if (group.validUntil === void 0) return null;
330
+ const fromManifest = DATE_IN_TIMESTAMP.exec(manifest.updatedAt);
331
+ if (fromManifest === null) {
332
+ throw new Error(
333
+ "manifest.updatedAt must start with YYYY-MM-DD when a group has validUntil (group: " + group.id + ")"
334
+ );
335
+ }
336
+ return fromManifest[1] + fromManifest[2] + fromManifest[3];
337
+ }
338
+ function contactCardUrl(group, manifest, options = {}) {
339
+ const base = (options.cdnBase ?? DEFAULT_CDN_BASE).replace(/\/+$/, "");
340
+ if (!/^https:\/\/[^\s"'<>]+$/i.test(base)) {
341
+ throw new Error('contact CDN base must be an absolute https URL (got "' + base + '")');
342
+ }
343
+ const card = group.card.trim();
344
+ if (card === "") throw new Error('contact group "' + group.id + '" has an empty card file name');
345
+ if (card.includes("/") || card.includes("\\") || /^[a-z]+:/i.test(card)) {
346
+ throw new Error('contact card must be a bare file name under data/img/ (got "' + card + '")');
347
+ }
348
+ const version = options.version ?? manifest.version;
349
+ if (version === "") throw new Error("contact CDN URL needs a manifest version");
350
+ let url = base + "@" + version + "/data/img/" + card;
351
+ const cacheDate = contactCardCacheDate(group, manifest);
352
+ if (cacheDate !== null) url += "?v=" + cacheDate;
353
+ return url;
354
+ }
355
+ function contactHeading(lang, options) {
356
+ const text = CONTACT_TEXT.heading[lang];
357
+ if (options.variant === "markdown-heading") return "## " + text;
358
+ return '<h2 align="center"><sub>' + CONTACT_TEXT.sub + "</sub><br>" + text + "</h2>";
359
+ }
360
+ function renderContactBlock(options = {}) {
361
+ const manifest = resolveManifest(options);
362
+ const lang = resolveLang(options);
363
+ const groups = sortByOrder(manifest.groups);
364
+ if (groups.length === 0) throw new Error("contact block needs at least one group in the manifest");
365
+ const headerCells = groups.map((group) => '<td align="center"><b>' + escapeAttribute(pickText(group.readmeTitle, lang)) + "</b></td>").join("");
366
+ const cardCells = groups.map((group) => {
367
+ const src = contactCardUrl(group, manifest, options);
368
+ const alt = escapeAttribute(pickText(group.alt, lang));
369
+ return '<td><img src="' + src + '" width="' + CONTACT_CARD_WIDTH + '" alt="' + alt + '" /></td>';
370
+ }).join("");
371
+ return [
372
+ contactHeading(lang, options),
373
+ "",
374
+ '<div align="center">',
375
+ "",
376
+ CONTACT_TEXT.welcome[lang],
377
+ "",
378
+ '<table align="center"><tr>' + headerCells + "</tr><tr>" + cardCells + "</tr></table>",
379
+ "",
380
+ "</div>"
381
+ ].join("\n");
382
+ }
383
+
384
+ // src/node/readme-sync.ts
385
+ var THANKS_ZH_MARKERS = {
386
+ start: "<!-- THANKS-TABLE-ZH-START -->",
387
+ end: "<!-- THANKS-TABLE-ZH-END -->"
388
+ };
389
+ var THANKS_EN_MARKERS = {
390
+ start: "<!-- THANKS-TABLE-EN-START -->",
391
+ end: "<!-- THANKS-TABLE-EN-END -->"
392
+ };
393
+ var BLOCK_MARKERS = {
394
+ contact: { start: "<!-- CONTACT-START -->", end: "<!-- CONTACT-END -->" },
395
+ more: { start: "<!-- MORE-START -->", end: "<!-- MORE-END -->" },
396
+ starHistory: { start: "<!-- STAR-HISTORY-START -->", end: "<!-- STAR-HISTORY-END -->" },
397
+ thanks: {
398
+ ...THANKS_ZH_MARKERS,
399
+ zh: THANKS_ZH_MARKERS,
400
+ en: THANKS_EN_MARKERS
401
+ }
402
+ };
403
+ function detectContact(raw) {
404
+ const parsed = parseContactBlock(raw);
405
+ const heading = parsed.heading?.text ?? "";
406
+ const lang = /[A-Za-z]/.test(heading) ? "en" : "zh";
407
+ const variant = parsed.variant === "markdown-heading" ? "markdown-heading" : "html-heading";
408
+ return { lang, variant };
409
+ }
410
+ function locateLegacyContact(markdown) {
411
+ const headingPattern = /^(?:<h2\b[^\n]*?(?:CONNECT|反馈与联系|Feedback and Contact)[^\n]*?|<sub>\s*CONNECT\s*<\/sub>[^\n]*?|<h2\b[^\n]*?>[^\n]*?(?:反馈与联系|Feedback and Contact)[^\n]*?>|##\s+[^\n]*(?:反馈与联系|Feedback and Contact)[^\n]*)\s*$/im;
412
+ const heading = headingPattern.exec(markdown);
413
+ if (heading === null) return null;
414
+ const start = heading.index;
415
+ const closingDiv = /^[ \t]*<\/div>[ \t]*$/m;
416
+ const rest = markdown.slice(start + heading[0].length);
417
+ const closing = closingDiv.exec(rest);
418
+ if (closing === null) return null;
419
+ return { start, end: start + heading[0].length + closing.index + closing[0].length };
420
+ }
421
+ var BLOCK_DEFINITIONS = [
422
+ {
423
+ name: "contact",
424
+ label: "contact",
425
+ markers: [{ start: BLOCK_MARKERS.contact.start, end: BLOCK_MARKERS.contact.end }],
426
+ render: (context) => renderContactBlock(context),
427
+ locateLegacy: locateLegacyContact,
428
+ detect: detectContact
429
+ },
430
+ // Reserved for ticket 09: renderer + legacy anchor for the author-plugins
431
+ // (MORE) block. Marker pair is fixed now so init/sync never invents one.
432
+ {
433
+ name: "more",
434
+ label: "more",
435
+ markers: [{ start: BLOCK_MARKERS.more.start, end: BLOCK_MARKERS.more.end }]
436
+ },
437
+ // Reserved for ticket 10.
438
+ {
439
+ name: "star-history",
440
+ label: "star-history",
441
+ markers: [{ start: BLOCK_MARKERS.starHistory.start, end: BLOCK_MARKERS.starHistory.end }]
442
+ },
443
+ // Reserved for ticket 10. One marker pair per language; which pair exists
444
+ // tells the language of the README.
445
+ {
446
+ name: "thanks",
447
+ label: "thanks",
448
+ markers: [
449
+ { lang: "zh", start: THANKS_ZH_MARKERS.start, end: THANKS_ZH_MARKERS.end },
450
+ { lang: "en", start: THANKS_EN_MARKERS.start, end: THANKS_EN_MARKERS.end }
451
+ ]
452
+ }
453
+ ];
454
+ function implementedBlockDefinitions() {
455
+ return BLOCK_DEFINITIONS.filter((definition) => definition.render !== void 0);
456
+ }
457
+ function writeFileAtomic(filePath, content, hooks = {}) {
458
+ const directory = dirname(filePath);
459
+ const tempPath = join(
460
+ directory,
461
+ "." + basename(filePath) + "." + process.pid + "." + randomBytes(6).toString("hex") + ".tmp"
462
+ );
463
+ let mode;
464
+ try {
465
+ mode = statSync(filePath).mode & 511;
466
+ } catch {
467
+ mode = void 0;
468
+ }
469
+ try {
470
+ writeFileSync(tempPath, content, "utf8");
471
+ if (mode !== void 0) chmodSync(tempPath, mode);
472
+ hooks.beforeRename?.(tempPath);
473
+ renameSync(tempPath, filePath);
474
+ } catch (error) {
475
+ try {
476
+ if (existsSync(tempPath)) unlinkSync(tempPath);
477
+ } catch {
478
+ }
479
+ throw error;
480
+ }
481
+ }
482
+ function detectLineEnding(markdown) {
483
+ return markdown.includes("\r\n") ? "\r\n" : "\n";
484
+ }
485
+ function markerIndexes(markdown, token) {
486
+ const indexes = [];
487
+ let from = 0;
488
+ for (; ; ) {
489
+ const index = markdown.indexOf(token, from);
490
+ if (index === -1) return indexes;
491
+ indexes.push(index);
492
+ from = index + token.length;
493
+ }
494
+ }
495
+ function renderSegment(definition, markerSet, context) {
496
+ if (definition.render === void 0) throw new Error("block has no renderer: " + definition.name);
497
+ return definition.render({ ...context, lang: markerSet.lang ?? context.lang });
498
+ }
499
+ function applyMarkerSet(markdown, definition, markerSet, context, command) {
500
+ const errors = [];
501
+ const { start, end } = markerSet;
502
+ const starts = markerIndexes(markdown, start);
503
+ const ends = markerIndexes(markdown, end);
504
+ const eol = detectLineEnding(markdown);
505
+ if (starts.length === 0 && ends.length === 0) {
506
+ if (definition.render === void 0) {
507
+ return { markdown, changed: false, status: "skipped", errors };
508
+ }
509
+ if (command === "sync") {
510
+ errors.push(definition.label + " markers are missing; run readme:init first");
511
+ return { markdown, changed: false, status: "skipped", errors };
512
+ }
513
+ const legacy = definition.locateLegacy?.(markdown) ?? null;
514
+ if (legacy === null) {
515
+ errors.push(
516
+ "cannot locate the legacy " + definition.label + " block; add " + start + " / " + end + " markers manually"
517
+ );
518
+ return { markdown, changed: false, status: "skipped", errors };
519
+ }
520
+ const content = renderSegment(definition, markerSet, context).split(/\r?\n/).join(eol);
521
+ const replacement = start + eol + content + eol + end;
522
+ return {
523
+ markdown: markdown.slice(0, legacy.start) + replacement + markdown.slice(legacy.end),
524
+ changed: true,
525
+ status: "inserted",
526
+ errors
527
+ };
528
+ }
529
+ if (starts.length === 1 && ends.length === 1 && starts[0] < ends[0]) {
530
+ if (definition.render === void 0) {
531
+ return { markdown, changed: false, status: "skipped", errors };
532
+ }
533
+ const startIndex = starts[0];
534
+ const endIndex = ends[0];
535
+ const inner = markdown.slice(startIndex + start.length, endIndex);
536
+ const content = renderSegment(definition, markerSet, context).split(/\r?\n/).join(eol);
537
+ const expectedInner = eol + content + eol;
538
+ if (inner === expectedInner) {
539
+ return { markdown, changed: false, status: "unchanged", errors };
540
+ }
541
+ const next = markdown.slice(0, startIndex + start.length) + expectedInner + markdown.slice(endIndex);
542
+ return { markdown: next, changed: true, status: "updated", errors };
543
+ }
544
+ if (starts.length > 1 || ends.length > 1) {
545
+ errors.push(
546
+ "duplicate " + definition.label + " markers (" + start + " x" + starts.length + ", " + end + " x" + ends.length + "); refusing to guess"
547
+ );
548
+ } else if (starts.length !== ends.length) {
549
+ errors.push(
550
+ "unpaired " + definition.label + " markers (" + start + " x" + starts.length + ", " + end + " x" + ends.length + ")"
551
+ );
552
+ } else {
553
+ errors.push("end marker appears before start marker for the " + definition.label + " block");
554
+ }
555
+ return { markdown, changed: false, status: "skipped", errors };
556
+ }
557
+ function detectContext(markdown, options) {
558
+ let lang = options.lang;
559
+ let variant = options.variant;
560
+ for (const definition of BLOCK_DEFINITIONS) {
561
+ if (definition.detect === void 0) continue;
562
+ let raw = null;
563
+ for (const markerSet of definition.markers) {
564
+ const starts = markerIndexes(markdown, markerSet.start);
565
+ const ends = markerIndexes(markdown, markerSet.end);
566
+ if (starts.length === 1 && ends.length === 1 && starts[0] < ends[0]) {
567
+ raw = markdown.slice(starts[0] + markerSet.start.length, ends[0]);
568
+ break;
569
+ }
570
+ }
571
+ if (raw === null) {
572
+ const legacy = definition.locateLegacy?.(markdown) ?? null;
573
+ if (legacy !== null) raw = markdown.slice(legacy.start, legacy.end);
574
+ }
575
+ if (raw === null) continue;
576
+ const detected = definition.detect(raw);
577
+ lang ??= detected.lang;
578
+ variant ??= detected.variant;
579
+ }
580
+ return {
581
+ manifest: options.manifest,
582
+ version: options.version,
583
+ cdnBase: options.cdnBase,
584
+ lang: lang ?? "zh",
585
+ variant
586
+ };
587
+ }
588
+ function updateReadme(options) {
589
+ const readmePath = resolve(options.root, options.readme ?? "README.md");
590
+ const command = options.command ?? "sync";
591
+ const result = {
592
+ readmePath,
593
+ ok: false,
594
+ changed: false,
595
+ written: false,
596
+ blocks: [],
597
+ errors: []
598
+ };
599
+ let markdown;
600
+ try {
601
+ markdown = readFileSync(readmePath, "utf8");
602
+ } catch (error) {
603
+ const code = error.code;
604
+ result.errors.push(
605
+ code === "ENOENT" ? "README not found: " + readmePath : "cannot read " + readmePath + ": " + error.message
606
+ );
607
+ return result;
608
+ }
609
+ const suspicious = findSuspiciousLines(markdown);
610
+ if (suspicious.length > 0) {
611
+ for (const line of suspicious) {
612
+ result.errors.push(
613
+ readmePath + ":" + line.line + ": suspicious merge-conflict residue (" + line.reason + '): "' + line.text + '"; refusing to modify the README, fix it manually first'
614
+ );
615
+ }
616
+ return result;
617
+ }
618
+ const context = detectContext(markdown, options);
619
+ let next = markdown;
620
+ for (const definition of implementedBlockDefinitions()) {
621
+ for (const markerSet of definition.markers) {
622
+ const applied = applyMarkerSet(next, definition, markerSet, context, command);
623
+ next = applied.markdown;
624
+ result.blocks.push({ name: definition.name, status: applied.status });
625
+ for (const error of applied.errors) result.errors.push(readmePath + ": " + error);
626
+ }
627
+ }
628
+ if (result.errors.length > 0) return result;
629
+ result.changed = next !== markdown;
630
+ if (options.check === true) {
631
+ if (result.changed) {
632
+ result.errors.push(
633
+ readmePath + ": managed blocks are out of date; run readme:" + command + " to fix"
634
+ );
635
+ return result;
636
+ }
637
+ result.ok = true;
638
+ return result;
639
+ }
640
+ if (result.changed) {
641
+ writeFileAtomic(readmePath, next);
642
+ result.written = true;
643
+ }
644
+ result.ok = true;
645
+ return result;
646
+ }
647
+ function updateReadmes(options) {
648
+ const files = options.roots.map(
649
+ (root) => updateReadme({
650
+ root,
651
+ command: options.command ?? "sync",
652
+ check: options.check,
653
+ manifest: options.manifest,
654
+ version: options.version,
655
+ cdnBase: options.cdnBase,
656
+ lang: options.lang,
657
+ variant: options.variant
658
+ })
659
+ );
660
+ return { ok: files.every((file) => file.ok), files };
661
+ }
662
+
663
+ // src/node/cli.ts
6
664
  var HELP = `dsh-base \u2014 FeatherHunter base package CLI
7
665
 
8
666
  Usage:
9
- dsh-base readme:init Insert the four managed blocks into a README
10
- dsh-base readme:sync [--check] Refresh managed blocks in every repo
11
- dsh-base readme:sync --all Refresh every managed block, even unchanged ones
667
+ dsh-base readme:init [--check] [--root <dir>]...
668
+ Insert the managed blocks (contact first) into a README
669
+ dsh-base readme:sync [--check] [--root <dir>]...
670
+ Refresh the text between the managed markers
671
+ dsh-base readme:init|readme:sync --all [--root <dir>]...
672
+ Process every target directory and keep going after errors
12
673
  dsh-base contact:update [--check]
13
674
  Refresh contact/ data from the QR source images
14
675
  dsh-base doctor Diagnose data, CDN and README state
15
676
  dsh-base --version Print the package version
16
677
  dsh-base --help Print this help
17
678
 
18
- Commands that change files only rewrite the text between their managed markers.
679
+ Options:
680
+ --root <dir> Repository root to update; repeatable (default: current directory)
681
+ --check Report drift without writing; nonzero exit when a README is out of date
682
+ --all Process every --root and continue after per-file errors
683
+
684
+ Commands that change files only rewrite the text between their managed markers and
685
+ refuse to touch a README with unpaired markers or merge-conflict residue.
686
+
687
+ Exit codes: 0 success / no drift, 1 drift or error, 2 usage error.
19
688
  `;
20
689
  function readVersion() {
21
690
  try {
22
691
  const pkgUrl = new URL("../../package.json", import.meta.url);
23
- const parsed = JSON.parse(readFileSync(pkgUrl, "utf8"));
692
+ const parsed = JSON.parse(readFileSync2(pkgUrl, "utf8"));
24
693
  return typeof parsed.version === "string" ? parsed.version : "0.0.0";
25
694
  } catch {
26
695
  return "0.0.0";
@@ -31,6 +700,57 @@ function notImplemented(command) {
31
700
  process.stderr.write("\n");
32
701
  return 1;
33
702
  }
703
+ function parseReadmeArgs(command, args) {
704
+ const roots = [];
705
+ let check = false;
706
+ let all = false;
707
+ for (let index = 0; index < args.length; index += 1) {
708
+ const arg = args[index];
709
+ if (arg === "--check") {
710
+ check = true;
711
+ } else if (arg === "--all") {
712
+ all = true;
713
+ } else if (arg === "--root") {
714
+ const value = args[index + 1];
715
+ if (value === void 0 || value.startsWith("-")) {
716
+ return { error: "readme:" + command + ': "--root" needs a directory value' };
717
+ }
718
+ roots.push(value);
719
+ index += 1;
720
+ } else if (arg.startsWith("--root=")) {
721
+ const value = arg.slice("--root=".length);
722
+ if (value.length === 0) {
723
+ return { error: "readme:" + command + ': "--root" needs a directory value' };
724
+ }
725
+ roots.push(value);
726
+ } else {
727
+ return { error: "readme:" + command + ': unknown option "' + arg + '"' };
728
+ }
729
+ }
730
+ if (roots.length === 0) roots.push(process.cwd());
731
+ return {
732
+ options: {
733
+ command,
734
+ roots: roots.map((root) => resolve2(root)),
735
+ check,
736
+ all
737
+ }
738
+ };
739
+ }
740
+ function reportReadmeBatch(result) {
741
+ for (const file of result.files) {
742
+ if (file.ok && file.changed && file.blocks.length > 0) {
743
+ const changed = file.blocks.filter((block) => block.status === "inserted" || block.status === "updated").map((block) => block.name + " " + block.status);
744
+ process.stdout.write(file.readmePath + ": " + changed.join(", ") + "\n");
745
+ } else if (file.ok) {
746
+ process.stdout.write(file.readmePath + ": up to date\n");
747
+ }
748
+ for (const error of file.errors) {
749
+ process.stderr.write("dsh-base: " + error + "\n");
750
+ }
751
+ }
752
+ return result.ok ? 0 : 1;
753
+ }
34
754
  async function main(argv = process.argv.slice(2)) {
35
755
  const command = argv[0];
36
756
  if (!command || command === "--help" || command === "-h" || command === "help") {
@@ -44,7 +764,17 @@ async function main(argv = process.argv.slice(2)) {
44
764
  }
45
765
  switch (command) {
46
766
  case "readme:init":
47
- case "readme:sync":
767
+ case "readme:sync": {
768
+ const readmeCommand = command === "readme:init" ? "init" : "sync";
769
+ const parsed = parseReadmeArgs(readmeCommand, argv.slice(1));
770
+ if ("error" in parsed) {
771
+ process.stderr.write("dsh-base: " + parsed.error + "\n\n");
772
+ process.stderr.write(HELP);
773
+ return 2;
774
+ }
775
+ const { roots, check, all } = parsed.options;
776
+ return reportReadmeBatch(updateReadmes({ roots, command: readmeCommand, check, all }));
777
+ }
48
778
  case "contact:update":
49
779
  case "doctor":
50
780
  return notImplemented(command);