@rch4com/agent-setup 1.1.0 → 1.4.0
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/LICENSE +21 -21
- package/README.md +197 -55
- package/install.mjs +152 -101
- package/lib/args.mjs +276 -311
- package/lib/bootstrap/adapter.mjs +96 -95
- package/lib/bootstrap/apply.mjs +380 -379
- package/lib/bootstrap/flow.mjs +73 -70
- package/lib/bootstrap/record.mjs +154 -142
- package/lib/bootstrap/templates.mjs +148 -148
- package/lib/bootstrap/text.mjs +19 -19
- package/lib/catalog.mjs +213 -145
- package/lib/claude-plugins.mjs +64 -64
- package/lib/clis.mjs +102 -102
- package/lib/context.mjs +66 -65
- package/lib/deps.mjs +5 -7
- package/lib/design-md/cache/awesome-design-md/LICENSE.md +38 -0
- package/lib/design-md/catalog.json +454 -454
- package/lib/design-md/catalog.mjs +266 -268
- package/lib/design-md/flow.mjs +181 -166
- package/lib/design-md/open.mjs +51 -50
- package/lib/design-md/providers/awesome-design-md.mjs +124 -114
- package/lib/design-md/providers/index.mjs +9 -9
- package/lib/design-md/scan.mjs +14 -10
- package/lib/engine.mjs +48 -44
- package/lib/gitignore.mjs +18 -18
- package/lib/i18n/catalog/en.mjs +369 -0
- package/lib/i18n/catalog/ko.mjs +359 -0
- package/lib/i18n/detect.mjs +39 -0
- package/lib/i18n/index.mjs +93 -0
- package/lib/items/mcp.codebase-memory.mjs +6 -6
- package/lib/items/mcp.graphify.mjs +8 -0
- package/lib/items/mcp.headroom.mjs +8 -0
- package/lib/items/mcp.notion.mjs +6 -6
- package/lib/items/mcp.supabase.mjs +6 -6
- package/lib/items/mcp.vercel.mjs +6 -6
- package/lib/items/plugin.bkit.mjs +7 -7
- package/lib/items/plugin.ecc.mjs +11 -0
- package/lib/items/plugin.impeccable.mjs +14 -0
- package/lib/items/plugin.mattpocock-skills.mjs +2 -2
- package/lib/items/plugin.ponytail.mjs +104 -0
- package/lib/items/plugin.superpowers.mjs +7 -7
- package/lib/items/plugin.understand-anything.mjs +10 -0
- package/lib/items/skill.caveman.mjs +7 -0
- package/lib/items/skill.gsd.mjs +25 -24
- package/lib/items/skill.gstack.mjs +40 -39
- package/lib/items/skill.karpathy.mjs +7 -0
- package/lib/items/skill.taste.mjs +9 -0
- package/lib/jsonfile.mjs +40 -40
- package/lib/status.mjs +93 -92
- package/lib/tomlfile.mjs +60 -60
- package/lib/tui/render.mjs +41 -63
- package/lib/tui/rows.mjs +278 -206
- package/lib/tui/run.mjs +64 -28
- package/lib/update.mjs +85 -85
- package/lib/width.mjs +57 -0
- package/package.json +36 -36
package/lib/clis.mjs
CHANGED
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
import { repoPath, repoPathStrict } from './context.mjs'
|
|
2
|
-
import { readJson, setKey, removeKey, getIn } from './jsonfile.mjs'
|
|
3
|
-
import { hasSection, appendSection, removeSection } from './tomlfile.mjs'
|
|
4
|
-
|
|
5
|
-
// 읽기(has)는 어휘적 경로면 충분하고, 실제로 만들거나 고치는 경로(add·remove)만
|
|
6
|
-
// 링크를 통한 저장소 이탈까지 검사한다 — bootstrap의 apply.mjs, design-md의
|
|
7
|
-
// designPaths와 같은 규칙이다. 저장소 안 `.codex`·`.claude`가 홈을 가리키는
|
|
8
|
-
// Junction일 때 MCP 등록 한 번으로 글로벌 설정이 생성·수정되는 것을 막는다.
|
|
9
|
-
function jsonAdapter(relFile, topKey, toEntry) {
|
|
10
|
-
return {
|
|
11
|
-
has(root, name) {
|
|
12
|
-
const data = readJson(repoPath(root, relFile))
|
|
13
|
-
return getIn(data, [topKey, name]) !== undefined
|
|
14
|
-
},
|
|
15
|
-
add(root, name, server) {
|
|
16
|
-
setKey(repoPathStrict(root, relFile), [topKey, name], toEntry(server))
|
|
17
|
-
},
|
|
18
|
-
remove(root, name) {
|
|
19
|
-
removeKey(repoPathStrict(root, relFile), [topKey, name])
|
|
20
|
-
},
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function tomlLines(server) {
|
|
25
|
-
if (server.kind === 'http') return [`url = ${JSON.stringify(server.url)}`]
|
|
26
|
-
return [
|
|
27
|
-
`command = ${JSON.stringify(server.command)}`,
|
|
28
|
-
`args = [${server.args.map((a) => JSON.stringify(a)).join(', ')}]`,
|
|
29
|
-
]
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const CLIS = {
|
|
33
|
-
claude: {
|
|
34
|
-
label: 'Claude Code',
|
|
35
|
-
...jsonAdapter('.mcp.json', 'mcpServers', (s) =>
|
|
36
|
-
s.kind === 'http'
|
|
37
|
-
? { type: 'http', url: s.url }
|
|
38
|
-
: { type: 'stdio', command: s.command, args: s.args }),
|
|
39
|
-
},
|
|
40
|
-
codex: {
|
|
41
|
-
label: 'Codex',
|
|
42
|
-
has: (root, name) => hasSection(repoPath(root, '.codex/config.toml'), name),
|
|
43
|
-
add: (root, name, s) => appendSection(repoPathStrict(root, '.codex/config.toml'), name, tomlLines(s)),
|
|
44
|
-
remove: (root, name) => removeSection(repoPathStrict(root, '.codex/config.toml'), name),
|
|
45
|
-
},
|
|
46
|
-
gemini: {
|
|
47
|
-
label: 'Gemini CLI',
|
|
48
|
-
...jsonAdapter('.gemini/settings.json', 'mcpServers', (s) =>
|
|
49
|
-
s.kind === 'http' ? { httpUrl: s.url } : { command: s.command, args: s.args }),
|
|
50
|
-
},
|
|
51
|
-
opencode: {
|
|
52
|
-
label: 'OpenCode',
|
|
53
|
-
...jsonAdapter('opencode.jsonc', 'mcp', (s) =>
|
|
54
|
-
s.kind === 'http'
|
|
55
|
-
? { type: 'remote', url: s.url, enabled: true }
|
|
56
|
-
: { type: 'local', command: [s.command, ...s.args], enabled: true }),
|
|
57
|
-
},
|
|
58
|
-
kilo: {
|
|
59
|
-
label: 'Kilo Code',
|
|
60
|
-
...jsonAdapter('.kilocode/mcp.json', 'mcpServers', (s) =>
|
|
61
|
-
s.kind === 'http'
|
|
62
|
-
? { type: 'streamable-http', url: s.url, disabled: false }
|
|
63
|
-
: { command: s.command, args: s.args, disabled: false }),
|
|
64
|
-
},
|
|
65
|
-
kiro: {
|
|
66
|
-
label: 'Kiro',
|
|
67
|
-
...jsonAdapter('.kiro/settings/mcp.json', 'mcpServers', (s) =>
|
|
68
|
-
s.kind === 'http'
|
|
69
|
-
? { url: s.url, disabled: false, autoApprove: [] }
|
|
70
|
-
: { command: s.command, args: s.args, disabled: false, autoApprove: [] }),
|
|
71
|
-
},
|
|
72
|
-
kimi: {
|
|
73
|
-
label: 'Kimi Code',
|
|
74
|
-
...jsonAdapter('.kimi-code/mcp.json', 'mcpServers', (s) =>
|
|
75
|
-
s.kind === 'http' ? { url: s.url } : { command: s.command, args: s.args }),
|
|
76
|
-
},
|
|
77
|
-
grok: {
|
|
78
|
-
label: 'Grok Build',
|
|
79
|
-
has: (root, name) => hasSection(repoPath(root, '.grok/config.toml'), name),
|
|
80
|
-
add: (root, name, s) => appendSection(repoPathStrict(root, '.grok/config.toml'), name, tomlLines(s)),
|
|
81
|
-
remove: (root, name) => removeSection(repoPathStrict(root, '.grok/config.toml'), name),
|
|
82
|
-
},
|
|
83
|
-
copilot: {
|
|
84
|
-
label: 'GitHub Copilot CLI',
|
|
85
|
-
// Copilot CLI는 루트 .mcp.json도 읽지만(같은 이름이면 그쪽이 우선),
|
|
86
|
-
// 도구마다 자기 파일을 갖는 이 저장소의 패턴을 따라 .github/mcp.json에 쓴다.
|
|
87
|
-
...jsonAdapter('.github/mcp.json', 'mcpServers', (s) =>
|
|
88
|
-
s.kind === 'http'
|
|
89
|
-
? { type: 'http', url: s.url }
|
|
90
|
-
: { type: 'local', command: s.command, args: s.args }),
|
|
91
|
-
},
|
|
92
|
-
vscode: {
|
|
93
|
-
label: 'VS Code Copilot',
|
|
94
|
-
// VS Code는 최상위 키가 servers이고 로컬 서버 타입이 stdio다.
|
|
95
|
-
...jsonAdapter('.vscode/mcp.json', 'servers', (s) =>
|
|
96
|
-
s.kind === 'http'
|
|
97
|
-
? { type: 'http', url: s.url }
|
|
98
|
-
: { type: 'stdio', command: s.command, args: s.args }),
|
|
99
|
-
},
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export const CLI_IDS = Object.keys(CLIS)
|
|
1
|
+
import { repoPath, repoPathStrict } from './context.mjs'
|
|
2
|
+
import { readJson, setKey, removeKey, getIn } from './jsonfile.mjs'
|
|
3
|
+
import { hasSection, appendSection, removeSection } from './tomlfile.mjs'
|
|
4
|
+
|
|
5
|
+
// 읽기(has)는 어휘적 경로면 충분하고, 실제로 만들거나 고치는 경로(add·remove)만
|
|
6
|
+
// 링크를 통한 저장소 이탈까지 검사한다 — bootstrap의 apply.mjs, design-md의
|
|
7
|
+
// designPaths와 같은 규칙이다. 저장소 안 `.codex`·`.claude`가 홈을 가리키는
|
|
8
|
+
// Junction일 때 MCP 등록 한 번으로 글로벌 설정이 생성·수정되는 것을 막는다.
|
|
9
|
+
function jsonAdapter(relFile, topKey, toEntry) {
|
|
10
|
+
return {
|
|
11
|
+
has(root, name) {
|
|
12
|
+
const data = readJson(repoPath(root, relFile))
|
|
13
|
+
return getIn(data, [topKey, name]) !== undefined
|
|
14
|
+
},
|
|
15
|
+
add(root, name, server) {
|
|
16
|
+
setKey(repoPathStrict(root, relFile), [topKey, name], toEntry(server))
|
|
17
|
+
},
|
|
18
|
+
remove(root, name) {
|
|
19
|
+
removeKey(repoPathStrict(root, relFile), [topKey, name])
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function tomlLines(server) {
|
|
25
|
+
if (server.kind === 'http') return [`url = ${JSON.stringify(server.url)}`]
|
|
26
|
+
return [
|
|
27
|
+
`command = ${JSON.stringify(server.command)}`,
|
|
28
|
+
`args = [${server.args.map((a) => JSON.stringify(a)).join(', ')}]`,
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const CLIS = {
|
|
33
|
+
claude: {
|
|
34
|
+
label: 'Claude Code',
|
|
35
|
+
...jsonAdapter('.mcp.json', 'mcpServers', (s) =>
|
|
36
|
+
s.kind === 'http'
|
|
37
|
+
? { type: 'http', url: s.url }
|
|
38
|
+
: { type: 'stdio', command: s.command, args: s.args }),
|
|
39
|
+
},
|
|
40
|
+
codex: {
|
|
41
|
+
label: 'Codex',
|
|
42
|
+
has: (root, name) => hasSection(repoPath(root, '.codex/config.toml'), name),
|
|
43
|
+
add: (root, name, s) => appendSection(repoPathStrict(root, '.codex/config.toml'), name, tomlLines(s)),
|
|
44
|
+
remove: (root, name) => removeSection(repoPathStrict(root, '.codex/config.toml'), name),
|
|
45
|
+
},
|
|
46
|
+
gemini: {
|
|
47
|
+
label: 'Gemini CLI',
|
|
48
|
+
...jsonAdapter('.gemini/settings.json', 'mcpServers', (s) =>
|
|
49
|
+
s.kind === 'http' ? { httpUrl: s.url } : { command: s.command, args: s.args }),
|
|
50
|
+
},
|
|
51
|
+
opencode: {
|
|
52
|
+
label: 'OpenCode',
|
|
53
|
+
...jsonAdapter('opencode.jsonc', 'mcp', (s) =>
|
|
54
|
+
s.kind === 'http'
|
|
55
|
+
? { type: 'remote', url: s.url, enabled: true }
|
|
56
|
+
: { type: 'local', command: [s.command, ...s.args], enabled: true }),
|
|
57
|
+
},
|
|
58
|
+
kilo: {
|
|
59
|
+
label: 'Kilo Code',
|
|
60
|
+
...jsonAdapter('.kilocode/mcp.json', 'mcpServers', (s) =>
|
|
61
|
+
s.kind === 'http'
|
|
62
|
+
? { type: 'streamable-http', url: s.url, disabled: false }
|
|
63
|
+
: { command: s.command, args: s.args, disabled: false }),
|
|
64
|
+
},
|
|
65
|
+
kiro: {
|
|
66
|
+
label: 'Kiro',
|
|
67
|
+
...jsonAdapter('.kiro/settings/mcp.json', 'mcpServers', (s) =>
|
|
68
|
+
s.kind === 'http'
|
|
69
|
+
? { url: s.url, disabled: false, autoApprove: [] }
|
|
70
|
+
: { command: s.command, args: s.args, disabled: false, autoApprove: [] }),
|
|
71
|
+
},
|
|
72
|
+
kimi: {
|
|
73
|
+
label: 'Kimi Code',
|
|
74
|
+
...jsonAdapter('.kimi-code/mcp.json', 'mcpServers', (s) =>
|
|
75
|
+
s.kind === 'http' ? { url: s.url } : { command: s.command, args: s.args }),
|
|
76
|
+
},
|
|
77
|
+
grok: {
|
|
78
|
+
label: 'Grok Build',
|
|
79
|
+
has: (root, name) => hasSection(repoPath(root, '.grok/config.toml'), name),
|
|
80
|
+
add: (root, name, s) => appendSection(repoPathStrict(root, '.grok/config.toml'), name, tomlLines(s)),
|
|
81
|
+
remove: (root, name) => removeSection(repoPathStrict(root, '.grok/config.toml'), name),
|
|
82
|
+
},
|
|
83
|
+
copilot: {
|
|
84
|
+
label: 'GitHub Copilot CLI',
|
|
85
|
+
// Copilot CLI는 루트 .mcp.json도 읽지만(같은 이름이면 그쪽이 우선),
|
|
86
|
+
// 도구마다 자기 파일을 갖는 이 저장소의 패턴을 따라 .github/mcp.json에 쓴다.
|
|
87
|
+
...jsonAdapter('.github/mcp.json', 'mcpServers', (s) =>
|
|
88
|
+
s.kind === 'http'
|
|
89
|
+
? { type: 'http', url: s.url }
|
|
90
|
+
: { type: 'local', command: s.command, args: s.args }),
|
|
91
|
+
},
|
|
92
|
+
vscode: {
|
|
93
|
+
label: 'VS Code Copilot',
|
|
94
|
+
// VS Code는 최상위 키가 servers이고 로컬 서버 타입이 stdio다.
|
|
95
|
+
...jsonAdapter('.vscode/mcp.json', 'servers', (s) =>
|
|
96
|
+
s.kind === 'http'
|
|
97
|
+
? { type: 'http', url: s.url }
|
|
98
|
+
: { type: 'stdio', command: s.command, args: s.args }),
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const CLI_IDS = Object.keys(CLIS)
|
package/lib/context.mjs
CHANGED
|
@@ -1,65 +1,66 @@
|
|
|
1
|
-
import { execFileSync } from 'node:child_process'
|
|
2
|
-
import { lstatSync, realpathSync } from 'node:fs'
|
|
3
|
-
import { dirname, resolve, sep } from 'node:path'
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
probe
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
import { execFileSync } from 'node:child_process'
|
|
2
|
+
import { lstatSync, realpathSync } from 'node:fs'
|
|
3
|
+
import { dirname, resolve, sep } from 'node:path'
|
|
4
|
+
import { LocalizedError } from './i18n/index.mjs'
|
|
5
|
+
|
|
6
|
+
export function findRepoRoot(cwd = process.cwd()) {
|
|
7
|
+
let out
|
|
8
|
+
try {
|
|
9
|
+
out = execFileSync('git', ['rev-parse', '--show-toplevel'], { cwd, encoding: 'utf8' })
|
|
10
|
+
} catch {
|
|
11
|
+
throw new LocalizedError('error.notGitRepo')
|
|
12
|
+
}
|
|
13
|
+
return resolve(out.trim())
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function repoPath(root, rel) {
|
|
17
|
+
const abs = resolve(root, rel)
|
|
18
|
+
const normRoot = resolve(root)
|
|
19
|
+
if (abs !== normRoot && !abs.startsWith(normRoot + sep)) {
|
|
20
|
+
throw new LocalizedError('error.pathOutsideRepo', { path: abs })
|
|
21
|
+
}
|
|
22
|
+
return abs
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function pathExists(target) {
|
|
26
|
+
try {
|
|
27
|
+
lstatSync(target)
|
|
28
|
+
return true
|
|
29
|
+
} catch {
|
|
30
|
+
return false
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// repoPath의 어휘적 검사에 더해, 가장 가까운 존재하는 조상의 realpath가
|
|
35
|
+
// 저장소 안인지 확인한다. 어휘적 검사만으로는 심볼릭 링크/Junction을 통한
|
|
36
|
+
// 이탈을 막지 못한다. 부트스트랩의 모든 쓰기 경로가 이 함수를 쓴다.
|
|
37
|
+
export function repoPathStrict(root, rel) {
|
|
38
|
+
const abs = repoPath(root, rel)
|
|
39
|
+
|
|
40
|
+
let probe = abs
|
|
41
|
+
while (!pathExists(probe)) {
|
|
42
|
+
const parent = dirname(probe)
|
|
43
|
+
if (parent === probe) break
|
|
44
|
+
probe = parent
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let realProbe
|
|
48
|
+
try {
|
|
49
|
+
realProbe = realpathSync(probe)
|
|
50
|
+
} catch (err) {
|
|
51
|
+
// 경합으로 사라졌거나(ENOENT) 링크가 순환하는(ELOOP) 경우다.
|
|
52
|
+
// 원인을 알 수 없는 raw 예외 대신 진단 가능한 메시지로 바꾼다.
|
|
53
|
+
throw new LocalizedError('error.pathUnresolvable', { path: probe, code: err.code ?? err.message })
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let realRoot
|
|
57
|
+
try {
|
|
58
|
+
realRoot = realpathSync(root)
|
|
59
|
+
} catch (err) {
|
|
60
|
+
throw new LocalizedError('error.pathUnresolvable', { path: root, code: err.code ?? err.message })
|
|
61
|
+
}
|
|
62
|
+
if (realProbe !== realRoot && !realProbe.startsWith(realRoot + sep)) {
|
|
63
|
+
throw new LocalizedError('error.pathEscapesViaLink', { path: probe, real: realProbe })
|
|
64
|
+
}
|
|
65
|
+
return abs
|
|
66
|
+
}
|
package/lib/deps.mjs
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
// 선택적 의존성 로딩. 부트스트랩은 npm install 없이 돌아야 하므로
|
|
2
2
|
// jsonc-parser·smol-toml에 닿는 모듈은 전부 동적 import로 가져오고,
|
|
3
3
|
// 없을 때는 Node의 원시 메시지 대신 설치 방법을 안내한다.
|
|
4
|
+
import { LocalizedError } from './i18n/index.mjs'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
' npm install --prefix agent-installer'
|
|
9
|
-
|
|
10
|
-
export async function withDeps(load) {
|
|
6
|
+
// t는 현재 안내 문구가 쓰지 않지만 시그니처에 남겨 둔다 — 호출부가 이미
|
|
7
|
+
// 넘기고 있고, 나중에 지역화된 안내가 늘어날 자리다.
|
|
8
|
+
export async function withDeps(load, t) {
|
|
11
9
|
try {
|
|
12
10
|
return await load()
|
|
13
11
|
} catch (err) {
|
|
14
12
|
// 모듈이 정말 없을 때만 안내로 바꾼다. 로드된 모듈 안에서 난 오류는
|
|
15
13
|
// 그대로 올려보내야 한다 — 삼키면 진짜 버그가 "의존성 없음"으로 둔갑한다.
|
|
16
14
|
if (err.code !== 'ERR_MODULE_NOT_FOUND') throw err
|
|
17
|
-
throw new
|
|
15
|
+
throw new LocalizedError('error.depsMissing')
|
|
18
16
|
}
|
|
19
17
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Third-party notice — awesome-design-md
|
|
2
|
+
|
|
3
|
+
이 디렉터리의 `DESIGN.md` 파일들은 아래 저장소에서 그대로 가져온 사본입니다.
|
|
4
|
+
오프라인 설치를 위해 동봉하며, 원문을 고치지 않습니다.
|
|
5
|
+
|
|
6
|
+
- Source: https://github.com/VoltAgent/awesome-design-md
|
|
7
|
+
- License: MIT
|
|
8
|
+
|
|
9
|
+
MIT는 재배포를 허용하되 저작권 고지와 허가 문구를 사본에 함께 담을 것을
|
|
10
|
+
요구합니다. 아래가 상류 `LICENSE`의 원문입니다.
|
|
11
|
+
|
|
12
|
+
파일 이름이 `LICENSE`가 아니라 `LICENSE.md`인 이유는 발행물 검사가 최상위
|
|
13
|
+
`LICENSE` 하나만 확장자 없는 파일로 허용하기 때문입니다 — 이름이 아니라
|
|
14
|
+
담긴 내용이 고지의 요건을 채웁니다.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
MIT License
|
|
19
|
+
|
|
20
|
+
Copyright (c) 2026 VoltAgent
|
|
21
|
+
|
|
22
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
23
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
24
|
+
in the Software without restriction, including without limitation the rights
|
|
25
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
26
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
27
|
+
furnished to do so, subject to the following conditions:
|
|
28
|
+
|
|
29
|
+
The above copyright notice and this permission notice shall be included in all
|
|
30
|
+
copies or substantial portions of the Software.
|
|
31
|
+
|
|
32
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
33
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
34
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
35
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
36
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
37
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
38
|
+
SOFTWARE.
|