@tienne/gestalt 0.72.7 → 0.72.9

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.
Files changed (49) hide show
  1. package/CLAUDE.md +11 -4
  2. package/README.ko.md +5 -5
  3. package/README.md +5 -5
  4. package/dist/package.json +1 -1
  5. package/dist/plugin/role-agents/explainer/AGENT.md +71 -0
  6. package/dist/plugin/role-agents/explainer/references/audience.md +147 -0
  7. package/dist/plugin/skills/_shared/agent-delegation.md +1 -1
  8. package/dist/plugin/skills/_shared/proactive-routing.md +2 -0
  9. package/dist/plugin/skills/explain/SKILL.md +179 -0
  10. package/dist/src/cli/commands/explain-check.d.ts +11 -0
  11. package/dist/src/cli/commands/explain-check.d.ts.map +1 -0
  12. package/dist/src/cli/commands/explain-check.js +53 -0
  13. package/dist/src/cli/commands/explain-check.js.map +1 -0
  14. package/dist/src/cli/commands/explain-eval.d.ts +110 -0
  15. package/dist/src/cli/commands/explain-eval.d.ts.map +1 -0
  16. package/dist/src/cli/commands/explain-eval.js +272 -0
  17. package/dist/src/cli/commands/explain-eval.js.map +1 -0
  18. package/dist/src/cli/index.d.ts.map +1 -1
  19. package/dist/src/cli/index.js +26 -0
  20. package/dist/src/cli/index.js.map +1 -1
  21. package/dist/src/explain/audience.d.ts +85 -0
  22. package/dist/src/explain/audience.d.ts.map +1 -0
  23. package/dist/src/explain/audience.js +121 -0
  24. package/dist/src/explain/audience.js.map +1 -0
  25. package/dist/src/explain/check.d.ts +83 -0
  26. package/dist/src/explain/check.d.ts.map +1 -0
  27. package/dist/src/explain/check.js +506 -0
  28. package/dist/src/explain/check.js.map +1 -0
  29. package/dist/src/explain/grounding.d.ts +40 -0
  30. package/dist/src/explain/grounding.d.ts.map +1 -0
  31. package/dist/src/explain/grounding.js +114 -0
  32. package/dist/src/explain/grounding.js.map +1 -0
  33. package/dist/src/explain/index.d.ts +5 -0
  34. package/dist/src/explain/index.d.ts.map +1 -0
  35. package/dist/src/explain/index.js +5 -0
  36. package/dist/src/explain/index.js.map +1 -0
  37. package/dist/src/explain/terms.d.ts +71 -0
  38. package/dist/src/explain/terms.d.ts.map +1 -0
  39. package/dist/src/explain/terms.js +266 -0
  40. package/dist/src/explain/terms.js.map +1 -0
  41. package/package.json +1 -1
  42. package/plugin/.codex-plugin/plugin.json +1 -1
  43. package/plugin/.mcp.json +1 -1
  44. package/plugin/mcp.json +1 -1
  45. package/plugin/role-agents/explainer/AGENT.md +71 -0
  46. package/plugin/role-agents/explainer/references/audience.md +147 -0
  47. package/plugin/skills/_shared/agent-delegation.md +1 -1
  48. package/plugin/skills/_shared/proactive-routing.md +2 -0
  49. package/plugin/skills/explain/SKILL.md +179 -0
