@jiugeqqqqq/dsh-house 0.3.2 → 0.3.4

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 CHANGED
@@ -3,6 +3,10 @@
3
3
  > 每次发版都必须在这里写一条:改了什么、为什么改、别人要不要跟着动。
4
4
  > 版本号跟 `package.json` 走,`npm i` 的人看这里就知道升了什么。
5
5
 
6
+ ## 0.3.3 — 2026-10-29
7
+
8
+ - 修版本自检:本地和 npm 同版本时不再显示「可更新」(之前缓存里的旧判断没重算,出现过 v0.3.2 → 0.3.2 可更新)
9
+
6
10
  ## 0.3.2 — 2026-10-29
7
11
 
8
12
  - 内容同 0.3.1:`house_write` + 两条轴引导。
package/lib/host/index.js CHANGED
@@ -17,7 +17,7 @@ import { readFile, writeFile, appendFile, mkdir, copyFile } from 'node:fs/promis
17
17
  import fs from 'node:fs';
18
18
  import zlib from 'node:zlib';
19
19
  import path from 'node:path';
20
- import { createUpdateChecker } from '../update-check.js';
20
+ import { createUpdateChecker, compareVersions } from '../update-check.js';
21
21
 
22
22
  export const name = 'house';
23
23
  export const inject = [];
@@ -444,6 +444,59 @@ export function apply(ctx, config = {}) {
444
444
  return r.ok ? { ok: true, data: { group: g, text: item } } : r;
445
445
  }
446
446
 
