axmap-cli 1.0.3 → 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/.claude/settings.local.json +32 -0
- package/CLAUDE.md +12 -8
- package/README.md +3 -2
- package/app/lib/teamview.mjs +15 -2
- package/bin/axmap.mjs +401 -96
- package/mcp/README.md +3 -2
- package/mcp/server.mjs +6 -4
- package/package.json +1 -1
- package/src/invariants.mjs +103 -2
- package/src/protocol.mjs +185 -144
- package/tools/bus.mjs +65 -2
package/tools/bus.mjs
CHANGED
|
@@ -633,6 +633,61 @@ function markSeen(who, id) {
|
|
|
633
633
|
const stamp = (d) => d.toISOString().replace(/[-:]/g, '').replace(/\.\d+Z$/, 'Z')
|
|
634
634
|
const slug = (s) => s.toLowerCase().replace(/[^\w가-힣]+/g, '-').replace(/^-|-$/g, '').slice(0, 40) || 'msg'
|
|
635
635
|
|
|
636
|
+
/**
|
|
637
|
+
* 시간대 치우침을 `+09:00` 처럼 적는다. 동쪽이 `+`, 서쪽이 `-` 다.
|
|
638
|
+
*
|
|
639
|
+
* 🔴 `getTimezoneOffset()` 은 **부호가 반대**다 — 서울에서 `-540`(분) 을 낸다.
|
|
640
|
+
* "이 시각을 UTC 로 만들려면 몇 분을 더해야 하나" 를 답하기 때문이다.
|
|
641
|
+
* 그래서 뒤집는다. 여기서 부호를 놓치면 화면에 `-09:00` 이 찍혀, 고치려던
|
|
642
|
+
* 것과 똑같은 병이 된다 — **시각은 맞는데 시간대가 거짓말**.
|
|
643
|
+
*
|
|
644
|
+
* 30분·45분 단위 시간대(인도 `+05:30`, 네팔 `+05:45`)도 그대로 나온다.
|
|
645
|
+
*/
|
|
646
|
+
function zoneOffset(d) {
|
|
647
|
+
const mins = -d.getTimezoneOffset()
|
|
648
|
+
const sign = mins < 0 ? '-' : '+'
|
|
649
|
+
const abs = Math.abs(mins)
|
|
650
|
+
const p = (n) => String(n).padStart(2, '0')
|
|
651
|
+
return `${sign}${p(Math.floor(abs / 60))}:${p(abs % 60)}`
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* 쪽지 시각을 **이 PC 의 시간대**로 그린다.
|
|
656
|
+
*
|
|
657
|
+
* 🔴 **여기 있던 버그다.** `m.at.slice(0, 16).replace('T', ' ')` 였다. 저장된
|
|
658
|
+
* UTC 문자열을 앞에서 잘라 놓고 그것을 지역 시각인 척 보여준 것이라, 서울에서
|
|
659
|
+
* **9시간 이른 시각**이 떴다.
|
|
660
|
+
*
|
|
661
|
+
* 실측 (2026-09-07): 파일 이름이 `20260903T071235Z` 인 쪽지가 목록에
|
|
662
|
+
* `2026-09-03 07:12` 로 떴다. 한국 시간으로는 `16:12` 다. 오후에 온 쪽지가
|
|
663
|
+
* 새벽에 온 것으로 보이니, 받은 사람은 그것을 **이미 지나간 일**로 여기고
|
|
664
|
+
* 넘긴다. 틀린 시각은 없는 시각보다 나쁘다 — 없으면 물어보지만 있으면 믿는다.
|
|
665
|
+
*
|
|
666
|
+
* 🔴 **저장은 그대로 UTC 다.** 파일 이름의 `…Z` 도 머리말의 `at:` 도 안 건드린다.
|
|
667
|
+
* 바뀌는 것은 **보여줄 때** 하나뿐이다. 저장을 지역 시간으로 옮기면 (1) 파일
|
|
668
|
+
* 이름이 곧 정렬 키이자 읽음 표시의 기준(`id <= seen`)인데 시간대가 다른 PC
|
|
669
|
+
* 끼리 순서가 어긋나고, (2) 이미 쌓인 쪽지가 전부 다른 시각을 뜻하게 된다.
|
|
670
|
+
*
|
|
671
|
+
* 🔴 `Asia/Seoul` 을 코드에 박지 않는다. 팀원이 다른 시간대에 있으면 그 사람
|
|
672
|
+
* 시계로 보여야 맞다. PC 의 시간대를 따른다.
|
|
673
|
+
*
|
|
674
|
+
* 🔴 `Intl` 을 안 쓴다. Node 를 small-icu 로 빌드하면 시간대 이름이 `GMT+9` 로만
|
|
675
|
+
* 나오거나 아예 없다. `Date` 의 지역 getter 와 `getTimezoneOffset()` 은 어느
|
|
676
|
+
* 빌드에도 있고 로케일에 따라 흔들리지도 않는다.
|
|
677
|
+
*
|
|
678
|
+
* 못 읽는 값이면 **원문을 그대로 돌려준다.** 지어내지 않는다 — 시각을 그럴듯하게
|
|
679
|
+
* 틀리게 보여주는 것이 이 함수가 고치러 온 버그다.
|
|
680
|
+
*/
|
|
681
|
+
function localTime(iso, { seconds = false } = {}) {
|
|
682
|
+
if (!iso) return '(시각 없음)'
|
|
683
|
+
const d = new Date(iso)
|
|
684
|
+
if (Number.isNaN(d.getTime())) return String(iso)
|
|
685
|
+
const p = (n) => String(n).padStart(2, '0')
|
|
686
|
+
const date = `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`
|
|
687
|
+
const time = `${p(d.getHours())}:${p(d.getMinutes())}${seconds ? `:${p(d.getSeconds())}` : ''}`
|
|
688
|
+
return `${date} ${time} ${zoneOffset(d)}`
|
|
689
|
+
}
|
|
690
|
+
|
|
636
691
|
function readAll() {
|
|
637
692
|
const found = []
|
|
638
693
|
let newBoxOpened = false
|
|
@@ -926,7 +981,12 @@ function list() {
|
|
|
926
981
|
return has('--quiet-if-empty') ? undefined : console.log('쪽지 없음.')
|
|
927
982
|
}
|
|
928
983
|
for (const m of rows) {
|
|
929
|
-
|
|
984
|
+
// 🔴 시간대 표시(`+09:00`)를 **줄마다** 붙인다. 목록 끝에 한 번만 적으면 안
|
|
985
|
+
// 되는 이유가 있다 — 이 줄들은 그대로 **잘려서 다른 곳에 다시 실린다.**
|
|
986
|
+
// MCP 배너(`mcp/server.mjs` 의 `busRows`)와 프롬프트 훅은 화살표가 있는
|
|
987
|
+
// 제목 줄만 가져가고 아래 요약 줄은 안 가져간다. 거기서 시간대가 사라지면
|
|
988
|
+
// 사람이 실제로 보는 자리에서 다시 "이게 무슨 시간인가" 가 된다.
|
|
989
|
+
console.log(`${localTime(m.at)} ${(m.from ?? '?').padEnd(18)} → ${(m.to ?? 'all').padEnd(18)} ${m.subject ?? ''}`)
|
|
930
990
|
console.log(` ${m.id}`)
|
|
931
991
|
}
|
|
932
992
|
console.log(`\n총 ${rows.length}개. 본문: ${selfCmd()} read <아이디>`)
|
|
@@ -953,7 +1013,10 @@ function read(id) {
|
|
|
953
1013
|
// 아이디를 잘못 적었다고 믿고 다시 치게 되는데, 몇 번을 쳐도 같은 답이 온다.
|
|
954
1014
|
if (!m && busProblem) { reportBusProblem(); process.exit(1) }
|
|
955
1015
|
if (!m) { console.error(`없는 쪽지: ${id}`); process.exit(1) }
|
|
956
|
-
|
|
1016
|
+
// 목록과 **같은 시간대**로 찍는다. 한쪽만 고치면 목록과 본문이 서로 다른 시각을
|
|
1017
|
+
// 말하게 되고, 숫자가 둘이면 사람은 어느 쪽도 안 믿는다. 본문은 한 통뿐이라
|
|
1018
|
+
// 초까지 보여준다 — 쪽지가 오간 순서를 따질 때 분 단위로는 모자란다.
|
|
1019
|
+
console.log(`── ${m.subject}\n ${m.from} → ${m.to} ${localTime(m.at, { seconds: true })}\n`)
|
|
957
1020
|
console.log(m.body)
|
|
958
1021
|
}
|
|
959
1022
|
|