@@ -0,0 +1,121 @@
1
+ /**
2
+ * 설명 대상 프리셋.
3
+ *
4
+ * 여섯 값이 용어 허용치와 문장 길이, 원문 핵심어를 얼마나 남겨야 하는지, 비유가 필요한지,
5
+ * 어미를 무엇으로 끝낼지를 한꺼번에 정한다. 사람이 읽는 기준은
6
+ * `plugin/role-agents/explainer/references/audience.md`가 말로 정하고 숫자는 이 파일이 갖는다.
7
+ * 두 곳에 같은 숫자를 적으면 갈라지므로 문서는 방향을, 코드는 값을 든다.
8
+ *
9
+ * 임계값이 프리셋마다 다른 이유는 설명이 잘될수록 원문에서 멀어지기 때문이다. 같은 잣대를
10
+ * 들이대면 `outsider`용 좋은 설명이 `peer` 기준으로는 내용을 버린 글이 된다.
11
+ */
12
+ export const AUDIENCES = [
13
+ 'nontech',
14
+ 'junior',
15
+ 'peer',
16
+ 'manager',
17
+ 'exec',
18
+ 'outsider',
19
+ ];
20
+ /**
21
+ * 대상을 안 밝히면 동료 개발자로 본다.
22
+ *
23
+ * 개발 레포 안에서 `outsider`를 기본으로 잡으면 옆자리 개발자에게 일상 비유를 늘어놓는
24
+ * 글이 나간다. 반대 방향 실수가 훨씬 싸다.
25
+ */
26
+ export const DEFAULT_AUDIENCE = 'peer';
27
+ /** 원문에서 핵심어로 볼 상위 몇 개 */
28
+ export const CORE_TERM_COUNT = 5;
29
+ /**
30
+ * 숫자를 고를 때 쓴 기준.
31
+ *
32
+ * 이 값들은 audience.md 의 프리셋 표에서 옮겨온 게 아니다. 그 표는 용어와 비유, 깊이를
33
+ * 말로 정하고 숫자는 여기서 처음 정해진다 — 두 곳에 같은 숫자를 적으면 갈라지므로
34
+ * 문서는 방향을, 코드는 값을 갖는다. 값을 바꿀 때 대조할 곳은 아래 근거지 문서가 아니다.
35
+ *
36
+ * **jargon** — nontech 과 exec 는 어절 200개에 풀이 없는 용어가 하나 나오면 경고(0.005)다.
37
+ * 그보다 잦으면 풀이를 빠뜨린 것이다. outsider 는 그보다 엄격해 하나만 나와도 바로
38
+ * 경고(warn 0)다 — 룰북이 그 대상에게는 우회할 수 없으면 그 얘기를 빼라고 적어서다.
39
+ * peer 는 반대로 거의 안 걸려야 한다 — 재보면 동료용 짧은 문장 하나에 용어 셋이 30%
40
+ * 근처라 그 위(0.35)에 둔다.
41
+ *
42
+ * **sentence** — 기준은 peer 의 70자다. 한글 산문에서 그쯤이면 한 번에 읽히는 끝이다.
43
+ * outsider 는 그 절반(35)이고 나머지는 사이에 둔다.
44
+ *
45
+ * **coverage** — 용어를 허용한 대상만 잰다. 핵심어를 다섯 개 잡으므로 0.6 은 셋, 0.8 은
46
+ * 넷이다. peer 는 넷을 요구하고 manager 는 절반이면 된다. 나머지 셋은 아래 CoverageRule
47
+ * 주석대로 축을 끈다.
48
+ */
49
+ export const PRESETS = {
50
+ nontech: {
51
+ audience: 'nontech',
52
+ who: '기획, 디자인, 마케팅 동료',
53
+ jargon: { warn: 0.005, abort: 0.02 },
54
+ sentence: { warn: 45, abort: 60 },
55
+ coverage: 'off',
56
+ analogy: 'required',
57
+ register: 'polite',
58
+ },
59
+ junior: {
60
+ audience: 'junior',
61
+ who: '주니어 개발자',
62
+ jargon: { warn: 0.06, abort: 0.12 },
63
+ sentence: { warn: 60, abort: 80 },
64
+ coverage: { warn: 0.7, abort: 0.5 },
65
+ analogy: 'recommended',
66
+ register: 'polite',
67
+ },
68
+ peer: {
69
+ audience: 'peer',
70
+ who: '동료 개발자',
71
+ jargon: { warn: 0.35, abort: 0.5 },
72
+ sentence: { warn: 70, abort: 95 },
73
+ coverage: { warn: 0.8, abort: 0.6 },
74
+ analogy: 'off',
75
+ register: 'polite',
76
+ },
77
+ manager: {
78
+ audience: 'manager',
79
+ who: '관리자',
80
+ jargon: { warn: 0.02, abort: 0.05 },
81
+ sentence: { warn: 55, abort: 75 },
82
+ coverage: { warn: 0.5, abort: 0.3 },
83
+ analogy: 'off',
84
+ register: 'formal',
85
+ },
86
+ exec: {
87
+ audience: 'exec',
88
+ who: '경영진',
89
+ jargon: { warn: 0.005, abort: 0.02 },
90
+ sentence: { warn: 50, abort: 70 },
91
+ coverage: 'off',
92
+ analogy: 'off',
93
+ register: 'formal',
94
+ },
95
+ outsider: {
96
+ audience: 'outsider',
97
+ who: '사외 비전문가, 가족',
98
+ jargon: { warn: 0, abort: 0.01 },
99
+ sentence: { warn: 35, abort: 50 },
100
+ coverage: 'off',
101
+ analogy: 'required',
102
+ register: 'polite',
103
+ },
104
+ };
105
+ export function isAudience(value) {
106
+ return AUDIENCES.includes(value);
107
+ }
108
+ /**
109
+ * 값이 없으면 기본값, 모르는 값이면 undefined. 종료 코드는 부르는 쪽이 정한다.
110
+ *
111
+ * 빈 문자열도 안 준 것으로 본다. commander 가 `--audience` 를 값 없이 받으면 그 꼴로 온다.
112
+ */
113
+ export function parseAudience(value) {
114
+ if (value === undefined || value === '')
115
+ return DEFAULT_AUDIENCE;
116
+ return isAudience(value) ? value : undefined;
117
+ }
118
+ export function presetOf(audience) {
119
+ return PRESETS[audience];
120
+ }
121
+ //# sourceMappingURL=audience.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audience.js","sourceRoot":"","sources":["../../../src/explain/audience.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * 설명이 그 대상에게 읽히는 글인지 코드가 판단하는 검사.
3
+ *
4
+ * humanize-check 와 판정 구조만 같고 재는 것은 반대다. 거기는 의미가 보존됐는지를 보고
5
+ * 원문을 절반 넘게 버리면 채택 금지다. 설명은 원문을 많이 버려야 성공이라 그 검사를 그대로
6
+ * 쓰면 잘된 설명일수록 막힌다. 그래서 축을 새로 잡았다 — 용어, 문장 길이, 핵심어 잔존,
7
+ * 비유, 어미, 사실 정확도.
8
+ *
9
+ * 여섯 중 다섯이 결정론이다. LLM 없이 돌고 같은 입력에 같은 점수가 나온다. 심판 모델은
10
+ * 사실이 틀렸는지 하나만 본다 — 그건 코드가 못 재는 자리라서다.
11
+ */
12
+ import { EXIT_CODE, MAX_ATTEMPTS, type Decision, type NextAction, type Verdict } from '../humanize/check.js';
13
+ import type { LLMAdapter } from '../llm/types.js';
14
+ import { type Audience } from './audience.js';
15
+ import { type Grounding } from './grounding.js';
16
+ export { EXIT_CODE, MAX_ATTEMPTS, type Decision, type NextAction, type Verdict };
17
+ export type ExplainAxis = 'jargon' | 'length' | 'grounding' | 'coverage' | 'analogy' | 'register' | 'accuracy';
18
+ /** 심판 모델 없이 도는 축. `--judge` 를 안 켜도 검사가 성립한다는 근거다 */
19
+ export declare const DETERMINISTIC_AXES: readonly ExplainAxis[];
20
+ export interface AxisResult {
21
+ axis: ExplainAxis;
22
+ verdict: Verdict;
23
+ detail: string;
24
+ evidence?: string[];
25
+ }
26
+ export interface ExplainMetrics {
27
+ words: number;
28
+ sentences: number;
29
+ avgSentenceLength: number;
30
+ /** 풀이 없이 남은 용어 출현 수를 어절 수로 나눈 값 */
31
+ jargonDensity: number;
32
+ unglossed: number;
33
+ glossed: number;
34
+ coverage: number;
35
+ coreTerms: string[];
36
+ coveredTerms: string[];
37
+ /** 원문에서 뽑은 전문용어 후보가 상한에서 잘렸나 */
38
+ termsTruncated: boolean;
39
+ grounding: Grounding;
40
+ analogyMarkers: string[];
41
+ register: RegisterStats;
42
+ }
43
+ export interface ExplainReport {
44
+ audience: Audience;
45
+ verdict: Verdict;
46
+ exitCode: number;
47
+ metrics: ExplainMetrics;
48
+ axes: AxisResult[];
49
+ }
50
+ export interface ExplainCheckOptions {
51
+ audience?: Audience;
52
+ }
53
+ export interface RegisterStats {
54
+ polite: number;
55
+ formal: number;
56
+ plain: number;
57
+ }
58
+ /**
59
+ * 어미를 갈래별로 센다.
60
+ *
61
+ * 인용줄을 뺀 산문을 따로 받는 건 남의 말투가 딸려오면 섞임으로 오판하기 때문이다.
62
+ * 그 산문을 만드는 일은 부르는 쪽이 한다 — runExplainCheck 가 같은 필터링을 두 번 태우지
63
+ * 않으려고 미리 만들어 넘긴다. 인자를 안 주면 여기서 만든다.
64
+ */
65
+ export declare function registerStats(text: string, prose?: string): RegisterStats;
66
+ export declare function runExplainCheck(source: string, explanation: string, options?: ExplainCheckOptions): ExplainReport;
67
+ /** 심판 축을 얹고 판정을 다시 낸다. 결정론 축은 그대로 둔다 */
68
+ export declare function withAxis(report: ExplainReport, axis: AxisResult): ExplainReport;
69
+ export interface JudgeInput {
70
+ source: string;
71
+ explanation: string;
72
+ audience: Audience;
73
+ }
74
+ /**
75
+ * 사실 정확도만 심판 모델에게 묻는다.
76
+ *
77
+ * 어댑터를 인자로 받아 이 파일이 설정을 안 읽게 막는다. 결정론 축은 파일만 있으면 돌아야
78
+ * 하는데 설정을 여기서 읽으면 그 조건이 깨진다.
79
+ */
80
+ export declare function judgeAccuracy(adapter: LLMAdapter, input: JudgeInput): Promise<AxisResult>;
81
+ export declare function decide(report: ExplainReport, attempt?: number, maxAttempts?: number): Decision;
82
+ export declare function formatExplainReport(report: ExplainReport, attempt?: number): string;
83
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/explain/check.ts"],"names":[],"mappings":"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"}