leerness 1.9.186 โ 1.9.187
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/CHANGELOG.md +113 -0
- package/README.md +3 -3
- package/bin/harness.js +174 -42
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,118 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.187 โ 2026-05-21
|
|
4
|
+
|
|
5
|
+
**๐ ๋น์ํฌ๋ฆฟ LEERNESS_* ์ค์ ์ .env โ .harness/leerness-config.json ์ผ๋ก ๋ถ๋ฆฌ (AI ๊ฐ์์ฑ).**
|
|
6
|
+
|
|
7
|
+
์์จ ๋ชจ๋ 117 ๋ผ์ด๋. ์ฌ์ฉ์ ๋ช
์: *".env์ ์
๋ ฅ๋์ด์ AI ์์ด์ ํธ๊ฐ ์ฐธ์กฐํ๊ฑฐ๋ ์ฝ์ ์ ์๋ ์์นํ๋ฉด ์
๋ ฅ๋๋ ์์น๋ฅผ ๋ณ๊ฒฝ"*.
|
|
8
|
+
|
|
9
|
+
### ๋ฐฐ๊ฒฝ & ๋ถ๋ฆฌ ์ ์ฑ
|
|
10
|
+
|
|
11
|
+
| ์์น | ๋ณด์ ์ ์ฑ
| ์ฉ๋ |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `.env` (.gitignore) | ์ํฌ๋ฆฟ only | NPM_TOKEN, GITHUB_TOKEN, *_API_KEY |
|
|
14
|
+
| `.harness/leerness-config.json` (git checked-in) | ๋น์ํฌ๋ฆฟ only | ํ์ฑํ ํ๋๊ทธ, ๊ณต๊ฐ URL, ๋ชจ๋ธ ์ด๋ฆ |
|
|
15
|
+
|
|
16
|
+
**ํต์ฌ**: `.env`๋ .gitignore + ์ํฌ๋ฆฟ์ฉ โ ๋ค๋ฅธ AI ์์ด์ ํธ(Claude Code, Cursor, Copilot ๋ฑ)๊ฐ ์ํฌ์คํ์ด์ค ์ฝ์ ๋ ์๋ ๋
ธ์ถ X. ๋น์ํฌ๋ฆฟ LEERNESS_* ์ค์ ์ AI ๊ฐ์ ์์น๋ก ์ฎ๊ฒจ **AI ์์ด์ ํธ ์ธ์ง๋ โ**.
|
|
17
|
+
|
|
18
|
+
### ๋ถ๋ฆฌ ๋์ (11๊ฐ ๋น์ํฌ๋ฆฟ ํค)
|
|
19
|
+
```js
|
|
20
|
+
const _LEERNESS_NONSECRET_KEYS = new Set([
|
|
21
|
+
'LEERNESS_OLLAMA_BASE_URL', // localhost URL โ ๋น๋ฐ X
|
|
22
|
+
'LEERNESS_OLLAMA_MODEL', // ๋ชจ๋ธ ์ด๋ฆ โ ๋น๋ฐ X
|
|
23
|
+
'LEERNESS_ENABLE_CLAUDE', // ํ์ฑํ ํ๋๊ทธ
|
|
24
|
+
'LEERNESS_ENABLE_CODEX',
|
|
25
|
+
'LEERNESS_ENABLE_GEMINI',
|
|
26
|
+
'LEERNESS_ENABLE_COPILOT',
|
|
27
|
+
'LEERNESS_ENABLE_OLLAMA',
|
|
28
|
+
'LEERNESS_SKILL_DISCOVER_URL', // ๊ณต๊ฐ URL
|
|
29
|
+
'LEERNESS_SKILL_AUTO_DISCOVER',
|
|
30
|
+
'LEERNESS_SKILL_AUTO_INSTALL',
|
|
31
|
+
'LEERNESS_SKILL_AUTO_PRESETS'
|
|
32
|
+
]);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### .harness/leerness-config.json ์์
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"_comment": "leerness ๋น์ํฌ๋ฆฟ ์ค์ . AI ์์ด์ ํธ๊ฐ ์ฝ์ ์ ์๋ ์์น (git checked-in). ์ํฌ๋ฆฟ(TOKEN/SECRET/PASSWORD)์ .env ์ฌ์ฉ.",
|
|
39
|
+
"_docs": "https://github.com/gugu9999gu/leerness#config",
|
|
40
|
+
"_version": "1.9.187",
|
|
41
|
+
"LEERNESS_OLLAMA_BASE_URL": "http://localhost:11434",
|
|
42
|
+
"LEERNESS_OLLAMA_MODEL": "llama3",
|
|
43
|
+
"LEERNESS_ENABLE_CLAUDE": "1",
|
|
44
|
+
"LEERNESS_ENABLE_CODEX": "1",
|
|
45
|
+
"LEERNESS_ENABLE_GEMINI": "0",
|
|
46
|
+
"LEERNESS_ENABLE_COPILOT": "0",
|
|
47
|
+
"LEERNESS_ENABLE_OLLAMA": "0",
|
|
48
|
+
"LEERNESS_SKILL_DISCOVER_URL": "",
|
|
49
|
+
"LEERNESS_SKILL_AUTO_DISCOVER": "0",
|
|
50
|
+
"LEERNESS_SKILL_AUTO_INSTALL": "0",
|
|
51
|
+
"LEERNESS_SKILL_AUTO_PRESETS": "vercel,anthropic"
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### .env (simplified)
|
|
56
|
+
```
|
|
57
|
+
# Leerness โ SECRET ํ๊ฒฝ๋ณ์๋ง (TOKEN/SECRET/PASSWORD). ๋น์ํฌ๋ฆฟ ์ค์ ์ .harness/leerness-config.json ์ฌ์ฉ.
|
|
58
|
+
# .env ๋ .gitignore โ AI ์์ด์ ํธ(Claude Code, Cursor ๋ฑ)์ ๋
ธ์ถ๋์ง ์์. ์ํฌ๋ฆฟ ์์ ๋ณด๊ด.
|
|
59
|
+
# ๋น์ํฌ๋ฆฟ (ํ์ฑํ ํ๋๊ทธ/๋ชจ๋ธ ์ด๋ฆ/๊ณต๊ฐ URL) ์ .harness/leerness-config.json ์ฐธ์กฐ โ AI ๊ฐ์์ฑ โ.
|
|
60
|
+
|
|
61
|
+
# === ์ํฌ๋ฆฟ (TOKEN/KEY) ===
|
|
62
|
+
LEERNESS_NPM_TOKEN=
|
|
63
|
+
LEERNESS_GITHUB_TOKEN=
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### ๋ณด์ ๊ฐ๋ (์ด์ค ์์ ๋ง)
|
|
67
|
+
- **load ๊ฐ๋**: `_loadLeernessConfig` ์์ `_isSecretKey(k)` ๋งค์น ์ inject ์ฐจ๋จ
|
|
68
|
+
- **write ๊ฐ๋**: `_writeLeernessConfig` ์์ ์ํฌ๋ฆฟ ํจํด ์๋ ์ ๊ฑฐ (์๋ชป ๋ค์ด๊ฐ ํค sanitize)
|
|
69
|
+
- **์ ๊ท์**: `/TOKEN|SECRET|PASSWORD|API_KEY|PRIVATE/i`
|
|
70
|
+
|
|
71
|
+
### ์๋ ๋ง์ด๊ทธ๋ ์ด์
(1.9.186 ์ด์ .env)
|
|
72
|
+
`_migrateNonsecretFromEnv(root)` โ ๊ธฐ์กด .env ์ ๋น์ํฌ๋ฆฟ LEERNESS_* ๊ฐ ์์ผ๋ฉด:
|
|
73
|
+
1. config ํ์ผ๋ก ์๋ ์ด๋
|
|
74
|
+
2. .env ์์ ์ ๊ฑฐ (์ง์ # ์ฃผ์๋ ํจ๊ป)
|
|
75
|
+
3. ์ํฌ๋ฆฟ (TOKEN/KEY/PASSWORD) ์ ์ ๋ ๊ฑด๋๋ฆฌ์ง ์์ (๋ณด์ first)
|
|
76
|
+
|
|
77
|
+
### ์ฐ์ ์์ (ํธํ์ฑ)
|
|
78
|
+
```
|
|
79
|
+
1. process.env (์ด๋ฏธ ์ค์ ๋ ํ๊ฒฝ๋ณ์)
|
|
80
|
+
2. .env ํ์ผ
|
|
81
|
+
3. .harness/leerness-config.json
|
|
82
|
+
4. ์ฝ๋ defaults
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
๊ธฐ์กด `process.env.LEERNESS_*` ์ง์ ์ ๊ทผ ์ฝ๋๋ ๋ณ๊ฒฝ X. leerness ์์ ์ `_loadEnvFile()` ๊ฐ `_loadLeernessConfig()` ๋ ์๋ ํธ์ถ โ config ๊ฐ์ process.env ๋ก inject.
|
|
86
|
+
|
|
87
|
+
### Live ๊ฒ์ฆ (์ฌ์ฉ์ ์ํฌ์คํ์ด์ค ์๋ฎฌ๋ ์ด์
)
|
|
88
|
+
```bash
|
|
89
|
+
# Before (1.9.186 .env)
|
|
90
|
+
LEERNESS_NPM_TOKEN=test-token-12345
|
|
91
|
+
LEERNESS_OLLAMA_BASE_URL=http://localhost:11434
|
|
92
|
+
LEERNESS_OLLAMA_MODEL=llama3
|
|
93
|
+
LEERNESS_ENABLE_CLAUDE=1
|
|
94
|
+
...
|
|
95
|
+
|
|
96
|
+
# After leerness init (1.9.187)
|
|
97
|
+
.env:
|
|
98
|
+
LEERNESS_NPM_TOKEN=test-token-12345 โ ์ํฌ๋ฆฟ ๋ณด์กด
|
|
99
|
+
LEERNESS_GITHUB_TOKEN=
|
|
100
|
+
|
|
101
|
+
.harness/leerness-config.json:
|
|
102
|
+
LEERNESS_OLLAMA_BASE_URL: "http://localhost:11434"
|
|
103
|
+
LEERNESS_OLLAMA_MODEL: "llama3"
|
|
104
|
+
LEERNESS_ENABLE_CLAUDE: "1"
|
|
105
|
+
...
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Verified
|
|
109
|
+
- stress-v132: **19/19 PASS** (์ฌ์ฉ์ ๋ช
์ 7 + live 3 + ๋์ 9)
|
|
110
|
+
- e2e 217/217 baseline ์ ์ง
|
|
111
|
+
- live ๋ง์ด๊ทธ๋ ์ด์
๊ฒ์ฆ: ์ํฌ๋ฆฟ ์์ค 0๊ฑด, ๋น์ํฌ๋ฆฟ 100% ์ด๋
|
|
112
|
+
- VERSION = 1.9.187 ยท autonomous-rounds = 117 ยท main ์๋ push 48 ๋ผ์ด๋ ์ฐ์
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
3
116
|
## 1.9.186 โ 2026-05-21
|
|
4
117
|
|
|
5
118
|
**๐ REPL claude stream 0์ ์๋ต BUG fix + ๊ตฌ์กฐ ์ต์ ํ ์ฒดํฌ (์ฌ์ฉ์ ๋ช
์ ํต์ฌ ๋ฒ๊ทธ).**
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **AI ์ฝ๋ฉ ์์ด์ ํธ์ ๊ฑฐ์ง ์๋ฃยท์ค๋ณตยท๋ง๊ฐยท์ถฉ๋์ ๋ง์์ฃผ๋ ๊ฒ์ยท๊ธฐ์ตยทํ์
CLI ํ๋ค์ค.**
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/leerness) [](https://www.npmjs.com/package/leerness) []() []() []() []() []() []() []() []() []() []() []() []()
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
โ โโโ โโโโโโ โโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโ โ
|
|
13
13
|
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโ โโโโโโโโโโโโโโโโโโโโโโ โ
|
|
14
14
|
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโ โโโโโโโโโโโโโโโโโโโโโ โ
|
|
15
|
-
โ v1.9.
|
|
15
|
+
โ v1.9.187 AI Agent Reliability Harness + Sandbox โ
|
|
16
16
|
โ verify ยท remember ยท orchestrate ยท audit ยท sandbox ยท drift โ
|
|
17
|
-
โ
|
|
17
|
+
โ ๐ .env ๋ถ๋ฆฌ (์ํฌ๋ฆฟ) ยท leerness-config.json (AI ๊ฐ์) โ
|
|
18
18
|
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
19
19
|
```
|
|
20
20
|
|
package/bin/harness.js
CHANGED
|
@@ -7,7 +7,7 @@ const cp = require('child_process');
|
|
|
7
7
|
const os = require('os'); // 1.9.178: _publishToNpm ์์ os.tmpdir() ์ฌ์ฉ (์ ์ญ import)
|
|
8
8
|
const readline = require('readline');
|
|
9
9
|
|
|
10
|
-
const VERSION = '1.9.
|
|
10
|
+
const VERSION = '1.9.187';
|
|
11
11
|
|
|
12
12
|
// 1.9.184: DEP0190 (child_process shell: true) deprecation warning ์ต์ (์ฌ์ฉ์ ๋ช
์).
|
|
13
13
|
// leerness ๋ cross-platform PATH resolution ์ ์ํด shell: true ๋ฅผ ์๋์ ์ผ๋ก ์ฌ์ฉ (claude.cmd / ollama.cmd ๋ฑ Windows .cmd ์ฒ๋ฆฌ).
|
|
@@ -904,44 +904,50 @@ async function install(root, opts = {}) {
|
|
|
904
904
|
return new Set([a]); // back-compat: ๋จ์ผ ๋ฌธ์์ด
|
|
905
905
|
})();
|
|
906
906
|
const enable = (cli) => enabledSet.has(cli);
|
|
907
|
-
// 1.9.
|
|
908
|
-
// .env ๋
|
|
909
|
-
//
|
|
907
|
+
// 1.9.187 (์ฌ์ฉ์ ๋ช
์): .env ์๋ ์ํฌ๋ฆฟ๋ง, ๋น์ํฌ๋ฆฟ LEERNESS_* ๋ .harness/leerness-config.json ์ผ๋ก ๋ถ๋ฆฌ.
|
|
908
|
+
// ๋ฐฐ๊ฒฝ: .env ๋ .gitignore + ์ํฌ๋ฆฟ์ฉ โ AI ์์ด์ ํธ ๊ฐ์์ฑ ์์.
|
|
909
|
+
// ๋น์ํฌ๋ฆฟ (ํ์ฑํ ํ๋๊ทธ, ๋ชจ๋ธ, ๊ณต๊ฐ URL) ์ git checked-in ์์น (.harness/) ์ ๋๋ฉด AI ๊ฐ ์๋ ์ฝ์.
|
|
910
|
+
// ํธํ์ฑ: leerness ์์ ์ _loadLeernessConfig() ๊ฐ config โ process.env inject. ๊ธฐ์กด ์ฝ๋ ๊ทธ๋๋ก ์๋.
|
|
910
911
|
const envLines = [
|
|
911
|
-
'# Leerness โ
|
|
912
|
+
'# Leerness โ SECRET ํ๊ฒฝ๋ณ์๋ง (TOKEN/SECRET/PASSWORD). ๋น์ํฌ๋ฆฟ ์ค์ ์ .harness/leerness-config.json ์ฌ์ฉ.',
|
|
912
913
|
`# Generated/migrated by leerness v${VERSION} at ${new Date().toISOString().slice(0, 10)}.`,
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
'#
|
|
917
|
-
'
|
|
918
|
-
'
|
|
919
|
-
`LEERNESS_ENABLE_CLAUDE=${enable('claude') ? 1 : 0}`,
|
|
920
|
-
`LEERNESS_ENABLE_CODEX=${enable('codex') ? 1 : 0}`,
|
|
921
|
-
`LEERNESS_ENABLE_GEMINI=${enable('gemini') ? 1 : 0}`,
|
|
922
|
-
`LEERNESS_ENABLE_COPILOT=${enable('copilot') ? 1 : 0}`,
|
|
923
|
-
`LEERNESS_ENABLE_OLLAMA=${enable('ollama') ? 1 : 0}`,
|
|
924
|
-
'# 1.9.42 โ agentskills.io ๊ณต๊ฐ ํ์ค ์คํฌ ์๋ ํ์ (opt-in). URL ์ค์ ์ `leerness skill discover` ์ฌ์ฉ ๊ฐ๋ฅ.',
|
|
925
|
-
'# ์์ URL: https://agentskills.io/llms.txt',
|
|
926
|
-
'LEERNESS_SKILL_DISCOVER_URL=',
|
|
927
|
-
'# (์ ํ) ์ฌ์ฉ์ ์์ฒญ ๋ถ์ ์ ์๋ ๋งค์นญ ์คํฌ ์ถ์ฒ. 1=ํ์ฑ, 0/๋ฏธ์ค์ =๋นํ์ฑ.',
|
|
928
|
-
'LEERNESS_SKILL_AUTO_DISCOVER=0',
|
|
929
|
-
'# 1.9.182 โ handoff ์ ๊ณต์ catalog (vercel-labs, anthropics) ์๋ ํ์ + ๋งค์นญ ์ ์๋ install. 1=ํ์ฑ (opt-in ๋ณด์).',
|
|
930
|
-
'LEERNESS_SKILL_AUTO_INSTALL=0',
|
|
931
|
-
'# 1.9.182 โ handoff ์๋ ํ์ ๋์ preset (์ฝค๋ง ๊ตฌ๋ถ). ์: vercel,anthropic',
|
|
932
|
-
'LEERNESS_SKILL_AUTO_PRESETS=vercel,anthropic'
|
|
914
|
+
`# .env ๋ .gitignore โ AI ์์ด์ ํธ(Claude Code, Cursor ๋ฑ)์ ๋
ธ์ถ๋์ง ์์. ์ํฌ๋ฆฟ ์์ ๋ณด๊ด.`,
|
|
915
|
+
`# ๋น์ํฌ๋ฆฟ (ํ์ฑํ ํ๋๊ทธ/๋ชจ๋ธ ์ด๋ฆ/๊ณต๊ฐ URL) ์ .harness/leerness-config.json ์ฐธ์กฐ โ AI ๊ฐ์์ฑ โ.`,
|
|
916
|
+
'',
|
|
917
|
+
'# === ์ํฌ๋ฆฟ (TOKEN/KEY) ===',
|
|
918
|
+
'LEERNESS_NPM_TOKEN=',
|
|
919
|
+
'LEERNESS_GITHUB_TOKEN=',
|
|
933
920
|
];
|
|
934
921
|
mergeLinesFile(path.join(root, '.env.example'), envLines);
|
|
935
|
-
// 1.9.153: .env ์ง์ ์์ฑ/๋ง์ด๊ทธ๋ ์ด์
(์ฌ์ฉ์ ๋ช
์ ์์ฒญ). ๋ณด์ = ๋น ๊ฐ๋ง โ ์ฌ์ฉ์๊ฐ ์ง์ ํ ํฐ ์ฑ์.
|
|
936
|
-
// ๊ธฐ์กด .env ๊ฐ ์์ผ๋ฉด mergeEnvFile ์ด KEY ๊ธฐ์ค ์ฒ๋ฆฌ:
|
|
937
|
-
// - ๊ธฐ์กด ํค (์ฌ์ฉ์๊ฐ ์ฑ์ด ๊ฐ ํฌํจ) ๋ ์ ๋ ๋ฎ์ด์ฐ์ง ์์
|
|
938
|
-
// - ๋๋ฝ๋ ํค๋ง ๋น ๊ฐ์ผ๋ก ์ถ๊ฐ
|
|
939
|
-
// .env ๊ฐ .gitignore ์ ๋ฑ๋ก๋์ด ์๋์ง audit ๊ฐ ๊ฒ์ฆ (1.9.75+).
|
|
940
922
|
try {
|
|
941
923
|
mergeEnvFile(path.join(root, '.env'), envLines);
|
|
942
924
|
} catch (e) {
|
|
943
925
|
warn(`.env ์์ฑ/๋ง์ด๊ทธ๋ ์ด์
์คํจ (๊ณ์ ์งํ): ${e.message}`);
|
|
944
926
|
}
|
|
927
|
+
// 1.9.187: ๋น์ํฌ๋ฆฟ LEERNESS_* ์ค์ โ .harness/leerness-config.json (AI ๊ฐ์์ฑ)
|
|
928
|
+
try {
|
|
929
|
+
_writeLeernessConfig(root, {
|
|
930
|
+
LEERNESS_OLLAMA_BASE_URL: enable('ollama') ? 'http://localhost:11434' : '',
|
|
931
|
+
LEERNESS_OLLAMA_MODEL: '',
|
|
932
|
+
LEERNESS_ENABLE_CLAUDE: enable('claude') ? '1' : '0',
|
|
933
|
+
LEERNESS_ENABLE_CODEX: enable('codex') ? '1' : '0',
|
|
934
|
+
LEERNESS_ENABLE_GEMINI: enable('gemini') ? '1' : '0',
|
|
935
|
+
LEERNESS_ENABLE_COPILOT: enable('copilot') ? '1' : '0',
|
|
936
|
+
LEERNESS_ENABLE_OLLAMA: enable('ollama') ? '1' : '0',
|
|
937
|
+
LEERNESS_SKILL_DISCOVER_URL: '',
|
|
938
|
+
LEERNESS_SKILL_AUTO_DISCOVER: '0',
|
|
939
|
+
LEERNESS_SKILL_AUTO_INSTALL: '0',
|
|
940
|
+
LEERNESS_SKILL_AUTO_PRESETS: 'vercel,anthropic'
|
|
941
|
+
});
|
|
942
|
+
} catch (e) {
|
|
943
|
+
warn(`.harness/leerness-config.json ์์ฑ ์คํจ (๊ณ์ ์งํ): ${e.message}`);
|
|
944
|
+
}
|
|
945
|
+
// 1.9.187: ๊ธฐ์กด .env์ ๋น์ํฌ๋ฆฟ LEERNESS_* ๊ฐ ์์ผ๋ฉด .harness/leerness-config.json ์ผ๋ก ๋ง์ด๊ทธ๋ ์ด์
ํ .env์์ ์ ๊ฑฐ.
|
|
946
|
+
try {
|
|
947
|
+
_migrateNonsecretFromEnv(root);
|
|
948
|
+
} catch (e) {
|
|
949
|
+
warn(`.env ๋น์ํฌ๋ฆฟ ๋ง์ด๊ทธ๋ ์ด์
์คํจ (๊ณ์ ์งํ): ${e.message}`);
|
|
950
|
+
}
|
|
945
951
|
// 1.9.146: agent ๊ถํ ํ์ผ ์๋ ์์ฑ (์ฌ์ฉ์ ๋ช
์ ์์ฒญ #5)
|
|
946
952
|
if (resolved.permissionMode) {
|
|
947
953
|
try { _writePermissionsPreset(root, resolved.permissionMode); } catch (e) { warn('permissions ์์ฑ ์คํจ: ' + e.message); }
|
|
@@ -4310,23 +4316,149 @@ function verifyClaimCmd(root, taskId) {
|
|
|
4310
4316
|
function _loadEnvFile(root) {
|
|
4311
4317
|
// root ๊ฒฝ๋ก(๋๋ cwd)์ .env ํ์ผ์ ๊ฐ๋จ ํ์ฑํด process.env์ ๋จธ์ง (์ด๋ฏธ ์๋ ํค๋ ๋ฎ์ด์ฐ์ง ์์)
|
|
4312
4318
|
const envFile = path.join(root || process.cwd(), '.env');
|
|
4313
|
-
|
|
4319
|
+
let loadedEnv = false;
|
|
4320
|
+
if (exists(envFile)) {
|
|
4321
|
+
try {
|
|
4322
|
+
const txt = read(envFile);
|
|
4323
|
+
for (const line of txt.split(/\r?\n/)) {
|
|
4324
|
+
const m = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*?)\s*$/);
|
|
4325
|
+
if (!m) continue;
|
|
4326
|
+
const key = m[1];
|
|
4327
|
+
let val = m[2];
|
|
4328
|
+
// ์ฃผ์ ์ ๊ฑฐ
|
|
4329
|
+
if (val.startsWith('#')) continue;
|
|
4330
|
+
// ๋ฐ์ดํ ์ ๊ฑฐ
|
|
4331
|
+
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) val = val.slice(1, -1);
|
|
4332
|
+
if (!process.env[key]) process.env[key] = val;
|
|
4333
|
+
}
|
|
4334
|
+
loadedEnv = true;
|
|
4335
|
+
} catch {}
|
|
4336
|
+
}
|
|
4337
|
+
// 1.9.187: .env ๋ก๋ ํ ๋น์ํฌ๋ฆฟ LEERNESS_* ๋ .harness/leerness-config.json ์์ ์๋ inject.
|
|
4338
|
+
// ์ฐ์ ์์: process.env (์ด๋ฏธ ์์) > .env > .harness/leerness-config.json > defaults.
|
|
4339
|
+
try { _loadLeernessConfig(root); } catch {}
|
|
4340
|
+
return loadedEnv;
|
|
4341
|
+
}
|
|
4342
|
+
|
|
4343
|
+
// 1.9.187 (์ฌ์ฉ์ ๋ช
์): ๋น์ํฌ๋ฆฟ LEERNESS_* ์ค์ ์ .env์์ .harness/leerness-config.json ์ผ๋ก ๋ถ๋ฆฌ.
|
|
4344
|
+
// ๋ฐฐ๊ฒฝ: .env ๋ .gitignore + ์ํฌ๋ฆฟ์ฉ โ ๋ค๋ฅธ AI ์์ด์ ํธ (Claude Code, Cursor ๋ฑ) ๊ฐ ์ํฌ์คํ์ด์ค ์ฝ์ ๋ ๋ณด์ ์ ์ฑ
์ ์๋ ๋
ธ์ถ X.
|
|
4345
|
+
// ๋น์ํฌ๋ฆฟ (ํ์ฑํ ํ๋๊ทธ, ๋ชจ๋ธ ์ด๋ฆ, ๊ณต๊ฐ URL) ์ .harness/leerness-config.json (git checked-in) ์ผ๋ก ์ฎ๊ธฐ๋ฉด AI ๊ฐ์์ฑ โ.
|
|
4346
|
+
// ํธํ์ฑ: ์์ ์์ ์ config ํ์ผ ์ฝ์ด์ process.env์ inject. ๊ธฐ์กด process.env.LEERNESS_* ์ฝ๋ ๊ทธ๋๋ก ์๋.
|
|
4347
|
+
// ์ฐ์ ์์: 1) process.env (์ด๋ฏธ ์ค์ ๋ ๊ฐ) > 2) .env ํ์ผ > 3) .harness/leerness-config.json > 4) defaults.
|
|
4348
|
+
const _LEERNESS_NONSECRET_KEYS = new Set([
|
|
4349
|
+
'LEERNESS_OLLAMA_BASE_URL', // ์ผ๋ฐ localhost URL โ ๋น๋ฐ X
|
|
4350
|
+
'LEERNESS_OLLAMA_MODEL', // ๋ชจ๋ธ ์ด๋ฆ โ ๋น๋ฐ X
|
|
4351
|
+
'LEERNESS_ENABLE_CLAUDE', // ํ์ฑํ ํ๋๊ทธ
|
|
4352
|
+
'LEERNESS_ENABLE_CODEX',
|
|
4353
|
+
'LEERNESS_ENABLE_GEMINI',
|
|
4354
|
+
'LEERNESS_ENABLE_COPILOT',
|
|
4355
|
+
'LEERNESS_ENABLE_OLLAMA',
|
|
4356
|
+
'LEERNESS_SKILL_DISCOVER_URL', // ๊ณต๊ฐ URL
|
|
4357
|
+
'LEERNESS_SKILL_AUTO_DISCOVER',
|
|
4358
|
+
'LEERNESS_SKILL_AUTO_INSTALL',
|
|
4359
|
+
'LEERNESS_SKILL_AUTO_PRESETS'
|
|
4360
|
+
]);
|
|
4361
|
+
// ์ํฌ๋ฆฟ์ ์ ๋ .harness/leerness-config.json ์ผ๋ก ์ฎ๊ธฐ์ง ์์ (TOKEN ํจํด ์๋ ์ฐจ๋จ)
|
|
4362
|
+
function _isSecretKey(k) {
|
|
4363
|
+
return /TOKEN|SECRET|PASSWORD|API_KEY|PRIVATE/i.test(k);
|
|
4364
|
+
}
|
|
4365
|
+
function _leernessConfigPath(root) { return path.join(absRoot(root || process.cwd()), '.harness', 'leerness-config.json'); }
|
|
4366
|
+
function _loadLeernessConfig(root) {
|
|
4367
|
+
const f = _leernessConfigPath(root);
|
|
4368
|
+
if (!exists(f)) return false;
|
|
4314
4369
|
try {
|
|
4315
|
-
const
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
if (
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
if (val.startsWith('#')) continue;
|
|
4323
|
-
// ๋ฐ์ดํ ์ ๊ฑฐ
|
|
4324
|
-
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) val = val.slice(1, -1);
|
|
4325
|
-
if (!process.env[key]) process.env[key] = val;
|
|
4370
|
+
const j = JSON.parse(read(f));
|
|
4371
|
+
// _comment ๊ฐ์ ๋ฉํ ํค๋ ๋ฌด์. ์ค์ LEERNESS_* ํค๋ง inject.
|
|
4372
|
+
for (const k of Object.keys(j || {})) {
|
|
4373
|
+
if (k.startsWith('_')) continue;
|
|
4374
|
+
if (_isSecretKey(k)) continue; // ๋ณด์ ๊ฐ๋ โ ์๋ชป ๋ค์ด๊ฐ ์ํฌ๋ฆฟ ์ฐจ๋จ
|
|
4375
|
+
if (typeof j[k] !== 'string' && typeof j[k] !== 'number' && typeof j[k] !== 'boolean') continue;
|
|
4376
|
+
if (!process.env[k]) process.env[k] = String(j[k]);
|
|
4326
4377
|
}
|
|
4327
4378
|
return true;
|
|
4328
4379
|
} catch { return false; }
|
|
4329
4380
|
}
|
|
4381
|
+
// 1.9.187: ๊ธฐ์กด .env ์ ๋น์ํฌ๋ฆฟ LEERNESS_* ๊ฐ ์์ผ๋ฉด โ .harness/leerness-config.json ์ผ๋ก ์ฎ๊ธฐ๊ณ .env ์์ ์ ๊ฑฐ.
|
|
4382
|
+
// ์ฌ์ฉ์๊ฐ 1.9.186 ์ด์ ๋ฒ์ ์ผ๋ก ๋ง๋ .env ๋ฅผ 1.9.187 ๋ก ๋ง์ด๊ทธ๋ ์ดํธํ ๋ ์๋ ์ ๋ฆฌ.
|
|
4383
|
+
// .env ์ ์ํฌ๋ฆฟ (TOKEN/KEY/PASSWORD) ์ ์ ๋ ๊ฑด๋๋ฆฌ์ง ์์. ๋ณด์ first.
|
|
4384
|
+
function _migrateNonsecretFromEnv(root) {
|
|
4385
|
+
const envFile = path.join(absRoot(root || process.cwd()), '.env');
|
|
4386
|
+
if (!exists(envFile)) return { migrated: 0, kept: 0 };
|
|
4387
|
+
const txt = read(envFile);
|
|
4388
|
+
const lines = txt.split(/\r?\n/);
|
|
4389
|
+
const migrated = {};
|
|
4390
|
+
const remaining = [];
|
|
4391
|
+
let movedCount = 0;
|
|
4392
|
+
let pendingComment = null; // ์ง์ # ์ฃผ์ ๋ผ์ธ ์ถ์ (๋น์ํฌ๋ฆฟ ํค ์ด๋ ์ ํจ๊ป ์ ๊ฑฐ)
|
|
4393
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4394
|
+
const line = lines[i];
|
|
4395
|
+
if (/^\s*#/.test(line) || /^\s*$/.test(line)) {
|
|
4396
|
+
// ์ฃผ์/๋น์ค โ ์ผ๋จ ๋ณด๊ด, ๋น์ํฌ๋ฆฟ ํค ๋ฐ๊ฒฌ ์ ์ง์ ์ฃผ์๋ ์ ๊ฑฐ ๋์
|
|
4397
|
+
if (/^\s*#/.test(line)) pendingComment = remaining.length;
|
|
4398
|
+
remaining.push(line);
|
|
4399
|
+
continue;
|
|
4400
|
+
}
|
|
4401
|
+
const m = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*?)\s*$/);
|
|
4402
|
+
if (!m) { remaining.push(line); pendingComment = null; continue; }
|
|
4403
|
+
const key = m[1];
|
|
4404
|
+
const val = m[2].replace(/^["']|["']$/g, '');
|
|
4405
|
+
if (_LEERNESS_NONSECRET_KEYS.has(key) && !_isSecretKey(key)) {
|
|
4406
|
+
// ๋น์ํฌ๋ฆฟ โ config ๋ก ์ด๋, .env ์์ ์ ๊ฑฐ (์ง์ # ์ฃผ์๋ ์ ๊ฑฐ)
|
|
4407
|
+
migrated[key] = val;
|
|
4408
|
+
movedCount++;
|
|
4409
|
+
if (pendingComment !== null) {
|
|
4410
|
+
// pendingComment ๋ผ์ธ๋ถํฐ ์ง์ ๊น์ง ์ ๊ฑฐ (๋จ, ์์ ๋ผ์ธ ๋ณดํธ)
|
|
4411
|
+
// ๋จ์ํ: ๊ทธ๋ฅ ์ง์ 1์ค๋ง ์ ๊ฑฐ (๋๋ถ๋ถ ์ฃผ์ 1์ค + ํค 1์ค ํจํด)
|
|
4412
|
+
if (remaining.length > 0 && /^\s*#/.test(remaining[remaining.length - 1])) {
|
|
4413
|
+
remaining.pop();
|
|
4414
|
+
}
|
|
4415
|
+
}
|
|
4416
|
+
pendingComment = null;
|
|
4417
|
+
continue;
|
|
4418
|
+
}
|
|
4419
|
+
remaining.push(line);
|
|
4420
|
+
pendingComment = null;
|
|
4421
|
+
}
|
|
4422
|
+
if (movedCount === 0) return { migrated: 0, kept: lines.length };
|
|
4423
|
+
// .env ๋ค์ ์ฐ๊ธฐ (์ํฌ๋ฆฟ + ์ฃผ์๋ง ์ ์ง)
|
|
4424
|
+
// ์ฐ์๋ ๋น ์ค ์ ๋ฆฌ
|
|
4425
|
+
const cleaned = [];
|
|
4426
|
+
let prevEmpty = false;
|
|
4427
|
+
for (const ln of remaining) {
|
|
4428
|
+
const isEmpty = /^\s*$/.test(ln);
|
|
4429
|
+
if (isEmpty && prevEmpty) continue;
|
|
4430
|
+
cleaned.push(ln);
|
|
4431
|
+
prevEmpty = isEmpty;
|
|
4432
|
+
}
|
|
4433
|
+
writeUtf8(envFile, cleaned.join('\n').replace(/\n+$/, '\n'));
|
|
4434
|
+
// config ์ ๋จธ์ง
|
|
4435
|
+
_writeLeernessConfig(root, migrated);
|
|
4436
|
+
return { migrated: movedCount, kept: cleaned.length };
|
|
4437
|
+
}
|
|
4438
|
+
|
|
4439
|
+
function _writeLeernessConfig(root, kv) {
|
|
4440
|
+
const f = _leernessConfigPath(root);
|
|
4441
|
+
mkdirp(path.dirname(f));
|
|
4442
|
+
// ๊ธฐ์กด ํ์ผ ๋จธ์ง (์ฌ์ฉ์๊ฐ ์๋ ํธ์งํ ๊ฐ ๋ณด์กด)
|
|
4443
|
+
let existing = {};
|
|
4444
|
+
if (exists(f)) {
|
|
4445
|
+
try { existing = JSON.parse(read(f)); } catch {}
|
|
4446
|
+
}
|
|
4447
|
+
const merged = {
|
|
4448
|
+
_comment: 'leerness ๋น์ํฌ๋ฆฟ ์ค์ . AI ์์ด์ ํธ๊ฐ ์ฝ์ ์ ์๋ ์์น (git checked-in). ์ํฌ๋ฆฟ(TOKEN/SECRET/PASSWORD)์ .env ์ฌ์ฉ.',
|
|
4449
|
+
_docs: 'https://github.com/gugu9999gu/leerness#config',
|
|
4450
|
+
_version: VERSION,
|
|
4451
|
+
...existing,
|
|
4452
|
+
...kv
|
|
4453
|
+
};
|
|
4454
|
+
// ๋ณด์ ๊ฐ๋ โ ์ํฌ๋ฆฟ ํจํด ์๋ ์ ๊ฑฐ
|
|
4455
|
+
for (const k of Object.keys(merged)) {
|
|
4456
|
+
if (k.startsWith('_')) continue;
|
|
4457
|
+
if (_isSecretKey(k)) { delete merged[k]; }
|
|
4458
|
+
}
|
|
4459
|
+
writeUtf8(f, JSON.stringify(merged, null, 2) + '\n');
|
|
4460
|
+
return f;
|
|
4461
|
+
}
|
|
4330
4462
|
|
|
4331
4463
|
function _httpPostJson(urlStr, body, timeoutMs = 300000) {
|
|
4332
4464
|
return new Promise((resolve, reject) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.187",
|
|
4
4
|
"description": "Leerness: ๋นํ๊ดด ๋ง์ด๊ทธ๋ ์ด์
, ์๋ ๋ฒ์ ๊ฐ์งยท์
๋ฐ์ดํธ, ๊ณํ/์งํ/ํธ๋์คํ ์๋ํ, ๊ฒ์ผ๋ฆยท์ํฌ๋ฆฟยท์ธ์ฝ๋ฉ ์๋ ๊ฐ๋, Claude Code ์ฌ๋์ ํตํฉ์ ๊ฐ์ถ ํ๊ตญ์ด ์ฐ์ AI ๊ฐ๋ฐ ํ๋ค์ค.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|