@pghoya2956/livemap 1.1.0 → 1.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  버전마다 `## [X.Y.Z] - YYYY-MM-DD` 절을 둔다. 릴리스 워크플로가 태그 버전의 절이 있는지 확인한다.
4
4
 
5
+ ## [1.1.1] - 2026-09-17
6
+
7
+ 작업 어댑터가 계획 항목·결정·열린 질문을 파일 하나에서만 센다. 생성물의 키와 형식은 그대로고 값만 바뀐다.
8
+
9
+ - 계획 항목(`pnDone`·`pnOpen`)은 계획 문서(`task_plan.md`, 없으면 `plan.md`)에서만 센다. 1.1.0은 `spec/final.md`의 계획 초안 체크박스를 더해, 실행 중 체크하지 않는 그 목록만큼 분모가 부풀었다(실제 프로젝트 하나에서 작업 48/61이 48/108로 보임). 로드맵 카드·작업 화면·개요 합계가 같이 바로잡힌다. 계획 문서가 없고 스펙에만 체크박스가 있는 작업은 계획 항목이 0이 된다.
10
+ - 결정(`dec`)·열린 질문(`oq`)은 `spec/final.md`에서만 센다. 계획 문서에 옮겨 적은 줄은 세지 않는다.
11
+ - 같은 계획 항목 번호가 스펙과 계획 문서에 모두 있으면 계획 문서의 줄을 정의로 삼는다. 기능 단계 `refs`의 `PN-nn`이 계획 문서의 완료 여부를 따른다(1.1.0은 체크되지 않는 스펙 줄을 읽어 늘 미완이었다).
12
+
5
13
  ## [1.1.0] - 2026-09-17
6
14
 
7
15
  상황판 화면을 React 다크 모니터형으로 다시 만들고, 로드맵 항목을 묶는 마일스톤과 날짜·결정 대기 자료를 더했다. README 「버전」이 major로 정한 항목(config 키, 여정 형식, 어댑터 계약, 명령·종료 코드, 생성물 파일 이름, export 배치, 예산 설정 경로)은 바꾸거나 지우지 않고, 로드맵 형식·어댑터 계약·생성물은 추가만 했다.
@@ -21,7 +21,7 @@
21
21
  | testreport | 생성(JUnit 리포트) | last | 마지막 검사 실행의 건수·실패·건너뜀과 그 커밋이 최신인지 |
22
22
  | commit | 생성(git) | sha | 최근 변경. 건드린 파일 → 영향받는 화면·여정 |
23
23
  | decision | 생성(위키 index, 작업 문서) | file 또는 번호 | 위키 결정 페이지와 상태(current/proposed/superseded). 작업 문서의 `- DEC-nn`(스펙 결정)과 `- [ ] PN-nn`(계획 항목, 완료 여부)도 이 종류로 둔다 |
24
- | task | 생성(작업 폴더 `tasks.dir`) | 폴더 이름 | 작업 하나. 제목·단계(스펙 초안~검증)·상태·결정 수·계획 항목 완료/미완·열린 질문 |
24
+ | task | 생성(작업 폴더 `tasks.dir`) | 폴더 이름 | 작업 하나. 제목·단계(스펙 초안~검증)·상태·결정 수·계획 항목 완료/미완·열린 질문 수. 계획 항목은 계획 문서(`task_plan.md`, 없으면 `plan.md`)에서만, 결정·열린 질문은 `spec/final.md`에서만 센다 |
25
25
  | ledger | 생성(tasks/index.md) | 행 | 지금 실행 중·대기 중인 작업 |
26
26
  | deploy | 생성(git·배포 매니페스트) | head, 배포 대상 | 브랜치 머리 커밋, 매니페스트 이미지 태그의 sha와 뒤처진 커밋 수 |
27
27
  | milestone | 손(로드맵 `## 제목` 절) | id | 로드맵 항목. 순서·상태·진행 방식·장면·작업·선행·결정 대기·완료 기준·마일스톤, git 이력에서 계산한 완료일(`completedAt`)·결정 대기 시작일(`waitingSince`) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pghoya2956/livemap",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Project status board engine: scans a repository into a graph and serves a one-screen map of journeys, screens, APIs, tests and work.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -31,16 +31,23 @@ export default function tasks(g, fs, cfg) {
31
31
  : mention('실행 대기·중단') ? '대기'
32
32
  : mention('현재 작업') ? '진행' : '기록';
33
33
  const title = heading(plan) || heading(`${base}/spec/final.md`) || heading(`${base}/spec/initial.md`) || heading(`${base}/README.md`) || heading(`${base}/${mdIn(base)[0] || ''}`) || name.slice(9);
34
+ // 수는 파일 하나에서만 센다: 계획 항목은 체크하는 계획 문서, 결정·열린 질문은 spec/final.md.
35
+ // 스펙에 적은 계획 초안 체크박스는 실행 중 체크되지 않아 더하면 분모만 부푼다. 노드는 두 문서 모두에서 만들되 세는 문서를 먼저 읽는다.
36
+ const finalSpec = `${base}/spec/final.md`;
34
37
  let dec = 0, pnDone = 0, pnOpen = 0, oq = 0;
35
- for (const f of [`${base}/spec/final.md`, plan].filter((f) => f && fs.has(f))) {
38
+ for (const f of [finalSpec, plan].filter((f) => f && fs.has(f))) {
39
+ const t = fs.read(f);
40
+ for (const m of t.matchAll(/^- (DEC-\d+)/gm)) { if (f === finalSpec) dec += 1; if (!g.get('decision', m[1])) { g.add('decision', m[1], m[1], { kind: 'spec-dec', file: f }, { file: f, line: fs.lineOf(t, m[0]), rule: 'tasks:- DEC-nn' }); g.link('task', name, 'defines', 'decision', m[1]); } }
41
+ if (f === finalSpec) oq += (t.match(/^\| OQ-\d+ \|/gm) || []).length;
42
+ }
43
+ for (const f of [plan, finalSpec].filter((f) => f && fs.has(f))) {
36
44
  const t = fs.read(f);
37
- for (const m of t.matchAll(/^- (DEC-\d+)/gm)) { dec += 1; if (!g.get('decision', m[1])) { g.add('decision', m[1], m[1], { kind: 'spec-dec', file: f }, { file: f, line: fs.lineOf(t, m[0]), rule: 'tasks:- DEC-nn' }); g.link('task', name, 'defines', 'decision', m[1]); } }
38
45
  for (const m of t.matchAll(/^- \[(x| )\] ((?:PN|P\d)-\d+)/gim)) {
39
- const done = m[1].toLowerCase() === 'x'; if (done) pnDone += 1; else pnOpen += 1;
46
+ const done = m[1].toLowerCase() === 'x';
47
+ if (f === plan) { if (done) pnDone += 1; else pnOpen += 1; }
40
48
  const pid = m[2].toUpperCase();
41
49
  if (!g.get('decision', pid)) { g.add('decision', pid, pid, { kind: 'plan-item', done, file: f }, { file: f, line: fs.lineOf(t, m[0]), rule: 'tasks:- [ ] PN-nn' }); g.link('task', name, 'defines', 'decision', pid); }
42
50
  }
43
- oq += (t.match(/^\| OQ-\d+ \|/gm) || []).length;
44
51
  }
45
52
  const ref = fs.hasGit() ? fs.resolveRef(cfg.git?.branch || 'main') : null;
46
53
  const recent = ref ? Number(fs.git('rev-list', '--count', ref, `--since=${cfg.git?.sinceDays || 14} days ago`, '--', base) || 0) : 0;