leerness 1.9.152 → 1.9.153
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 +45 -0
- package/README.md +2 -2
- package/bin/harness.js +120 -15
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.153 — 2026-05-20
|
|
4
|
+
|
|
5
|
+
**`.env` 직접 생성/마이그레이션 + REPL 배너 leerness 고유 문구 + multi-provider REPL (사용자 명시 3종).**
|
|
6
|
+
|
|
7
|
+
자율 모드 83 라운드.
|
|
8
|
+
|
|
9
|
+
### Added — install 흐름에서 `.env` 직접 생성/마이그레이션 (사용자 명시)
|
|
10
|
+
- 기존 `.env.example` 만 작성 → **이제 `.env` 도 직접 생성** (보안 = 빈 키만)
|
|
11
|
+
- `mergeEnvFile()` — KEY 기준 처리:
|
|
12
|
+
- 기존 키 (사용자가 채운 값 포함) **절대 덮어쓰지 않음**
|
|
13
|
+
- 누락된 키만 빈 값으로 추가
|
|
14
|
+
- 주석/빈 줄은 substring 미포함 시만 append
|
|
15
|
+
- `.gitignore` 에 `.env` 자동 등록 (1.9.71/75 audit 검증과 통합)
|
|
16
|
+
- `.env.example` 은 계속 생성 (참조 템플릿)
|
|
17
|
+
|
|
18
|
+
### Changed — REPL 배너 leerness 고유 문구 (사용자 명시)
|
|
19
|
+
- 기존: `Hermes / OpenClaw / OpenCode 스타일 + Sandbox`
|
|
20
|
+
- 변경: `검수·기억·샌드박스 통합 자율 AI 에이전트`
|
|
21
|
+
- agent 사용법 (non-TTY) 헤더도 동일 — leerness 자체 정체성 강화
|
|
22
|
+
|
|
23
|
+
### Added — REPL multi-provider 세션 관리 (사용자 명시)
|
|
24
|
+
- 기존: Ollama 전용 채팅
|
|
25
|
+
- 변경: **ollama / claude / codex / gemini / copilot** 5종 세션 관리
|
|
26
|
+
- `_cliChat(root, provider, prompt, opts)` — 외부 CLI 호출 헬퍼
|
|
27
|
+
- 각 CLI 별 비-인터랙티브 호출 인자 자동 매핑
|
|
28
|
+
- `runCommandSafe` 경유 (env scrub + permissions + observability 자동)
|
|
29
|
+
- 활성 (`_checkAgent` ready) 확인 후 실행 — 비활성 시 friendly 에러
|
|
30
|
+
- REPL 진입 시:
|
|
31
|
+
- `.env` 자동 로드 (LEERNESS_ENABLE_* 즉시 반영)
|
|
32
|
+
- 활성 CLI 단일 → 자동 선택 / 복수 → 사용자 번호 선택 / 0개 → Ollama fallback
|
|
33
|
+
- `:provider <p>` 메타 명령으로 세션 중 전환 가능
|
|
34
|
+
- `:role <r>` 와 조합하여 planner=claude / actor=codex 같은 multi-CLI 워크플로 가능
|
|
35
|
+
|
|
36
|
+
### Security
|
|
37
|
+
- `.env` 가 `.gitignore` 에 등록 (실제 시크릿 누출 방지)
|
|
38
|
+
- `_cliChat` 가 `runCommandSafe` 경유 → env scrub 화이트리스트만 자식 프로세스에 전파
|
|
39
|
+
- `.harness/runs/run-*.jsonl` 에 `kind: 'agent_repl_cli'` 로 모든 외부 CLI 호출 기록
|
|
40
|
+
|
|
41
|
+
### Verified
|
|
42
|
+
- e2e 217/217 ✓
|
|
43
|
+
- stress-v98: 23/23 (env 생성 7종 + REPL 배너 3종 + multi-provider 6종 + 누적 회귀 7종)
|
|
44
|
+
- VERSION = 1.9.153 / autonomous-rounds = 83
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
3
48
|
## 1.9.152 — 2026-05-20
|
|
4
49
|
|
|
5
50
|
**`agents multi` — 활성 N개 에이전트 일괄 dispatch + handoff 헤드라인 활성 에이전트 카운트 (1.9.151 복수 선택 후속).**
|
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,7 +12,7 @@
|
|
|
12
12
|
║ ██║ ██╔══╝ ██╔══╝ ██╔══██╗██║╚██╗██║██╔══╝ ╚════██║ ║
|
|
13
13
|
║ ███████╗███████╗███████╗██║ ██║██║ ╚████║███████╗███████║ ║
|
|
14
14
|
║ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝ ║
|
|
15
|
-
║ v1.9.
|
|
15
|
+
║ v1.9.153 AI Agent Reliability Harness + Sandbox ║
|
|
16
16
|
║ verify · remember · orchestrate · audit · sandbox · drift ║
|
|
17
17
|
╚══════════════════════════════════════════════════════════════╝
|
|
18
18
|
```
|
package/bin/harness.js
CHANGED
|
@@ -6,7 +6,7 @@ const path = require('path');
|
|
|
6
6
|
const cp = require('child_process');
|
|
7
7
|
const readline = require('readline');
|
|
8
8
|
|
|
9
|
-
const VERSION = '1.9.
|
|
9
|
+
const VERSION = '1.9.153';
|
|
10
10
|
const MARK = '<!-- leerness:managed -->';
|
|
11
11
|
const README_START = '<!-- leerness:project-readme:start -->';
|
|
12
12
|
const README_END = '<!-- leerness:project-readme:end -->';
|
|
@@ -579,6 +579,31 @@ function mergeLinesFile(p, lines) {
|
|
|
579
579
|
writeUtf8(p, next);
|
|
580
580
|
}
|
|
581
581
|
|
|
582
|
+
// 1.9.153: env 파일 전용 key-aware merge — KEY=VALUE 줄을 키 기준 처리 (기존 값 보존, 빈 키만 추가)
|
|
583
|
+
// 사용자가 .env 의 LEERNESS_NPM_TOKEN=abc123 처럼 직접 편집한 값을 절대 덮어쓰지 않음.
|
|
584
|
+
// 주석 / 빈 줄은 substring includes 로 중복 방지 (mergeLinesFile 와 동일).
|
|
585
|
+
function mergeEnvFile(p, lines) {
|
|
586
|
+
const current = exists(p) ? read(p) : '';
|
|
587
|
+
const existingKeys = new Set();
|
|
588
|
+
for (const ln of current.split(/\r?\n/)) {
|
|
589
|
+
const m = ln.match(/^\s*([A-Z][A-Z0-9_]+)\s*=/);
|
|
590
|
+
if (m) existingKeys.add(m[1]);
|
|
591
|
+
}
|
|
592
|
+
let next = current;
|
|
593
|
+
for (const line of lines) {
|
|
594
|
+
const km = line.match(/^\s*([A-Z][A-Z0-9_]+)\s*=/);
|
|
595
|
+
if (km) {
|
|
596
|
+
if (existingKeys.has(km[1])) continue; // 기존 키 값 보존 (덮어쓰기 X)
|
|
597
|
+
next += (next.endsWith('\n') || !next ? '' : '\n') + line + '\n';
|
|
598
|
+
existingKeys.add(km[1]);
|
|
599
|
+
} else {
|
|
600
|
+
// 주석 또는 빈 줄 — substring 미포함 시만 append
|
|
601
|
+
if (!next.includes(line)) next += (next.endsWith('\n') || !next ? '' : '\n') + line + '\n';
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
writeUtf8(p, next);
|
|
605
|
+
}
|
|
606
|
+
|
|
582
607
|
function writeMigrationReport(root, backup, actions, opts = {}) {
|
|
583
608
|
const p = path.join(root, '.harness/migration-report.md');
|
|
584
609
|
const rows = actions.map(a => `| ${a.file} | ${a.action} |`).join('\n');
|
|
@@ -820,7 +845,10 @@ async function install(root, opts = {}) {
|
|
|
820
845
|
}
|
|
821
846
|
if (!opts.dry) {
|
|
822
847
|
mergeLinesFile(path.join(root, '.gitignore'), [
|
|
823
|
-
|
|
848
|
+
// 1.9.153: .env 직접 생성 + 사용자 글로벌 룰 SECRET_PATTERNS 6종 일괄 ignore (audit 통합)
|
|
849
|
+
// audit 가 검사하는 6 패턴: .env / .env.local / .env.production / .env.*.local / *.pem / credentials.json
|
|
850
|
+
'.env', '.env.local', '.env.production', '.env.*.local', '*.pem', 'credentials.json',
|
|
851
|
+
'.harness/skill-publish.local.json','.harness/**/*.local.json',
|
|
824
852
|
'.harness/archive/','.harness/migration-report.md','.harness/cache/',
|
|
825
853
|
// 1.9.147: 자동 유지보수 — 자격증명 + incident 페이로드 비공개 (보안)
|
|
826
854
|
'.harness/credentials.local.json','.harness/incidents/',
|
|
@@ -836,8 +864,12 @@ async function install(root, opts = {}) {
|
|
|
836
864
|
return new Set([a]); // back-compat: 단일 문자열
|
|
837
865
|
})();
|
|
838
866
|
const enable = (cli) => enabledSet.has(cli);
|
|
839
|
-
|
|
840
|
-
|
|
867
|
+
// 1.9.153: .env.example 은 템플릿 (배포 가능, 실제 시크릿 값 없음)
|
|
868
|
+
// .env 는 실 사용 파일 — 사용자가 토큰 채워 넣음. 보안 정책: 토큰 값은 절대 자동 채우지 않음 (키만).
|
|
869
|
+
// .gitignore 에 .env 가 들어가 있어야 함 (audit 가 자동 검증). mergeLinesFile 은 기존 키 유지 + 신규 추가.
|
|
870
|
+
const envLines = [
|
|
871
|
+
'# Leerness — environment variable names only. Do not commit real secrets (this file is in .gitignore).',
|
|
872
|
+
`# Generated/migrated by leerness v${VERSION} at ${new Date().toISOString().slice(0, 10)}.`,
|
|
841
873
|
'LEERNESS_NPM_TOKEN=','LEERNESS_GITHUB_TOKEN=',
|
|
842
874
|
'# 1.9.22 — orchestrate opt-in. URL이 설정되면 leerness가 Ollama를 사용 가능. 미설정 시 LLM 호출 자동 시작 금지.',
|
|
843
875
|
`LEERNESS_OLLAMA_BASE_URL=${enable('ollama') ? 'http://localhost:11434' : ''}`,
|
|
@@ -850,11 +882,22 @@ async function install(root, opts = {}) {
|
|
|
850
882
|
`LEERNESS_ENABLE_COPILOT=${enable('copilot') ? 1 : 0}`,
|
|
851
883
|
`LEERNESS_ENABLE_OLLAMA=${enable('ollama') ? 1 : 0}`,
|
|
852
884
|
'# 1.9.42 — agentskills.io 공개 표준 스킬 자동 탐색 (opt-in). URL 설정 시 `leerness skill discover` 사용 가능.',
|
|
853
|
-
'#
|
|
885
|
+
'# 예시 URL: https://agentskills.io/llms.txt',
|
|
854
886
|
'LEERNESS_SKILL_DISCOVER_URL=',
|
|
855
887
|
'# (선택) 사용자 요청 분석 시 자동 매칭 스킬 추천. 1=활성, 0/미설정=비활성.',
|
|
856
888
|
'LEERNESS_SKILL_AUTO_DISCOVER=0'
|
|
857
|
-
]
|
|
889
|
+
];
|
|
890
|
+
mergeLinesFile(path.join(root, '.env.example'), envLines);
|
|
891
|
+
// 1.9.153: .env 직접 생성/마이그레이션 (사용자 명시 요청). 보안 = 빈 값만 — 사용자가 직접 토큰 채움.
|
|
892
|
+
// 기존 .env 가 있으면 mergeEnvFile 이 KEY 기준 처리:
|
|
893
|
+
// - 기존 키 (사용자가 채운 값 포함) 는 절대 덮어쓰지 않음
|
|
894
|
+
// - 누락된 키만 빈 값으로 추가
|
|
895
|
+
// .env 가 .gitignore 에 등록되어 있는지 audit 가 검증 (1.9.75+).
|
|
896
|
+
try {
|
|
897
|
+
mergeEnvFile(path.join(root, '.env'), envLines);
|
|
898
|
+
} catch (e) {
|
|
899
|
+
warn(`.env 생성/마이그레이션 실패 (계속 진행): ${e.message}`);
|
|
900
|
+
}
|
|
858
901
|
// 1.9.146: agent 권한 파일 자동 생성 (사용자 명시 요청 #5)
|
|
859
902
|
if (resolved.permissionMode) {
|
|
860
903
|
try { _writePermissionsPreset(root, resolved.permissionMode); } catch (e) { warn('permissions 생성 실패: ' + e.message); }
|
|
@@ -10073,6 +10116,41 @@ async function _ollamaListModels() {
|
|
|
10073
10116
|
});
|
|
10074
10117
|
}
|
|
10075
10118
|
|
|
10119
|
+
// 1.9.153: 외부 CLI 채팅 호출 (multi-provider REPL — 사용자 명시 요청)
|
|
10120
|
+
// claude/codex/gemini/copilot 를 child_process 로 호출 후 stdout 캡처.
|
|
10121
|
+
// runCommandSafe 경유 — env scrub + permissions + observability 자동 적용.
|
|
10122
|
+
async function _cliChat(root, provider, prompt, opts) {
|
|
10123
|
+
opts = opts || {};
|
|
10124
|
+
const agent = EXTERNAL_AGENTS.find(a => a.id === provider);
|
|
10125
|
+
if (!agent) return { ok: false, error: `unknown provider: ${provider}`, provider };
|
|
10126
|
+
const status = _checkAgent(agent);
|
|
10127
|
+
if (status.status !== 'ready') {
|
|
10128
|
+
return { ok: false, error: `${provider} 비활성 (${status.status}) — .env 에서 ${agent.envFlag}=1 + CLI 설치 필요`, provider };
|
|
10129
|
+
}
|
|
10130
|
+
// CLI 별 비-인터랙티브 호출 인자 매핑 (read-only 모드 — REPL 안에서 파일 수정 X)
|
|
10131
|
+
let cmd, args;
|
|
10132
|
+
if (provider === 'claude') { cmd = 'claude'; args = ['--print', prompt]; }
|
|
10133
|
+
else if (provider === 'codex') { cmd = 'codex'; args = ['exec', '--skip-git-repo-check', prompt]; }
|
|
10134
|
+
else if (provider === 'gemini') { cmd = 'gemini'; args = ['-p', prompt]; }
|
|
10135
|
+
else if (provider === 'copilot') { cmd = 'gh'; args = ['copilot', 'suggest', prompt]; }
|
|
10136
|
+
else return { ok: false, error: `provider ${provider} 미지원`, provider };
|
|
10137
|
+
// runCommandSafe — env scrub + observability 자동
|
|
10138
|
+
const r = runCommandSafe(cmd, args, {
|
|
10139
|
+
cwd: process.cwd(), root,
|
|
10140
|
+
timeout: opts.timeout || 60000,
|
|
10141
|
+
allowOutsideCwd: true, // CLI 가 cwd 밖에서 실행될 수 있음
|
|
10142
|
+
kind: 'agent_repl_cli', label: `repl-${provider}`
|
|
10143
|
+
});
|
|
10144
|
+
if (r.status === 0) {
|
|
10145
|
+
return { ok: true, response: (r.stdout || '').trim(), provider, model: provider };
|
|
10146
|
+
}
|
|
10147
|
+
return {
|
|
10148
|
+
ok: false,
|
|
10149
|
+
error: `exit=${r.status} ${(r.stderr || r.stdout || '').slice(0, 200)}`,
|
|
10150
|
+
provider
|
|
10151
|
+
};
|
|
10152
|
+
}
|
|
10153
|
+
|
|
10076
10154
|
// 1.9.149: observability lite — 모든 agent 호출의 traceId + duration + exit + failureCause 기록
|
|
10077
10155
|
function _runsDir(root) { return path.join(absRoot(root), '.harness', 'runs'); }
|
|
10078
10156
|
function _recordRun(root, entry) {
|
|
@@ -10228,8 +10306,10 @@ const _AGENT_ROLE_PROMPTS = {
|
|
|
10228
10306
|
reviewer: '역할: reviewer. planner 의 계획 또는 actor 의 결과를 비판적으로 검토. 누락된 검증, 잠재 cascade, 오류 가능성 지적. 동의/수정 결론 명시.',
|
|
10229
10307
|
actor: '역할: actor. 계획에 따라 정확한 명령/코드만 실행. evidence(파일 경로 + 테스트 결과) 함께 기록. 새 계획 생성 금지.'
|
|
10230
10308
|
};
|
|
10231
|
-
// 1.9.149: REPL 모드 —
|
|
10309
|
+
// 1.9.149+1.9.153: REPL 모드 — leerness 자율 AI 에이전트 (multi-provider 세션)
|
|
10232
10310
|
async function _agentRepl(root, opts) {
|
|
10311
|
+
// 1.9.153: .env 자동 로드 (REPL 진입 직전) — install 직후 LEERNESS_ENABLE_* 즉시 반영
|
|
10312
|
+
try { _loadEnvFile(root); } catch {}
|
|
10233
10313
|
const readline = require('readline');
|
|
10234
10314
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
10235
10315
|
const isTty = process.stdout.isTTY;
|
|
@@ -10238,9 +10318,28 @@ async function _agentRepl(root, opts) {
|
|
|
10238
10318
|
bold: s => `\x1b[1m${s}\x1b[0m`, green: s => `\x1b[32m${s}\x1b[0m`,
|
|
10239
10319
|
yel: s => `\x1b[33m${s}\x1b[0m`, mag: s => `\x1b[35m${s}\x1b[0m`
|
|
10240
10320
|
} : { cy:s=>s, dim:s=>s, bold:s=>s, green:s=>s, yel:s=>s, mag:s=>s };
|
|
10321
|
+
// 1.9.153: provider 자동 선택 — opts.provider 명시 안 됨 + 활성 CLI 가 있으면 사용자에게 선택지 표시
|
|
10322
|
+
let initialProvider = opts.provider;
|
|
10323
|
+
if (!initialProvider) {
|
|
10324
|
+
const ready = EXTERNAL_AGENTS.map(a => ({ def: a, status: _checkAgent(a) }))
|
|
10325
|
+
.filter(x => x.status.status === 'ready');
|
|
10326
|
+
if (ready.length === 1) {
|
|
10327
|
+
initialProvider = ready[0].def.id; // 단일 활성 → 자동 선택
|
|
10328
|
+
} else if (ready.length > 1 && isTty) {
|
|
10329
|
+
// 복수 활성 → 사용자에게 선택지 (Ollama 우선이 아닌, 활성된 CLI 중 선택)
|
|
10330
|
+
console.log('');
|
|
10331
|
+
console.log(` 사용 가능한 CLI 에이전트 ${ready.length}개:`);
|
|
10332
|
+
ready.forEach((x, i) => console.log(` ${i + 1}) ${x.def.id}${x.status.version ? ' (v' + x.status.version + ')' : ''}`));
|
|
10333
|
+
const choice = await new Promise(res => rl.question(`\n provider 선택 (Enter=1): `, res));
|
|
10334
|
+
const idx = parseInt(choice, 10) - 1;
|
|
10335
|
+
initialProvider = (idx >= 0 && idx < ready.length) ? ready[idx].def.id : ready[0].def.id;
|
|
10336
|
+
} else {
|
|
10337
|
+
initialProvider = 'ollama'; // 활성 0개 → fallback (사용 시 friendly 경고)
|
|
10338
|
+
}
|
|
10339
|
+
}
|
|
10241
10340
|
// 세션 state
|
|
10242
10341
|
let state = {
|
|
10243
|
-
provider:
|
|
10342
|
+
provider: initialProvider,
|
|
10244
10343
|
model: opts.model || process.env.LEERNESS_OLLAMA_MODEL || null,
|
|
10245
10344
|
role: opts.role || 'actor',
|
|
10246
10345
|
history: [], // [{role: 'user'|'assistant', content: ''}]
|
|
@@ -10258,8 +10357,8 @@ async function _agentRepl(root, opts) {
|
|
|
10258
10357
|
// 환영 메시지 + 모델 선택
|
|
10259
10358
|
log('');
|
|
10260
10359
|
log(C.bold(C.cy(' ╔════════════════════════════════════════════════════╗')));
|
|
10261
|
-
log(C.bold(C.cy(' ║ leerness agent — REPL mode
|
|
10262
|
-
log(C.bold(C.cy(' ║
|
|
10360
|
+
log(C.bold(C.cy(' ║ leerness agent — REPL mode ║')));
|
|
10361
|
+
log(C.bold(C.cy(' ║ 검수·기억·샌드박스 통합 자율 AI 에이전트 ║')));
|
|
10263
10362
|
log(C.bold(C.cy(' ╚════════════════════════════════════════════════════╝')));
|
|
10264
10363
|
log('');
|
|
10265
10364
|
// Ollama 모델 자동 감지 — model이 명시되지 않았으면 사용자에게 선택지 제공
|
|
@@ -10374,11 +10473,15 @@ async function _agentRepl(root, opts) {
|
|
|
10374
10473
|
const finalPrompt = `${rolePrompt}\n\nConversation so far:\n${state.history.slice(-6).map(m => `[${m.role}] ${m.content}`).join('\n')}\n\nRespond as ${state.role}:`;
|
|
10375
10474
|
const t0 = Date.now();
|
|
10376
10475
|
let result;
|
|
10476
|
+
// 1.9.153: multi-provider REPL — ollama 외 claude/codex/gemini/copilot 도 세션 관리 (사용자 명시)
|
|
10377
10477
|
if (state.provider === 'ollama') {
|
|
10378
|
-
log(C.dim(` → ollama
|
|
10478
|
+
log(C.dim(` → ollama${state.model ? ' (' + state.model + ')' : ''} 호출 중...`));
|
|
10379
10479
|
result = await _ollamaChat(finalPrompt, state.model);
|
|
10480
|
+
} else if (['claude', 'codex', 'gemini', 'copilot'].includes(state.provider)) {
|
|
10481
|
+
log(C.dim(` → ${state.provider} CLI 호출 중...`));
|
|
10482
|
+
result = await _cliChat(root, state.provider, finalPrompt, { timeout: 90000 });
|
|
10380
10483
|
} else {
|
|
10381
|
-
log(C.yel(` ⚠ ${state.provider}
|
|
10484
|
+
log(C.yel(` ⚠ ${state.provider} provider 미지원 — :provider ollama|claude|codex|gemini|copilot`));
|
|
10382
10485
|
rl.prompt(); return;
|
|
10383
10486
|
}
|
|
10384
10487
|
const dt = Date.now() - t0;
|
|
@@ -10415,17 +10518,19 @@ async function agentCmd(root, taskArg) {
|
|
|
10415
10518
|
return;
|
|
10416
10519
|
}
|
|
10417
10520
|
// non-TTY: 사용법만 출력
|
|
10418
|
-
log('# leerness agent
|
|
10521
|
+
log('# leerness agent — 검수·기억·샌드박스 통합 자율 AI 에이전트');
|
|
10419
10522
|
log('');
|
|
10420
10523
|
log('사용법:');
|
|
10421
|
-
log(' leerness agent #
|
|
10524
|
+
log(' leerness agent # REPL 모드 (provider 자동 선택 + 채팅)');
|
|
10422
10525
|
log(' leerness agent "<task>" # 1회 위임 (actor 역할 기본)');
|
|
10423
10526
|
log(' leerness agent "<task>" --role planner # 계획만 (1.9.148)');
|
|
10424
10527
|
log(' leerness agent "<task>" --role reviewer # 비판적 검토 (1.9.148)');
|
|
10425
|
-
log(' leerness agent --
|
|
10528
|
+
log(' leerness agent --provider claude # provider 명시 (ollama/claude/codex/gemini/copilot)');
|
|
10529
|
+
log(' leerness agent --interactive --model qwen2.5-coder # 명시적 REPL + Ollama 모델 선택');
|
|
10426
10530
|
log('');
|
|
10427
10531
|
log('REPL 메타 명령: :help / :model / :role / :provider / :history / :save / :quit');
|
|
10428
10532
|
log('REPL Slash 명령 (1.9.150): :verify / :audit / :handoff / :health (sandboxed runCommandSafe)');
|
|
10533
|
+
log('REPL Multi-provider (1.9.153): ollama / claude / codex / gemini / copilot — 활성 CLI 자동 감지');
|
|
10429
10534
|
log('');
|
|
10430
10535
|
log('현재 활성 provider: ' + (_activeCliAgents().join(', ') || '(없음) — .env에서 LEERNESS_ENABLE_* 활성화'));
|
|
10431
10536
|
log('권한 모드: ' + (_readPermissions(root).mode || 'basic'));
|