feat: 브리프 인터뷰 단계와 브라우저 도구를 넣고 온보딩 말투를 고친다
세 가지를 고친다. 전부 실제 사용에서 드러난 것이다.
1) 0단계에서 가정으로 채우던 것을 인터뷰로 바꾼다
"꽃집 사이트 만들어보자"를 받고 업종 성격·목표 행동·톤·이름을 혼자 정했다.
물어보니 넷 중 넷이 달랐다(일상 구독 → 하이엔드 스튜디오, 문의 하나 → 넷 다,
톤 미정 → 에디토리얼, 이름 지어냄 → 목요일의 화원).
그대로 갔으면 레퍼런스 세 개를 전부 틀린 방향에서 골랐다.
SKILL.md 0단계에 질문 도구로 한 번에 묻는 절차를 넣었다. 무엇을 묻고
무엇을 묻지 않는지, 답이 모순될 때 어떻게 정리하는지까지 적었다.
2) 레퍼런스가 막히면 브라우저를 띄운다
Aesop(403) → Kinto(404) → Hasami(DNS) → MUJI(타임아웃)로 네 번 왕복하고
톤 레퍼런스를 하나도 못 얻었다. 좋은 레퍼런스일수록 봇을 막는다.
galleries.md 에 headed 브라우저로 직접 열어 스크린샷과 실측값을 받는
방법을 넣고, 접근 실패 2회면 바로 전환하도록 규칙을 세웠다.
Playwright 를 선택 의존성으로 잡았다(core/tools.ts).
- 온보딩 마지막에 설치 여부를 묻는다. 건너뛰어도 스킬은 동작한다
- `designpaca tools` 로 상태 확인, `--yes` 로 설치
- 수백 MB 라 --yes 없이는 상태만 보여준다
- MCP 서버는 설치만 하고 등록 명령은 안내만 한다(에이전트 설정을
대신 건드리지 않는다)
3) 온보딩 말투
"이제 브리프를 던져라", "설치해라", "건너뛴다" — 사용자를 향한 문구가
명령조였다. 스킬 문서의 단정한 반말은 의도지만 CLI UI 는 다르다.
전부 존댓말로 바꾸고, 각 단계가 왜 필요한지 설명을 붙였다.
명령조가 다시 섞이지 않도록 검사하는 테스트를 넣었다(테스트 22 → 25개).
This commit is contained in:
parent
eb9f61e907
commit
4e1e5f0073
15 changed files with 486 additions and 39 deletions
|
|
@ -18,7 +18,7 @@ export async function runDoctor(): Promise<number> {
|
|||
if (pruned > 0) console.log(info(`사라진 설치 기록 ${pruned}건을 정리했다`));
|
||||
|
||||
if (manifest.installs.length === 0) {
|
||||
console.log(warn("설치된 곳이 없다. `npx designpaca install` 로 설치해라."));
|
||||
console.log(warn("아직 설치된 곳이 없습니다. `npx designpaca install` 로 설치하실 수 있습니다."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ export async function runDoctor(): Promise<number> {
|
|||
if (rec.version !== version) problems++;
|
||||
if (missing.length > 0) {
|
||||
problems++;
|
||||
console.log(bad(`파일 ${missing.length}개가 사라졌다 — \`designpaca update --force\` 로 복구해라`));
|
||||
console.log(bad(`파일 ${missing.length}개가 보이지 않습니다 — \`designpaca update --force\` 로 복구하실 수 있습니다`));
|
||||
for (const m of missing.slice(0, 5)) console.log(dim(` ${tildify(m.path)}`));
|
||||
}
|
||||
if (modified.length > 0) {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export function printOutcomes(outcomes: InstallOutcome[], dryRun = false): void
|
|||
const verb = dryRun ? "쓸 파일" : "설치됨";
|
||||
console.log(ok(`${o.target} — ${verb} ${o.written}개 ${dim(tildify(o.root))}`));
|
||||
if (o.skipped.length > 0) {
|
||||
console.log(warn(` 직접 수정한 파일이라 건드리지 않았다 (--force 로 덮어쓴다):`));
|
||||
console.log(warn(` 직접 수정하신 파일이라 그대로 두었습니다 (--force 로 덮어쓸 수 있습니다):`));
|
||||
for (const s of fold(o.skipped)) console.log(dim(` ${tildify(s)}`));
|
||||
}
|
||||
}
|
||||
|
|
@ -70,7 +70,7 @@ export function printOutcomes(outcomes: InstallOutcome[], dryRun = false): void
|
|||
export function printNextSteps(targets: TargetId[]): void {
|
||||
console.log(heading("다음 단계"));
|
||||
if (targets.includes("claude-code")) {
|
||||
console.log(info(`Claude Code 를 새로 열고 ${dim("/designpaca")} 를 실행해라`));
|
||||
console.log(info(`Claude Code 를 새로 연 뒤 ${dim("/designpaca")} 를 실행해 주세요`));
|
||||
}
|
||||
if (targets.includes("codex")) {
|
||||
console.log(info(`Codex CLI 에서 designpaca 스킬이 자동으로 잡힌다`));
|
||||
|
|
|
|||
67
packages/cli/src/commands/tools.ts
Normal file
67
packages/cli/src/commands/tools.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import { checkTools } from "@designpaca/core";
|
||||
import { bad, dim, heading, info, ok, table, warn } from "../ui.ts";
|
||||
|
||||
/**
|
||||
* 선택 도구의 상태를 보여주고, 없는 것을 설치한다.
|
||||
*
|
||||
* 온보딩에서 건너뛴 사람과, 나중에 필요해진 사람 모두를 위한 자리다.
|
||||
* `--yes` 없이 비대화형으로 부르면 **상태만 보여주고 아무것도 설치하지 않는다** —
|
||||
* 도구 설치는 수백 MB 를 받는 일이라 조용히 시작하면 안 된다.
|
||||
*/
|
||||
export async function runTools(opts: { install: boolean }): Promise<number> {
|
||||
const status = await checkTools();
|
||||
|
||||
console.log(heading("브라우저 도구"));
|
||||
console.log(
|
||||
table(
|
||||
status.map(({ tool, installed }) => [
|
||||
tool.label,
|
||||
installed ? "설치됨" : dim("설치되지 않음"),
|
||||
]),
|
||||
),
|
||||
);
|
||||
|
||||
const missing = status.filter((s) => !s.installed);
|
||||
|
||||
if (missing.length === 0) {
|
||||
console.log(ok("필요한 도구가 모두 준비돼 있습니다."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
console.log();
|
||||
for (const { tool } of missing) {
|
||||
console.log(`${tool.label} ${dim(`· ${tool.size}`)}`);
|
||||
console.log(` ${dim(tool.why)}`);
|
||||
}
|
||||
|
||||
if (!opts.install) {
|
||||
console.log();
|
||||
console.log(info("설치하시려면 `designpaca tools --yes` 를 실행해 주세요."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
console.log();
|
||||
let failed = 0;
|
||||
const followUps: string[] = [];
|
||||
for (const { tool } of missing) {
|
||||
process.stdout.write(`${tool.label} 설치 중… `);
|
||||
try {
|
||||
await tool.install();
|
||||
console.log("완료");
|
||||
if (tool.followUp) followUps.push(tool.followUp);
|
||||
} catch (err) {
|
||||
failed++;
|
||||
console.log("실패");
|
||||
const first = err instanceof Error ? (err.message.split("\n")[0] ?? err.message) : String(err);
|
||||
console.log(` ${bad(first)}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (followUps.length > 0) {
|
||||
console.log();
|
||||
console.log(warn("아래는 에이전트 설정을 바꾸는 것이라 직접 실행해 주세요."));
|
||||
for (const f of followUps) console.log(` ${f}`);
|
||||
}
|
||||
|
||||
return failed > 0 ? 1 : 0;
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ export async function runUninstall(opts: {
|
|||
);
|
||||
|
||||
if (targets.length === 0) {
|
||||
console.log(warn("제거할 설치 기록이 없다"));
|
||||
console.log(warn("제거할 설치 기록이 없습니다"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export async function runUpdate(opts: { force?: boolean } = {}): Promise<number>
|
|||
const manifest = await readManifest();
|
||||
|
||||
if (manifest.installs.length === 0) {
|
||||
console.log(warn("설치 기록이 없다. `npx designpaca install` 을 먼저 실행해라."));
|
||||
console.log(warn("설치 기록이 없습니다. `npx designpaca install` 을 먼저 실행해 주세요."));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ export async function runUpdate(opts: { force?: boolean } = {}): Promise<number>
|
|||
const stale = manifest.installs.filter((i) => i.version !== version);
|
||||
|
||||
if (stale.length === 0) {
|
||||
console.log(ok("모든 설치가 이미 최신이다"));
|
||||
console.log(ok("설치된 스킬이 모두 최신 버전입니다"));
|
||||
|
||||
// 버전이 같아도 파일이 사라졌거나 수정됐을 수 있다. 조용히 넘기면 사용자가 모른다.
|
||||
let broken = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue