dsh-xingxi 0.1.0 → 0.1.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.
Files changed (2) hide show
  1. package/index.js +120 -77
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1888,48 +1888,52 @@ export function apply(ctx, 配置 = {}) {
1888
1888
  return 项 ? 项.目录 : ''
1889
1889
  }
1890
1890
 
1891
- /** 档案里的所有 md(本机那两个文件 + 会话文件夹里的) */
1891
+ /** 档案里的所有 md:会话绑了文件夹就只读它,没绑才读本机那两份 */
1892
1892
  const 所有档案 = (sid) => {
1893
1893
  const 出 = []
1894
- for (const p of 本机文件()) {
1895
- try {
1896
- 出.push({ 名: basename(p, '.md'), 路: p, 文: readFileSync(p, 'utf8') })
1897
- } catch {}
1898
- }
1899
- // ⚠ 两处都要试:列会话 找不到时(比如会话还没进列表),就直接查绑定表
1900
- let 夹 = 会话文件夹(sid)
1894
+ let 夹 = ''
1895
+ try {
1896
+ 夹 = 会话文件夹(sid)
1897
+ } catch {}
1901
1898
  if (!夹 || !existsSync(夹)) {
1902
1899
  try {
1903
1900
  const 绑 = 读存配置().绑定 || {}
1904
1901
  if (绑[sid] && existsSync(绑[sid])) 夹 = String(绑[sid])
1905
1902
  } catch {}
1906
1903
  }
1907
- if (夹 && existsSync(夹)) {
1908
- const 走 = (目录, 前缀) => {
1909
- let 项们 = []
1904
+ // 没有自己的文件夹 → 用本机档案
1905
+ if (!夹 || !existsSync(夹)) {
1906
+ for (const p of 本机文件()) {
1910
1907
  try {
1911
- 项们 = readdirSync(目录, { withFileTypes: true })
1912
- } catch {
1913
- return
1914
- }
1915
- for (const d of 项们) {
1916
- if (d.isDirectory()) {
1917
- if (/^(\.|备份|备注)/.test(d.name)) continue
1918
- 走(join(目录, d.name), (前缀 ? 前缀 + '/' : '') + d.name)
1919
- continue
1920
- }
1921
- if (!d.name.toLowerCase().endsWith('.md')) continue
1922
- try {
1923
- 出.push({
1924
- 名: (前缀 ? 前缀 + '/' : '') + basename(d.name, '.md'),
1925
- 路: join(目录, d.name),
1926
- 文: readFileSync(join(目录, d.name), 'utf8'),
1927
- })
1928
- } catch {}
1908
+ 出.push({ 名: basename(p, '.md'), 路: p, 文: readFileSync(p, 'utf8') })
1909
+ } catch {}
1910
+ }
1911
+ return 出
1912
+ }
1913
+ const 走 = (目录, 前缀) => {
1914
+ let 项们 = []
1915
+ try {
1916
+ 项们 = readdirSync(目录, { withFileTypes: true })
1917
+ } catch {
1918
+ return
1919
+ }
1920
+ for (const d of 项们) {
1921
+ if (d.isDirectory()) {
1922
+ if (/^(\.|备份|备注)/.test(d.name)) continue
1923
+ 走(join(目录, d.name), (前缀 ? 前缀 + '/' : '') + d.name)
1924
+ continue
1929
1925
  }
1926
+ if (!/\.(md|txt)$/i.test(d.name)) continue
1927
+ try {
1928
+ 出.push({
1929
+ 名: (前缀 ? 前缀 + '/' : '') + basename(d.name, '.md'),
1930
+ 路: join(目录, d.name),
1931
+ 文: readFileSync(join(目录, d.name), 'utf8'),
1932
+ })
1933
+ } catch {}
1930
1934
  }
1931
- 走(夹, '')
1932
1935
  }
1936
+ 走(夹, '')
1933
1937
  return 出
1934
1938
  }
1935
1939
 
@@ -2137,31 +2141,59 @@ export function apply(ctx, 配置 = {}) {
2137
2141
  try {
2138
2142
  const sid = String((exec && exec.sessionId) || '')
2139
2143
  const 档 = 所有档案(sid)
2140
- const 限 = Math.max(500, Math.min(20000, Number((args && args.最多字) || 4000)))
2144
+ const 限 = Math.max(600, Math.min(20000, Number((args && args.最多字) || 4000)))
2141
2145
  const 词 = String((args && args.关键词) || '').trim()
2142
2146
  const 日 = String((args && args.日期) || '').trim()
2143
2147
  const 名 = String((args && args.文件) || '').trim()
2144
2148
 
2145
- let 们 = 档
2146
- if (名) 们 = 们.filter((f) => f.名.includes(名) || f.路.includes(名))
2147
- if (日) {
2148
- // ⚠ 日记里写的是 `- **08-26 周X**:`,没有年份 —— 拿 2026-08-26 去比会一条都不中
2149
- const 短 = 日.length >= 10 ? 日.slice(5) : 日
2150
- const 命中 = 们.filter((f) => f.名.includes(日) || f.文.includes(日) || f.文.includes(短))
2151
- if (命中.length) 们 = 命中
2149
+ if (!档.length) {
2150
+ return { ok: false, text: '这个会话还没有档案(先去星坊里指定文件夹)' }
2152
2151
  }
2153
- if (!们.length) {
2154
- 记一笔('xingxi_read 没找到:sid=' + sid + ' 档=' + 档.length + ' 名=' + 名 + ' 日=' + 日 + ' 词=' + 词)
2155
- return { ok: false, text: '档案里没有匹配:' + (名 || 日 || 词) + '(翻了 ' + 档.length + ' 个文件)' }
2152
+
2153
+ // 把文件按「一类一份」归拢,方便说清楚有什么
2154
+ const 分组 = { 记忆卡: [], 日记: [], 原始对话: [], 其他: [] }
2155
+ for (const f of 档) {
2156
+ if (/^日记\//.test(f.名)) 分组.日记.push(f)
2157
+ else if (/^原始对话\//.test(f.名)) 分组.原始对话.push(f)
2158
+ else if (/记忆卡/.test(f.名)) 分组.记忆卡.push(f)
2159
+ else 分组.其他.push(f)
2156
2160
  }
2161
+ const 日期们 = 分组.日记.map((f) => (/(\d{4}-\d{2}-\d{2})/.exec(f.名) || [])[1]).filter(Boolean).sort()
2157
2162
 
2158
- const 出 = []
2159
- let 总 = 0
2163
+ // ── 0. 什么都不给:给索引(在外面先看清有什么,再决定钻哪一天)──
2164
+ if (!词 && !日 && !名) {
2165
+ const 行们 = ['这个档案里有 ' + 档.length + ' 个文件:', '']
2166
+ for (const f of 分组.记忆卡) {
2167
+ 行们.push('· ' + f.名 + '(' + Math.round(f.文.length / 1000) / 10 + ' 万字)')
2168
+ }
2169
+ for (const f of 分组.其他) 行们.push('· ' + f.名 + '(' + f.文.length + ' 字)')
2170
+ if (日期们.length) {
2171
+ 行们.push(
2172
+ '· 日记 ' + 日期们.length + ' 天:' + 日期们[0] + ' ~ ' + 日期们[日期们.length - 1] + '(一天一个文件)',
2173
+ )
2174
+ }
2175
+ if (分组.原始对话.length) {
2176
+ const 原日 = 分组.原始对话
2177
+ .map((f) => (/(\d{4}-\d{2}-\d{2})/.exec(f.名) || [])[1])
2178
+ .filter(Boolean)
2179
+ .sort()
2180
+ 行们.push('· 原始对话 ' + 原日.length + ' 天:' + 原日[0] + ' ~ ' + 原日[原日.length - 1] + '(当天原话)')
2181
+ }
2182
+ 行们.push('', '怎么查:给「关键词」全文搜(日记也会搜);给「日期」看那一天;给「文件」看整篇。')
2183
+ return { ok: true, text: 行们.join(String.fromCharCode(10)) }
2184
+ }
2160
2185
 
2161
- // 按日期问:只给那一天的日记条目
2162
- if (日 && !词) {
2186
+ // ── 1. 日期:直接定位那一天的日记(不用挨个翻)──
2187
+ if (日) {
2163
2188
  const 短 = 日.length >= 10 ? 日.slice(5) : 日
2164
- for (const f of 们) {
2189
+ const 目标 = 档.filter((f) => f.名.includes(日) || f.名.includes(短))
2190
+ if (目标.length) {
2191
+ const 段 = 目标.slice(0, 3).map((f) => '【' + f.名 + '】' + String.fromCharCode(10) + f.文.slice(0, 限))
2192
+ return { ok: true, text: 段.join(String.fromCharCode(10, 10)).slice(0, 限) }
2193
+ }
2194
+ // 没有那天的文件 → 在全文里找那天的条目
2195
+ const 出 = []
2196
+ for (const f of 档) {
2165
2197
  const 行们 = f.文.split(String.fromCharCode(10))
2166
2198
  const 块 = []
2167
2199
  let 收 = false
@@ -2171,47 +2203,58 @@ export function apply(ctx, 配置 = {}) {
2171
2203
  if (新条) 收 = t.includes(短) || t.includes(日)
2172
2204
  if (收) 块.push(l)
2173
2205
  }
2174
- if (块.length) {
2175
- const 段 = '【' + f.名 + '】' + String.fromCharCode(10) + 块.join(String.fromCharCode(10))
2176
- 出.push(段)
2177
- 总 += 段.length
2178
- }
2206
+ if (块.length) 出.push('【' + f.名 + '】' + String.fromCharCode(10) + 块.join(String.fromCharCode(10)))
2179
2207
  }
2180
- if (!出.length) {
2181
- // 那天真没有 → 给最后三条并说明
2182
- for (const f of 们) {
2183
- const 段 = '【' + f.名 + '】(' + 日 + ' 没有记录,给你最后三条)' + String.fromCharCode(10) + 取近几天(f.文, 3)
2184
- 出.push(段)
2185
- 总 += 段.length
2186
- if (总 >= 限) break
2187
- }
2208
+ if (出.length) return { ok: true, text: 出.join(String.fromCharCode(10, 10)).slice(0, 限) }
2209
+ return {
2210
+ ok: false,
2211
+ text: 日 + ' 没有记录。日记范围:' + (日期们.length ? 日期们[0] + ' ~ ' + 日期们[日期们.length - 1] : '没有日记'),
2188
2212
  }
2189
- return { ok: true, text: 出.join(String.fromCharCode(10, 10)).slice(0, 限) }
2190
2213
  }
2191
2214
 
2192
- // 按关键词
2193
- if (词) {
2194
- for (const f of 们) {
2195
- const 行们 = f.文.split(String.fromCharCode(10))
2196
- for (let i = 0; i < 行们.length; i++) {
2197
- if (!行们[i].includes(词)) continue
2198
- const 段 = '【' + f.名 + '】' + String.fromCharCode(10) +
2199
- 行们.slice(Math.max(0, i - 2), Math.min(行们.length, i + 4)).join(String.fromCharCode(10))
2200
- if (总 + 段.length > 限) break
2201
- 出.push(段)
2202
- 总 += 段.length
2215
+ // ── 2. 文件名:给整篇 ──
2216
+ if (名 && !词) {
2217
+ const 目标 = 档.filter((f) => f.名.includes(名) || f.路.includes(名))
2218
+ if (!目标.length) return { ok: false, text: '没有这个文件:' + 名 }
2219
+ const 段 = 目标.slice(0, 2).map((f) => '【' + f.名 + '】' + String.fromCharCode(10) + f.文.slice(0, 限))
2220
+ return { ok: true, text: 段.join(String.fromCharCode(10, 10)).slice(0, 限) }
2221
+ }
2222
+
2223
+ // ── 3. 关键词:全文搜,**每个文件都看**,每个文件最多取 2 段 ──
2224
+ // ⚠ 以前是按文件顺序扫、扫到预算用完就停 —— 记忆卡一大就把日记挤没了。
2225
+ const 命中 = []
2226
+ for (const f of 档) {
2227
+ const 行们 = f.文.split(String.fromCharCode(10))
2228
+ let 次 = 0
2229
+ const 段们 = []
2230
+ for (let i = 0; i < 行们.length; i++) {
2231
+ if (!行们[i].includes(词)) continue
2232
+ 次++
2233
+ if (段们.length < 2) {
2234
+ 段们.push(行们.slice(Math.max(0, i - 2), Math.min(行们.length, i + 4)).join(String.fromCharCode(10)))
2203
2235
  }
2204
- if (总 >= 限) break
2205
2236
  }
2206
- return { ok: true, text: 出.length ? 出.join(String.fromCharCode(10, 10)) : '没有「' + 词 + '」' }
2237
+ if (次) 命中.push({ 名: f.名, 次, 段们 })
2207
2238
  }
2208
2239
 
2209
- // 只给文件名:给整篇(截到上限)
2210
- for (const f of 们) {
2211
- const 段 = '【' + f.名 + '】' + String.fromCharCode(10) + f.文.slice(0, Math.max(0, 限 - 总))
2240
+ if (!命中.length) {
2241
+ 记一笔('xingxi_read 没找到:sid=' + sid + ' 档=' + 档.length + ' 词=' + 词)
2242
+ return { ok: false, text: '档案里没有「' + 词 + '」(翻了 ' + 档.length + ' 个文件)' }
2243
+ }
2244
+
2245
+ 命中.sort((x, y) => y.次 - x.次)
2246
+ const 总次 = 命中.reduce((s, x) => s + x.次, 0)
2247
+ const 头 = '「' + 词 + '」在 ' + 命中.length + ' 个文件里出现 ' + 总次 + ' 次:'
2248
+ const 出 = [头]
2249
+ let 总 = 头.length
2250
+ for (const h of 命中) {
2251
+ const 段 = '【' + h.名 + '】(' + h.次 + ' 处)' + String.fromCharCode(10) + h.段们.join(String.fromCharCode(10, 10))
2252
+ if (总 + 段.length > 限) {
2253
+ 出.push('…还有 ' + (命中.length - 出.length + 1) + ' 个文件也提到,想看就给「文件」参数点名')
2254
+ break
2255
+ }
2212
2256
  出.push(段)
2213
2257
  总 += 段.length
2214
- if (总 >= 限) break
2215
2258
  }
2216
2259
  return { ok: true, text: 出.join(String.fromCharCode(10, 10)) }
2217
2260
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-xingxi",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "星汐:把整理好的记忆档案连成一张看得见的星图。八章散成星群,日记排成时间星带,点一颗星看见原话。",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",