cdsa-harness 0.19.0 → 0.20.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/README.md +2 -2
- package/package.json +1 -1
- package/src/builtins.js +1 -1
- package/src/cli.js +35 -6
- package/src/config.js +2 -2
- package/src/loop.js +2 -1
- package/src/tools.js +1 -1
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ Claude Code·OpenCode 컨벤션을 따릅니다.
|
|
|
84
84
|
| `/status` (=`/cost`) | 상태 · 세션 누적 토큰 |
|
|
85
85
|
| `/models [검색어]` | **실시간 모델 목록에서 번호로 선택**(4개 제공자 모두) |
|
|
86
86
|
| `/guide` · `/tutorial` | 빠른 시작 안내 · 단계별 인터랙티브 튜토리얼 |
|
|
87
|
-
| `/workspace <폴더>` | 작업 폴더 보기/변경
|
|
87
|
+
| `/workspace <폴더>` | 작업 폴더 보기/변경 — **기본은 현재 폴더(cwd)**, 터미널답게 |
|
|
88
88
|
| `/color` | 색상 켜기/끄기(흑백) |
|
|
89
89
|
| `/setup` | 제공자·API 키·모델 대화형 연결 |
|
|
90
90
|
| `/provider <이름>` | openai · anthropic · openrouter · mock 전환 |
|
|
@@ -231,7 +231,7 @@ cdsa-harness
|
|
|
231
231
|
"provider": "openai",
|
|
232
232
|
"api_key": "",
|
|
233
233
|
"model": "gpt-4o-mini",
|
|
234
|
-
"workspace": "
|
|
234
|
+
"workspace": ".",
|
|
235
235
|
"approval_mode": "manual",
|
|
236
236
|
"allow_shell": false,
|
|
237
237
|
"max_steps": 8,
|
package/package.json
CHANGED
package/src/builtins.js
CHANGED
package/src/cli.js
CHANGED
|
@@ -198,9 +198,17 @@ function makeApproval(ask, cfg) {
|
|
|
198
198
|
} else {
|
|
199
199
|
console.log(panel([JSON.stringify(req.args)], { title: `🔐 ${req.toolLabel}`, color: "yellow" }));
|
|
200
200
|
}
|
|
201
|
-
const raw = await ask(c.yellow("
|
|
201
|
+
const raw = await ask(c.yellow("승인할까요? ") + c.green("[y=승인") + c.yellow(" / n=거부 / ") + c.cyan("a=승인+이후 자동수락]") + " ");
|
|
202
202
|
const ans = (raw || "").trim().toLowerCase();
|
|
203
|
+
if (ans === "a" || ans === "always") {
|
|
204
|
+
cfg.approval_mode = "auto";
|
|
205
|
+
console.log(c.green("✅ 승인 + 자동 수락 ON — 이후엔 묻지 않아요. (해제: /auto)"));
|
|
206
|
+
return { approved: true, reason: "" };
|
|
207
|
+
}
|
|
203
208
|
const approved = ans === "y" || ans === "yes";
|
|
209
|
+
if (!approved) {
|
|
210
|
+
console.log(c.yellow("→ 거부로 처리했어요.") + c.dim(" (엔터는 거부예요 — 승인은 y, 항상 승인은 a 또는 /auto)"));
|
|
211
|
+
}
|
|
204
212
|
streak = approved ? streak + 1 : 0;
|
|
205
213
|
if (approved && streak >= 3 && !hinted && cfg.approval_mode === "manual") {
|
|
206
214
|
hinted = true;
|
|
@@ -376,7 +384,7 @@ function printIntro(cfg) {
|
|
|
376
384
|
const lines = rows.map(([k, v]) => `${c.grey(k.padEnd(9))} ${c.bold(v)}`);
|
|
377
385
|
console.log(panel(lines, { title: "⚙️ CDSA Harness 설정", color: "cyan" }));
|
|
378
386
|
console.log(
|
|
379
|
-
c.bold(c.cyan("👉 처음이세요? /guide ")) + c.dim("
|
|
387
|
+
c.bold(c.cyan("👉 처음이세요? /guide ")) + c.dim("· '/' 만 치면 명령 팔레트 · ") + c.cyan("Tab") + c.dim(" 키로 /명령·@파일 자동완성")
|
|
380
388
|
);
|
|
381
389
|
console.log(
|
|
382
390
|
c.dim("명령: ") +
|
|
@@ -832,9 +840,8 @@ export async function main(argv = []) {
|
|
|
832
840
|
"AI 가 파일을 다룰 ‘작업 폴더’를 정하세요.",
|
|
833
841
|
c.dim("이 폴더 밖은 절대 건드리지 않아요(안전장치)."),
|
|
834
842
|
"",
|
|
835
|
-
` ${c.bold("엔터")}
|
|
836
|
-
` ${c.bold("
|
|
837
|
-
` ${c.bold("경로")} 예) ${c.cyan("./문서")} 또는 ${c.cyan("C:\\작업\\프로젝트")}`,
|
|
843
|
+
` ${c.bold("엔터")} ${c.cyan("지금 이 폴더")} 를 그대로 사용 (터미널답게, 기본)`,
|
|
844
|
+
` ${c.bold("경로")} 따로 격리하고 싶으면 입력 — 예) ${c.cyan("./sandbox")} 또는 ${c.cyan("C:\\작업\\프로젝트")}`,
|
|
838
845
|
],
|
|
839
846
|
{ title: "📁 작업 폴더 설정 (처음 한 번)", color: "cyan" }
|
|
840
847
|
));
|
|
@@ -872,6 +879,21 @@ export async function main(argv = []) {
|
|
|
872
879
|
const low = user.toLowerCase();
|
|
873
880
|
|
|
874
881
|
if (["/quit", "/exit", "quit", "exit", ":q"].includes(low)) break;
|
|
882
|
+
if (user === "/") {
|
|
883
|
+
const skillNames = Object.keys(skills).sort();
|
|
884
|
+
console.log(panel([
|
|
885
|
+
c.bold("대화")+" "+c.cyan("/new /compact /resume /undo /context"),
|
|
886
|
+
c.bold("프로젝트")+" "+c.cyan("/init /memory /workspace"),
|
|
887
|
+
c.bold("모델·설정")+" "+c.cyan("/setup /models /model /provider /auto /status /teach /stream /update"),
|
|
888
|
+
c.bold("확장")+" "+c.cyan("/skills /plugins /mcp"),
|
|
889
|
+
c.bold("기타")+" "+c.cyan("/guide /tutorial /about /config /quit"),
|
|
890
|
+
"",
|
|
891
|
+
c.bold(`스킬 ${skillNames.length}개`)+" "+c.grey(skillNames.slice(0,10).map(s=>"/"+s).join(" ")+(skillNames.length>10?" …":"")),
|
|
892
|
+
"",
|
|
893
|
+
c.dim("💡 Tab 키로 자동완성 — 예: /mi[Tab], /provider o[Tab], @파일[Tab]"),
|
|
894
|
+
], { title: "⌨️ 명령 팔레트", color: "cyan" }));
|
|
895
|
+
continue;
|
|
896
|
+
}
|
|
875
897
|
if (low === "/help") { printHelp(); continue; }
|
|
876
898
|
if (low === "/guide" || low === "/start") { printGuide(); continue; }
|
|
877
899
|
if (low === "/tutorial") { await runTutorial(ask); continue; }
|
|
@@ -1162,7 +1184,14 @@ export async function main(argv = []) {
|
|
|
1162
1184
|
console.log(c.dim(`(스킬 '/${name}' 실행)`));
|
|
1163
1185
|
await runTurn(renderSkill(skills[name], argStr));
|
|
1164
1186
|
} else {
|
|
1165
|
-
|
|
1187
|
+
const { BUILTIN_COMMANDS } = await import("./completion.js");
|
|
1188
|
+
const all = [...BUILTIN_COMMANDS, ...Object.keys(skills).map((s) => "/" + s)];
|
|
1189
|
+
const near = all.filter((n) => n.includes(name.slice(0, 3)) || n.slice(1).startsWith(name[0] || "")).slice(0, 4);
|
|
1190
|
+
console.log(
|
|
1191
|
+
c.yellow(`알 수 없는 명령: /${name}`) +
|
|
1192
|
+
(near.length ? c.dim(" 혹시? ") + c.cyan(near.join(" ")) : "") +
|
|
1193
|
+
c.dim(" · '/' 입력=팔레트 · Tab=자동완성")
|
|
1194
|
+
);
|
|
1166
1195
|
}
|
|
1167
1196
|
continue;
|
|
1168
1197
|
}
|
package/src/config.js
CHANGED
|
@@ -34,7 +34,7 @@ const DEFAULTS = {
|
|
|
34
34
|
api_key: "",
|
|
35
35
|
base_url: "", // OpenAI 호환 사내/폐쇄망 LLM 의 전체 엔드포인트 직접 지정(있으면 우선)
|
|
36
36
|
model: "mock-agent",
|
|
37
|
-
workspace: "
|
|
37
|
+
workspace: ".", // 기본 = 현재 폴더(cwd). Claude Code/OpenCode 와 동일 — 별도 폴더를 만들지 않는다.
|
|
38
38
|
approval_mode: "manual",
|
|
39
39
|
allow_shell: false,
|
|
40
40
|
max_steps: 8,
|
|
@@ -70,7 +70,7 @@ export class Config {
|
|
|
70
70
|
|
|
71
71
|
// CLI 도구이므로 작업 폴더 상대경로는 '현재 폴더' 기준으로 해석한다(직관적).
|
|
72
72
|
workspacePath() {
|
|
73
|
-
let p = this.workspace || "
|
|
73
|
+
let p = this.workspace || ".";
|
|
74
74
|
if (!path.isAbsolute(p)) p = path.resolve(process.cwd(), p);
|
|
75
75
|
return p;
|
|
76
76
|
}
|
package/src/loop.js
CHANGED
|
@@ -135,7 +135,8 @@ export class AgentLoop {
|
|
|
135
135
|
const parts = [
|
|
136
136
|
"# 정체성",
|
|
137
137
|
"당신은 CDSA Harness(made by CDSA) 안에서 동작하는 코딩·업무 에이전트입니다.",
|
|
138
|
-
"
|
|
138
|
+
"작업 폴더의 파일을 도구(list_dir/read_file/search_files/edit_file/write_file)로 직접 읽고·검색하고·수정할 수 있습니다.",
|
|
139
|
+
"'파일에 접근할 수 없다'고 답하지 마세요 — 필요한 도구를 호출하면 됩니다. 도구가 곧 당신의 손입니다.",
|
|
139
140
|
"",
|
|
140
141
|
"# 환경",
|
|
141
142
|
`- 작업 폴더(루트): ${ws}`,
|
package/src/tools.js
CHANGED
|
@@ -86,7 +86,7 @@ export class Toolbox {
|
|
|
86
86
|
const root = this.workspace + path.sep;
|
|
87
87
|
if (candidate !== this.workspace && !candidate.startsWith(root)) {
|
|
88
88
|
throw new ToolError(
|
|
89
|
-
`작업 폴더 밖
|
|
89
|
+
`작업 폴더 밖 경로입니다: ${rel} — 현재 작업 폴더는 ${this.workspace} 입니다. 다른 폴더에서 작업하려면 사용자가 /workspace <경로> 로 변경할 수 있다고 안내하세요.`
|
|
90
90
|
);
|
|
91
91
|
}
|
|
92
92
|
return candidate;
|