axmap-cli 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.
@@ -0,0 +1,32 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(sed -i 's|/\\\\*\\\\* 궤도 모드에서 허용하는 yaw 한계 \\(약 35°\\). cos 이 0.82 아래로 내려가지 않는다. \\\\*/\\\\nconst YAW_LIMIT = 0.62|X|' app/web/graph.js)",
5
+ "Bash(sed -i 's|const YAW_LIMIT = 0.62|const TILT_LIMIT = 0.62|; s|허용하는 yaw 한계|허용하는 기울기 한계 \\(yaw · pitch 공통\\)|' app/web/graph.js)",
6
+ "Bash(sed -i 's|인코딩은 인코딩이 아니다. cos\\(TILT_LIMIT\\)=0.82 이면 고리의 화면 반지름이\\\\n \\\\* \\\\[0.82R, R\\\\] 안에 머물러 이웃 단계와 절대 겹치지 않는다.|X|' app/web/graph.js)",
7
+ "Bash(sed -n '/인코딩은 인코딩이 아니다/,+2p' app/web/graph.js)",
8
+ "Bash(sed -i 's|import { applyEdits, draft, editRecord } from|import { applyEdits, draft } from|' app/server.mjs)",
9
+ "Bash(sed -i 's|\"test\": \"node --test test/protocol.test.mjs test/model.test.mjs test/analyze.test.mjs\"|\"test\": \"node --test test/protocol.test.mjs test/model.test.mjs test/analyze.test.mjs test/features.test.mjs\"|' package.json)",
10
+ "Bash(npm test *)",
11
+ "Bash(sed -i 's| .filter\\(\\(\\\\[t\\\\]\\) => t !== name \\\\&\\\\& !taken.has\\(t\\)\\)| .filter\\(\\([t]\\) => t !== name \\\\&\\\\& !taken.has\\(t\\) \\\\&\\\\& !tooCommon\\(t\\)\\)|' app/lib/features.mjs)",
12
+ "Bash(node -e ' *)",
13
+ "Bash(npm run *)",
14
+ "Bash(export AXMAP_AGENT=claude-fix GIT_AUTHOR_NAME=claude-fix GIT_AUTHOR_EMAIL=claude-fix@local GIT_COMMITTER_NAME=claude-fix GIT_COMMITTER_EMAIL=claude-fix@local)",
15
+ "Bash(node bin/axmap.mjs claim app/web/app.js app/web/graph.js app/web/style.css --task fix-click-color --intent \"이름 클릭=강조/더블클릭=이름변경, 단계 없을 때 색 회귀 수정\" --actor agent)",
16
+ "Bash(sed 's/\\\\$$//')",
17
+ "Bash(python -)",
18
+ "Bash(sed -n '/import 를 뽑을 수 있는 언어 이름/,/^\\\\]\\)/p' app/lib/analyze.mjs)",
19
+ "Bash(export AXMAP_AGENT=janghyojoon)",
20
+ "Bash(node bin/axmap.mjs release)",
21
+ "Bash(echo \"// 테스트\")",
22
+ "Bash(git add *)",
23
+ "Bash(git commit *)",
24
+ "Bash(git reset *)",
25
+ "Bash(git checkout *)"
26
+ ]
27
+ },
28
+ "enabledMcpjsonServers": [
29
+ "axmap"
30
+ ],
31
+ "enableAllProjectMcpServers": true
32
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "//name": "🔴 npm 의 'axmap' 은 2022년부터 남이 쓰고 있는 다른 꾸러미다(leozin_ 의 Map 라이브러리, 1.1.2). 그래서 `npx axmap` 은 우리 것이 아니고, 누구에게도 그렇게 안내하면 안 된다. 2026-08-28 에 axmap-cli 로 정했다 — 스코프(@사용자/이름)를 쓰지 않는 이유는 스코프가 npm 계정 이름에 묶여서 나중에 팀이나 조직으로 옮길 때 이름이 통째로 바뀌기 때문이다. 사람이 치는 **명령** 이름은 그대로 axmap 이다 (아래 bin) — 꾸러미 이름과 명령 이름은 달라도 된다.",
3
3
  "name": "axmap-cli",
4
- "version": "1.1.0",
4
+ "version": "1.1.1",
5
5
  "//private": "🔴 여기 있던 \"private\": true 를 2026-08-28 에 지웠다. 그 줄이 있는 동안 npm publish 는 거부됐다. 되돌리려면 다시 넣으면 되지만, 이미 올라간 버전은 그래도 안 사라진다 — npm 은 같은 번호를 덮어쓰지 못하고 삭제도 72시간 안에만 된다. 즉 이 줄을 되살리는 것은 '앞으로 안 올린다' 는 뜻이지 '올린 것을 없앤다' 는 뜻이 아니다.",
6
6
  "//publishConfig": "axmap-cli 는 스코프가 없어서 기본이 이미 공개다. 즉 지금은 없어도 된다. 그래도 남겨 두는 이유: 나중에 @조직/axmap 처럼 스코프를 붙이는 날 이 줄이 없으면 publish 가 '유료 플랜이 필요하다'는 엉뚱한 말로 실패한다.",
7
7
  "publishConfig": {
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
- console.log(`${m.at?.slice(0, 16).replace('T', ' ')} ${(m.from ?? '?').padEnd(18)} ${(m.to ?? 'all').padEnd(18)} ${m.subject ?? ''}`)
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
- console.log(`── ${m.subject}\n ${m.from} ${m.to} ${m.at}\n`)
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