447
+ /**
448
+ * 把清单里某一条从一个分组搬到另一个分组(工具 house_done 用)。
449
+ * 典型用法:「正在长出来的」某件事做完了 → 搬到「已经完工的」。
450
+ * 匹配规则:同一组里第一个「- 」条目,其文本包含关键词(不区分大小写)。
451
+ * 缩进的子说明跟着一起搬,不会留下孤儿行。
452
+ */
453
+ async function promoteHouseItem(query, fromGroup, toGroup) {
454
+ const q = String(query || '').trim();
455
+ if (!q) return { ok: false, error: { code: 'invalid', message: '要搬哪一条?给个关键词。' } };
456
+ const from = String(fromGroup || '正在长出来的').trim() || '正在长出来的';
457
+ const to = String(toGroup || '已经完工的').trim() || '已经完工的';
458
+ if (!fs.existsSync(assetsPath)) return { ok: false, error: { code: 'missing', message: '清单还不存在。' } };
459
+ let moved = null;
460
+ const r = await mutate((lines) => {
461
+ const groupRange = (name) => {
462
+ const i = lines.findIndex((l) => l.trim() === '## ' + name);
463
+ if (i < 0) return null;
464
+ let end = lines.length;
465
+ for (let j = i + 1; j < lines.length; j++) if (/^##\s+/.test(lines[j])) { end = j; break; }
466
+ return { start: i, end };
467
+ };
468
+ const range = groupRange(from);
469
+ if (!range) return false;
470
+ const needle = q.toLowerCase();
471
+ let hit = -1;
472
+ for (let i = range.start + 1; i < range.end; i++) {
473
+ if (/^- /.test(lines[i]) && lines[i].toLowerCase().includes(needle)) { hit = i; break; }
474
+ }
475
+ if (hit < 0) return false;
476
+ // 条目 + 紧随的缩进子行
477
+ const block = [lines[hit]];
478
+ let j = hit + 1;
479
+ while (j < range.end && /^\s{2,}\S/.test(lines[j])) { block.push(lines[j]); j += 1; }
480
+ lines.splice(hit, block.length);
481
+ // 目标组:没有就新建(放在文件末尾)
482
+ let dest = groupRange(to);
483
+ if (!dest) {
484
+ lines.push('', '## ' + to);
485
+ dest = groupRange(to);
486
+ }
487
+ let insertAt = dest.end;
488
+ for (let k = dest.end - 1; k > dest.start; k -= 1) {
489
+ if (lines[k].trim()) { insertAt = k + 1; break; }
490
+ }
491
+ lines.splice(insertAt, 0, ...block);
492
+ moved = block[0].replace(/^-\s*/, '').slice(0, 80);
493
+ return true;
494
+ });
495
+ return r.ok
496
+ ? { ok: true, data: { from, to, item: moved } }
497
+ : { ok: false, error: { code: 'not_found', message: `在「${from}」里没找到含「${q}」的条目。` } };
498
+ }
499
+
447
500
  /** 在积木目录里按关键词翻(工具 house_search 用)。 */
448
501
  function walkKnowledge(dir, out = [], depth = 0) {
449
502
  if (depth > 4) return out;
@@ -500,6 +553,7 @@ export function apply(ctx, config = {}) {
500
553
  '【房子怎么用】做完一件大事,用 house_add 往清单加一行(分组写「已经有的」或「正在长出来的」);' +
501
554
  '写积木分两种:按能力写(`手机-接入与操作`、`画图-Agnes`,回答「怎么做」)、按任务写(`任务-调通一直发`,回答「那段对话干了什么」,一段任务一篇,按时间轴切,切完要覆盖全程、不重不漏);' +
502
555
  '细节、命令、踩过的坑,用 house_write 写进积木(knowledge 目录,默认追加,别一个坑建一个文件);' +
556
+ '一件事真做完了(跑通、验证过),用 house_done 把它从「正在长出来的」搬到「已经完工的」——别让旧条目一直挂着;' +
503
557
  '清单和最近对话里找不到的东西,用 house_search 去积木里按关键词翻,翻到再答,别猜。';
504
558
 
505
559
  function assetsAsPrompt() {
@@ -652,6 +706,38 @@ export function apply(ctx, config = {}) {
652
706
  }),
653
707
  'dsh-house: house_write',
654
708
  );
709
+
710
+ // 0.3.4:把清单里的一条从「正在长出来的」搬到「已经完工的」。
711
+ // 为什么要这个:以前她做完一件事只会再 add 一行,旧的那条永远躺在 pending 里,
712
+ // 要么人去页面手改,要么清单越穿越乱。
713
+ scoped.effect(
714
+ () =>
715
+ tools.register({
716
+ name: 'house_done',
717
+ description:
718
+ '把「房子」清单里的某一条从「正在长出来的」搬到「已经完工的」。' +
719
+ '一件事真做完了(跑通、验证过)就调一次,别让旧条目一直挂着;' +
720
+ '拿不准算不算做完就别搬。item 传条目里的一小段关键词就行。',
721
+ parameters: {
722
+ type: 'object',
723
+ properties: {
724
+ item: { type: 'string', description: '条目里的关键词,比如「her2」' },
725
+ from: { type: 'string', description: '从哪个分组搬,默认「正在长出来的」' },
726
+ to: { type: 'string', description: '搬到哪个分组,默认「已经完工的」' },
727
+ },
728
+ required: ['item'],
729
+ additionalProperties: false,
730
+ },
731
+ output,
732
+ async execute(args) {
733
+ const r = await promoteHouseItem(args?.item, args?.from, args?.to);
734
+ return r.ok
735
+ ? { ok: true, message: `已从「${r.data.from}」搬到「${r.data.to}」:${r.data.item}` }
736
+ : { ok: false, message: r.error?.message || '没搬成' };
737
+ },
738
+ }),
739
+ 'dsh-house: house_done',
740
+ );
655
741
  });
656
742
 
657
743
  // ---------------------------------------------------------------- web API
@@ -697,7 +783,9 @@ export function apply(ctx, config = {}) {
697
783
  const u = updateChecker.get() || {};
698
784
  result.data.version = pkgVersion;
699
785
  result.data.latest = u.latest || '';
700
- result.data.updateAvailable = u.updateAvailable === true;
786
+ // 用**实时**的本机版本重算,别信缓存里的 updateAvailable:
787
+ // 本地升到和 npm 同版本后,缓存的 true 会让页面显示「0.3.2 → 0.3.2 可更新」。
788
+ result.data.updateAvailable = u.latest ? compareVersions(u.latest, pkgVersion) > 0 : false;
701
789
  }
702
790
  writeJson(response, 200, result);
703
791
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jiugeqqqqq/dsh-house",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "房子 — 常驻的资产/能力清单,配一个侧边栏页面。清单会自动进系统提示(装了就生效);房子只记有没有、到哪一步,细节放 knowledge 和日志里。",
5
5
  "type": "module",
6
6
  "license": "MIT",