cdsa-harness 0.20.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdsa-harness",
3
- "version": "0.20.0",
3
+ "version": "0.20.1",
4
4
  "description": "AI 에이전트의 내부 동작을 단계별로 드러내는 교육용 터미널 하네스. 실시간 스트리밍 + OpenAI/Claude/OpenRouter + MCP + npm 플러그인·크로스포맷 스킬.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/builtins.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // 스킬/플러그인/버전을 바꾼 뒤 `node scripts/gen-builtins.mjs` 로 재생성하세요.
3
3
  import p0 from "../plugins/hwpx_read.mjs";
4
4
 
5
- export const VERSION = "0.20.0";
5
+ export const VERSION = "0.20.1";
6
6
 
7
7
  export const BUILTIN_PLUGINS = [p0];
8
8
 
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(" 작업을 승인하시겠습니까? [y/N] "));
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("명령: ") +
@@ -871,6 +879,21 @@ export async function main(argv = []) {
871
879
  const low = user.toLowerCase();
872
880
 
873
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
+ }
874
897
  if (low === "/help") { printHelp(); continue; }
875
898
  if (low === "/guide" || low === "/start") { printGuide(); continue; }
876
899
  if (low === "/tutorial") { await runTutorial(ask); continue; }
@@ -1161,7 +1184,14 @@ export async function main(argv = []) {
1161
1184
  console.log(c.dim(`(스킬 '/${name}' 실행)`));
1162
1185
  await runTurn(renderSkill(skills[name], argStr));
1163
1186
  } else {
1164
- console.log(c.yellow(`알 없는 명령/스킬: /${name} ${c.cyan("/help")}, ${c.cyan("/skills")} 참고`));
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
+ );
1165
1195
  }
1166
1196
  continue;
1167
1197
  }