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/mcp/install.ps1
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
<#
|
|
2
|
+
axMap MCP 전역 설치 (Windows) — 팀 저장소 밖의 사람도 이 한 줄로 붙는다.
|
|
3
|
+
|
|
4
|
+
powershell -ExecutionPolicy Bypass -File axmap\mcp\install.ps1
|
|
5
|
+
|
|
6
|
+
🔴 이 파일은 **UTF-8 BOM 으로 저장한다. BOM 을 지우지 마라.**
|
|
7
|
+
|
|
8
|
+
Windows PowerShell 5.1 은 BOM(**파일 맨 앞에 붙는 3바이트 표식. "이 파일은
|
|
9
|
+
UTF-8 이다" 를 알린다**)이 없는 스크립트를 UTF-8 이 아니라 시스템 ANSI 코드페이지
|
|
10
|
+
(한국어 윈도우면 CP949)로 읽는다. 이 파일에는 한글이 가득하고, CP949 디코더는
|
|
11
|
+
한글의 UTF-8 바이트를 잘못 묶으면서 뒤따르는 ASCII 바이트까지 삼킨다. 삼켜지는
|
|
12
|
+
것이 하필 겹따옴표나 줄바꿈이면 문자열이 엉뚱한 곳에서 닫히고 **파일 전체가
|
|
13
|
+
문법 오류**가 된다. 고친 줄과 아무 상관없는 줄 번호에 "Unexpected token" 이 뜬다.
|
|
14
|
+
같은 사고가 저장소 루트의 setup.ps1 에서 실제로 한 번 났다.
|
|
15
|
+
|
|
16
|
+
고친 뒤에는 문법 검사를 돌린다 (npm test 는 이 파일을 실행하지 않는다):
|
|
17
|
+
$t=$null; $e=$null
|
|
18
|
+
[System.Management.Automation.Language.Parser]::ParseFile('axmap\mcp\install.ps1',[ref]$t,[ref]$e)
|
|
19
|
+
$e.Count # 0 이어야 한다
|
|
20
|
+
|
|
21
|
+
── 무엇을 하나 ───────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
1. node 20 이상이 있는지 본다
|
|
24
|
+
2. 이 PC 에서 쓸 이름을 정한다 (사람마다 달라야 한다)
|
|
25
|
+
3. axMap 을 %USERPROFILE%\.axmap\app 으로 복사한다
|
|
26
|
+
4. node ...\tools\mcp-register.mjs 로 이 PC 의 AI CLI 에 등록한다
|
|
27
|
+
5. CLI 마다 붙었는지 한 줄씩 찍고, 하나라도 실패하면 종료 코드 1 을 낸다
|
|
28
|
+
|
|
29
|
+
── 왜 홈 디렉터리에 복사하나 ─────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
목표가 "아무 저장소에서나 붙는다" 이기 때문이다. 작업할 저장소 안에 axMap 파일을
|
|
32
|
+
하나도 남기지 않는다 — 남기면 남의 저장소에 우리 파일이 커밋되거나, 남의
|
|
33
|
+
.gitignore 를 고치게 만든다. 프로그램은 홈에, 데이터(장부)는 대상 저장소에.
|
|
34
|
+
|
|
35
|
+
git clone 이 아니라 복사인 이유: git 이 없어도 설치가 끝나야 한다. 여기까지
|
|
36
|
+
왔다는 것은 이미 axMap 파일을 어떤 방법으로든 손에 넣었다는 뜻이다.
|
|
37
|
+
|
|
38
|
+
── 🔴 AXMAP_REPO 는 어디에도 적지 않는다 ─────────────────────────────────
|
|
39
|
+
|
|
40
|
+
MCP 서버는 도구를 부를 때마다 대상 저장소를 다시 정한다(axmap/docs/DECISIONS.md 의
|
|
41
|
+
D19). 그 순서의 맨 위가 AXMAP_REPO 다. 전역 등록인데 여기에 한 폴더를 박아 두면
|
|
42
|
+
다른 저장소를 열어도 아무 오류 없이 엉뚱한 장부에 claim 이 쌓인다.
|
|
43
|
+
비워 두면 CLI 를 켠 폴더가 그대로 대상이 된다.
|
|
44
|
+
|
|
45
|
+
── 🔴 AXMAP_AGENT 는 반대로 반드시 적는다 ────────────────────────────────
|
|
46
|
+
|
|
47
|
+
tools\mcp-register.mjs 는 이름을 어디에도 적지 않는다. 그건 저장소에 커밋되는
|
|
48
|
+
.mcp.json 에 이름이 들어가면 clone 한 모두가 한 사람이 되기 때문이고, 그 판단은
|
|
49
|
+
옳다. 여기는 사정이 다르다 — 우리가 쓰는 곳은 %USERPROFILE% 아래의 개인 설정이라
|
|
50
|
+
커밋되지 않는다. 그리고 전역 설치는 팀 저장소가 아닌 폴더에서도 뜨는데, 그런
|
|
51
|
+
폴더에는 git config user.name 이 없을 수 있다. 그러면 서버가 이름을 못 정하고
|
|
52
|
+
그냥 죽는다(exit 1). 그래서 설치할 때 사람마다 다른 이름을 한 번 박아 둔다.
|
|
53
|
+
#>
|
|
54
|
+
param(
|
|
55
|
+
[string]$Source = '',
|
|
56
|
+
[string]$Dest = '',
|
|
57
|
+
[string]$Name = ''
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
$ErrorActionPreference = 'Stop'
|
|
61
|
+
|
|
62
|
+
function Say($m) { Write-Host $m }
|
|
63
|
+
function Ok($m) { Write-Host " OK $m" -ForegroundColor Green }
|
|
64
|
+
function Hm($m) { Write-Host " ~~ $m" -ForegroundColor Yellow }
|
|
65
|
+
function Bad($m) { Write-Host " !! $m" -ForegroundColor Red }
|
|
66
|
+
function Fail($m) { Write-Host ''; Write-Host "중단: $m" -ForegroundColor Red; exit 1 }
|
|
67
|
+
|
|
68
|
+
# ── 이 아래 세 개의 JS 조각은 install.sh 의 것과 같아야 한다 ─────────────────
|
|
69
|
+
#
|
|
70
|
+
# 셸 두 벌에 같은 판단을 적으면 반드시 한쪽만 고쳐지고, 그 순간 두 OS 의 사용자가
|
|
71
|
+
# 서로 다른 설정을 갖게 된다. 그래서 판단은 node 에 몰아넣고 셸은 부르기만 한다.
|
|
72
|
+
# (한 파일로 합치지 못한 이유: 이 작업은 파일 넷 안에서 끝나야 했다.)
|
|
73
|
+
|
|
74
|
+
# 이름이 쓸 수 있는 이름인지 — 저장소의 검사기를 그대로 부른다. 여기서 다시 짜면
|
|
75
|
+
# 설치기가 통과시킨 이름을 서버가 거부하는 일이 생긴다.
|
|
76
|
+
$JS_NAME = @'
|
|
77
|
+
const { pathToFileURL } = require('url')
|
|
78
|
+
import(pathToFileURL(process.argv[1]).href).then((m) => {
|
|
79
|
+
const err = m.agentNameError(process.argv[2])
|
|
80
|
+
if (err) { console.error(err); process.exit(1) }
|
|
81
|
+
})
|
|
82
|
+
'@
|
|
83
|
+
|
|
84
|
+
# Claude Code 의 user 범위 등록(~/.claude.json)을 들여다본다.
|
|
85
|
+
# NONE 없다 / OTHER 다른 것이 들어 있다 / MATCH 원하는 그대로 / UNREADABLE 못 읽었다
|
|
86
|
+
$JS_CLAUDE = @'
|
|
87
|
+
const fs = require('fs'), path = require('path'), os = require('os')
|
|
88
|
+
const file = path.join(os.homedir(), '.claude.json')
|
|
89
|
+
const want = process.argv[1], name = process.argv[2]
|
|
90
|
+
let raw = null
|
|
91
|
+
try { raw = fs.readFileSync(file, 'utf8') } catch (e) { console.log('NONE'); process.exit(0) }
|
|
92
|
+
let cfg = null
|
|
93
|
+
try { cfg = JSON.parse(raw) } catch (e) { console.log('UNREADABLE'); process.exit(0) }
|
|
94
|
+
const s = cfg && cfg.mcpServers && cfg.mcpServers.axmap
|
|
95
|
+
if (!s) { console.log('NONE'); process.exit(0) }
|
|
96
|
+
const argsOk = String((s.args || [])[0]) === want
|
|
97
|
+
const nameOk = (s.env || {}).AXMAP_AGENT === name
|
|
98
|
+
console.log(argsOk && nameOk ? 'MATCH' : 'OTHER')
|
|
99
|
+
'@
|
|
100
|
+
|
|
101
|
+
# Antigravity(agy) 의 전역 설정에 이름만 덧쓴다.
|
|
102
|
+
# 항목 자체는 mcp-register 가 만든다. 여기서는 AXMAP_AGENT 한 줄을 더할 뿐이다.
|
|
103
|
+
# 🔴 항목이 우리 서버를 가리킬 때만 손댄다. 남이 만든 axmap 항목을 덮어쓰지 않는다.
|
|
104
|
+
$JS_AGY = @'
|
|
105
|
+
const fs = require('fs'), path = require('path'), os = require('os')
|
|
106
|
+
const file = path.join(os.homedir(), '.gemini', 'config', 'mcp_config.json')
|
|
107
|
+
const want = process.argv[1], name = process.argv[2]
|
|
108
|
+
let raw = null
|
|
109
|
+
try { raw = fs.readFileSync(file, 'utf8') } catch (e) { console.log('NONE'); process.exit(0) }
|
|
110
|
+
let cfg = null
|
|
111
|
+
try { cfg = JSON.parse(raw) } catch (e) { console.log('UNREADABLE'); process.exit(0) }
|
|
112
|
+
const s = cfg && cfg.mcpServers && cfg.mcpServers.axmap
|
|
113
|
+
if (!s) { console.log('NONE'); process.exit(0) }
|
|
114
|
+
if (String((s.args || [])[0]) !== want) { console.log('OTHER'); process.exit(0) }
|
|
115
|
+
s.env = s.env || {}
|
|
116
|
+
if (s.env.AXMAP_AGENT === name) { console.log('MATCH'); process.exit(0) }
|
|
117
|
+
s.env.AXMAP_AGENT = name
|
|
118
|
+
try { fs.writeFileSync(file, JSON.stringify(cfg, null, 2) + '\n') }
|
|
119
|
+
catch (e) { console.log('WRITEFAIL'); process.exit(0) }
|
|
120
|
+
console.log('STAMPED')
|
|
121
|
+
'@
|
|
122
|
+
|
|
123
|
+
Say ''
|
|
124
|
+
Say 'axMap MCP 전역 설치'
|
|
125
|
+
Say ''
|
|
126
|
+
|
|
127
|
+
# ── 1. node ─────────────────────────────────────────────────────────────────
|
|
128
|
+
$nodeCmd = Get-Command node -ErrorAction SilentlyContinue
|
|
129
|
+
if (-not $nodeCmd) { Fail 'node 를 찾을 수 없습니다. Node 20 이상을 설치한 뒤 다시 실행하세요.' }
|
|
130
|
+
$ver = (& node --version) -replace '^v', ''
|
|
131
|
+
if ([int](($ver -split '\.')[0]) -lt 20) { Fail "Node $ver 입니다. 20 이상이 필요합니다." }
|
|
132
|
+
Ok "node $ver"
|
|
133
|
+
|
|
134
|
+
# ── 2. 원본 ─────────────────────────────────────────────────────────────────
|
|
135
|
+
#
|
|
136
|
+
# 기본값은 이 스크립트가 들어 있는 axmap\ 폴더다. 저장소 루트를 -Source 로 줘도
|
|
137
|
+
# 알아듣는다 — 사람이 둘을 자주 헷갈리는데, 여기서 틀리면 "파일이 없습니다" 만 보인다.
|
|
138
|
+
if ($Source -eq '') { $Source = Split-Path -Parent $PSScriptRoot }
|
|
139
|
+
if (-not (Test-Path -LiteralPath $Source)) { Fail "원본 폴더가 없습니다: $Source" }
|
|
140
|
+
$Source = (Resolve-Path -LiteralPath $Source).Path
|
|
141
|
+
if (-not (Test-Path -LiteralPath (Join-Path $Source 'bin\axmap.mjs'))) {
|
|
142
|
+
$inner = Join-Path $Source 'axmap'
|
|
143
|
+
if (Test-Path -LiteralPath (Join-Path $inner 'bin\axmap.mjs')) { $Source = (Resolve-Path -LiteralPath $inner).Path }
|
|
144
|
+
}
|
|
145
|
+
foreach ($need in @('bin\axmap.mjs', 'mcp\server.mjs', 'src\protocol.mjs', 'tools\mcp-register.mjs', 'app\lib\agentcli.mjs', 'package.json')) {
|
|
146
|
+
if (-not (Test-Path -LiteralPath (Join-Path $Source $need))) {
|
|
147
|
+
Fail @"
|
|
148
|
+
axMap 원본이 온전하지 않습니다. 없는 파일: $need
|
|
149
|
+
본 곳: $Source
|
|
150
|
+
|
|
151
|
+
이 스크립트만 따로 내려받으면 설치할 수 없습니다. 저장소를 통째로 받은 뒤
|
|
152
|
+
그 안의 axmap\mcp\install.ps1 을 실행하거나, -Source 로 axmap\ 폴더를 지정하세요.
|
|
153
|
+
"@
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
Ok "원본 $Source"
|
|
157
|
+
|
|
158
|
+
# ── 3. 이름 ─────────────────────────────────────────────────────────────────
|
|
159
|
+
#
|
|
160
|
+
# [!] 여기서 모두에게 같은 기본값을 주면 안 된다. 장부에 한 명만 존재하게 되고,
|
|
161
|
+
# 겹침 판정은 자기 claim 을 겹침으로 보지 않으므로 팀 전원이 서로의 영역을
|
|
162
|
+
# 아무 경고 없이 덮어쓴다. 락이 조용히 여러 명에게 발급되는 것이고, 그게 이
|
|
163
|
+
# 도구가 막으려는 사고 그 자체다.
|
|
164
|
+
#
|
|
165
|
+
# 그래서 이 PC 에서 사람마다 이미 다른 값만 후보로 쓴다. 사람에게 묻지는
|
|
166
|
+
# 않는다 — 물어보는 순간 AI 에이전트가 대신 지어낸다.
|
|
167
|
+
#
|
|
168
|
+
# 🔴 이름은 이 스크립트를 켠 폴더의 git 설정에서 나온다. git 은 저장소 안이면
|
|
169
|
+
# 그 저장소의 user.name 을, 밖이면 전역 user.name 을 답한다. 그래서 앞으로
|
|
170
|
+
# 일할 저장소 안에서 실행하는 것이 맞다 — 그래야 MCP 가 쓰는 이름과, 같은
|
|
171
|
+
# 저장소에서 손으로 axmap 을 칠 때의 이름이 같아진다. 다르면 한 사람이 장부에서
|
|
172
|
+
# 둘이 되고, 자기가 잡은 것을 자기가 반납하지 못한다(release 종료 코드 5).
|
|
173
|
+
$nameFrom = '-Name 인자'
|
|
174
|
+
if ($Name -eq '') {
|
|
175
|
+
$gitCmd = Get-Command git -ErrorAction SilentlyContinue
|
|
176
|
+
if ($gitCmd) {
|
|
177
|
+
$g = (& git config user.name)
|
|
178
|
+
if ($LASTEXITCODE -eq 0 -and $g) { $Name = "$g".Trim(); $nameFrom = 'git config user.name' }
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if ($Name -eq '' -and $env:USERNAME) { $Name = "$env:USERNAME".Trim(); $nameFrom = 'Windows 사용자 이름' }
|
|
182
|
+
if ($Name -eq '' -and $env:COMPUTERNAME) { $Name = "$env:COMPUTERNAME".Trim(); $nameFrom = '컴퓨터 이름' }
|
|
183
|
+
if ($Name -eq '') { Fail '이 PC 에서 쓸 이름을 정하지 못했습니다. -Name "홍길동" 으로 직접 주세요.' }
|
|
184
|
+
|
|
185
|
+
& node -e $JS_NAME (Join-Path $Source 'src\protocol.mjs') $Name
|
|
186
|
+
if ($LASTEXITCODE -ne 0) { Fail "이 이름은 장부에서 쓸 수 없습니다: $Name (-Name 으로 다른 이름을 주세요)" }
|
|
187
|
+
Ok "이름 $Name ($nameFrom)"
|
|
188
|
+
|
|
189
|
+
# ── 4. 복사 ─────────────────────────────────────────────────────────────────
|
|
190
|
+
#
|
|
191
|
+
# [!] 이미 설치돼 있어도 묻지 않고 갱신한다. 물어보는 설치기는 AI 에이전트가
|
|
192
|
+
# 실행할 수 없다 — 프롬프트 앞에서 멈춰 버린다. 대신 무엇을 갱신했는지 찍는다.
|
|
193
|
+
$homeDir = $env:USERPROFILE
|
|
194
|
+
if (-not $homeDir) { $homeDir = $HOME }
|
|
195
|
+
if ($Dest -eq '') { $Dest = Join-Path $homeDir '.axmap\app' }
|
|
196
|
+
|
|
197
|
+
Say ''
|
|
198
|
+
Say "복사합니다 -> $Dest"
|
|
199
|
+
New-Item -ItemType Directory -Force -Path $Dest | Out-Null
|
|
200
|
+
|
|
201
|
+
# desktop\ 은 뺀다. Electron 껍데기라 MCP 에 필요 없고 node_modules 가 수백 MB 다.
|
|
202
|
+
foreach ($item in @('bin', 'src', 'mcp', 'tools', 'app', 'package.json', 'LICENSE')) {
|
|
203
|
+
$from = Join-Path $Source $item
|
|
204
|
+
$to = Join-Path $Dest $item
|
|
205
|
+
if (-not (Test-Path -LiteralPath $from)) { Hm "$item 없음 — 건너뜁니다"; continue }
|
|
206
|
+
|
|
207
|
+
$verb = '새로'
|
|
208
|
+
if (Test-Path -LiteralPath $to) { $verb = '갱신'; Remove-Item -LiteralPath $to -Recurse -Force }
|
|
209
|
+
Copy-Item -LiteralPath $from -Destination $to -Recurse -Force
|
|
210
|
+
|
|
211
|
+
if (Test-Path -LiteralPath $to -PathType Container) {
|
|
212
|
+
# 혹시 원본에 node_modules 가 딸려 있으면 여기서 뗀다. 크고, 쓰지도 않는다.
|
|
213
|
+
Get-ChildItem -LiteralPath $to -Recurse -Directory -Filter 'node_modules' -ErrorAction SilentlyContinue |
|
|
214
|
+
ForEach-Object { Remove-Item -LiteralPath $_.FullName -Recurse -Force }
|
|
215
|
+
$n = @(Get-ChildItem -LiteralPath $to -Recurse -File).Count
|
|
216
|
+
Ok "$verb $item ($n 개 파일)"
|
|
217
|
+
} else {
|
|
218
|
+
Ok "$verb $item"
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
$server = Join-Path $Dest 'mcp\server.mjs'
|
|
223
|
+
if (-not (Test-Path -LiteralPath $server)) { Fail "복사가 끝났는데 서버가 없습니다: $server" }
|
|
224
|
+
|
|
225
|
+
# ── 5. 등록 ─────────────────────────────────────────────────────────────────
|
|
226
|
+
#
|
|
227
|
+
# 이 PC 에 어떤 CLI 가 있는지 찾고 각자의 설정에 넣는 일은 tools\mcp-register.mjs 가
|
|
228
|
+
# 이미 한다. 여기서 다시 짜지 않는다.
|
|
229
|
+
Say ''
|
|
230
|
+
& node (Join-Path $Dest 'tools\mcp-register.mjs')
|
|
231
|
+
Say ' (위에 claude 가 ".mcp.json 이 없습니다" 로 나왔다면, 그건 "저장소 안의'
|
|
232
|
+
Say ' .mcp.json" 을 찾는 검사입니다. 전역 설치에는 그 파일이 없는 것이 정상이고,'
|
|
233
|
+
Say ' Claude Code 는 바로 아래에서 따로 등록합니다.)'
|
|
234
|
+
|
|
235
|
+
# ── 6. CLI 마다 붙었는지 확인한다 ────────────────────────────────────────────
|
|
236
|
+
#
|
|
237
|
+
# 🔴 여기가 이 스크립트가 mcp-register 위에 얹는 유일한 층이다.
|
|
238
|
+
#
|
|
239
|
+
# mcp-register 의 안내는 if (!any) 라서 셋 중 하나라도 찾으면 아무 말이 없다.
|
|
240
|
+
# Claude Code 만 깔린 PC 에서 Codex 로 일하는 사람은 "OK claude" 만 보고 자기
|
|
241
|
+
# 도구는 안 붙은 채 넘어간다. 그래서 여기서 CLI 마다 한 줄씩 찍는다.
|
|
242
|
+
#
|
|
243
|
+
# 그리고 mcp-register 는 Claude Code 에 아무것도 등록하지 않는다 — 저장소의
|
|
244
|
+
# .mcp.json 이 알아서 발견되는 것에 기대기 때문이다. 전역 설치에는 그 파일이
|
|
245
|
+
# 없으므로 여기서 user 범위(이 PC 의 모든 폴더에 적용되는 개인 설정)로 직접 넣는다.
|
|
246
|
+
$stClaude = ''; $whyClaude = ''
|
|
247
|
+
$stAgy = ''; $whyAgy = ''
|
|
248
|
+
$stCodex = ''; $whyCodex = ''
|
|
249
|
+
|
|
250
|
+
# Claude Code
|
|
251
|
+
if (-not (Get-Command claude -ErrorAction SilentlyContinue)) {
|
|
252
|
+
$stClaude = 'skip'; $whyClaude = '이 PC 에 claude 가 없습니다'
|
|
253
|
+
} else {
|
|
254
|
+
$before = "$(& node -e $JS_CLAUDE $server $Name)".Trim()
|
|
255
|
+
if ($before -eq 'UNREADABLE') {
|
|
256
|
+
$stClaude = 'fail'; $whyClaude = '~/.claude.json 을 읽지 못했습니다 — 건드리지 않았습니다'
|
|
257
|
+
} elseif ($before -eq 'MATCH') {
|
|
258
|
+
$stClaude = 'ok'; $whyClaude = '이미 그대로 등록돼 있습니다 (user 범위)'
|
|
259
|
+
} else {
|
|
260
|
+
if ($before -eq 'OTHER') { & claude mcp remove -s user axmap | Out-Null }
|
|
261
|
+
& claude mcp add -s user axmap -e "AXMAP_AGENT=$Name" -e 'AXMAP_ACTOR=agent' -e 'AXMAP_TTL=45m' '--' node $server | Out-Null
|
|
262
|
+
$after = "$(& node -e $JS_CLAUDE $server $Name)".Trim()
|
|
263
|
+
if ($after -eq 'MATCH') { $stClaude = 'ok'; $whyClaude = 'user 범위에 등록했습니다 (~/.claude.json)' }
|
|
264
|
+
else { $stClaude = 'fail'; $whyClaude = "claude mcp add 뒤에도 확인되지 않습니다 ($after)" }
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
# Antigravity (agy) — 항목은 mcp-register 가 만들고, 이름만 여기서 덧쓴다
|
|
269
|
+
if (-not (Get-Command agy -ErrorAction SilentlyContinue)) {
|
|
270
|
+
$stAgy = 'skip'; $whyAgy = '이 PC 에 agy 가 없습니다'
|
|
271
|
+
} else {
|
|
272
|
+
$r = "$(& node -e $JS_AGY $server $Name)".Trim()
|
|
273
|
+
if ($r -eq 'STAMPED' -or $r -eq 'MATCH') {
|
|
274
|
+
$stAgy = 'ok'; $whyAgy = '~/.gemini/config/mcp_config.json (전역) — 이름까지 적었습니다'
|
|
275
|
+
} elseif ($r -eq 'NONE') {
|
|
276
|
+
$stAgy = 'fail'; $whyAgy = 'mcp_config.json 에 axmap 항목이 없습니다 — 위 mcp-register 줄을 보세요'
|
|
277
|
+
} elseif ($r -eq 'OTHER') {
|
|
278
|
+
$stAgy = 'fail'; $whyAgy = 'axmap 항목이 다른 서버를 가리킵니다 — 건드리지 않았습니다'
|
|
279
|
+
} elseif ($r -eq 'WRITEFAIL') {
|
|
280
|
+
$stAgy = 'fail'; $whyAgy = 'mcp_config.json 에 쓰지 못했습니다 (권한 또는 잠금)'
|
|
281
|
+
} else {
|
|
282
|
+
$stAgy = 'fail'; $whyAgy = 'mcp_config.json 을 읽지 못했습니다 — 건드리지 않았습니다'
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
# Codex — 등록은 mcp-register 가 codex 자신의 명령으로 한다. 여기서는 확인만 한다.
|
|
287
|
+
#
|
|
288
|
+
# 🔴 이름(AXMAP_AGENT)은 codex 설정에 넣지 못한다. mcp-register 가 codex mcp add 를
|
|
289
|
+
# 부를 때 이름을 빼고 부르고, 이미 등록돼 있으면 다시 부르지도 않기 때문이다.
|
|
290
|
+
# 확인 안 된 도구(이 팀에 codex 가 있는 PC 가 아직 없다)의 설정을 우리가 추측으로
|
|
291
|
+
# 덮어쓰는 것보다, 한 줄을 손으로 넣게 하는 편이 낫다.
|
|
292
|
+
if (-not (Get-Command codex -ErrorAction SilentlyContinue)) {
|
|
293
|
+
$stCodex = 'skip'; $whyCodex = '이 PC 에 codex 가 없습니다'
|
|
294
|
+
} else {
|
|
295
|
+
$listed = "$(& codex mcp list)"
|
|
296
|
+
if ($listed -match 'axmap') {
|
|
297
|
+
$stCodex = 'ok'
|
|
298
|
+
$whyCodex = "~/.codex/config.toml (codex mcp list 로 확인). 이름은 손으로 넣으세요: [mcp_servers.axmap.env] 아래에 AXMAP_AGENT = ""$Name"""
|
|
299
|
+
} else {
|
|
300
|
+
$stCodex = 'fail'; $whyCodex = 'codex mcp list 에 axmap 이 없습니다 — 위 TOML 조각을 손으로 넣으세요'
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
# ── 7. 보고 ─────────────────────────────────────────────────────────────────
|
|
305
|
+
#
|
|
306
|
+
# [!] "설치했습니다" 한 줄로 끝내지 않는다. 이 도구의 실패는 대부분 조용해서,
|
|
307
|
+
# 오류가 안 났다는 것이 붙었다는 뜻이 아니다. CLI 마다 한 줄씩 찍는다.
|
|
308
|
+
function Line($label, $st, $why) {
|
|
309
|
+
if ($st -eq 'ok') { Ok ("$label".PadRight(8) + $why); return }
|
|
310
|
+
if ($st -eq 'skip') { Hm ("$label".PadRight(8) + "$why (건너뜀 — 실패가 아닙니다)"); return }
|
|
311
|
+
Bad ("$label".PadRight(8) + $why)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
Say ''
|
|
315
|
+
Say '등록 결과'
|
|
316
|
+
Line 'claude' $stClaude $whyClaude
|
|
317
|
+
Line 'agy' $stAgy $whyAgy
|
|
318
|
+
Line 'codex' $stCodex $whyCodex
|
|
319
|
+
|
|
320
|
+
Say ''
|
|
321
|
+
Say "설치 위치: $Dest"
|
|
322
|
+
Say "이 PC 의 이름: $Name ($nameFrom)"
|
|
323
|
+
Say ''
|
|
324
|
+
|
|
325
|
+
$failed = @(@($stClaude, $stAgy, $stCodex) | Where-Object { $_ -eq 'fail' })
|
|
326
|
+
if ($failed.Count -gt 0) {
|
|
327
|
+
Say '🔴 위의 !! 줄이 남아 있습니다. 그 CLI 에서는 axMap 이 뜨지 않습니다.'
|
|
328
|
+
Say ''
|
|
329
|
+
exit 1
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
$good = @(@($stClaude, $stAgy, $stCodex) | Where-Object { $_ -eq 'ok' })
|
|
333
|
+
if ($good.Count -eq 0) {
|
|
334
|
+
Say '🔴 이 PC 에서 AI CLI 를 하나도 찾지 못했습니다. 설치한 뒤 이 스크립트를 다시 실행하세요.'
|
|
335
|
+
Say ''
|
|
336
|
+
exit 1
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
Say '다음: AI CLI 를 완전히 껐다가 다시 켠 뒤, 작업할 저장소에서 "ax_status 로 지금 누가 뭘 잡고 있는지 보여줘" 라고 시켜 보세요.'
|
|
340
|
+
Say ''
|
|
341
|
+
exit 0
|