axmap-cli 1.3.0 → 1.3.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-setup.md +9 -12
- package/README.ko.md +5 -7
- package/README.md +5 -7
- package/bin/axmap.mjs +1 -1
- package/mcp/README.md +6 -18
- package/mcp/SETUP-FOR-AI.md +2 -3
- package/mcp/install.ps1 +2 -1
- package/mcp/install.sh +2 -2
- package/package.json +1 -1
- package/tools/mcp-register.mjs +44 -14
- package/tools/setup.mjs +29 -66
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: axMap —
|
|
2
|
+
description: axMap — 어느 폴더에서든 이 PC에 전역 설치·등록한다
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
이
|
|
6
|
-
|
|
5
|
+
이 PC에서 axMap을 전역으로 사용할 수 있게 설정해줘.
|
|
6
|
+
추가 setup 옵션: $ARGUMENTS
|
|
7
7
|
|
|
8
|
-
1. 지금 폴더가
|
|
9
|
-
axMap 의 장부와 쪽지는 git 의 고아 브랜치로 오간다 — 저장소가 없으면 claim 이
|
|
10
|
-
아무에게도 안 가면서 조용히 성공한다.
|
|
8
|
+
1. 지금 폴더가 Git 저장소가 아니어도 진행한다. setup은 PC 전역 설치이며 작업 repo는 나중에 CLI를 켠 위치에서 결정한다.
|
|
11
9
|
|
|
12
10
|
2. Bash 로 아래를 실행한다.
|
|
13
11
|
|
|
14
|
-
npx -y axmap-cli@latest setup
|
|
12
|
+
npx -y axmap-cli@latest setup $ARGUMENTS
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
추가 옵션이 없으면 setup만 실행한다. repo를 지정하거나 현재 폴더를 타겟으로 저장하지 않는다.
|
|
15
|
+
사용자가 특정 repo의 장부와 커밋 훅까지 미리 준비하길 요청한 경우에만 `--repo <경로>`를 지정한다.
|
|
18
16
|
|
|
19
17
|
먼저 무엇이 바뀔지만 보고 싶으면 `--dry-run` 을 붙인다. 아무것도 쓰지 않는다.
|
|
20
18
|
|
|
@@ -25,7 +23,6 @@ description: axMap — 이 저장소에 axMap 을 붙인다 (내 git 주소를
|
|
|
25
23
|
- AI CLI 를 **완전히 껐다가 다시 켜야** MCP 도구(`ax_*`)가 뜬다
|
|
26
24
|
- 그 뒤 `/ax-start` 로 시작하면 된다
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
`setup` 은 몇 번 돌려도 안전하지만, 이미 되는 것을 다시 설치하는 것은 시간 낭비다.
|
|
26
|
+
설치·업데이트 때 setup을 한 번 실행한다. 이후 repo를 옮길 때는 setup이나 init을 반복하지 않고 그 repo에서 `ax_status` 또는 `ax_claim`을 호출한다.
|
|
30
27
|
|
|
31
|
-
|
|
28
|
+
각 repo의 장부는 첫 조회·선점 때 자동 준비하며, 같은 원격 장부를 공유하는 세션끼리 서로의 선점이 보인다.
|
package/README.ko.md
CHANGED
|
@@ -13,22 +13,20 @@ npm 패키지 이름은 `axmap-cli`, 실행 명령은 `axmap`이다.
|
|
|
13
13
|
|
|
14
14
|
## 설치
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Git 저장소 밖을 포함해 어느 폴더에서든 실행한다.
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
npm install -g axmap-cli@latest
|
|
20
|
-
cd <프로젝트-저장소>
|
|
21
20
|
axmap setup
|
|
22
|
-
axmap doctor
|
|
23
21
|
```
|
|
24
22
|
|
|
25
|
-
`setup`은
|
|
23
|
+
`setup`은 이 PC에 axMap을 설치하고 AI 도구의 사용자 설정에 MCP를 등록한다. 실행한 폴더에 타겟을 고정하거나 repo를 초기화하지 않는다.
|
|
26
24
|
MCP를 사용하려면 설정 후 AI 도구를 다시 시작한다.
|
|
27
25
|
함께 작업하는 사람과 에이전트는 같은 원격 장부를 사용해야 서로의 선점을 볼 수 있다.
|
|
28
26
|
|
|
29
27
|
자세한 설치·설정은 [docs/INSTALL.md](https://github.com/rl2aderjoon/axmap/blob/main/docs/INSTALL.md)를 참고한다.
|
|
30
28
|
|
|
31
|
-
## 1.3.
|
|
29
|
+
## 1.3.1: 어느 폴더에서든 setup 한 번, 이후 repo 자동 연결
|
|
32
30
|
|
|
33
31
|
axMap을 한 번 설정하면 다른 Git 저장소에서도 Codex 등 AI CLI를 열어 바로 사용할 수 있다. 세션의 작업 repo를 자동으로 선택하고, 첫 조회·선점 때 장부를 준비하므로 매번 `axmap init`을 실행하지 않아도 된다.
|
|
34
32
|
|
|
@@ -36,14 +34,14 @@ axMap을 한 번 설정하면 다른 Git 저장소에서도 Codex 등 AI CLI를
|
|
|
36
34
|
|
|
37
35
|
MCP는 클라이언트가 알려주는 작업 폴더(roots)를 따라간다. 미지원 클라이언트는 시작 폴더를 사용하며, 도중에 폴더를 바꾸면 도구의 `cwd`에 작업 폴더 절대 경로를 전달한다. 커밋 훅을 적용할 새 repo에서는 `axmap hook install`을 실행한다.
|
|
38
36
|
|
|
39
|
-
기존 설치를 업그레이드할
|
|
37
|
+
기존 설치를 업그레이드할 때도 어느 폴더에서든 아래 명령을 한 번 실행하고 AI CLI를 다시 시작한다.
|
|
40
38
|
|
|
41
39
|
```bash
|
|
42
40
|
npm install -g axmap-cli@latest
|
|
43
41
|
axmap setup
|
|
44
42
|
```
|
|
45
43
|
|
|
46
|
-
`setup`은 MCP와
|
|
44
|
+
`setup`은 MCP와 공유 훅 실행 사본 및 등록을 갱신한다. 이후 repo를 옮길 때는 setup이나 init을 반복하지 않는다. 특정 repo의 장부와 커밋 훅까지 미리 준비하려면 `axmap setup --repo <경로>`를 명시한다.
|
|
47
45
|
|
|
48
46
|
## 작업 흐름
|
|
49
47
|
|
package/README.md
CHANGED
|
@@ -13,22 +13,20 @@ The npm package is `axmap-cli`; the command is `axmap`.
|
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
16
|
-
Run these commands
|
|
16
|
+
Run these commands from any folder, including outside a Git repository.
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
npm install -g axmap-cli@latest
|
|
20
|
-
cd <your-project-repository>
|
|
21
20
|
axmap setup
|
|
22
|
-
axmap doctor
|
|
23
21
|
```
|
|
24
22
|
|
|
25
|
-
`setup`
|
|
23
|
+
`setup` installs axMap and registers MCP in your AI tool's user settings. It does not bind the installation to the current folder or initialize a repository.
|
|
26
24
|
Restart your AI tool after setup to use MCP.
|
|
27
25
|
People and agents working together must share the same remote ledger to see each other's claims.
|
|
28
26
|
|
|
29
27
|
See [docs/INSTALL.md](https://github.com/rl2aderjoon/axmap/blob/main/docs/INSTALL.md) for installation and configuration details (Korean).
|
|
30
28
|
|
|
31
|
-
##
|
|
29
|
+
## Global setup and automatic repositories in 1.3.1
|
|
32
30
|
|
|
33
31
|
Set up axMap once, then open Codex or another AI CLI in any Git repository. axMap selects that session's repository and prepares its ledger on the first status or claim request. There is no per-repository `axmap init` step.
|
|
34
32
|
|
|
@@ -36,14 +34,14 @@ Existing remote ledgers are reused. Linked worktrees share one ledger, and simul
|
|
|
36
34
|
|
|
37
35
|
MCP follows workspace roots supplied by the client. When roots are unsupported, it uses the launch directory; pass the absolute working directory through the tool's `cwd` argument for later directory changes. Run `axmap hook install` in each repository where you want commit enforcement.
|
|
38
36
|
|
|
39
|
-
To upgrade an existing installation, run this once from
|
|
37
|
+
To upgrade an existing installation, run this once from any folder, then restart your AI CLI:
|
|
40
38
|
|
|
41
39
|
```bash
|
|
42
40
|
npm install -g axmap-cli@latest
|
|
43
41
|
axmap setup
|
|
44
42
|
```
|
|
45
43
|
|
|
46
|
-
`setup` refreshes the installed MCP and hook
|
|
44
|
+
`setup` refreshes the installed MCP and shared hook runner as well as its registration. Subsequent repository changes do not require another setup or init. To explicitly prepare one repository and its commit hook during setup, use `axmap setup --repo <path>`.
|
|
47
45
|
|
|
48
46
|
## Workflow
|
|
49
47
|
|
package/bin/axmap.mjs
CHANGED
|
@@ -2778,7 +2778,7 @@ function warnIfStale() {
|
|
|
2778
2778
|
|
|
2779
2779
|
const HELP = `axmap - AI 에이전트 작업 선점 프로토콜
|
|
2780
2780
|
|
|
2781
|
-
axmap setup
|
|
2781
|
+
axmap setup 어느 폴더에서든 이 PC에 전역 설치·등록한다 (첫 한 번)
|
|
2782
2782
|
[--remote <이름|git 주소>] [--name] [--dry-run]
|
|
2783
2783
|
axmap init 장부(고아 브랜치 + worktree)를 준비한다
|
|
2784
2784
|
axmap bus-repair 쪽지함만 준비한다 (장부는 안 건드린다)
|
package/mcp/README.md
CHANGED
|
@@ -11,15 +11,14 @@
|
|
|
11
11
|
|
|
12
12
|
## 설치
|
|
13
13
|
|
|
14
|
-
Node 20 이상과 git이 필요하다.
|
|
14
|
+
Node 20 이상과 git이 필요하다. Git 저장소 밖을 포함해 어느 폴더에서든 실행한다.
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
17
|
npm install -g axmap-cli@latest
|
|
18
18
|
axmap setup
|
|
19
|
-
axmap doctor
|
|
20
19
|
```
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
어느 폴더에서든 setup을 실행한 뒤 AI CLI를 다시 시작한다. `setup`은 PC 전역에 MCP와 명령을 설치·등록하며 repo를 초기화하거나 타겟으로 저장하지 않는다. 이후 AI CLI를 켠 repo에서 장부를 자동 준비한다. 소스 개발 환경에서는 `node bin/axmap.mjs setup`을 사용한다. 명시적 repo 준비는 `setup --repo <경로>`를 사용한다.
|
|
23
22
|
|
|
24
23
|
AI에게 설치를 맡기려면 다음 공개 문서를 제공한다.
|
|
25
24
|
|
|
@@ -73,7 +72,7 @@ Claude Code 에서는 `/ax`, `/ax-start`, `/ax-done`, `/ax-tell` 로도 부른
|
|
|
73
72
|
| Claude Code (`claude`) | `~/.claude.json` 의 user 범위 (**이 PC 의 모든 폴더에 적용되는 개인 설정**) | 설치기가 `claude mcp add -s user` 로 | ✅ 이 PC 에서 확인 |
|
|
74
73
|
| Claude Code (`claude`) | 저장소의 `.mcp.json` | 저장소에 들어 있으면 스스로 발견 | ✅ 이 저장소가 그렇게 쓴다 |
|
|
75
74
|
| Antigravity (`agy`) | `~/.gemini/config/mcp_config.json` (전역, `mcpServers`) | `tools/mcp-register.mjs` | ✅ `agy` 1.1.10 으로 확인 |
|
|
76
|
-
| Codex (`codex`) | `~/.codex/config.toml` (전역, `[mcp_servers.axmap]`) | `tools/mcp-register.mjs
|
|
75
|
+
| Codex (`codex`) | `~/.codex/config.toml` (전역, `[mcp_servers.axmap]`) | `tools/mcp-register.mjs`가 Codex CLI로 등록·검증 | 임시 사용자 환경에서 실제 CLI 등록과 repo별 MCP 실행 확인 |
|
|
77
76
|
|
|
78
77
|
`agy` 에서 확인한 것: 전역 파일은 먹고, 저장소의 `.mcp.json` 은 **안 먹는다.**
|
|
79
78
|
공식 문서의 작업 폴더용 `.agents/mcp_config.json` 도 CLI 에서는 안 먹었다(IDE 쪽으로 보인다).
|
|
@@ -163,11 +162,7 @@ clone 하면 장부에는 `claude` 라는 **한 명**만 존재하고, 겹침
|
|
|
163
162
|
3. OS 사용자 이름
|
|
164
163
|
4. 호스트 이름
|
|
165
164
|
|
|
166
|
-
|
|
167
|
-
`user.name` 을, 밖이면 전역 값을 답한다. 그래서 앞으로 일할 저장소 안에서 설치하는
|
|
168
|
-
것이 맞다 — 그래야 MCP 가 쓰는 이름과 같은 저장소에서 손으로 `axmap` 을 칠 때의
|
|
169
|
-
이름이 같아진다. 다르면 한 사람이 장부에서 둘이 되고, **자기가 잡은 것을 자기가
|
|
170
|
-
반납하지 못한다**(`release` 종료 코드 5).
|
|
165
|
+
**기본 전역 setup의 이름은 전역 Git 설정에서 정한다.** setup을 실행한 repo의 로컬 이름을 다른 repo에 가져가지 않는다. 명시적 프로젝트 설정에서는 해당 repo의 이름을 사용할 수 있다. 선점부터 반납까지 같은 이름·세션을 사용해야 한다.
|
|
171
166
|
|
|
172
167
|
이름 검증은 설치기가 다시 짜지 않고 저장소의 `agentNameError()` 를 그대로 부른다.
|
|
173
168
|
설치기가 통과시킨 이름을 서버가 거부하는 일이 없어야 하기 때문이다.
|
|
@@ -207,16 +202,9 @@ clone 하면 장부에는 `claude` 라는 **한 명**만 존재하고, 겹침
|
|
|
207
202
|
|
|
208
203
|
## 안 되는 것 / 아직 확인 못 한 것
|
|
209
204
|
|
|
210
|
-
**Codex
|
|
211
|
-
`~/.codex/config.toml` 형식은 공식 문서를 따른 것이고, `mcp-register` 는
|
|
212
|
-
`codex mcp --help` 를 먼저 찔러 보고 그 하위 명령이 실제로 있을 때만 등록한다.
|
|
213
|
-
TOML 을 직접 파싱하지도 쓰지도 않는다 — 어설픈 파서가 남의 `config.toml` 을 깨뜨리는
|
|
214
|
-
것이 이 작업에서 나올 수 있는 최악의 결과다.
|
|
205
|
+
**Codex CLI 등록은 임시 사용자 환경에서 실제 실행으로 확인했다.** `codex mcp list --json`으로 서버 경로·환경·시작 cwd를 확인하고 `codex mcp add`로 갱신한 뒤 다시 검증한다. TOML을 직접 파싱하거나 덮어쓰지 않는다. 모델 클라이언트별 roots 지원 여부는 별도 확인이 필요하다.
|
|
215
206
|
|
|
216
|
-
|
|
217
|
-
`AXMAP_AGENT` 를 빼고 부르고, 이미 등록돼 있으면 다시 부르지도 않는다. 그래서 설치기는
|
|
218
|
-
codex 에 대해서는 **확인만 하고 이름은 손으로 넣으라고 한 줄 찍는다.** 확인 안 된
|
|
219
|
-
도구의 설정을 추측으로 덮어쓰는 것보다 낫다고 봤다.
|
|
207
|
+
**개인 환경값은 보존한다.** Codex의 기존 `AXMAP_AGENT` 등 개인 환경값은 유지하며, 전역 setup은 예전 서버 경로·고정 `AXMAP_REPO`·시작 cwd를 제거한다. 이름을 따로 지정하지 않았으면 MCP가 작업 repo의 Git 설정에서 정한다.
|
|
220
208
|
|
|
221
209
|
**MCP `roots`는 1.3.0부터 지원한다.** 클라이언트가 지원을 선언하면 `roots/list`로 작업 폴더를 받고 변경 알림도 처리한다. 지원하지 않는 클라이언트는 시작 repo를 사용하고, 실행 중 경로 변경은 도구의 `cwd`로 전달한다. 프로토콜 회귀 테스트로 검증했으며 클라이언트별 실제 지원 여부는 별도 확인이 필요하다.
|
|
222
210
|
|
package/mcp/SETUP-FOR-AI.md
CHANGED
|
@@ -8,15 +8,14 @@ Node 20 이상과 git을 확인한다. npm 패키지 이름은 `axmap-cli`다.
|
|
|
8
8
|
npm install -g axmap-cli@latest
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Git 저장소 밖을 포함해 어느 폴더에서든 다음 명령을 실행한다. setup에는 작업 repo를 지정할 필요가 없다.
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
axmap setup --dry-run
|
|
15
15
|
axmap setup
|
|
16
|
-
axmap doctor
|
|
17
16
|
```
|
|
18
17
|
|
|
19
|
-
`setup`은 AI CLI의 사용자 설정에 MCP를
|
|
18
|
+
`setup`은 프로그램과 전역 명령을 설치하고 AI CLI의 사용자 설정에 MCP를 등록한다. repo를 초기화하거나 `AXMAP_REPO`를 특정 폴더로 고정하지 않는다. repo의 장부와 커밋 훅도 미리 준비하려면 `--repo <경로>`를 명시하고, 다른 원격을 공유하려면 `--remote <git-주소>`도 지정한다.
|
|
20
19
|
|
|
21
20
|
1.3.0부터 다른 repo로 이동할 때 `setup`이나 `init`을 반복하지 않는다. 새 작업 repo에서 AI CLI를 실행하면 첫 조회·선점 시 장부를 자동 준비한다. MCP roots가 지원되면 작업 폴더 변경도 따라간다. 지원되지 않거나 여러 repo가 열려 있으면 도구의 `cwd`에 현재 작업 폴더 절대 경로를 전달한다. 커밋 훅을 새 repo에도 적용하려면 `axmap hook install`을 실행한다.
|
|
22
21
|
|
package/mcp/install.ps1
CHANGED
|
@@ -228,6 +228,7 @@ if (-not (Test-Path -LiteralPath $server)) { Fail "복사가 끝났는데 서버
|
|
|
228
228
|
# 이미 한다. 여기서 다시 짜지 않는다.
|
|
229
229
|
Say ''
|
|
230
230
|
& node (Join-Path $Dest 'tools\mcp-register.mjs')
|
|
231
|
+
if ($LASTEXITCODE -ne 0) { Fail 'AI CLI 전역 등록을 확인하지 못했습니다. 위 오류를 해결하고 setup을 다시 실행하세요.' }
|
|
231
232
|
Say ' (위에 claude 가 ".mcp.json 이 없습니다" 로 나왔다면, 그건 "저장소 안의'
|
|
232
233
|
Say ' .mcp.json" 을 찾는 검사입니다. 전역 설치에는 그 파일이 없는 것이 정상이고,'
|
|
233
234
|
Say ' Claude Code 는 바로 아래에서 따로 등록합니다.)'
|
|
@@ -295,7 +296,7 @@ if (-not (Get-Command codex -ErrorAction SilentlyContinue)) {
|
|
|
295
296
|
$listed = "$(& codex mcp list)"
|
|
296
297
|
if ($listed -match 'axmap') {
|
|
297
298
|
$stCodex = 'ok'
|
|
298
|
-
$whyCodex =
|
|
299
|
+
$whyCodex = '~/.codex/config.toml (codex mcp list로 확인). 작업 repo는 실행 위치에서 결정하고 이름은 git 설정을 사용합니다.'
|
|
299
300
|
} else {
|
|
300
301
|
$stCodex = 'fail'; $whyCodex = 'codex mcp list 에 axmap 이 없습니다 — 위 TOML 조각을 손으로 넣으세요'
|
|
301
302
|
}
|
package/mcp/install.sh
CHANGED
|
@@ -226,7 +226,7 @@ SERVER="$DEST/mcp/server.mjs"
|
|
|
226
226
|
# 이 PC 에 어떤 CLI 가 있는지 찾고 각자의 설정에 넣는 일은 tools/mcp-register.mjs 가
|
|
227
227
|
# 이미 한다. 여기서 다시 짜지 않는다.
|
|
228
228
|
say ''
|
|
229
|
-
node "$DEST/tools/mcp-register.mjs"
|
|
229
|
+
node "$DEST/tools/mcp-register.mjs" || fail 'AI CLI 전역 등록을 확인하지 못했습니다. 위 오류를 해결하고 setup을 다시 실행하세요.'
|
|
230
230
|
say ' (위에 claude 가 ".mcp.json 이 없습니다" 로 나왔다면, 그건 "저장소 안의'
|
|
231
231
|
say ' .mcp.json" 을 찾는 검사입니다. 전역 설치에는 그 파일이 없는 것이 정상이고,'
|
|
232
232
|
say ' Claude Code 는 바로 아래에서 따로 등록합니다.)'
|
|
@@ -293,7 +293,7 @@ if ! command -v codex >/dev/null 2>&1; then
|
|
|
293
293
|
else
|
|
294
294
|
if codex mcp list 2>/dev/null | grep -q axmap; then
|
|
295
295
|
ST_CODEX='ok'
|
|
296
|
-
WHY_CODEX=
|
|
296
|
+
WHY_CODEX='~/.codex/config.toml (codex mcp list로 확인). 작업 repo는 실행 위치에서 결정하고 이름은 git 설정을 사용합니다.'
|
|
297
297
|
else
|
|
298
298
|
ST_CODEX='fail'; WHY_CODEX='codex mcp list 에 axmap 이 없습니다 — 위 TOML 조각을 손으로 넣으세요'
|
|
299
299
|
fi
|
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.3.
|
|
4
|
+
"version": "1.3.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/mcp-register.mjs
CHANGED
|
@@ -105,6 +105,7 @@ const same = (a, b) => JSON.stringify(a) === JSON.stringify(b)
|
|
|
105
105
|
*/
|
|
106
106
|
const sameEntry = (cur, want) =>
|
|
107
107
|
!!cur && cur.command === want.command &&
|
|
108
|
+
!cur.cwd && !Object.hasOwn(cur.env ?? {}, 'AXMAP_REPO') &&
|
|
108
109
|
JSON.stringify(cur.args || []) === JSON.stringify(want.args) &&
|
|
109
110
|
Object.entries(want.env).every(([k, v]) => ((cur.env || {})[k] === v))
|
|
110
111
|
|
|
@@ -118,6 +119,8 @@ function doClaude(bin, repo) {
|
|
|
118
119
|
snippetClaude()
|
|
119
120
|
return
|
|
120
121
|
}
|
|
122
|
+
want.env = { ...(cur?.env ?? {}), ...want.env }
|
|
123
|
+
delete want.env.AXMAP_REPO
|
|
121
124
|
if (sameEntry(cur, want)) { ok('claude', '이미 등록돼 있습니다 (user 범위)'); return }
|
|
122
125
|
|
|
123
126
|
// 문서에 있다고 믿고 부르지 않는다 — 먼저 물어본다. doCodex 와 같다.
|
|
@@ -133,7 +136,7 @@ function doClaude(bin, repo) {
|
|
|
133
136
|
'--', want.command, ...want.args]
|
|
134
137
|
|
|
135
138
|
if (DRY) {
|
|
136
|
-
hm('claude',
|
|
139
|
+
hm('claude', '(dry-run) Claude 사용자 설정의 axmap 서버 경로·환경을 갱신합니다')
|
|
137
140
|
return
|
|
138
141
|
}
|
|
139
142
|
|
|
@@ -220,6 +223,8 @@ function mergeJson(label, file) {
|
|
|
220
223
|
}
|
|
221
224
|
|
|
222
225
|
const servers = cfg.mcpServers ?? {}
|
|
226
|
+
want.env = { ...(servers.axmap?.env ?? {}), ...want.env }
|
|
227
|
+
delete want.env.AXMAP_REPO
|
|
223
228
|
if (same(servers.axmap, want)) { ok(label, `이미 등록돼 있습니다: ${file}`); return }
|
|
224
229
|
|
|
225
230
|
const had = servers.axmap !== undefined
|
|
@@ -261,31 +266,56 @@ function snippetJson() {
|
|
|
261
266
|
// 🔴 TOML 을 직접 파싱하지 않는다. 파서를 새로 짜는 것은 이 저장소의 "의존성 없음" 과
|
|
262
267
|
// "판정을 복잡하게 만들지 않는다" 에 둘 다 어긋나고, 어설픈 파서가 남의 config.toml 을
|
|
263
268
|
// 깨뜨리는 것이 이 작업에서 나올 수 있는 최악의 결과다. 쓰는 일은 codex 자신에게 맡긴다.
|
|
264
|
-
function doCodex(bin) {
|
|
265
|
-
const run = (args) => spawnSync(bin, args, { encoding: 'utf8', windowsHide: true })
|
|
269
|
+
export function doCodex(bin, { run: injectedRun, dry = DRY } = {}) {
|
|
270
|
+
const run = injectedRun ?? ((args) => spawnSync(bin, args, { cwd: os.homedir(), encoding: 'utf8', windowsHide: true }))
|
|
266
271
|
|
|
267
272
|
const help = run(['mcp', '--help'])
|
|
268
273
|
if (help.status !== 0 || !/\badd\b/.test(`${help.stdout}${help.stderr}`)) {
|
|
269
274
|
hm('codex', "'codex mcp add' 를 확인하지 못했습니다 — 손으로 넣으세요")
|
|
270
275
|
snippetToml()
|
|
271
|
-
return
|
|
276
|
+
return false
|
|
272
277
|
}
|
|
273
278
|
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
+
// Check the actual command and environment, not just the server name. An old
|
|
280
|
+
// registration may still point at a temporary install or pin AXMAP_REPO.
|
|
281
|
+
const list = run(['mcp', 'list', '--json'])
|
|
282
|
+
let servers
|
|
283
|
+
try { servers = JSON.parse(list.stdout) } catch { /* reported below */ }
|
|
284
|
+
if (list.status !== 0 || !Array.isArray(servers)) {
|
|
285
|
+
no('codex', '기존 MCP 설정을 확인하지 못했습니다 — 설정을 덮어쓰지 않았습니다')
|
|
286
|
+
return false
|
|
287
|
+
}
|
|
288
|
+
const current = servers.find((s) => s.name === 'axmap')
|
|
289
|
+
const transport = current?.transport
|
|
290
|
+
const want = entry()
|
|
291
|
+
const wantedEnv = { ...(transport?.env ?? {}), ...want.env }
|
|
292
|
+
delete wantedEnv.AXMAP_REPO
|
|
293
|
+
if (transport?.type === 'stdio' && sameEntry(transport, { ...want, env: wantedEnv }) &&
|
|
294
|
+
!transport.cwd && !Object.hasOwn(transport.env ?? {}, 'AXMAP_REPO') && current.enabled !== false) {
|
|
295
|
+
ok('codex', '전역 등록이 최신입니다 — 실행 위치의 repo를 사용합니다')
|
|
296
|
+
return true
|
|
279
297
|
}
|
|
280
298
|
|
|
281
|
-
const add = ['mcp', 'add', 'axmap',
|
|
282
|
-
if (
|
|
299
|
+
const add = ['mcp', 'add', 'axmap', ...Object.entries(wantedEnv).flatMap(([k, v]) => ['--env', `${k}=${v}`]), '--', want.command, ...want.args]
|
|
300
|
+
if (dry) { hm('codex', '(dry-run) codex mcp add로 전역 axmap 서버 경로·환경을 갱신합니다'); return true }
|
|
283
301
|
|
|
284
302
|
const r = run(add)
|
|
285
|
-
if (r.status === 0)
|
|
303
|
+
if (r.status === 0) {
|
|
304
|
+
const check = run(['mcp', 'list', '--json'])
|
|
305
|
+
let saved
|
|
306
|
+
try { saved = JSON.parse(check.stdout)?.find((s) => s.name === 'axmap') } catch { /* below */ }
|
|
307
|
+
if (check.status === 0 && sameEntry(saved?.transport, { ...want, env: wantedEnv }) &&
|
|
308
|
+
!saved.transport.cwd && !Object.hasOwn(saved.transport.env ?? {}, 'AXMAP_REPO')) {
|
|
309
|
+
ok('codex', '전역 등록을 갱신했습니다 — 실행 위치의 repo를 사용합니다')
|
|
310
|
+
return true
|
|
311
|
+
}
|
|
312
|
+
no('codex', '등록 후 서버 경로·작업 폴더 설정이 일치하지 않습니다')
|
|
313
|
+
return false
|
|
314
|
+
}
|
|
286
315
|
else {
|
|
287
316
|
no('codex', `codex mcp add 가 실패했습니다 (${(r.stderr || r.stdout || '').trim().split('\n')[0] || `exit ${r.status}`})`)
|
|
288
317
|
snippetToml()
|
|
318
|
+
return false
|
|
289
319
|
}
|
|
290
320
|
}
|
|
291
321
|
|
|
@@ -339,7 +369,7 @@ function main() {
|
|
|
339
369
|
any = true
|
|
340
370
|
if (a.id === 'claude') doClaude(bin, root)
|
|
341
371
|
else if (a.id === 'agy') doAgy()
|
|
342
|
-
else if (a.id === 'codex'
|
|
372
|
+
else if (a.id === 'codex' && !doCodex(bin)) return 1
|
|
343
373
|
}
|
|
344
374
|
|
|
345
375
|
if (!any) hm('CLI', '이 PC 에서 AI CLI 를 찾지 못했습니다 — 나중에 다시 실행하세요')
|
|
@@ -350,4 +380,4 @@ function main() {
|
|
|
350
380
|
return 0
|
|
351
381
|
}
|
|
352
382
|
|
|
353
|
-
process.exit(main())
|
|
383
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) process.exit(main())
|
package/tools/setup.mjs
CHANGED
|
@@ -1,43 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* npx -y axmap-cli@latest setup --remote https://lab.ssafy.com/우리팀/우리저장소.git
|
|
8
|
-
*
|
|
9
|
-
* ── 이 파일이 메우는 구멍 ───────────────────────────────────────────────────
|
|
10
|
-
*
|
|
11
|
-
* `mcp/install.sh` · `mcp/install.ps1` 은 이미 "홈에 복사하고 이 PC 의 AI CLI 에
|
|
12
|
-
* 등록한다" 를 한다. 다만 **axMap 파일이 이미 손에 있어야** 시작할 수 있다 —
|
|
13
|
-
* 스크립트만 따로 내려받으면 대놓고 거절한다. 그래서 지금까지 설치의 첫 단계는
|
|
14
|
-
* 언제나 "저장소를 통째로 clone" 이었다.
|
|
15
|
-
*
|
|
16
|
-
* npm 꾸러미가 그 첫 단계를 대신한다. `npx` 가 꾸러미를 받아 풀어 주므로,
|
|
17
|
-
* 이 파일이 도는 시점에는 axMap 원본이 이미 옆에 있다. 여기서는 그 뒤를 잇는다.
|
|
18
|
-
*
|
|
19
|
-
* 1. 이 PC 에 프로그램을 둔다 → mcp/install.{sh,ps1} 에 맡긴다 (다시 안 짠다)
|
|
20
|
-
* 2. 이 PC 의 AI CLI 에 등록한다 → 위와 같음
|
|
21
|
-
* 3. 대상 저장소에 장부를 만든다 → axmap init
|
|
22
|
-
* 4. 커밋 훅을 심는다 → axmap hook install
|
|
23
|
-
* 5. 슬래시 명령을 놓는다 → ~/.claude/commands/ (또는 저장소 안)
|
|
24
|
-
*
|
|
25
|
-
* ── 🔴 git 을 떼어내지 않는다 ───────────────────────────────────────────────
|
|
26
|
-
*
|
|
27
|
-
* 없앤 것은 **"axMap 코드를 받는 수단으로서의 git"**(clone·벤더링·git pull)이지
|
|
28
|
-
* **"협업 백엔드로서의 git"** 이 아니다. 장부와 쪽지는 그대로 고아 브랜치
|
|
29
|
-
* (`axmap/claims` · `axmap/bus`)로 오간다. git push 의 ref CAS(Compare-And-Swap —
|
|
30
|
-
* "내가 읽은 뒤로 바뀐 게 없을 때만 쓴다") 가 직렬화를 공짜로 주기 때문이고,
|
|
31
|
-
* 그것을 버리면 락 서버를 따로 세워야 한다. 그건 다른 제품이다.
|
|
32
|
-
*
|
|
33
|
-
* 그래서 대상이 git 저장소가 아니면 **여기서 멈춘다.** 반쯤 되는 상태로 두면
|
|
34
|
-
* claim 이 아무에게도 안 가면서 조용히 성공한다 — 이 도구에서 제일 나쁜 실패다.
|
|
35
|
-
*
|
|
36
|
-
* ── 종료 코드 ───────────────────────────────────────────────────────────────
|
|
37
|
-
*
|
|
38
|
-
* 0 다 됐다
|
|
39
|
-
* 1 시작할 수 없다 (node 가 낮다 · git 저장소가 아니다 · 이름을 못 정했다)
|
|
40
|
-
* 2 일부가 안 됐다. 무엇이 안 됐는지 !! 줄에 있다
|
|
3
|
+
* Install axMap globally from any directory. Installation is machine state;
|
|
4
|
+
* repository ledgers are prepared at runtime in the caller's working repo.
|
|
5
|
+
* Only explicit project options (--repo / --remote / --commands project)
|
|
6
|
+
* select a repository during setup. Commit enforcement remains opt-in.
|
|
41
7
|
*/
|
|
42
8
|
|
|
43
9
|
import { spawnSync } from 'node:child_process'
|
|
@@ -84,21 +50,21 @@ const has = (n) => argv.includes(n)
|
|
|
84
50
|
|
|
85
51
|
if (has('-h') || has('--help')) {
|
|
86
52
|
say(`
|
|
87
|
-
axmap setup —
|
|
53
|
+
axmap setup — 어느 폴더에서든 이 PC에 axMap을 전역 설치·등록한다
|
|
88
54
|
|
|
89
55
|
npx -y axmap-cli@latest setup
|
|
90
56
|
npx -y axmap-cli@latest setup --remote <이름 또는 git 주소>
|
|
91
57
|
|
|
92
|
-
--repo <경로>
|
|
58
|
+
--repo <경로> 선택 사항: 이 저장소의 장부·커밋 훅도 명시적으로 준비한다
|
|
93
59
|
--remote <이름|URL> 장부를 둘 원격. git 주소를 주면, 그 주소를 가리키는 원격이
|
|
94
60
|
없을 때 'axmap' 이라는 이름으로 하나 더한다
|
|
95
|
-
--name <이름>
|
|
61
|
+
--name <이름> 내 이름 (기본: 전역 git config user.name, 명시적 repo는 로컬 값)
|
|
96
62
|
--dest <경로> 프로그램을 둘 자리 (기본: ~/.axmap/app)
|
|
97
63
|
--commands <곳> 슬래시 명령을 둘 자리: global(기본) · project · none
|
|
98
64
|
--hook 프롬프트마다 쪽지를 받는 하네스 훅을 settings.json 에 더한다
|
|
99
65
|
(기본은 안 더한다 — 매 턴 도는 명령이라 사람이 고를 일이다)
|
|
100
66
|
--no-register 이 PC 의 AI CLI 등록을 건너뛴다
|
|
101
|
-
--no-ledger
|
|
67
|
+
--no-ledger --repo를 지정했어도 장부·커밋 훅을 건드리지 않는다
|
|
102
68
|
--dry-run 아무것도 쓰지 않고 무엇을 할지만 찍는다
|
|
103
69
|
|
|
104
70
|
종료 코드: 0 성공 · 1 시작 불가 · 2 일부 실패
|
|
@@ -132,24 +98,19 @@ ok('node', `v${process.versions.node}`)
|
|
|
132
98
|
|
|
133
99
|
// ── 2. 대상 저장소 ──────────────────────────────────────────────────────────
|
|
134
100
|
//
|
|
135
|
-
//
|
|
136
|
-
const
|
|
137
|
-
if (!
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
` 먼저 작업할 저장소 안으로 들어간 뒤 다시 실행하세요:\n` +
|
|
148
|
-
` cd <저장소> && npx -y axmap-cli@latest setup`,
|
|
149
|
-
)
|
|
101
|
+
// Installation has no working repository. Only explicit project options use one.
|
|
102
|
+
const projectRequested = has('--repo') || has('--remote') || commandsWhere === 'project'
|
|
103
|
+
if (has('--repo') && !flag('--repo')) die('--repo 뒤에 저장소 경로를 지정하세요.')
|
|
104
|
+
let REPO = null
|
|
105
|
+
if (projectRequested) {
|
|
106
|
+
const where = path.resolve(flag('--repo') ?? process.cwd())
|
|
107
|
+
const top = git(['rev-parse', '--show-toplevel'], where)
|
|
108
|
+
if (top.code !== 0) die(`프로젝트 옵션의 대상이 Git 저장소가 아닙니다: ${where}\n전역 설치만 하려면 --repo, --remote, --commands project 없이 axmap setup을 실행하세요.`)
|
|
109
|
+
REPO = path.resolve(top.out)
|
|
110
|
+
ok('저장소', `${REPO} (명시적 프로젝트 설정)`)
|
|
111
|
+
} else {
|
|
112
|
+
ok('설치 범위', '이 PC 전체 — 작업 repo는 이후 CLI·MCP 실행 위치에서 결정합니다')
|
|
150
113
|
}
|
|
151
|
-
const REPO = path.resolve(top.out)
|
|
152
|
-
ok('저장소', REPO)
|
|
153
114
|
|
|
154
115
|
// ── 3. 이름 ─────────────────────────────────────────────────────────────────
|
|
155
116
|
//
|
|
@@ -159,8 +120,8 @@ ok('저장소', REPO)
|
|
|
159
120
|
let name = flag('--name')
|
|
160
121
|
let nameFrom = '--name'
|
|
161
122
|
if (!name) {
|
|
162
|
-
const g = git(['config', 'user.name'], REPO)
|
|
163
|
-
if (g.code === 0 && g.out) { name = g.out; nameFrom = 'git config user.name' }
|
|
123
|
+
const g = git(REPO ? ['config', 'user.name'] : ['config', '--global', 'user.name'], REPO ?? os.homedir())
|
|
124
|
+
if (g.code === 0 && g.out) { name = g.out; nameFrom = REPO ? 'git config user.name' : 'git config --global user.name' }
|
|
164
125
|
}
|
|
165
126
|
if (!name) {
|
|
166
127
|
try { name = os.userInfo().username; nameFrom = 'OS 사용자 이름' } catch { /* 아래 */ }
|
|
@@ -230,7 +191,7 @@ function configureRemote(spec) {
|
|
|
230
191
|
else ok('장부 원격', `git config axmap.remote = ${picked}`)
|
|
231
192
|
}
|
|
232
193
|
|
|
233
|
-
configureRemote(flag('--remote'))
|
|
194
|
+
if (REPO) configureRemote(flag('--remote'))
|
|
234
195
|
|
|
235
196
|
// ── 5. 프로그램을 이 PC 에 둔다 + AI CLI 에 등록한다 ────────────────────────
|
|
236
197
|
//
|
|
@@ -250,8 +211,8 @@ function installAndRegister() {
|
|
|
250
211
|
|
|
251
212
|
say('')
|
|
252
213
|
const r = win
|
|
253
|
-
? spawnSync('powershell', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', script, '-Source', SOURCE_ROOT, '-Dest', DEST, '-Name', name], { stdio: 'inherit', windowsHide: true })
|
|
254
|
-
: spawnSync('bash', [script, '--source', SOURCE_ROOT, '--dest', DEST, '--name', name], { stdio: 'inherit' })
|
|
214
|
+
? spawnSync('powershell', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', script, '-Source', SOURCE_ROOT, '-Dest', DEST, '-Name', name], { cwd: os.homedir(), stdio: 'inherit', windowsHide: true })
|
|
215
|
+
: spawnSync('bash', [script, '--source', SOURCE_ROOT, '--dest', DEST, '--name', name], { cwd: os.homedir(), stdio: 'inherit' })
|
|
255
216
|
say('')
|
|
256
217
|
|
|
257
218
|
if (r.status === 0) ok('설치·등록', DEST)
|
|
@@ -266,6 +227,7 @@ installAndRegister()
|
|
|
266
227
|
// 부르면 `hook install` 이 그 임시 경로를 훅에 박고, npx 캐시가 비워지는 순간
|
|
267
228
|
// 훅이 없는 파일을 가리킨다 — 커밋할 때마다 오류가 나는데 원인은 안 보인다.
|
|
268
229
|
function ledgerAndHook() {
|
|
230
|
+
if (!REPO) { hm('장부·커밋 훅', '작업 repo의 장부는 첫 사용 때 자동 준비합니다. 커밋 훅은 axmap hook install로 선택합니다.'); return }
|
|
269
231
|
if (has('--no-ledger')) { hm('장부', '--no-ledger — 건너뜁니다'); return }
|
|
270
232
|
|
|
271
233
|
const installed = path.join(DEST, 'bin', 'axmap.mjs')
|
|
@@ -482,9 +444,10 @@ say('설치가 끝났습니다.')
|
|
|
482
444
|
say('')
|
|
483
445
|
say('다음:')
|
|
484
446
|
say(' 1. AI CLI 를 완전히 껐다가 다시 켭니다')
|
|
485
|
-
say(
|
|
447
|
+
say(' 2. 원하는 Git repo에서 AI CLI를 실행합니다. 실행한 repo에 자동으로 연결됩니다.')
|
|
448
|
+
say(' 3. "ax_status로 지금 누가 뭘 잡고 있는지 보여줘"로 시작합니다. repo마다 setup이나 init을 반복하지 않습니다.')
|
|
486
449
|
say('')
|
|
487
450
|
say(`${C.d} 파일을 고치기 전에 claim → 끝나면 release. 그게 전부입니다.${C.x}`)
|
|
488
|
-
say(`${C.d}
|
|
451
|
+
say(`${C.d} 조회: 원하는 Git repo에서 axmap status${C.x}`)
|
|
489
452
|
say('')
|
|
490
453
|
process.exit(EXIT.OK)
|