axmap-cli 0.0.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/commands/ax-done.md +10 -0
- package/.claude/commands/ax-setup.md +31 -0
- package/.claude/commands/ax-start.md +15 -0
- package/.claude/commands/ax-tell.md +14 -0
- package/.claude/commands/ax-update.md +19 -0
- package/.claude/commands/ax.md +13 -0
- package/CLAUDE.md +309 -0
- package/LICENSE +20 -0
- package/README.md +207 -0
- package/app/README.md +366 -0
- package/app/eval/edges.mjs +242 -0
- package/app/lib/adjacent.mjs +125 -0
- package/app/lib/agentcli.mjs +153 -0
- package/app/lib/analyze.mjs +1159 -0
- package/app/lib/cochange.mjs +421 -0
- package/app/lib/datanodes.mjs +127 -0
- package/app/lib/entry.mjs +192 -0
- package/app/lib/featuregraph.mjs +389 -0
- package/app/lib/features.mjs +645 -0
- package/app/lib/fetchrepo-run.mjs +37 -0
- package/app/lib/fetchrepo.mjs +164 -0
- package/app/lib/flow.mjs +1089 -0
- package/app/lib/ladder.mjs +387 -0
- package/app/lib/langs.mjs +630 -0
- package/app/lib/live.mjs +346 -0
- package/app/lib/llm.mjs +594 -0
- package/app/lib/newfile.mjs +126 -0
- package/app/lib/prdiff.mjs +651 -0
- package/app/lib/reveal.mjs +316 -0
- package/app/lib/roots.mjs +186 -0
- package/app/lib/scope.mjs +342 -0
- package/app/lib/session.mjs +389 -0
- package/app/lib/slots.mjs +233 -0
- package/app/lib/ssot.mjs +277 -0
- package/app/lib/teamview.mjs +962 -0
- package/app/lib/terms.ko.mjs +169 -0
- package/app/server.mjs +1959 -0
- package/app/web/shell.css +538 -0
- package/app/web/shell.html +197 -0
- package/app/web/shell.js +638 -0
- package/app/web/stage.js +347 -0
- package/app/web/words.js +85 -0
- package/bin/axmap.mjs +1918 -0
- package/governance/GOVERNANCE.md +433 -0
- package/governance/gate.mjs +526 -0
- package/governance/vote.mjs +501 -0
- package/mcp/README.md +254 -0
- package/mcp/SETUP-FOR-AI.md +186 -0
- package/mcp/install.ps1 +341 -0
- package/mcp/install.sh +339 -0
- package/mcp/server.mjs +969 -0
- package/package.json +48 -0
- package/src/closure.mjs +343 -0
- package/src/governance.mjs +839 -0
- package/src/invariants.mjs +226 -0
- package/src/mrtarget.mjs +284 -0
- package/src/promote.mjs +177 -0
- package/src/protocol.mjs +423 -0
- package/src/repotarget.mjs +81 -0
- package/src/update.mjs +177 -0
- package/src/version.mjs +186 -0
- package/tools/bus.mjs +520 -0
- package/tools/cluster-experiment.mjs +256 -0
- package/tools/cluster-sweep.mjs +226 -0
- package/tools/make-icon.mjs +108 -0
- package/tools/mcp-register.mjs +269 -0
- package/tools/mr-target.mjs +49 -0
- package/tools/persona-bench.mjs +362 -0
- package/tools/pick-repo.mjs +229 -0
- package/tools/promote.mjs +550 -0
- package/tools/reveal-demo.mjs +158 -0
- package/tools/run-tests.mjs +42 -0
- package/tools/setup.mjs +490 -0
- package/tools/shortcut.mjs +121 -0
- package/tools/smoke.mjs +166 -0
- package/tools/topicgraph.py +154 -0
- package/tools/vendor.mjs +382 -0
- package/tools/version.mjs +115 -0
package/src/version.mjs
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 버전 계산 — 브랜치의 **단계**가 어느 자리를 올릴지 정한다.
|
|
3
|
+
*
|
|
4
|
+
* 순수 로직만 둔다. git 호출도 시계도 여기 없다 (`tools/version.mjs` 가 담당).
|
|
5
|
+
* 이 저장소가 `src/protocol.mjs` 와 `bin/axmap.mjs` 를 가른 것과 같은 이유다 —
|
|
6
|
+
* 판정을 30분 기다리지 않고 검증할 수 있어야 한다.
|
|
7
|
+
*
|
|
8
|
+
* ── 왜 날짜가 아니라 병합인가 ────────────────────────────────────────────────
|
|
9
|
+
*
|
|
10
|
+
* 요구는 "하루가 지나면 minor, 한 주가 지나면 major" 였다. 그런데 달력으로
|
|
11
|
+
* 올리면 **아무 일도 안 한 날에도 버전이 올라간다.** 금요일에 2.0.0 을 찍었는데
|
|
12
|
+
* 그 주에 머지된 것이 하나도 없으면, 그 숫자는 무엇도 가리키지 않는다.
|
|
13
|
+
*
|
|
14
|
+
* 팀의 실제 리듬이 이미 그 주기다 — dev 는 수시로, dev→func 는 하루 한 번,
|
|
15
|
+
* func→main 은 주 한 번. 그래서 **병합이 일어난 그 순간** 버전을 올린다.
|
|
16
|
+
* 결과는 요구한 것과 같고(하루 지나면 1.1.0, 한 주 지나면 2.0.0), 다른 점은
|
|
17
|
+
* 그 숫자가 언제나 실제로 들어간 코드를 가리킨다는 것이다.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 브랜치 이름 → 단계.
|
|
22
|
+
*
|
|
23
|
+
* 🔴 **최상위 `main` 은 접두사가 없는 것뿐이다.** `back/main` 은 파트 브랜치이지
|
|
24
|
+
* 최상위가 아니다.
|
|
25
|
+
*
|
|
26
|
+
* 이 팀의 컨벤션은 파트의 중간 단계를 `<파트>/main` 으로 쓴다 (옛 저장소의
|
|
27
|
+
* `be_system/main`, 지금 실제로 만들어진 `back/main`·`front/main`).
|
|
28
|
+
* 접두사를 통째로 버리면 `back/main` 이 `main` 과 같아져 **파트에 머지할 때마다
|
|
29
|
+
* major 가 올라간다.** 하루 두 번 머지하면 이틀 만에 5.0.0 이 되고,
|
|
30
|
+
* 그 숫자는 아무것도 가리키지 않는다.
|
|
31
|
+
*
|
|
32
|
+
* 그래서 슬래시가 있으면 최상위가 아니다. 이름이 `func` 이든 `main` 이든
|
|
33
|
+
* 파트의 중간 단계는 minor 다.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* main → main (major)
|
|
37
|
+
* back/main → func (minor) ← 파트 브랜치
|
|
38
|
+
* fe/func → func (minor)
|
|
39
|
+
* back/dev → dev (patch)
|
|
40
|
+
* feat/S15…-144 → null (버전을 올리지 않는다)
|
|
41
|
+
*/
|
|
42
|
+
export function levelOf(branch) {
|
|
43
|
+
if (!branch || typeof branch !== 'string') return null
|
|
44
|
+
const name = branch.trim()
|
|
45
|
+
if (name === 'main' || name === 'master') return 'main'
|
|
46
|
+
const leaf = name.replace(/^.*\//, '')
|
|
47
|
+
// 접두사가 붙은 main 은 파트의 중간 단계다. func 과 같은 자리를 올린다.
|
|
48
|
+
if (leaf === 'main' || leaf === 'master' || leaf === 'func') return 'func'
|
|
49
|
+
if (leaf === 'dev') return 'dev'
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* `front/dev` → `front`. 슬래시가 없으면 `null`.
|
|
55
|
+
*
|
|
56
|
+
* 🔴 `mrtarget.mjs` 가 여기서 **가져다 쓴다.** 거기서 다시 만들면 한 저장소에
|
|
57
|
+
* 파트 판정이 둘이 되고, `levelOf` 를 공유하기로 한 이유가 그대로 무너진다.
|
|
58
|
+
*/
|
|
59
|
+
export function partOf(branch) {
|
|
60
|
+
const i = String(branch ?? '').lastIndexOf('/')
|
|
61
|
+
return i < 0 ? null : branch.slice(0, i)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 제품 코드가 없는 파트 — **버전을 올리지 않고, 파트 브랜치 단계도 없다.**
|
|
66
|
+
*
|
|
67
|
+
* ── 왜 예외가 필요한가 ──────────────────────────────────────────────────────
|
|
68
|
+
*
|
|
69
|
+
* `levelOf` 는 이름의 **마지막 칸만** 본다. 그래서 `common/main` 은 파트 브랜치로
|
|
70
|
+
* 읽히고 minor 를, `common` 의 내용이 최상위 `main` 에 들어가면 major 를 올린다.
|
|
71
|
+
* 그런데 `common` 에 들어 있는 것은 문서·CI·공용 설정이다. **제품이 아니다.**
|
|
72
|
+
* 문서 오타 하나를 고쳤다고 제품 버전이 오르면 그 숫자는 아무것도 가리키지 않는다 —
|
|
73
|
+
* 이 파일 머리말이 "달력으로 올리면 아무 일도 안 한 날에도 올라간다" 며 날짜 방식을
|
|
74
|
+
* 버린 것과 **똑같은 이유**다.
|
|
75
|
+
*
|
|
76
|
+
* 그리고 파트 브랜치 단계(`<파트>/main`)의 뜻은 "이 파트의 릴리스 후보" 다.
|
|
77
|
+
* 릴리스할 제품이 없는 파트에는 그 자리가 없다. 그래서 `common/dev` 는
|
|
78
|
+
* **최상위 `main` 으로 바로 간다** (`mrtarget.mjs` 가 그 판정을 한다).
|
|
79
|
+
*
|
|
80
|
+
* 🔴 **이름 목록이지 규칙이 아니다.** 파트가 제품인지 아닌지는 코드가 알 수 없다.
|
|
81
|
+
* 새 파트를 여기 넣는 것은 팀의 결정이고, 넣는 순간 그 파트는 버전을 갖지 않는다.
|
|
82
|
+
*/
|
|
83
|
+
export const NON_PRODUCT_PARTS = new Set(['common'])
|
|
84
|
+
|
|
85
|
+
/** 이 브랜치가 제품이 아닌 파트에 속하는가. */
|
|
86
|
+
export function isNonProductPart(branch) {
|
|
87
|
+
const p = partOf(branch)
|
|
88
|
+
return p !== null && NON_PRODUCT_PARTS.has(p)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** 단계 → 올릴 자리. */
|
|
92
|
+
const PART = { main: 'major', func: 'minor', dev: 'patch' }
|
|
93
|
+
|
|
94
|
+
const RE = /^v?(\d+)\.(\d+)\.(\d+)$/
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* `v1.2.3` → `{major, minor, patch}`.
|
|
98
|
+
*
|
|
99
|
+
* 🔴 못 읽으면 **0.0.0 으로 치지 않고 null 을 준다.**
|
|
100
|
+
* 태그를 잘못 읽고 0 에서 다시 시작하면 이미 나간 버전을 다시 발급하게 되고,
|
|
101
|
+
* 그러면 같은 번호가 서로 다른 코드를 가리킨다. 이 저장소가 락에서 지킨 원칙과
|
|
102
|
+
* 같다 — 애매하면 치환하지 말고 거부한다.
|
|
103
|
+
*/
|
|
104
|
+
export function parseVersion(s) {
|
|
105
|
+
const m = RE.exec(String(s ?? '').trim())
|
|
106
|
+
if (!m) return null
|
|
107
|
+
return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]) }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const formatVersion = (v) => `${v.major}.${v.minor}.${v.patch}`
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 다음 버전. `from` 이 null 이면 첫 버전이다.
|
|
114
|
+
*
|
|
115
|
+
* 첫 버전은 단계와 무관하게 `1.0.0` 이다. dev 에서 시작했다고 `0.0.1` 을 주면
|
|
116
|
+
* 사람이 "아직 아무것도 없다" 로 읽는데, 실제로는 첫 기능이 들어간 상태다.
|
|
117
|
+
*/
|
|
118
|
+
export function nextVersion(from, level) {
|
|
119
|
+
const part = PART[level]
|
|
120
|
+
if (!part) throw new Error(`알 수 없는 단계: ${level} (main | func | dev)`)
|
|
121
|
+
if (!from) return { major: 1, minor: 0, patch: 0 }
|
|
122
|
+
|
|
123
|
+
// 🔴 아래 자리를 반드시 0 으로 되돌린다. 1.2.3 에서 minor 를 올리면 1.3.0 이지
|
|
124
|
+
// 1.3.3 이 아니다. 안 되돌리면 patch 자리가 영원히 남아 두 갈래의 이력이
|
|
125
|
+
// 한 숫자에 섞인다.
|
|
126
|
+
if (part === 'major') return { major: from.major + 1, minor: 0, patch: 0 }
|
|
127
|
+
if (part === 'minor') return { major: from.major, minor: from.minor + 1, patch: 0 }
|
|
128
|
+
return { major: from.major, minor: from.minor, patch: from.patch + 1 }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 태그 목록에서 가장 높은 버전. 이름순이 아니라 **숫자순**으로 고른다.
|
|
133
|
+
*
|
|
134
|
+
* 🔴 문자열 정렬은 `v1.10.0 < v1.9.0` 이라고 답한다. `git tag --sort=-v:refname`
|
|
135
|
+
* 이 대신 해주긴 하지만, 여기서 다시 세는 이유는 그 정렬 옵션이 없는 git
|
|
136
|
+
* 버전과 CI 이미지가 실제로 있기 때문이다. 판정을 남에게 맡기지 않는다.
|
|
137
|
+
*
|
|
138
|
+
* 읽을 수 없는 태그는 **건너뛴다.** 여기서는 그것이 안전한 쪽이다 —
|
|
139
|
+
* `v` 로 시작하는 아무 태그(`v-old`, `vNext`)나 붙을 수 있고, 그것 때문에
|
|
140
|
+
* 릴리스 전체를 멈추는 것은 과하다. 버전 형식인 것만 후보로 센다.
|
|
141
|
+
*/
|
|
142
|
+
export function latestVersion(tags) {
|
|
143
|
+
let best = null
|
|
144
|
+
for (const t of tags ?? []) {
|
|
145
|
+
const v = parseVersion(t)
|
|
146
|
+
if (!v) continue
|
|
147
|
+
if (!best || v.major > best.major
|
|
148
|
+
|| (v.major === best.major && v.minor > best.minor)
|
|
149
|
+
|| (v.major === best.major && v.minor === best.minor && v.patch > best.patch)) best = v
|
|
150
|
+
}
|
|
151
|
+
return best
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 브랜치와 태그 목록에서 다음 태그 이름까지.
|
|
156
|
+
* @returns {{level: string, from: string|null, next: string, tag: string}}
|
|
157
|
+
*/
|
|
158
|
+
export function planBump(branch, tags) {
|
|
159
|
+
// 🔴 제품이 아닌 파트는 **버전을 안 갖는다.** 던지지 않고 skip 을 준다 —
|
|
160
|
+
// 던지면 `common/dev` 에 push 할 때마다 CI 의 version 잡이 빨개지고,
|
|
161
|
+
// 그건 "고칠 것이 있다" 는 뜻이 아니라 "여긴 버전이 없다" 는 뜻이다.
|
|
162
|
+
// 고장과 해당 없음을 같은 색으로 칠하면 사람이 둘을 구분하지 못한다.
|
|
163
|
+
if (isNonProductPart(branch)) {
|
|
164
|
+
return {
|
|
165
|
+
level: levelOf(branch),
|
|
166
|
+
skip: true,
|
|
167
|
+
part: partOf(branch),
|
|
168
|
+
reason: `${partOf(branch)} 은 제품 코드가 없는 파트라 버전을 올리지 않습니다.`,
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const level = levelOf(branch)
|
|
172
|
+
if (!level) {
|
|
173
|
+
throw new Error(
|
|
174
|
+
`버전을 올리는 브랜치가 아닙니다: ${branch}\n` +
|
|
175
|
+
` main / func / dev 로 끝나는 브랜치에서만 올립니다 (fe/dev 처럼 접두사는 괜찮습니다).`,
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
const from = latestVersion(tags)
|
|
179
|
+
const next = nextVersion(from, level)
|
|
180
|
+
return {
|
|
181
|
+
level,
|
|
182
|
+
from: from ? formatVersion(from) : null,
|
|
183
|
+
next: formatVersion(next),
|
|
184
|
+
tag: `v${formatVersion(next)}`,
|
|
185
|
+
}
|
|
186
|
+
}
|